这里写目录标题
最终效果菜单打印函数棋盘的初始化和打印人人对战落子判空函数悔棋函数判胜负函数人人对战 人机对战一是将直接调用rand生成随机值,这就不可控二是根据棋子赢面来判断哪里落子最好 如果选择退出程序直接exit就行主函数调用逻辑源代码
最终效果
五子棋c语言实现
菜单打印函数
使用这个函数来接收用户选择的模式,并通过返回值返回。
逻辑是使用一个死循环来打印,根据玩家输入的数来判断进入什么模式,输入错误数字就不出循环,正确就出循环。
int menu(){ int choice = -1; while (1) { printf("----------------欢迎使用五子棋------------------------\n"); printf("- 请选择模式 -\n"); printf("- 1.人-人对战游戏 -\n"); printf("- 2.人-机对战游戏 -\n"); printf("- 0.退出游戏 -\n"); printf("------------------------------------------------------\n"); printf("------------------------------------------------------\n"); scanf("%d", &choice); if (choice > 4 || choice < 0) printf("错误输入"); else break; } return choice;}
棋盘的初始化和打印
在这个函数中将表示棋盘的二维数组初始化为空状态,并通过棋盘数组的只来打印棋盘。打印棋盘时用到的符号:┏ ┳ ┓┣ ╋ ┫┗ ┻ ┛。要注意有些地方添加━和空格来控制打印的棋盘是正确的。
里面每一次打印都调用draw_chessman这个函数,在这个函数中将根据数组值来判断如何打印。
//绘制棋子void draw_chessman(int type, char* tableline) { if (type == WHITE) printf(" ●"); if (type == BLACK) printf(" ○"); if (type == NO) printf("%s", tableline);}
打印棋盘的逻辑就是因为没能设置光标坐标那就只有一行一行打印然后根据边界行列值来判断。
如果要看如何打印改变光标可以参考这篇文章win32 API
void initMap(int map[N + 1][N + 1]){ //第一行和第一列显示数字 for (int i = 0; i < N + 1; i++) { map[0][i] = i; map[i][0] = i; if (i >= 10) { map[0][i] = i - 10; map[i][0] = i - 10; } } for (int i = 0; i < N + 1; i++) { //打印第一行数字 if (i == 0) { for (int j = 0; j < N + 1; j++) { printf("%-2d", map[0][j]); } printf("\n"); } //打印第一行棋盘 else if (i == 1) { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┏"); else if (j == N) draw_chessman(map[i][j], "━┓"); else draw_chessman(map[i][j], "━┳"); } printf("\n"); } //打印最后一行 else if (i == N) { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┗"); else if (j == N) draw_chessman(map[i][j], "━┛"); else draw_chessman(map[i][j], "━┻"); } printf("\n"); } else { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┣"); else if (j == N) draw_chessman(map[i][j], "━┫"); else draw_chessman(map[i][j], "━╋"); } printf("\n"); } }}
人人对战
人人对战逻辑中就是先让黑方下棋,输入坐标,输入错误就再次输入(死循环实现),将该坐标的二维数组值变为黑,然后让其选择悔不悔棋,我实现的是只要1是悔棋其他数字就是不悔棋。执行完不悔棋后就判断是否胜利,如果胜就跳出选择是否重来一局,如果没胜就白棋下执行相同逻辑。
落子判空函数
在这个函数中判断坐标代表的二维数组值是不是空,不是就重新输入坐标。
void judgeEmpty(int map[][N + 1], int x, int y, int goal){ while (1) { if (map[x][y] != NO) { printf("已有棋子,重新输入\n"); scanf("%d%d", &x, &y); } else { map[x][y] = goal; initMap(map); break; } }}
悔棋函数
该函数里面就是根据用户选择,如果悔棋然后将刚才的地方的数组值变回空。
int retract(int map[][N + 1], int x, int y){ int choice = -1; printf("是否悔棋:是1\n"); scanf("%d", &choice); if (choice == 1) { map[x][y] = NO; initMap(map); } return choice;}
执行完不悔棋后就判断是否胜利
判胜负函数
这个函数就是将下的这个棋子的横竖斜方向判胜负。(没有判断和棋情况),如果要判断就是二维数组全不为空状态,使用遍历判断就行。
int judgeWin(int map[][N + 1], int x, int y){ for (int i = 1; i < N + 1; i++) { for (int j = 1; j < N + 1; j++) { if (j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//横 { if (map[i][j] == map[i][j + 1] && map[i][j + 1] == map[i][j + 2] && map[i][j + 2] == map[i][j + 3] && map[i][j + 3] == map[i][j + 4]) return map[i][j]; } if (i < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//竖 { if (map[i][j] == map[i + 1][j] && map[i + 1][j] == map[i + 2][j] && map[i + 2][j] == map[i + 3][j] && map[i + 3][j] == map[i + 4][j]) return map[i][j]; } if (i < N + 1 - 4 && j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右下_ { if (map[i][j] == map[i + 1][j + 1] && map[i + 1][j + 1] == map[i + 2][j + 2] && map[i + 2][j + 2] == map[i + 3][j + 3] && map[i + 3][j + 3] == map[i + 4][j + 4]) return map[i][j]; } if (i > 4 && j > 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右上 { if (map[i][j] == map[i - 1][j - 1] && map[i - 1][j - 1] == map[i - 2][j - 2] && map[i - 2][j - 2] == map[i - 3][j - 3] && map[i - 3][j - 3] == map[i - 4][j - 4]) return map[i][j]; } } } return NO;}
人人对战
void peopleFight(int map[][N + 1]){ printf("--------人-人对战---------------\n"); initMap(map); while (1) { int x = -1; int y = -1; black: while (1) { printf("黑方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, BLACK); if (retract(map, x, y) == 1) goto black; //判断胜利 int ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } white: while (1) { printf("白方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, WHITE); if (retract(map, x, y) == 1) goto white; //判断胜利 ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } }}
人机对战
在这个函数中用户选择落子方,然后执行逻辑与人人对战一样。
但是电脑生成棋子提供两种选择:
一是将直接调用rand生成随机值,这就不可控
方法一这样写对棋子的位置生成是很不可控的,会让机器随机乱落子。
void machine(int map[][N + 1]){ printf("--------人-机对战---------------\n"); srand(time(NULL)); int choice = -1; printf("请输入你执黑棋还是白棋,黑1,白2\n"); scanf("%d", &choice); if (choice == 1) { while (1) { int x = -1; int y = -1; black: while (1) { printf("黑方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, BLACK); //判断胜利 int ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } if (retract(map, x, y) == 1) goto black; next: x = rand() % 15 + 1; y = rand() % 15 + 1; if (map[x][y] != NO) goto next; judgeEmpty(map, x, y, WHITE); //判断胜利 ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } } } else if (choice == 2) { while (1) { int x = -1; int y = -1; next2: x = rand() % 15 + 1; y = rand() % 15 + 1; if (map[x][y] != NO) goto next2; judgeEmpty(map, x, y, BLACK); //判断胜利 int ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } white: while (1) { printf("白方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, WHITE); //判断胜利 ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } if (retract(map, x, y) == 1) goto white; } }}
二是根据棋子赢面来判断哪里落子最好
这样实现就会让机器落子一直是去围堵你的棋子,虽然还是很垃圾,但是比方法一好多了。
void AIjudge(int color, int map[N+1][N+1]){ int num = 1, left = 0, right = 0; int n, m, score = 0, max = 0; int dx, dy; for (int i = 1; i < N+1; i++) { for (int j = 1; j < N+1; j++) { score = 0; if (map[i][j] != 0) continue; else { dx = 1, dy = 0, n = i, m = j; while (1)//水平向右 { n += dx, m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || n > 15) { right++; break; } else if (num < 5) { num++; } } dx = -1, dy = 0; while (1) {//水平向左 n += dx; m += dy; if (map[n][m] == 0) { left = 0; break; } else if (map[n][m] != color || n < 1) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left);//用data来算分数,并用score来记录 // |方向 num = 1; right = 0, left = 0;//每一次改变方向要重置这些变量 dx = 0; dy = -1; n = i; m = j; //向上 while (1) { n += dx; m += dy; if (map[n][m] == 0) { left = 0; break; } else if (map[n][m] != color || m < 1) { left++; break; } else if (num < 5) { num++; } } //向下 dx = 0; dy = 1; n = i; m = j; while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || m > 15) { right++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); // \方向 num = 1; right = 0, left = 0; dx = 1; dy = 1; n = i; m = j; //向右下 while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || m > 15 || n > 15) { right++; break; } else if (num < 5) { num++; } } //向左上 dx = -1; dy = -1; n = i; m = j; while (1) { n += dx; m += dy; if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; } else if ((n > 0 && m > 0 && map[n][m] != color) || m < 1 || n < 1) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); // /方向` num = 1; right = 0, left = 0; dx = 1; dy = -1; n = i; m = j; //向右上 while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || n > 15 || m < 1) { right++; break; } else if (num < 5) { num++; } } //向左下 dx = -1; dy = 1; n = i; m = j; while (1) { n += dx; m += dy; if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; } else if ((n > 0 && m > 0 && map[n][m] != color) || n < 1 || m > 15) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); if (score > max) {//每一次用max保存分数,下一次比较,最后找出最大值 max = score; position[0] = i;//用来保存每一次的位置和分数 position[1] = j; position[2] = score; } } } }}int Data(int num, int count){ switch (num) { case 1:if (count == 0)//活一:表示在该处落子,就只有这一个棋子,两边都没有阻挡(边界或对方的棋子)优势较大 return 2; else if (count == 1)//冲一:表示在该处落子,就只有这一个棋子,两边有一种阻挡(边界或对方的棋子)优势较小 return 1; else return 0; break; case 2: if (count == 0)//活二;接下来都同理活一和冲一 return 20; else if (count == 1)//冲二 return 10; else return 0; break; case 3: if (count == 0)//活三 return 300; else if (count == 1)//冲三 return 50; else return 0; break; case 4: if (count == 0)//活四 return 4000; else if (count == 1)//冲四 return 1000; else return 0; break; case 5://五 return 5000; break; default: return 0; break; }}void machine(int map[][N + 1]){ printf("--------人-机对战---------------\n"); int choice = -1; do { printf("请输入你执黑棋还是白棋,黑1,白2\n"); scanf("%d", &choice); } while (choice != 1 && choice != 2); initMap(map); if (choice == 1) { while (1) { int x = -1; int y = -1; black: while (1) { printf("黑方落子\n"); printf("现在棋盘为%d*%d请输入要落下的坐标x y\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, BLACK); if (retract(map, x, y)) { map[x][y] = 0; initMap(map); goto black; } int ret = judgeWin(map, x, y); if (ret == BLACK) //判断胜利 break; int old_max = 0, new_max = 0, n = 0, m = 0; int AIx = -1, AIy = -1; AIjudge(1, map);//判断黑子的优势位置 old_max = position[2];//保存该位置分数 AIx = position[0]; AIy = position[1];//保存该位置的坐标,注意行列和xy轴的对应关系 position[0] = 0, position[1] = 0, position[2] = 0; AIjudge(-1, map);//判断白子的优势位置 new_max = position[2];//保存分数 if (new_max >= old_max) //判断哪个位置的分数大,从而判断是堵截还是进攻 { AIx = position[0]; AIy = position[1]; } judgeEmpty(map, AIx, AIy, WHITE); ret = judgeWin(map, x, y); if (ret == WHITE) //判断胜利 break; } } else if (choice == 2) { while (1) { int x = -1, y = -1; int old_max = 0, new_max = 0, n = 0, m = 0; int AIx = -1, AIy = -1; AIjudge(1, map);//判断黑子的优势位置 old_max = position[2];//保存该位置分数 AIx = position[0]; AIy = position[1];//保存该位置的坐标,注意行列和xy轴的对应关系 position[0] = 0, position[1] = 0, position[2] = 0; AIjudge(-1, map);//判断白子的优势位置 new_max = position[2];//保存分数 if (new_max >= old_max) //判断哪个位置的分数大,从而判断是堵截还是进攻 { AIx = position[0]; AIy = position[1]; } judgeEmpty(map, AIx, AIy, BLACK); int ret = judgeWin(map, x, y); if (ret == BLACK) //判断胜利 break; white: while (1) { printf("白方落子\n"); printf("现在棋盘为%d*%d请输入要落下的坐标x y\n", N, N); scanf("%d,%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, WHITE); if (retract(map, x, y)) { map[x][y] = 0; initMap(map); goto white; } ret = judgeWin(map, x, y); if (ret == WHITE) //判断胜利 break; } }}
如果选择退出程序直接exit就行
主函数调用逻辑
用死循环调用,然后根据menu返回值通过switch-case来调用相应模式函数,最后在让用户选择是否再来一局,如果再来一局就不出循环,不再来就出循环。
int main(){ while (1) { int map[N + 1][N + 1] = { 0 }; int choice = menu(); switch (choice) { case 1: //调用人人对打 peopleFight(map); break; case 2: //调用人机对打 machine(map); break; case 0: printf("退出成功\n"); exit(0); break; } int a = 0; printf("是否再来一盘:是1,不是0\n"); scanf("%d", &a); if (a == 0) break; } return 0;}
源代码
源码呈上,为方便复制写在同一个文件之下,可以多文件进行。
# define _CRT_SECURE_NO_WARNINGS 1;#include<stdio.h>#include <stdlib.h>#include<time.h>#define N 15 //表示棋盘的行列#define NO 0 //表示没下子的状态#define BLACK 1#define WHITE -1//棋盘初始化函数void initMap(int map[N + 1][N + 1]);//落子函数void judgeEmpty(int map[][N + 1], int x, int y, int goal);//人人对打void peopleFight(int map[][N + 1]);//判断胜利int judgeWin(int map[][N + 1], int x, int y);//悔棋int retract(int map[][N + 1], int x, int y);//人机对打void machine(int map[][N + 1]);//打印菜单并返回选择的模式int menu();void AIjudge(int color, int map[N + 1][N + 1]);int Data(int num, int count);int position[3];int main(){ while (1) { int map[N + 1][N + 1] = { 0 }; int choice = menu(); switch (choice) { case 1: //调用人人对打 peopleFight(map); break; case 2: //调用人机对打 machine(map); break; case 0: printf("退出成功\n"); exit(0); break; } int a = 0; printf("是否再来一盘:是1,不是0\n"); scanf("%d", &a); if (a == 0) break; } return 0;}int menu(){ int choice = -1; while (1) { printf("----------------欢迎使用五子棋------------------------\n"); printf("- 请选择模式 -\n"); printf("- 1.人-人对战游戏 -\n"); printf("- 2.人-机对战游戏 -\n"); printf("- 0.退出游戏 -\n"); printf("------------------------------------------------------\n"); printf("------------------------------------------------------\n"); scanf("%d", &choice); if (choice > 4 || choice < 0) printf("错误输入"); else break; } return choice;}void judgeEmpty(int map[][N + 1], int x, int y, int goal){ while (1) { if (map[x][y] != NO) { printf("已有棋子,重新输入\n"); scanf("%d%d", &x, &y); } else { map[x][y] = goal; initMap(map); break; } }}int judgeWin(int map[][N + 1], int x, int y){ for (int i = 1; i < N + 1; i++) { for (int j = 1; j < N + 1; j++) { if (j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//横 { if (map[i][j] == map[i][j + 1] && map[i][j + 1] == map[i][j + 2] && map[i][j + 2] == map[i][j + 3] && map[i][j + 3] == map[i][j + 4]) return map[i][j]; } if (i < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//竖 { if (map[i][j] == map[i + 1][j] && map[i + 1][j] == map[i + 2][j] && map[i + 2][j] == map[i + 3][j] && map[i + 3][j] == map[i + 4][j]) return map[i][j]; } if (i < N + 1 - 4 && j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右下_ { if (map[i][j] == map[i + 1][j + 1] && map[i + 1][j + 1] == map[i + 2][j + 2] && map[i + 2][j + 2] == map[i + 3][j + 3] && map[i + 3][j + 3] == map[i + 4][j + 4]) return map[i][j]; } if (i > 4 && j > 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右上 { if (map[i][j] == map[i - 1][j - 1] && map[i - 1][j - 1] == map[i - 2][j - 2] && map[i - 2][j - 2] == map[i - 3][j - 3] && map[i - 3][j - 3] == map[i - 4][j - 4]) return map[i][j]; } } } return NO;}//绘制棋子void draw_chessman(int type, char* tableline) { if (type == WHITE) printf(" ●"); if (type == BLACK) printf(" ○"); if (type == NO) printf("%s", tableline);}void initMap(int map[N + 1][N + 1]){ //第一行和第一列显示数字 for (int i = 0; i < N + 1; i++) { map[0][i] = i; map[i][0] = i; if (i >= 10) { map[0][i] = i - 10; map[i][0] = i - 10; } } for (int i = 0; i < N + 1; i++) { //打印第一行数字 if (i == 0) { for (int j = 0; j < N + 1; j++) { printf("%-2d", map[0][j]); } printf("\n"); } //打印第一行棋盘 else if (i == 1) { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┏"); else if (j == N) draw_chessman(map[i][j], "━┓"); else draw_chessman(map[i][j], "━┳"); } printf("\n"); } //打印最后一行 else if (i == N) { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┗"); else if (j == N) draw_chessman(map[i][j], "━┛"); else draw_chessman(map[i][j], "━┻"); } printf("\n"); } else { for (int j = 0; j < N + 1; j++) { if (j == 0) printf("%d", map[i][j]); else if (j == 1) draw_chessman(map[i][j], " ┣"); else if (j == N) draw_chessman(map[i][j], "━┫"); else draw_chessman(map[i][j], "━╋"); } printf("\n"); } }}//void machine(int map[][N + 1])//{// printf("--------人-机对战---------------\n");// srand(time(NULL));// int choice = -1;// printf("请输入你执黑棋还是白棋,黑1,白2\n");// scanf("%d", &choice);// if (choice == 1)// {// while (1)// {// int x = -1;// int y = -1;// black:// while (1)// {// printf("黑方落子\n");// printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N);// scanf("%d%d", &x, &y);// if (x < 0 || x > N || y < 0 || y > N)// printf("错误输入\n");// else// break;// }// judgeEmpty(map, x, y, BLACK);// //判断胜利// int ret = judgeWin(map, x, y);// if (ret == BLACK)// {// printf("黑方获胜\n");// return;// }// else if (ret == WHITE)// {// printf("白方获胜\n");// return;// }// if (retract(map, x, y) == 1)// goto black;// next:// x = rand() % 15 + 1;// y = rand() % 15 + 1;// if (map[x][y] != NO)// goto next;// judgeEmpty(map, x, y, WHITE);// //判断胜利// ret = judgeWin(map, x, y);// if (ret == BLACK)// {// printf("黑方获胜\n");// return;// }// else if (ret == WHITE)// {// printf("白方获胜\n");// return;// }// }// }// else if (choice == 2)// {// while (1)// {// int x = -1;// int y = -1;// next2:// x = rand() % 15 + 1;// y = rand() % 15 + 1;// if (map[x][y] != NO)// goto next2;// judgeEmpty(map, x, y, BLACK);// //判断胜利// int ret = judgeWin(map, x, y);// if (ret == BLACK)// {// printf("黑方获胜\n");// return;// }// else if (ret == WHITE)// {// printf("白方获胜\n");// return;// }// white:// while (1)// {// printf("白方落子\n");// printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N);// scanf("%d%d", &x, &y);// if (x < 0 || x > N || y < 0 || y > N)// printf("错误输入\n");// else// break;// }// judgeEmpty(map, x, y, WHITE);// //判断胜利// ret = judgeWin(map, x, y);// if (ret == BLACK)// {// printf("黑方获胜\n");// return;// }// else if (ret == WHITE)// {// printf("白方获胜\n");// return;// }// if (retract(map, x, y) == 1)// goto white;//// }// }////}void peopleFight(int map[][N + 1]){ printf("--------人-人对战---------------\n"); initMap(map); while (1) { int x = -1; int y = -1; black: while (1) { printf("黑方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, BLACK); if (retract(map, x, y) == 1) goto black; //判断胜利 int ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } white: while (1) { printf("白方落子\n"); printf("请输入要落下的坐标现在棋盘为%d*%d\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, WHITE); if (retract(map, x, y) == 1) goto white; //判断胜利 ret = judgeWin(map, x, y); if (ret == BLACK) { printf("黑方获胜\n"); return; } else if (ret == WHITE) { printf("白方获胜\n"); return; } }}int retract(int map[][N + 1], int x, int y){ int choice = -1; printf("是否悔棋:是1\n"); scanf("%d", &choice); if (choice == 1) { map[x][y] = NO; initMap(map); } return choice;}void AIjudge(int color, int map[N+1][N+1]){ int num = 1, left = 0, right = 0; int n, m, score = 0, max = 0; int dx, dy; for (int i = 1; i < N+1; i++) { for (int j = 1; j < N+1; j++) { score = 0; if (map[i][j] != 0) continue; else { dx = 1, dy = 0, n = i, m = j; while (1)//水平向右 { n += dx, m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || n > 15) { right++; break; } else if (num < 5) { num++; } } dx = -1, dy = 0; while (1) {//水平向左 n += dx; m += dy; if (map[n][m] == 0) { left = 0; break; } else if (map[n][m] != color || n < 1) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left);//用data来算分数,并用score来记录 // |方向 num = 1; right = 0, left = 0;//每一次改变方向要重置这些变量 dx = 0; dy = -1; n = i; m = j; //向上 while (1) { n += dx; m += dy; if (map[n][m] == 0) { left = 0; break; } else if (map[n][m] != color || m < 1) { left++; break; } else if (num < 5) { num++; } } //向下 dx = 0; dy = 1; n = i; m = j; while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || m > 15) { right++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); // \方向 num = 1; right = 0, left = 0; dx = 1; dy = 1; n = i; m = j; //向右下 while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || m > 15 || n > 15) { right++; break; } else if (num < 5) { num++; } } //向左上 dx = -1; dy = -1; n = i; m = j; while (1) { n += dx; m += dy; if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; } else if ((n > 0 && m > 0 && map[n][m] != color) || m < 1 || n < 1) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); // /方向` num = 1; right = 0, left = 0; dx = 1; dy = -1; n = i; m = j; //向右上 while (1) { n += dx; m += dy; if (map[n][m] == 0) { right = 0; break; } else if (map[n][m] != color || n > 15 || m < 1) { right++; break; } else if (num < 5) { num++; } } //向左下 dx = -1; dy = 1; n = i; m = j; while (1) { n += dx; m += dy; if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; } else if ((n > 0 && m > 0 && map[n][m] != color) || n < 1 || m > 15) { left++; break; } else if (num < 5) { num++; } } score += Data(num, right + left); if (score > max) {//每一次用max保存分数,下一次比较,最后找出最大值 max = score; position[0] = i;//用来保存每一次的位置和分数 position[1] = j; position[2] = score; } } } }}int Data(int num, int count){ switch (num) { case 1:if (count == 0)//活一:表示在该处落子,就只有这一个棋子,两边都没有阻挡(边界或对方的棋子)优势较大 return 2; else if (count == 1)//冲一:表示在该处落子,就只有这一个棋子,两边有一种阻挡(边界或对方的棋子)优势较小 return 1; else return 0; break; case 2: if (count == 0)//活二;接下来都同理活一和冲一 return 20; else if (count == 1)//冲二 return 10; else return 0; break; case 3: if (count == 0)//活三 return 300; else if (count == 1)//冲三 return 50; else return 0; break; case 4: if (count == 0)//活四 return 4000; else if (count == 1)//冲四 return 1000; else return 0; break; case 5://五 return 5000; break; default: return 0; break; }}void machine(int map[][N + 1]){ printf("--------人-机对战---------------\n"); int choice = -1; do { printf("请输入你执黑棋还是白棋,黑1,白2\n"); scanf("%d", &choice); } while (choice != 1 && choice != 2); initMap(map); if (choice == 1) { while (1) { int x = -1; int y = -1; black: while (1) { printf("黑方落子\n"); printf("现在棋盘为%d*%d请输入要落下的坐标x y\n", N, N); scanf("%d%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, BLACK); if (retract(map, x, y)) { map[x][y] = 0; initMap(map); goto black; } int ret = judgeWin(map, x, y); if (ret == BLACK) //判断胜利 break; int old_max = 0, new_max = 0, n = 0, m = 0; int AIx = -1, AIy = -1; AIjudge(1, map);//判断黑子的优势位置 old_max = position[2];//保存该位置分数 AIx = position[0]; AIy = position[1];//保存该位置的坐标,注意行列和xy轴的对应关系 position[0] = 0, position[1] = 0, position[2] = 0; AIjudge(-1, map);//判断白子的优势位置 new_max = position[2];//保存分数 if (new_max >= old_max) //判断哪个位置的分数大,从而判断是堵截还是进攻 { AIx = position[0]; AIy = position[1]; } judgeEmpty(map, AIx, AIy, WHITE); ret = judgeWin(map, x, y); if (ret == WHITE) //判断胜利 break; } } else if (choice == 2) { while (1) { int x = -1, y = -1; int old_max = 0, new_max = 0, n = 0, m = 0; int AIx = -1, AIy = -1; AIjudge(1, map);//判断黑子的优势位置 old_max = position[2];//保存该位置分数 AIx = position[0]; AIy = position[1];//保存该位置的坐标,注意行列和xy轴的对应关系 position[0] = 0, position[1] = 0, position[2] = 0; AIjudge(-1, map);//判断白子的优势位置 new_max = position[2];//保存分数 if (new_max >= old_max) //判断哪个位置的分数大,从而判断是堵截还是进攻 { AIx = position[0]; AIy = position[1]; } judgeEmpty(map, AIx, AIy, BLACK); int ret = judgeWin(map, x, y); if (ret == BLACK) //判断胜利 break; white: while (1) { printf("白方落子\n"); printf("现在棋盘为%d*%d请输入要落下的坐标x y\n", N, N); scanf("%d,%d", &x, &y); if (x < 0 || x > N || y < 0 || y > N) printf("错误输入\n"); else break; } judgeEmpty(map, x, y, WHITE); if (retract(map, x, y)) { map[x][y] = 0; initMap(map); goto white; } ret = judgeWin(map, x, y); if (ret == WHITE) //判断胜利 break; } }}