人工智能博弈树算法做的井字棋游戏
不会输,超碉!井字棋这个游戏真是太无聊啦!
算法大概就是,有一个给状况进行估价的函数,深搜每种状况,假设每个人都按对自己最有利的方式走(假设玩家也是不傻),最后让电脑走出最有利的一步。
代码:
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 // REP(i,v.size()) { 187 // printf("(%d,%d) %d\n",v[i].second.first, v[i].second.second, v[i].first); 188 // } 189 j=1; 190 if(v.size()>1)while(v[j].first ==v[0].first)j++; 191 if(j>1)printf("电脑:“想完啦!我有%d种不同的效果差不多的棋可以走,看我随便走一个!”\n",j); 192 else printf("电脑:“想完啦!看我要走出这步惊天之棋了!”\n"); 193 if(v.size()>j && v[j].first==1000)puts("电脑:“要是我走除此之外的棋我就输了,我已经看出来了。”"); 194 if(v[0].first==-1000)puts("电脑:“现在,高下立判,你输定了!”"); 195 j=rand()%j; 196 x=v[j].second.first; 197 y=v[j].second.second; 198 bod.a[x][y]=2; 199 //OutBoard(bod); 200 printf("电脑:“经过我的精确思考,我下到了(%d,%d)位置。”\n",x,y); 201 puts(""); 202 } 203 204 int WhoWin(Board bod) { 205 int i,j,k=0; 206 int t = Evaluate(bod); 207 if(t==1000)return 1; 208 if(t==-1000)return 2; 209 REP(i,3)REP(j,3)if(bod.a[i][j]!=0)k++; 210 if(k==9)return 3; 211 return 0; 212 } 213 214 void Game() { 215 int playerFirst, nowMove, whoWin, continueGame=1; 216 Board now; 217 int t; 218 int step; 219 srand(time(NULL)); 220 while(continueGame) { 221 system("cls"); 222 puts("欢迎来到 【带鱼人工智能博弈树井字棋游戏】!"); 223 playerFirst = GetInput("请选择玩家先后手(0先手,1后手):",2); 224 if(playerFirst==0){ 225 puts("电脑:“就算你选先手,我也不会输,不信走着瞧!”"); 226 }else puts("电脑:“居然敢选后手,要是你稍有不慎,就输定了!”"); 227 now.Init(); 228 printf("(棋盘说明:%c是空位,%c是你的棋子,%c是电脑的棋子,上面是横坐标,左边是纵坐标)\n\n",CHESS[0],CHESS[1],CHESS[2]); 229 nowMove=playerFirst; 230 whoWin=0; 231 step=0; 232 while(!whoWin) { 233 printf("【第%d手】\n",++step); 234 if(nowMove==0) { 235 PlayerMove(now); 236 } else { 237 ComputerMove(now); 238 } 239 whoWin=WhoWin(now); 240 if(whoWin!=0) { 241 OutBoard(now); 242 if(whoWin==1) { 243 printf("电脑:“哇,你居然赢了,真是不敢相信!我输了!”\n"); 244 } 245 if(whoWin==2) { 246 printf("电脑:“蛤铪哈!我赢了,你太弱啦!”\n"); 247 } 248 if(whoWin==3) { 249 printf("电脑:“平局!你还是有点实力,但是我是绝对不会输的!”\n"); 250 } 251 } 252 nowMove^=1; 253 } 254 continueGame=GetInput("是否继续游戏?(0结束游戏,1重新开始):",2); 255 } 256 } 257 258 int main() { 259 Game(); 260 return 0; 261 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。