黑白棋人机对战完整代码

举报
用户已注销 发表于 2021/11/19 04:57:03 2021/11/19
【摘要】 本文所有内容(包括每一行代码)都是笔者原创。 在我的 控制台上的黑白棋 这篇博客中,给出了起初我写的双人对战的代码,在本文中,我加入了人机对战的功能,并完善了代码。 完整代码: #include "stdafx.h"#include<iostream>#include <stdli...

本文所有内容(包括每一行代码)都是笔者原创。


在我的 控制台上的黑白棋 这篇博客中,给出了起初我写的双人对战的代码,在本文中,我加入了人机对战的功能,并完善了代码。

完整代码:


  
  1. #include "stdafx.h"
  2. #include<iostream>
  3. #include <stdlib.h>
  4. #include<windows.h>
  5. using namespace std;
  6. int list[8][8] = { 0 }; //棋盘状态,1是黑子,2是白子,0是空的
  7. int p = 1, aip = 0, air, aic, lastr = 0, lastc = 0; //p是现在该谁下,1是黑方,2是白方
  8. int p1, p2, p3, p4, temp1[8][8], temp2[8][8], temp3[8][8], temp4[8][8];//4层博弈对应的AI分数和棋局
  9. const int dr[8] = { 0, 0, 1, 1, 1, -1, -1, -1 }, dc[8] = { 1, -1, 0, 1, -1, 0, 1, -1 };//8个方向向量
  10. int book[65]; //棋谱
  11. const int no = 1000;//AI的分数不可能达到的上界值
  12. const int prio[8][8] =
  13. { //prio是每个位置的优先级,数值越高越好
  14. { 80, -20, 8, 6, 6, 8, -20, 80 },
  15. { -20, -20, 0, -1, -1, 0, -20, -20 },
  16. { 8, 0, 3, 5, 5, 3, 0, 8 },
  17. { 6, -1, 5, 1, 1, 5, -1, 6 },
  18. { 6, -1, 5, 1, 1, 5, -1, 6 },
  19. { 8, 0, 3, 5, 5, 3, 0, 8 },
  20. { -20, -20, 0, -1, -1, 0, -20, -20 },
  21. { 80, -20, 8, 6, 6, 8, -20, 80 }
  22. };
  23. bool playOK(int r, int c, int dr, int dc) //判断某个格子的某个方向能否下子
  24. {
  25. if (list[r][c] != 0)return false;
  26. int tr = r, tc = c; //tr和tc分别表示该点通过行和列往特定方向移动后的坐标
  27. while (tr + dr >= 0 && tr + dr < 8 && tc + dc >= 0 && tc + dc < 8 && list[tr + dr][tc + dc] == 3 - p)
  28. { //循环遍历,未到达边界或者右边的棋子是对方的则循环继续,否则循环退出
  29. tr += dr, tc += dc; //移动坐标
  30. }
  31. //若使循环退出的那一格里,是对方的棋子,则(r,c)可落子,否则不可落子
  32. if (tr == r && tc == c)return false; //难点,这一句不可少
  33. if (tr + dr >= 0 && tr + dr < 8 && tc + dc >= 0 && tc + dc < 8 && list[tr + dr][tc + dc] == p)return true;
  34. return false;
  35. }
  36. bool OK(int r, int c) //判断某个格子能否下子
  37. {
  38. if (list[r][c])return false;
  39. for (int i = 0; i < 8; i++) //只要一个方向满足可以下的条件,就可以下
  40. if (playOK(r, c, dr[i], dc[i]))return true; //调用
  41. return false;
  42. }
  43. int num(int k) //统计棋子数目,1是黑子,2是白子
  44. {
  45. int s = 0;
  46. for (int i = 0; i < 8; i++)for (int j = 0; j < 8; j++)if (list[i][j] == k)s++;
  47. return s;
  48. }
  49. void display() //显示棋盘和棋子
  50. {
  51. system("cls");
  52. for (int i = 0; i < 8; i++)
  53. {
  54. if (!i)
  55. {
  56. cout << " ";
  57. for (int j = 0; j < 8; j++)cout << char('A' + j) << " ";
  58. cout << endl;
  59. }
  60. cout << i + 1 << " ";
  61. for (int j = 0; j < 8; j++)
  62. {
  63. if (list[i][j] == 2)cout << "○"; else if (list[i][j] == 1)cout << "●";
  64. else if (OK(i, j))cout << "?"; else cout << " ."; //调用
  65. cout << " ";
  66. }
  67. cout << endl << endl;
  68. }
  69. cout << "黑方:" << num(1) << " 白方:" << num(2) << " 轮到"; //调用
  70. if (p == 1)cout << "黑方下\n"; else cout << "白方下\n";
  71. cout << "候选项:";
  72. for (int i = 0; i < 8; i++)for (int j = 0; j < 8; j++)if (OK(i, j)) //调用
  73. cout << " " << char('1' + i) << char('A' + j);
  74. cout << "\n最后一个落子位置是" << lastr + 1 << char(lastc + 'A');
  75. }
  76. void init() //初始化
  77. {
  78. list[3][3] = list[4][4] = 2;
  79. list[3][4] = list[4][3] = 1;
  80. while (aip != 1 && aip != 2 && aip != 3)
  81. {
  82. cout << "选择\n1,人机对战,AI先\n2,人机对战,玩家先\n3,双人对战\n";
  83. cin >> aip;
  84. }
  85. display(); //调用
  86. }
  87. bool end_() //判断游戏是否结束
  88. {
  89. for (int i = 0; i < 8; i++)for (int j = 0; j < 8; j++)if (OK(i, j))return false; //调用
  90. p = 3 - p; //改变p的2个地方之一
  91. for (int i = 0; i < 8; i++)for (int j = 0; j < 8; j++)if (OK(i, j))return false; //调用
  92. display();
  93. cout << "\n游戏结束\n";
  94. if (num(1) < num(2))cout << "白方胜利"; //调用
  95. else if (num(1)>num(2))cout << "黑方胜利"; //调用
  96. else cout << "平局";
  97. return true;
  98. }
  99. void turn(int tr, int tc, int dr, int dc) //吃子函数play()的一个方向
  100. {
  101. if (!playOK(tr, tc, dr, dc))return; //难点,这一句不可少 //调用
  102. while (tr + dr >= 0 && tr + dr < 8 && tc + dc >= 0 && tc + dc < 8 && list[tr + dr][tc + dc] == 3 - p)
  103. {
  104. list[tr + dr][tc + dc] = p; //在该处换掉棋子的颜色
  105. tr += dr, tc += dc;
  106. }
  107. }
  108. void play(int r, int c)
  109. {
  110. lastr = r, lastc = c;
  111. for (int i = 0; i < 8; i++)turn(r, c, dr[i], dc[i]); //调用
  112. list[r][c] = p;
  113. book[num(1) + num(2)] = r * 8 + c; //调用
  114. p = 3 - p; //改变p的2个地方之一
  115. }
  116. int getPoint()
  117. {
  118. int point = 0;
  119. for (int i1 = 0; i1<8; i1++)for (int j1 = 0; j1<8; j1++)
  120. {
  121. if (list[i1][j1] == aip)point += prio[i1][j1]; //若是ai的子,则加上该位置的积分
  122. if (list[i1][j1] == 3 - aip) point -= prio[i1][j1]; //若是玩家的子,则减去该位置的积分
  123. }
  124. return point;
  125. }
  126. void AI3()//函数里面会改变p,但是调用函数不会改变p
  127. {
  128. p4 = no;
  129. for (int iiii = 0; iiii < 8; iiii++)for (int jjjj = 0; jjjj < 8; jjjj++) //第四层
  130. {
  131. if (!OK(iiii, jjjj))continue; //调用
  132. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)temp4[i][j] = list[i][j];
  133. play(iiii, jjjj);//调用
  134. p = 3 - p;
  135. if (p4 > getPoint())p4 = getPoint();//调用
  136. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)list[i][j] = temp4[i][j];
  137. }
  138. if (p4 == no)p4 = getPoint(); //调用
  139. if (p3 < p4)p3 = p4;
  140. }
  141. void AI2()//函数里面会改变p,但是调用函数不会改变p
  142. {
  143. p3 = -no;
  144. for (int iii = 0; iii < 8; iii++)for (int jjj = 0; jjj < 8; jjj++) //第三层
  145. {
  146. if (!OK(iii, jjj))continue; //调用
  147. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)temp3[i][j] = list[i][j];
  148. play(iii, jjj);//调用
  149. AI3();
  150. p = 3 - p;
  151. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)list[i][j] = temp3[i][j];
  152. }
  153. if (p3 == -no)
  154. {
  155. p = 3 - p;
  156. AI3();
  157. p = 3 - p;
  158. }
  159. if (p2 > p3)p2 = p3;
  160. }
  161. void AI() //函数里面会改变p,但是调用函数不会改变p
  162. {
  163. p1 = -no;
  164. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++) //第一层
  165. {
  166. if (!OK(i, j))continue; //调用
  167. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)temp1[i][j] = list[i][j];
  168. play(i, j);//调用
  169. p2 = no;
  170. for (int ii = 0; ii < 8; ii++)for (int jj = 0; jj < 8; jj++) //第二层
  171. {
  172. if (!OK(ii, jj))continue; //调用
  173. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)temp2[i][j] = list[i][j];
  174. play(ii, jj);//调用
  175. AI3(); //调用
  176. p = 3 - p;
  177. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)list[i][j] = temp2[i][j];
  178. }
  179. if (p2 == no)
  180. {
  181. p = 3 - p;
  182. AI2(); //调用
  183. p = 3 - p;
  184. }
  185. if (p1 < p2)p1 = p2, air = i, aic = j; //难点,如果调用AI函数却1次都没有执行这条语句,那么AI就会下错位置
  186. p = 3 - p;
  187. for (int i = 0; i<8; i++)for (int j = 0; j<8; j++)list[i][j] = temp1[i][j];
  188. }
  189. }
  190. void go() //落下一个子
  191. {
  192. display(); //调用
  193. if (p == aip)
  194. {
  195. AI();//调用
  196. play(air, aic);//调用
  197. Sleep(1000);
  198. return;
  199. }
  200. cout << "\n输入落子位置:行(1-8)和列(A-H) 输入00查看棋谱" << endl;
  201. char x, y;
  202. cin >> x >> y;
  203. if (x == '0')
  204. {
  205. for (int i = 5; i <= num(1) + num(2); i++)cout << " " << book[i] / 8 + 1 << char(book[i] % 8 + 'A');
  206. cout << "\n按任意键退出";
  207. system("pause>nul");
  208. return;
  209. }
  210. int r = x - '1', c = y - 'a';
  211. if (y >= 'A' && y < 'Z')c = y - 'A';
  212. if (!OK(r, c)) //调用
  213. {
  214. cout << "ERROR!";
  215. return;
  216. }
  217. play(r, c); //调用
  218. }
  219. int main()
  220. {
  221. system("color f0");//白底黑字
  222. init();
  223. while (!end_())go();
  224. system("pause>nul");
  225. return 0;
  226. }

AI的算法是分析四层的博弈树,即考虑 AI-玩家-AI-玩家 轮流下完4步之后可能出现的所有情况。

对每个局面赋予一个值point,用来表示该局面对AI的有利程度,玩家总是尽量使得point小,而AI总是尽量使得point大。至于如何计算point,有一个专门完成该工作的函数getPoint()
计算的方法比较简陋,直接对每个格子赋予一个权值
prio,然后用AI的所有格子权值之和减掉玩家的所有格子权值之和即可。

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/64442189

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。