失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > (简易版)c语言人机对战五子棋

(简易版)c语言人机对战五子棋

时间:2022-10-06 03:14:13

相关推荐

(简易版)c语言人机对战五子棋

概要

琐碎的地方就不提了,人机对战五子棋的核心在于如何分析棋局,使程序落子最优化。当然我只是简易版本,没有棋盘界面化,没有禁手,策略也不能算是精良,只能勉强当作一个参考供大家学习。

Ps:AI有时候会犯傻,可能是分值设置的原因,请谅解??

如何分析棋局

这里只是概括,具体可以看之后挂出来的网址。

确定有效空位(即AI下棋的空位选项):落子处周围米字型区域(8个点),每次落子都要更新记录空位的集合。空位的评分:这里需要对每种棋局进行打分(四子、三子、两子、一子都有各自的情况),最后累加得到该空位的局势得分,具体评分内容可以看这里的网址(https://www.write-/article/1372.html) [转载自write-]求最高分的空位:即为程序最优落子点

下面po上代码

fivechess.c

#include <stdio.h>#include <stdlib.h>#define CHESS_MAX 24//行列坐标struct local //空位信息{int local_carrier; //存储四位坐标信息int score; //空位的得分信息}empty1[CHESS_MAX*CHESS_MAX];int judge[CHESS_MAX][CHESS_MAX] = {{0}};//用于判断该空位是否在空位结构体中 0:不在 1:在 排除重复性计入结构体int board[CHESS_MAX][CHESS_MAX] = {{0}};//棋盘数组int number_empty = 0;//空位数int x, y; //临时记录坐标//根据棋型计算空位得分,count1为相连棋子数,//leftStatus、rightStatus为1或2,1代表为空,2为墙或者对方棋子int getScoreBySituation(int count1, int left1, int right1);//这个需要对照评分表//横向扫描计算得分 cur表示AI或者人类int getXScore(int x, int y, int cur);//纵向扫描计算得分int getYScore(int x, int y, int cur);//正斜向扫描计算得分int getSkewScore1(int x, int y, int cur);//反斜向扫描计算得分int getSkewScore2(int x, int y, int cur);//上面五个函数在get_score.c中定义//显示棋盘void show_chess_board(int (*a)[CHESS_MAX][CHESS_MAX]);//用户下棋 返回落子信息int get_inputchess();//落子处为中心的米字型区域记录空位void add_empty(int x, int y);//双方在空位处下子 要在judge数组中更新状态void update_judge_empty(int x, int y);//更新各个空位的总得分void update_score_empty();//返回得分最高int return_high();int win(int a);//以上为函数//将空位存入数组中void add_empty(int x, int y){int i, j;for (i = x - 1; i <= x + 1; i++){for (j = y - 1; j <= y + 1; j++){if(i == x && j == y)break;if(board[i][j] == 0 && judge[i][j] == 0)//该位置没有下过并且不在空位结构体中{empty1[number_empty].local_carrier = i*100+j;number_empty++;judge[i][j] = 1;}}}}//人类或者AI下一次棋后更新空位分数void update_score_empty(){int i, grade;for(i = 0; i < number_empty; i++){grade = empty1[i].local_carrier;int X = grade / 100, Y = grade % 100;if(board[X][Y] != 0)//空位被下过就不再计算得分{empty1[i].score = 0;continue;}else{empty1[i].score = getXScore(X,Y,1) + getXScore(X,Y,2)+ getYScore(X,Y,1) + getYScore(X,Y,2) + getSkewScore1(X,Y,1)+ getSkewScore1(X,Y,2) + getSkewScore2(X,Y,1) + getSkewScore2(X,Y,2);}}}int win(int a){//判断胜负int x,y;//x means line,y means column//judge linefor(y=0;y<17;y++)//last four column no need to judge{for(x=0;x<20;x++){if(a==board[x][y]&&a==board[x+1][y]&&a==board[x+2][y]&&a==board[x+3][y]&&a==board[x+4][y])return a;//win}}//judge viticalfor(y=0;y<20;y++){for(x=0;x<17;x++)//last four line no need to judge{if(a==board[x][y]&&a==board[x][y+1]&&a==board[x][y+2]&&a==board[x][y+3]&&a==board[x][y+4])return a;}}// judge "\"for(y=0;y<20;y++){for(x=0;x<17;x++)//last four line no need to judge{if(a==board[x][y]&&a==board[x+1][y+1]&&a==board[x+2][y+2]&&a==board[x+3][y+3]&&a==board[x+4][y+4])return a;}}// judge "/"for(y=19;y>3;y--){for(x=0;x<17;x++)//last four line no need to judge{if(a==board[x][y]&&a==board[x+1][y-1]&&a==board[x+2][y-2]&&a==board[x+3][y-3]&&a==board[x+4][y+4])return a;}}return 0;}//返回得分最高int return_high(){int i, grade_msg;int max = 0, max_location;for (i = 0; i < number_empty; i++){grade_msg = empty1[i].local_carrier;if(judge[grade_msg/100][grade_msg%100] == 1 && board[grade_msg/100][grade_msg%100] == 0)//在空位结构体中 且未下过{if(empty1[i].score > max)//若得分都相同,就返回第一个找到的空位{max = empty1[i].score;max_location = empty1[i].local_carrier;}}}return max_location;}//人类落子int get_inputchess(){int a, circle_x = 0, circle_y = 0;char local_x, local_y;do//记录x坐标{printf("please input the chess of line:");scanf("%c", &local_x);getchar();//换行符去掉switch(local_x){case '0':x = 0;case '1':x = 1;break;case '2':x = 2;break;case '3':x = 3;break;case '4':x = 4;break;case '5':x = 5;break;case '6':x = 6;break;case '7':x = 7;break;case '8':x = 8;break;case '9':x = 9;break;case 'a':x = 10;break;case 'b':x = 11;break;case 'c':x = 12;break;case 'd':x = 13;break;case 'e':x = 14;break;case 'f':x = 15;break;case 'g':x = 16;break;case 'h':x = 17;break;case 'i':x = 18;break;case 'j':x = 19;break;case 'k':x = 20;break;case 'l':x = 21;break;case 'm':x = 22;break;case 'n':x = 23;break;default:printf("wrong input%c\n",local_x);circle_x = 1;break;}}while(circle_x != 0);printf("please input the chess of row:"); //y的处理同上do{scanf("%c", &local_y); //获取列坐标getchar();switch (local_y){case '0':y = 0;case '1':y = 1;break;case '2':y = 2;break;case '3':y = 3;break;case '4':y = 4;break;case '5':y = 5;break;case '6':y = 6;break;case '7':y = 7;break;case '8':y = 8;break;case '9':y = 9;break;case 'a':y = 10;break;case 'b':y = 11;break;case 'c':y = 12;break;case 'd':y = 13;break;case 'e':y = 14;break;case 'f':y = 15;break;case 'g':y = 16;break;case 'h':y = 17;break;case 'i':y = 18;break;case 'j':y = 19;break;case 'k':y = 20;break;case 'l':y = 21;break;case 'm':y = 22;break;case 'n':y = 23;break;default:printf("wrong input %c\n", local_y);circle_y = 1;break;}}while (circle_y == 1);a = x*100+y;//坐标信息board[x][y] = 1;return a;}//显示棋盘void show_chess_board(int (*a)[CHESS_MAX][CHESS_MAX]){int i, j, k = 0; //k用来控制显示空格,换行printf("\n\n");printf(" 0123 4567 89ab cdef ghij klmn\n"); //打印出列坐标for (i = 0; i < CHESS_MAX; i++) //i为行{for (j = 0; j < CHESS_MAX; j++) //j为列{//实现每四个棋子就出现一个空格,方便查找位置去下子if (k > 0 && (k % 4 == 0))printf(" ");//每24个棋子输出,就换行显示if (k > 0 && (k % CHESS_MAX == 0))printf("\n");//显示每行的开头的数字if (j == 0){if (i <= 9)printf("%d", i); //开始9行用数字显示else{switch (i){case 10:printf("%c", 'a');break;case 11:printf("%c", 'b'); //1-9不够显示行坐标,9后用a-k表示break;case 12:printf("%c", 'c');break;case 13:printf("%c", 'd');break;case 14:printf("%c", 'e');break;case 15:printf("%c", 'f');break;case 16:printf("%c", 'g');break;case 17:printf("%c", 'h');break;case 18:printf("%c", 'i');break;case 19:printf("%c", 'j');break;case 20:printf("%c", 'k');break;case 21:printf("%c", 'l');break;case 22:printf("%c", 'm');break;case 23:printf("%c", 'n');break;}}}int l = (*a)[i][j];if (l == 0)printf("-"); //此时代表未落子else if (l == 1)printf("O"); // 人类落子else if (l == 2)printf("X"); // AI落子k++; //每落一个子后k++来控制空格与换行}}printf("\n"); //打印棋盘完后再输出一个换行,让用户看得更清楚}

get_score.c(计算空位处分数)

#include <stdio.h>#include <stdlib.h>#define CHESS_MAX 24//根据棋型计算空位得分,count1为相连棋子数,leftStatus、rightStatus为1或2,1代表为空,2为墙或者对方棋子int getScoreBySituation(int count1, int left1, int right1);//这个需要对照评分表//横向扫描计算得分 cur表示AI或者人类int getXScore(int x, int y, int cur);//纵向扫描计算得分int getYScore(int x, int y, int cur);//正斜向扫描计算得分int getSkewScore1(int x, int y, int cur);//反斜向扫描计算得分int getSkewScore2(int x, int y, int cur);extern int board[CHESS_MAX][CHESS_MAX]; //棋盘数组int left = 0, right = 0;//空位左右两边的情况int count_left, count_right;//左右连子数int temp, temp_1, temp_2; //记录空位坐标的临时变量int getScoreBySituation(int count1, int left1, int right1)//评分表参照网站中的设定(不固定){if(count1 == 4)return 200000;if(count1 == 3){if(left1 == 1 && right1 == 1)return 50000;else if( (left1 == 1 && right1 == 2) || (left1 == 2 && right1 == 1) )return 3000;elsereturn 1000;}if(count1 == 2){if(left1 == 1 && right1 == 1)return 3000;else if( (left1 == 1 && right1 == 2) || (left1 == 2 && right1 == 1) )return 1000;elsereturn 500;}if(count1 == 1){if(left1 == 1 && right1 == 1)return 500;else if( (left1 == 1 && right1 == 2) || (left1 == 2 && right1 == 1) )return 200;elsereturn 100;}if(count1 == 0){if(left1 == 1 && right1 == 1)return 100;else if( (left1 == 1 && right1 == 2) || (left1 == 2 && right1 == 1) )return 50;elsereturn 30;}return 0;}int getXScore(int x, int y, int cur)//对同一个位置要调用两次函数(AI和人类){temp = y;count_left = count_right = 0;while(1)//左边移动{--y;if(y == -1 || board[x][y] != cur)//对方棋子或者墙{left = 2;break;}else if(board[x][y] == cur)//自己棋子{++count_left;continue;}if(board[x][y] == 0)//空格{left = 1;break;}}while(1)//右边移动{++temp;if(y == CHESS_MAX || board[x][temp] != cur)//对方棋子或者墙{right = 2;break;;}else if(board[x][temp] == cur)//自己棋子{++count_right;continue;}if(board[x][temp] == 0)//空格{right = 1;break;}}return getScoreBySituation(count_left + count_right, left, right);}int getYScore(int x, int y, int cur){temp = x;count_left = count_right = 0;while(1)//向下移动{++x;if(x == CHESS_MAX || board[x][y] != cur)//对方棋子或者墙{left = 2;break;}else if(board[x][y] == cur)//自己棋子{++count_left;continue;}if(board[x][y] == 0)//空格{left = 1;break;}}while(1)//向上移动{--temp;if(temp == -1 || board[temp][y] != cur)//对方棋子或者墙{right = 2;break;;}else if(board[temp][y] == cur)//自己棋子{++count_right;continue;}if(board[temp][y] == 0)//空格{right = 1;break;}}return getScoreBySituation(count_left + count_right, left, right);}int getSkewScore1(int x, int y, int cur){temp_1 = x, temp_2 = y;count_left = count_right = 0;while(1)//斜向左下移动{++x;--y;if(x == CHESS_MAX || y == -1 || board[x][y] != cur)//对方棋子或者墙{left = 2;break;}else if(board[x][y] == cur)//自己棋子{++count_left;continue;}if(board[x][y] == 0)//空格{left = 1;break;}}while(1)//斜向右下移动{--temp_1;++temp_2;if(temp_1 == -1 || temp_2 == CHESS_MAX ||board[temp_1][temp_2] != cur)//对方棋子或者墙{right = 2;break;}else if(board[temp_1][temp_2] == cur)//自己棋子{++count_right;continue;}if(board[temp_1][temp_2] == 0)//空格{right = 1;break;}}return getScoreBySituation(count_left + count_right, left, right);}int getSkewScore2(int x, int y, int cur){temp_1 = x, temp_2 = y;count_left = count_right = 0;while(1)//斜向左上移动{--x;--y;if(x == -1 || y == -1 || board[x][y] != cur)//对方棋子或者墙{left = 2;break;}else if(board[x][y] == cur)//自己棋子{++count_left;continue;}if(board[x][y] == 0)//空格{left = 1;break;}}while(1)//斜向右下移动{++temp_1;++temp_2;if(temp_1 == CHESS_MAX || temp_2 == CHESS_MAX ||board[temp_1][temp_2] != cur)//对方棋子或者墙{right = 2;break;}else if(board[temp_1][temp_2] == cur)//自己棋子{++count_right;continue;}if(board[temp_1][temp_2] == 0)//空格{right = 1;break;}}return getScoreBySituation(count_left + count_right, left, right);}

main.c

int main(){printf("如果打算开始请输入1\n");int msg;scanf("%d", &msg);getchar();if(msg == 1){board[12][12] = 2;//AI先落子show_chess_board(&board);add_empty(12,12);while(1){//人类后落子int Chess_msg = get_inputchess();show_chess_board(&board);if(win(1)){printf("人类胜利\n");break;}printf("请按任意键继续\n");getchar();//落子后机器分析add_empty(Chess_msg / 100, Chess_msg % 100);//记录空位update_score_empty();//更新空位得分//AI落子int max_location = return_high();board[max_location/100][max_location%100] = 2;show_chess_board(&board);if(win(2)){printf("AI胜利");break;}// 落子后机器分析add_empty(max_location / 100, max_location % 100);update_score_empty();//更新空位得分}}return 0;}

演示图片:

感谢sky老师的指导

做到有些粗糙,有不对的地方欢迎在评论区留言哟?~~~~~~~~~~~~~~~~~~~~~~~~~~~~

如果觉得《(简易版)c语言人机对战五子棋》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。