计算机博弈六子棋人机人人对弈系统开发

    xiaoxiao2025-07-09  7

    六子棋(Connect6)

    规则: 与“传统的五子棋”(这里指的是没有禁着的五子棋)非常相似, 规则非常简单仅有以下三条: 玩家: 如五子棋及围棋,有黑白两方,各持黑子与白子,黑先。 玩法: 除了第一次黑方下一颗子外,之后黑白双方轮流每次各下两子,直的、横的、斜的连成 6 子(或以上)者获胜。 若全部棋盘填满仍未分出胜负,则为和局。没有禁手;例如长连仍算赢。 棋盘: 因为公平性不是问题,棋盘是可以任意地大,甚至是无限大亦可。然而为了让游戏可实质地来玩,目前棋盘采用围棋的十九路棋盘。

    本文使用代码为纯C代码,适合初学编程的同学理解使用,高级代码详见c#版六子棋代码。 注:C语言很难实现界面交互化,此系统使用的是printf打印刷新方式进行对弈,棋盘打印只适用于win7电脑环境,win10或其他系统会有bug嗷!

    #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <conio.h> #include <time.h> #include <mmsystem.h> void AI(int board[][40], int wcount[][2751], int &player, int &step_num, int &winner, const int entry); /****************************************/ //基础设置 struct Point //点坐标的结构体 { int x,y; }point; void goto_xy(int x, int y) //光标移动函数 { COORD c; c.X = 2*x; c.Y = y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); } void Init(int board[][40], int wcount[][2751], int &step_num) //初始化函数,将记录棋子的数组初始化 { int i, j; for(i = 0; i < 40; i++) {//初始换棋盘状态 for(j = 0; j < 40; j++) { board[i][j] = 0; } } for(i = 0; i < 3; i++) { for(j = 0; j < 2750; j++) { wcount[i][j] = 0; } } srand((unsigned)time(NULL)); step_num = 0; } void Window() //界面设置函数 { system("mode con cols=120 lines=45"); char *pTitle = "六子棋对战"; SetConsoleTitle(pTitle); } /************************************************************************************************/ //菜单设置 void WelcomeInterface() { system("color 3F"); system("cls"); goto_xy(24,16); printf("欢迎来到六子棋对战程序"); Sleep(1000); system("cls"); } void Menu() //主菜单 { system("color 3F"); goto_xy(22,16); printf("→"); goto_xy(27,13); printf(" 主菜单"); goto_xy(24,16); printf(" ***人人对战***"); goto_xy(24,17); printf(" ***人机对战***"); goto_xy(24,18); printf(" ***游戏说明***"); goto_xy(24,19); printf(" ***退出***"); point.y = 16; } void Clean(const int x, const int ymax, const int ymin) //清除→ { int i; for(i = ymin; i <= ymax; i++) { goto_xy(x, i); printf(" "); } } void menu_choose(int button, int &choice, int x, int ymax, int ymin) //菜单选择函数 { switch(button) { case 72: //↑ if(point.y != ymin) point.y--; else point.y = ymax; break; case 80: //↓ if(point.y != ymax) point.y++; else point.y = ymin; break; case 13: //回车 choice = point.y; break; default: ; } Clean(x, ymax, ymin); goto_xy(x, point.y); printf("→"); } /************************************************************************************************/ //棋盘显示设置 void ShowWho_renren(const int player) //显示轮到哪一方下棋 { goto_xy(23, 35); if(player == 1) { printf("轮到甲方落子"); } else { printf("轮到乙方落子"); } goto_xy(point.x, point.y); } void ShowWho_renji(const int player) //显示轮到哪一方下棋 { goto_xy(23, 35); if(player == 1) { printf("轮到电脑落子"); } else { printf("轮到玩家落子"); } goto_xy(point.x, point.y); } void Draw() //绘画游戏界面 { struct Point game_xy; game_xy.x = 10; game_xy.y = 3; system("cls"); system("color 3F"); goto_xy(1, 23); printf("退出 ESC"); goto_xy(1, 24); printf("提示 F10"); const int i = 9; const int j = 31; const int k = 3; goto_xy(game_xy.x-i, game_xy.y+k); //输出甲方 printf("甲方: ●"); goto_xy(game_xy.x-i, game_xy.y+k+2); printf("移动: 上 ↑"); goto_xy(game_xy.x-i, game_xy.y+k+4); printf(" 下 ↓"); goto_xy(game_xy.x-i, game_xy.y+k+6); printf(" 左 ←"); goto_xy(game_xy.x-i, game_xy.y+k+8); printf(" 右 →"); goto_xy(game_xy.x-i, game_xy.y+k+10); printf("落子: Enter"); goto_xy(game_xy.x+j, game_xy.y+k); //输出乙方 printf("乙方: ¤"); goto_xy(game_xy.x+j, game_xy.y+k+2); printf("移动: 上 ↑"); goto_xy(game_xy.x+j,game_xy.y+k+4); printf(" 下 ↓"); goto_xy(game_xy.x+j, game_xy.y+k+6); printf(" 左 ←"); goto_xy(game_xy.x+j, game_xy.y+k+8); printf(" 右 →"); goto_xy(game_xy.x+j, game_xy.y+k+10); printf("落子: Enter"); for(int l = 0; l < 30; l++) //画棋盘 { if(l == 0) //画第一行 { goto_xy(10, l+3); printf("┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐"); } if(l !=0 && l != 29) //画出中间28行 { goto_xy(10, l+3); printf("├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤"); } if(l == 29) //画最后一行 { goto_xy(10, l+3); printf("└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘"); } } } /***********************************************************************************************/ //六子棋核心部分(先后手,胜负判定,棋盘记录) void Player_Random(int &player) //棋手随机程序 { player = 1; } void Record(int board[][40], int wcount[][2751], const int player) //记录棋子、棋手的情况 { board[point.x][point.y] = player; //棋盘状态记录 0表示空 1表示甲 2表示乙 int k; int x, y; int flag; int anti; x = point.x - 9; y = point.y - 2; anti = (player == 1 ? 2 : 1); for(k = 0; k < 6; k++) { if(x - k <= 25 && x - k >= 1) { flag = 25*(y-1)+x-k; if(wcount[player][flag] != -1) { wcount[player][flag]++; wcount[anti][flag] = -1; } else { wcount[anti][flag] = -1; } } if(y - k <= 25 && y - k >= 1) { flag = 30*(y-1-k)+x+750;; if(wcount[player][flag] != -1) { wcount[player][flag]++; wcount[anti][flag] = -1; } else { wcount[anti][flag] = -1; } } if(x - k <= 25 && x - k >= 1 && y - k <= 25 && y - k >= 1) { flag = 25*(y-1-k)+x-k+1500; if(wcount[player][flag] != -1) { wcount[player][flag]++; wcount[anti][flag] = -1; } else { wcount[anti][flag] = -1; } } if(x + k <= 30 && x + k >= 6 && y - k <= 25 && y - k >= 1) { flag = 25*(y-1-k)+x-5+k+2125; if(wcount[player][flag] != -1) { wcount[player][flag]++; wcount[anti][flag] = -1; } else { wcount[anti][flag] = -1; } } } goto_xy(point.x, point.y); } int Judge(int wcount[][2751], const int player) //胜负判断 { int i; int temp; int anti; anti = (player == 1 ? 2 : 1); temp = 0; for(i = 1; i < 2751; i++) { if(wcount[player][i] >= 0) { temp++; if(wcount[player][i] == 6) { return player; } } } if(!temp) { for(i = 1; i < 2751; i++) { if(wcount[anti][i] >= 0) { temp++; } } } if(temp) return 0; else return 3; //平局 } void PutDown(int board[][40], int wcount[][2751], int &player, int &step_num, int &winner) //显示落子函数 { if(!board[point.x][point.y]) //先判断该位置是否有棋子 { if(player == 1) printf("●"); else printf("¤"); Record(board, wcount, player); winner = Judge(wcount, player); step_num++; //交换棋手 if(step_num==1||step_num==2) player=2; else if(step_num==3 || step_num==4) player=1; else { if((step_num-1)%4==0 || (step_num-2)%4==0) player=2; else player=1; } } } void HideFlag(const int board[][40]) { if(!board[point.x][point.y]) { if(point.x == 10) //绘制左栏 { if(point.y == 3) { printf("┌"); } else { if(point.y == 32) { printf("└"); } else { printf("├"); } } } else { if(point.x == 39) //绘制右栏 { if(point.y == 3) { printf("┐"); } else { if(point.y == 32) { printf("┘"); } else { printf("┤"); } } } else { if(point.y == 3) //填充中间部分 { printf("┬"); } else { if(point.y == 32) { printf("┴"); } else { printf("┼"); } } } } } goto_xy(point.x, point.y); //回到原光标位置 } void ShowFlag(const int board[][40]) { if(!board[point.x][point.y]) { printf("□"); } } void Play(int board[][40], int wcount[][2751], int &player, int &step_num, char ch, int &winner) //键盘的操作 移动光标 下棋和悔棋操作 { HideFlag(board); if(ch == 72) //↑的控制码 光标上移 { if(point.y <= 3) point.y = 32; else point.y--; goto_xy(point.x, point.y); } if(ch == 75) //←的控制码 光标左移 { if(point.x <= 10) point.x = 39; else point.x--; goto_xy(point.x, point.y); } if(ch == 77) //→的控制码 光标右移 { if(point.x >= 39) point.x = 10; else point.x++; goto_xy(point.x, point.y); } if(ch == 80) //↓的控制码 光标下移 { if(point.y >= 32) point.y = 3; else point.y++; goto_xy(point.x, point.y); } if(ch != 13 && ch != 68) ShowFlag(board); if(ch == 13) //回车键的控制码 下棋 { PutDown(board, wcount, player, step_num, winner); } if(ch == 68) { struct Point temp; temp = point; AI(board, wcount, player, step_num, winner, 0); ShowFlag(board); goto_xy(point.x, point.y); Sleep(1000); HideFlag(board); point = temp; goto_xy(point.x, point.y); ShowFlag(board); } } /*****************************************************************************************************/ //AI核心 void Grade(const int board[][40], const int wcount[][2751], int table[][40], int ply) //棋盘评分的程序,给予棋盘每个点一定的分数 { int x, y, k; int temp = 0; int anti; anti = (ply == 1 ? 2 : 1); /*六连=888888(极值),活五=2500,冲五=600,双活四=400 单活四加200,每个眠四加100,每个活三加50,每个眠三加10 每个活二加4, 每个眠二加1*/ for(x = 10; x <= 39; x++) { for(y = 3; y <= 32; y++) { for(k = 0; k < 6; k++) { if(x-k >= 10 && x-k <= 34) { temp = 0; if(x-k == 10 || board[x-k-1][y] == anti) temp++; if(x-k == 34 || board[x-k+6][y] == anti) temp++; switch(wcount[ply][25*(y-2-1)+x-9-k]) { case 1: if(temp == 0) table[x][y] += 4; else table[x][y] += 1; break; case 2: if(temp == 0) table[x][y] += 50; else table[x][y] += 10; break; case 3: if(temp == 0) { table[x][y] += 400; break; } if(temp == 1) { table[x][y] += 200; break; } if(temp == 2) { table[x][y] += 100; break; } case 4: if(temp == 0) table[x][y] += 2500; else table[x][y] += 600; case 5: table[x][y] += 888888; break; default: ; } } else { table[x][y] += 0; } if(y-k >= 3 && y-k <= 27) { temp = 0; if(y-k == 3 || board[x][y-k-1] == anti) temp++; if(y-k == 27 || board[x][y-k+6] == anti) temp++; switch(wcount[ply][30*(y-2-k-1)+x-9+750]) { case 1: if(temp == 0) table[x][y] += 4; else table[x][y] += 1; break; case 2: if(temp == 0) table[x][y] += 50; else table[x][y] += 10; break; case 3: if(temp == 0) { table[x][y] += 400; break; } if(temp == 1) { table[x][y] += 200; break; } if(temp == 2) { table[x][y] += 100; break; } case 4: if(temp == 0) table[x][y] += 2500; else table[x][y] += 600; case 5: table[x][y] += 888888; break; default: ; } } else { table[x][y] += 0; } if(x-k >= 10 && x-k <= 34 && y-k >= 3 && y-k <= 27) { temp = 0; if(x-k == 10 || y-k == 3 || board[x-k-1][y-k-1] == anti) temp++; if(x-k == 34 || y-k == 27 || board[x-k+6][y-k+6] == anti) temp++; switch(wcount[ply][25*(y-2-k-1)+x-9-k+1500]) { case 1: if(temp == 0) table[x][y] += 4; else table[x][y] += 1; break; case 2: if(temp == 0) table[x][y] += 50; else table[x][y] += 10; break; case 3: if(temp == 0) { table[x][y] += 400; break; } if(temp == 1) { table[x][y] += 200; break; } if(temp == 2) { table[x][y] += 100; break; } case 4: if(temp == 0) table[x][y] += 2500; else table[x][y] += 600; case 5: table[x][y] += 888888; break; default: ; } } else { table[x][y] += 0; } if(x+k >= 15 && x+k <= 39 && y-k >= 3 && y-k <= 27) { temp = 0; if(x+k == 39 || y-k == 3 || board[x+k+1][y-k-1] == anti) temp++; if(x+k == 15 || y-k == 27 || board[x+k-6][y-k+6] == anti) temp++; switch(wcount[ply][25*(y-2-k-1)+x-9+k-5+2125]) { case 1: if(temp == 0) table[x][y] += 4; else table[x][y] += 1; break; case 2: if(temp == 0) table[x][y] += 50; else table[x][y] += 10; break; case 3: if(temp == 0) { table[x][y] += 400; break; } if(temp == 1) { table[x][y] += 200; break; } if(temp == 2) { table[x][y] += 100; break; } case 4: if(temp == 0) table[x][y] += 2500; else table[x][y] += 600; case 5: table[x][y] += 888888; break; default: ; } } else { table[x][y] += 0; } } } } } void Search(const int table[][40], const int player, int &x, int &y, int board[][40]) //搜索函数 找出评分表中分值最大的位置 { int i, j; double max; int num = 0, time = 0; max = 0.; for(i = 10; i <= 39; i++) { for(j = 3; j <= 32; j++) { if(!board[i][j] && table[i][j] && table[i][j] > max) { max = table[i][j]; } } } if(!board[24][17] && !max) { x = 24; y = 17; return; } for(i = 10; i <= 39; i++) { for(j = 3; j <= 32; j++) { if(!board[i][j] && table[i][j] == max) { time++; } } } num = rand() % time + 1; for(i = 10; i <= 39; i++) { for(j = 3; j <= 32; j++) { if(!board[i][j] && table[i][j] == max) { num--; } if(!num) { x = i; y = j; return; } } } } void AI(int board[][40], int wcount[][2751], int &player, int &step_num, int &winner, const int entry) //AI函数 先调用评分函数,对双方棋盘评分, 再调用搜索函数,找出最优位置 { int x1_max, y1_max; int x2_max, y2_max; int table_cmp[40][40]={0}; int table_ply[40][40]={0}; Grade(board, wcount, table_cmp, 1); Grade(board, wcount, table_ply, 2); Search(table_cmp, 1, x1_max, y1_max, board); Search(table_ply, 2, x2_max, y2_max, board); if(table_cmp[x1_max][y1_max] >= table_ply[x2_max][y2_max]) { point.x = x1_max; point.y = y1_max; } else { point.x = x2_max; point.y = y2_max; } goto_xy(point.x, point.y); if(entry) PutDown(board, wcount, player, step_num, winner); } /**************************************************************************************************************/ void renren() //人人对战 { while(1) { char button1; char button2; int winner = 0; //记录游戏中的胜者 0表示无胜者 1表示甲胜 2表示乙胜 3表示平局 int player = 0; //棋手 1表示甲 2表示乙 int step_num = 0; //步数记录 int board[40][40]; //棋盘记录 int wcount[3][2751]; system("cls"); Init(board, wcount, step_num); Draw(); Player_Random(player); point.x = 24; point.y = 17; //起始点初始化 goto_xy(point.x, point.y); printf("□"); while(!winner) { ShowWho_renren(player); button1 = getch(); if(button1 == 27) return; Play(board, wcount, player, step_num, button1, winner); } goto_xy(23, 35); switch(winner) { case 1: printf("恭喜!甲方获胜"); break; case 2: printf("恭喜!乙方获胜"); break; default: printf(" "); goto_xy(23,35); printf("平局"); } goto_xy(23,36); printf("是否继续(y/n)"); while(button2 != 'y' && button2 != 'Y') { button2 = getch(); switch(button2) { case 'y': break; case 'Y': break; case 'n': if(MessageBox(NULL, TEXT("确定退出游戏吗?"), TEXT("退出"), MB_ICONQUESTION|MB_OKCANCEL)==IDOK) { system("cls"); printf("\n\n 谢谢使用!\n"); Sleep(1000); exit(0); } else { break; } case 'N': if(MessageBox(NULL, TEXT("确定退出游戏吗?"), TEXT("退出"), MB_ICONQUESTION|MB_OKCANCEL)==IDOK) { system("cls"); printf("\n\n 谢谢使用!\n"); Sleep(1000); exit(0); } else { break; } default: ; } } } } void renji() //人机对战 { while(1) { char button1; char button2; int winner = 0; //记录游戏中的胜者 0表示无胜者 1表示甲胜 2表示乙胜 3表示平局 int player = 0; //棋手 1表示甲 2表示乙 int step_num = 0; //步数记录 int board[40][40]; //棋盘记录 int wcount[3][2751]; int speed = 0; char button; int i = 15; system("cls"); goto_xy(25,14); printf("请选择电脑下棋速度:1-10"); for(i = 15; i <= 24; i++) { goto_xy(30,i); printf("%d", i-14); } goto_xy(28,15); printf("→"); point.x = 28; point.y = 15; while(!speed) { button = getch(); menu_choose(button, speed, 28, 24, 15); } speed -= 14; system("cls"); Init(board, wcount, step_num); Draw(); Player_Random(player); point.x = 24; point.y = 17; //起始点初始化 goto_xy(point.x, point.y); printf("□"); while(!winner) { ShowWho_renji(player); if(player == 1) { Sleep(200*speed); AI(board, wcount, player, step_num, winner, 1); } else { button1 = getch(); if(button1 == 27) return; Play(board, wcount, player, step_num, button1, winner); } } goto_xy(23, 35); switch(winner) { case 1: printf("恭喜!电脑获胜"); break; case 2: printf("恭喜!玩家获胜"); break; default: printf(" "); goto_xy(23,35); printf("平局"); } goto_xy(23,36); printf("是否继续(y/n)"); while(button2 != 'y' && button2 != 'Y') { button2 = getch(); switch(button2) { case 'y': break; case 'Y': break; case 'n': if(MessageBox(NULL, TEXT("确定退出当前游戏吗?"), TEXT("退出"), MB_ICONQUESTION|MB_OKCANCEL)==IDOK) { return; } else { break; } case 'N': if(MessageBox(NULL, TEXT("确定退出当前游戏吗?"), TEXT("退出"), MB_ICONQUESTION|MB_OKCANCEL)==IDOK) { return; } else { break; } default: ; } } } } /*****************************************************************************************************/ //游戏说明 void Page1() { goto_xy(22,20); printf("欢迎来到六子棋对战游戏"); goto_xy(22,21); printf("下面将对游戏做基本的介绍"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page2() { goto_xy(22,20); printf("本游戏共两种模式,分别为"); goto_xy(15,23); printf("----------"); goto_xy(15,24); printf("|人人对战|"); goto_xy(15,25); printf("----------"); goto_xy(36,23); printf("----------"); goto_xy(36,24); printf("|人机对战|"); goto_xy(36,25); printf("----------"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page3() { goto_xy(20,20); printf("游戏中共有三种类型棋子,分别为"); goto_xy(24,23); printf("●:甲方棋子"); goto_xy(24,24); printf("¤:乙方棋子"); goto_xy(24,25); printf("□:光标所在位置,即要落子的位置"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page4() { goto_xy(23,20); printf("人人对战模式中:"); goto_xy(18,21); printf("玩家一为甲方,执:●"); goto_xy(32,21); printf("玩家二为乙方,执:¤"); goto_xy(23,24); printf("人机对战模式中:"); goto_xy(18,25); printf("电脑为甲方,执:●"); goto_xy(32,25); printf("玩家为乙方,执:¤"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page5() { goto_xy(18,20); printf("游戏中先后手与执棋颜色无关,在开局时随机决定"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page6() { goto_xy(20,20); printf("在对局中可以按ESC返回主界面"); goto_xy(20,21); printf("在对局中按F11可以提示适合的落子位置"); goto_xy(20,22); printf("对局结束后按Y则继续游戏,按N则返回主菜单"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 下一页"); goto_xy(50,42); printf("退出 ESC"); } void Page7() { goto_xy(23,20); printf("欢迎进行六子棋对决"); goto_xy(22,42); printf("← 上一页"); goto_xy(30,42); printf("→ 返回主菜单"); goto_xy(50,42); printf("退出 ESC"); } void Page(const int num) { system("cls"); switch(num) { case 1: Page1(); break; case 2: Page2(); break; case 3: Page3(); break; case 4: Page4(); break; case 5: Page5(); break; case 6: Page6(); break; case 7: Page7(); break; default: ; } } void Instruction() { int pagenum = 1; char button; while(1) { Page(pagenum); button = getch(); while(button == 27) return; switch(button) { case 75: if(pagenum <= 1) ; else pagenum--; break; case 77: if(pagenum >= 7) return; else pagenum++; break; default: ; } } } /*****************************************************************************************************/ void Run(char choice) //不同模式调用函数 { switch(choice) { case 16: renren(); break; case 17: renji(); break; case 18: Instruction(); break; case 19: if(MessageBox(NULL, TEXT("确定退出游戏吗?"), TEXT("退出"), MB_ICONQUESTION|MB_OKCANCEL)==IDOK) { goto_xy(25,19); printf("谢谢使用"); Sleep(1000); exit(0); } default: ; } } int main() //主函数 { while(1) { int choice = 0; char button; Window(); WelcomeInterface(); Menu(); while(!choice) { button = getch(); menu_choose(button, choice, 22, 19, 16); } system("cls"); Run(choice); } }

    界面:

    最新回复(0)