引用自matrix67的博客。
让我们来玩一个游戏。下面有五行石子,白色的石子都是我的,黑色的石子都是你的。我们轮流拿走一个自己的石子,并且规定如果一个石子被拿走了,它后面的所有石子都要被扔掉。谁先没有拿的了,谁就输了。
○●●○●●○●●○
●○○●○●●○●
○○○○
●●●○●●●
●..比如说,如果你先走的话,你可以把第四行的第三个石子拿走,按规定第四行将会只剩下前面两个石子:
○●●○●●○●●○
●○○●○●●○●
○○○○
●●
●
现在轮到我走了。我可以拿走第二行倒数第二个石子,于是整个棋局变成了这样:
○●●○●●○●●○
●○○●○●●
○○○○
●●
●
现在,假如说你拿走了第二行中的第一个石子(于是第二行就没了),那么我就赢定了。我可以拿走第一行中的第一个石子,从而让整个棋局只剩下后面三行:
○○○○
●●
●
要求给出一种最合理的走法。
如果是残局
○○○○
●●
●
把每个白色石子记作 +1 ,把每个黑色石子记作 -1 。于是 ○○○○ + ●● + ● = 4 – 2 – 1 = 1 ,结果是一个正数(记这个结果为特征值),这就表明该局面下我将必胜,即使此时轮到我先走。你会发现上面的说法很有道理 如果棋局是这样
○○
●●●●
○○ + ●●●● = 2 – 4 = -2 ,是一个负数,这就意味着不管谁先走,你都能必胜,如果是
○○
●●如果我先走你后走,你就赢定了;如果你先走我后走,我就赢定了。因为 和为0。
所以正确的走法:只需要走特征值最大的就可以了。
博客原文http://www.matrix67.com/blog/archives/6333
算法:
#include <stdio.h> #include <stdlib.h> template <class type> void inline Swap(type &a,type &b) { type tmp=a; a=b; b=tmp; } class Chess { public: Chess() { int i,j; int c[5][10]= {{0,1,1,0,1,1,0,1,1,0}, {1,0,0,1,0,1,1,0,1,-1}, {0,0,0,0,-1,-1,-1,-1,-1,-1}, {1,1,1,0,1,1,1,-1,-1,-1}, {1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }; //1是黑棋 0是白棋 for(i=0;i<5;i++) for(j=0;j<10;j++) chess[i][j]=c[i][j]; rows=5; } Chess(Chess &other) { int i,j; for(i=0;i<other.rows;i++) {for(j=0;j<10;j++) chess[i][j]=other.chess[i][j]; } rows=other.rows; } int isWin(int turn) const //1该黑棋走,0该白棋走 { if (rows==0) return 1; int i,j; for(i=0;i<rows;i++) { for(j=0;j<10;j++) { if(chess[i][j]==!turn) return 0; } } return 1; } void takeout(int k,int l) { int i,j,flag=0; for(j=l;j<10;j++) chess[k][j]=-1; for(j=0;j<10;j++) { flag=chess[k][j]!=-1; if (flag==1) break; } if(flag==0) { for(i=k;i<rows-1;i++) { for(j=0;j<10;j++) { Swap(chess[i][j],chess[i+1][j]); } } rows--; } } int CheckInput(int i,int j) { if(i<0||i>=rows||j<0||j>=10) { printf("该棋子不存在!\n"); return 0; } else { if(chess[i][j]==-1) { printf("该棋子不存在!2\n"); return 0; } if(chess[i][j]==0) { printf("您不能选择白棋!\n"); return 0; } } return 1; } double EigenValue() const { double value = 0; int i,j; for(i=0;i<rows;i++) { if (chess[i][0] == 0 && chess[i][1] == 0 && chess[i][2] == -1) { value+= 0.5; } else { for(j=0;j<10;j++) { switch(chess[i][j]) { case 1:value--;break; case 0:value++;break; } } } } return value; } void print() const { int i,j; for(i=0;i<rows;i++) { for(j=0;j<10;j++) { switch(chess[i][j]) { case 1:printf("●");break; case 0:printf("○");break; } } printf("\n"); } } int chess[5][10]; int rows; }; //AI下棋的程序 void AIPredict(Chess c,int &AIi,int &AIj) { struct v{ int i,j; double value; } value[50]; int count=0,i,j; for(i=0;i<c.rows;i++) { for(j=0;j<10;j++) { if(c.chess[i][j]==0) { Chess predict=c; predict.takeout(i,j); value[count].i=i; value[count].j=j; value[count].value=predict.EigenValue(); count++; } } } v maxvalue=value[0]; for(i=1;i<count;i++) { if(value[i].value>maxvalue.value) { maxvalue=value[i]; } } AIi=maxvalue.i; AIj=maxvalue.j; } int main() { system("color F0"); printf("游戏规则:\n下面有五行石子,白色空心○的石子都是我的,黑色实心●的石子都是你的。\n我们轮流拿走一个自己的石子,并且规定如果一个石子被拿走了,\n它后面的所有石子都要被扔掉。谁先没有拿的了,谁就输了。\n\n"); Chess c; c.print(); printf("\n\n"); int i,j,turn; printf("你想先手还是后手?1为先手,0为后手:"); scanf("%d", &turn); printf("\n"); while(!c.isWin(turn)) { if (turn==1) { do{ printf("请输入i j表示你要下的位置:(从0开始)"); scanf("%d %d",&i,&j); }while(!c.CheckInput(i,j)); c.takeout(i,j); printf("\n\n"); c.print(); } else { AIPredict(c,i,j); printf("电脑下的位置是:<%d,%d>\n",i,j); c.takeout(i,j); printf("\n\n"); c.print(); } turn = !turn; } if(turn) { printf("你赢了!\n"); } else { printf("你输了!\n"); } system("pause"); return 0; }
时间: 2024-10-15 08:24:29