当前位置: 首页 > news >正文

人工智能博弈树算法做的井字棋游戏

不会输,超碉!井字棋这个游戏真是太无聊啦!

算法大概就是,有一个给状况进行估价的函数,深搜每种状况,假设每个人都按对自己最有利的方式走(假设玩家也是不傻),最后让电脑走出最有利的一步。

实验报告:

http://wenku.baidu.com/view/b48996b78bd63186bcebbcba.html

代码:

  1 //#pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<queue>
 12 #include<conio.h>
 13 #include<time.h>
 14 using namespace std;
 15 #define mz(array) memset(array, 0, sizeof(array))
 16 #define mf1(array) memset(array, -1, sizeof(array))
 17 #define minf(array) memset(array, 0x3f, sizeof(array))
 18 #define REP(i,n) for(i=0;i<(n);i++)
 19 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
 20 #define FORD(i,x,y) for(i=(x);i>=(y);i--)
 21 #define RD(x) scanf("%d",&x)
 22 #define RD2(x,y) scanf("%d%d",&x,&y)
 23 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 24 #define WN(x) printf("%d\n",x);
 25 #define RE  freopen("D.in","r",stdin)
 26 #define WE  freopen("huzhi.txt","w",stdout)
 27 #define mp make_pair
 28 #define pb push_back
 29 #define pf push_front
 30 #define ppf pop_front
 31 #define ppb pop_back
 32 typedef long long ll;
 33 typedef unsigned long long ull;
 34 
 35 const char CHESS[3]= {'-', '@', '#'};
 36 
 37 struct Board {
 38     int a[3][3];
 39     inline void Init() {
 40         memset(a,0,sizeof(a));
 41     }
 42     inline void operator =(Board b) {
 43         int i,j;
 44         REP(i,3)REP(j,3)a[i][j]=b.a[i][j];
 45     }
 46 };
 47 
 48 int GetInput(string s, int maxNum) {
 49     int t;
 50     char c;
 51     while(1) {
 52         cout<<s;
 53         c=getch();
 54         t=c-'0';
 55         if(t>=0 && t<maxNum)break;
 56         else {
 57             puts("输入错误,请重新输入!");
 58         }
 59     }
 60     puts("");
 61     return t;
 62 }
 63 
 64 void OutBoard(Board bod) {
 65     int i,j;
 66     printf("   ");
 67     REP(i,3)printf("%2d",i);
 68     puts("\n   ======");
 69     REP(i,3) {
 70         printf("%2d|",i);
 71         REP(j,3) {
 72             printf("%2c",CHESS[bod.a[i][j]]);
 73         }
 74         puts("");
 75     }
 76 }
 77 
 78 void PlayerMove(Board &bod) {
 79     int x,y;
 80     OutBoard(bod);
 81     while(true) {
 82         printf("该你了,请输入你要下%c的横纵坐标(用空格隔开的两个数):",CHESS[1]);
 83         scanf("%d%d",&x,&y);
 84         if(!(x>=0 && x<=2 && y>=0 && y<=2)) {
 85             puts("输入错误!请重新输入!横纵坐标都要是0或者1或者2。");
 86             continue;
 87         }
 88         if(bod.a[x][y]!=0) {
 89             puts("下错了,这个位置有棋!请选择其他位置。");
 90             continue;
 91         }
 92         break;
 93     }
 94     bod.a[x][y]=1;
 95     //OutBoard(bod);
 96     printf("你下到了(%d,%d)位置。\n",x,y);
 97     puts("");
 98 //    puts("(按回车键继续)");
 99 //    getch();
100 //    system("cls");
101 }
102 
103 inline int Evaluate(const Board &bod) {
104     int i,j;
105     int cnt[3];
106     int re=0;
107     REP(i,3) {
108         mz(cnt);
109         REP(j,3)cnt[bod.a[i][j]]++;
110         if(cnt[1]==3)return 1000;
111         if(cnt[2]==3)return -1000;
112         if(cnt[1]==2&&cnt[0]==1)re+=50;
113         else if(cnt[1]==1 && cnt[0]==2)re+=10;
114         if(cnt[2]==2&&cnt[0]==1)re-=50;
115         else if(cnt[2]==1 && cnt[0]==2)re-=10;
116         mz(cnt);
117         REP(j,3)cnt[bod.a[j][i]]++;
118         if(cnt[1]==3)return 1000;
119         if(cnt[2]==3)return -1000;
120         if(cnt[1]==2&&cnt[0]==1)re+=50;
121         else if(cnt[1]==1 && cnt[0]==2)re+=10;
122         if(cnt[2]==2&&cnt[0]==1)re-=50;
123         else if(cnt[2]==1 && cnt[0]==2)re-=10;
124     }
125     mz(cnt);
126     REP(i,3) {
127         cnt[bod.a[i][i]]++;
128     }
129     if(cnt[1]==3)return 1000;
130     if(cnt[2]==3)return -1000;
131     if(cnt[1]==2&&cnt[0]==1)re+=50;
132     else if(cnt[1]==1 && cnt[0]==2)re+=10;
133     if(cnt[2]==2&&cnt[0]==1)re-=50;
134     else if(cnt[2]==1 && cnt[0]==2)re-=10;
135     mz(cnt);
136     REP(i,3) {
137         cnt[bod.a[i][2-i]]++;
138     }
139     if(cnt[1]==3)return 1000;
140     if(cnt[2]==3)return -1000;
141     if(cnt[1]==2&&cnt[0]==1)re+=50;
142     else if(cnt[1]==1 && cnt[0]==2)re+=10;
143     if(cnt[2]==2&&cnt[0]==1)re-=50;
144     else if(cnt[2]==1 && cnt[0]==2)re-=10;
145     return re;
146 }
147 
148 Board boa;
149 
150 inline int dfs(const int &depth, const int &nowWho) {
151     int i,j,t,ma=-100000,mi=100000,ok=0;
152     int eva = Evaluate(boa);
153     if(depth==0 || (eva>=1000)|| (eva<=-1000)) {
154         return eva;
155     }
156 
157     REP(i,3) {
158         REP(j,3) {
159             if(boa.a[i][j]!=0)continue;
160             ok=1;
161             boa.a[i][j]=nowWho+1;
162             t=dfs(depth-1 , nowWho^1);
163             boa.a[i][j]=0;
164             ma=max(t,ma);
165             mi=min(t,mi);
166         }
167     }
168     if(!ok)return eva;
169     if(nowWho==0)return ma;
170     if(nowWho==1)return mi;
171 }
172 
173 void ComputerMove(Board &bod) {
174     int x,y,i,j;
175     boa=bod;
176     puts("电脑:“该我啦!看我思考一下...”");
177     vector<pair<int , pair<int,int> > > v;
178     v.clear();
179     REP(i,3)REP(j,3) {
180         if(boa.a[i][j]!=0)continue;
181         boa.a[i][j]=2;
182         v.pb(mp(dfs(9,0),mp(i,j)));
183         boa.a[i][j]=0;
184     }
185     sort(v.begin(),v.end());
186     j=1;
187     while(j<v.size() && v[j].first ==v[0].first)
188         j++;
189     if(j>1)printf("电脑:“想完啦!我有%d种不同的效果差不多的棋可以走,看我随便走一个!”\n",j);
190     else printf("电脑:“想完啦!看我要走出这步惊天之棋了!”\n");
191     if(v.size()>j && v[j].first==1000)puts("电脑:“要是我走除此之外的棋我就输了,我已经看出来了。”");
192     if(v[0].first==-1000)puts("电脑:“现在,高下立判,你输定了!”");
193     j=rand()%j;
194     x=v[j].second.first;
195     y=v[j].second.second;
196     bod.a[x][y]=2;
197     //OutBoard(bod);
198     printf("电脑:“经过我的精确思考,我下到了(%d,%d)位置。”\n",x,y);
199     puts("");
200 }
201 
202 int WhoWin(Board bod) {
203     int i,j,k=0;
204     int t = Evaluate(bod);
205     if(t==1000)return 1;
206     if(t==-1000)return 2;
207     REP(i,3)REP(j,3)if(bod.a[i][j]!=0)k++;
208     if(k==9)return 3;
209     return 0;
210 }
211 
212 void Game() {
213     int playerFirst, nowMove, whoWin, continueGame=1;
214     Board now;
215     int t;
216     int step;
217     srand(time(NULL));
218     while(continueGame) {
219         system("cls");
220         puts("欢迎来到 【带鱼人工智能博弈树井字棋游戏】!");
221         playerFirst = GetInput("请选择玩家先后手(0先手,1后手):",2);
222         if(playerFirst==0){
223             puts("电脑:“就算你选先手,我也不会输,不信走着瞧!”");
224         }else puts("电脑:“居然敢选后手,要是你稍有不慎,就输定了!”");
225         now.Init();
226         printf("(棋盘说明:%c是空位,%c是你的棋子,%c是电脑的棋子,上面是横坐标,左边是纵坐标)\n\n",CHESS[0],CHESS[1],CHESS[2]);
227         nowMove=playerFirst;
228         whoWin=0;
229         step=0;
230         while(!whoWin) {
231             printf("【第%d手】\n",++step);
232             if(nowMove==0) {
233                 PlayerMove(now);
234             } else {
235                 ComputerMove(now);
236             }
237             whoWin=WhoWin(now);
238             if(whoWin!=0) {
239                 OutBoard(now);
240                 if(whoWin==1) {
241                     printf("电脑:“哇,你居然赢了,真是不敢相信!我输了!”\n");
242                 }
243                 if(whoWin==2) {
244                     printf("电脑:“蛤铪哈!我赢了,你太弱啦!”\n");
245                 }
246                 if(whoWin==3) {
247                     printf("电脑:“平局!你还是有点实力,但是我是绝对不会输的!”\n");
248                 }
249             }
250             nowMove^=1;
251         }
252         continueGame=GetInput("是否继续游戏?(0结束游戏,1重新开始):",2);
253     }
254 }
255 
256 int main() {
257     Game();
258     return 0;
259 }
View Code

 

 

2017.1.20 update: 

  187行由

    if(v.size()>1)while(v[j].first ==v[0].first)j++;

  改为: 

    while(j<v.size() && v[j].first ==v[0].first)
        j++;

 

转载于:https://www.cnblogs.com/yuiffy/p/4235128.html

相关文章:

  • CSS z-index 属性
  • Error No matching provisioning profiles found
  • 微软消息分析器(Microsoft Message Analyzer )更新至1.2版-2015-1-20
  • java的动态代理机制详解
  • 查询句柄引用计数源码
  • PHP 启动 cURL模块以及启动失败的解决方案
  • selenium webdriver 学习笔记(三)
  • 4在二元树中找出和为某一值的所有路径
  • Android.Hack.02_Animations
  • [转]Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 区别和用法
  • PowerManager Android 电源管理
  • ZeroMQ接口函数之 :zmq_strerror - 获取ZMQ错误描述字符串
  • 世界国家省份城市县区街道村地址邮编常用通用功能最全API - 多级联动 - 淘宝天猫阿里巴巴技术赏析...
  • ×××S 2012 Report Items -- 独立报表单元
  • 基于Netty与RabbitMQ的消息服务
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 〔开发系列〕一次关于小程序开发的深度总结
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • ES6 ...操作符
  • ES6 学习笔记(一)let,const和解构赋值
  • HTTP中的ETag在移动客户端的应用
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • js 实现textarea输入字数提示
  • JS学习笔记——闭包
  • Promise初体验
  • python 学习笔记 - Queue Pipes,进程间通讯
  • SQLServer之索引简介
  • windows下如何用phpstorm同步测试服务器
  • 从PHP迁移至Golang - 基础篇
  • 免费小说阅读小程序
  • 使用API自动生成工具优化前端工作流
  • 项目实战-Api的解决方案
  • 用Canvas画一棵二叉树
  • 2017年360最后一道编程题
  • 从如何停掉 Promise 链说起
  • 整理一些计算机基础知识!
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #define、const、typedef的差别
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2)nginx 安装、启停
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (九)信息融合方式简介
  • (转) 深度模型优化性能 调参
  • (转)ORM
  • (转)人的集合论——移山之道
  • *** 2003
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .NET 4.0中的泛型协变和反变
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .net 验证控件和javaScript的冲突问题
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则