1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > TicTacToe(井字棋)的算法——不比人的智商低的AI

TicTacToe(井字棋)的算法——不比人的智商低的AI

时间:2020-05-14 20:42:44

相关推荐

TicTacToe(井字棋)的算法——不比人的智商低的AI

何为TicTacToe?

TicTacToe也俗称井字棋或三连棋(两人轮流在一有九格方盘上划加字或圆圈, 谁先把三个同一记号排成横线、直线、斜线, 即是胜者),男女老少皆宜的入门级棋类游戏。

关于游戏的实现方式,比较简单,在这就不多说了。直接谈一谈如何写出在TicTacToe游戏中不输给人类棋手的电脑。

想要写出游戏AI,第一步是自己要会玩游戏,有自己的策略。第二部才是告诉我们的AI如何实现这样的策略。我们在玩的时候发现能尽可能占据有利的位置会帮助我们快速赢下比赛,玩游戏还能发现的一点就是一定要防住对面即将连成一条线的一路,还有很多,很多。这些特征可以说明,游戏中不同情况下,盘面的每一个位置似乎有着不同的重要性,我们完全可以利用这一点来指导我们的AI去驰骋沙场。(我一开始打算仔细判断每一种情况,比如双二单二什么的,结果不但代码量大而且效果和这样的思路没什么区别)

也就是说,给与AI一个非常重要的变量(一个3*3的数组),表示每一个位置的权值,也就是该位置的重要性的体现。比赛中第一重要的当然是自己连成一条线,这可以赋予最高的权值。而且,这个权值应该大到什么地步呢?当然应该大到无论其他什么情况发生都以此为第一要素的地步。所以我们可以在AI检查出自己能成一条线的位置时,给这个位置赋值10000,代表这个位置至高无上的地位。

第二重要的则是防止对手成一条线,此举的重要性,可谓一人之下万人之上,就在有这种情况的时候赋予这个位置1000的值吧。

其他需要赋值的三种情况是:1.某条线仅仅有己方棋子一枚;2.某条线仅仅有敌方棋子一枚;3.某条线上空空如也。如果是我们的AI先手,我认为第一条的权重大于第二条大于第三条。而AI后手则2>3>1。

因为玩过Tictactoe的朋友一定知道,这是一个先手赢不了,后手输不了的游戏。但是作为后手一旦失误就会输棋,先手若能抓住后手的失误则能赢棋。数年前中国五子棋第一人那威曾经说过“先手要攻,后手要守”。虽然是说五子棋,不过Tictactoe实际上就是三字棋,与五子棋的区别仅仅是少了很多很多的变化而已。所以我们需要给我们的AI贯彻这样的思想:先手要积极进攻,后手要小心放手。好了,AI的思路基本上就是这样了,下面贴上核心部分的代码(java)

注:游戏的地图保存在一个叫net的数组里,每一个位置值为0表示没有棋,1表示为X棋,2表示为O棋

int[][] net=new int[4][4];//0 means null;1 means X;2 means O;

int level[][]=new int[4][4];//越大优先级越高

IOHelper h=new IOHelper();

int o2=10000;//一个己方活二权值

int x2=1000;//一个对方活二权值

int x=10;//一个对方活一权值

int o=6;//一个己方活一权值

int nothing=4;//一个空行权值

for(int i=0;i<3;i++){

for(int j=0;j<3;j++){

if(net[i][j]!=0)level[i][j]=0;

else{

//横竖两条,每人都有

//自己活二,,220

if(((net[0][j]+net[1][j]+net[2][j])==4)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==-1)

level[i][j]=level[i][j]+o2;

if(((net[i][0]+net[i][1]+net[i][2])==4)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==-1)

level[i][j]=level[i][j]+o2;

//对方活二,110

if(((net[0][j]+net[1][j]+net[2][j])==2)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==0)

level[i][j]=level[i][j]+x2;

if(((net[i][0]+net[i][1]+net[i][2])==2)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==0)

level[i][j]=level[i][j]+x2;

//单个X,100

if(((net[0][j]+net[1][j]+net[2][j])==1)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==0)

level[i][j]=level[i][j]+x;

if(((net[i][0]+net[i][1]+net[i][2])==1)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==0)

level[i][j]=level[i][j]+x;

//单个O,200

if(((net[0][j]+net[1][j]+net[2][j])==2)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==1)

level[i][j]=level[i][j]+o;

if(((net[i][0]+net[i][1]+net[i][2])==2)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==1)

level[i][j]=level[i][j]+o;

//空行,000

if(((net[0][j]+net[1][j]+net[2][j])==0)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==-1)

level[i][j]=level[i][j]+nothing;

if(((net[i][0]+net[i][1]+net[i][2])==0)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==-1)

level[i][j]=level[i][j]+nothing;

//分情况

//主对角线

if((i==0&&j==0)||(i==2&&j==2)||(i==1&&j==1)){

//己方活二

if(((net[0][0]+net[1][1]+net[2][2])==4)&&(net[0][0]*net[1][1]*net[2][2])==0&&

((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==-1)

level[i][j]=level[i][j]+o2;

//对方活二

if(((net[0][0]+net[1][1]+net[2][2])==2)&&(net[0][0]*net[1][1]*net[2][2])==0&&

((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==0)

level[i][j]=level[i][j]+x2;

//单个X

if(((net[0][0]+net[1][1]+net[2][2])==1)&&(net[0][0]*net[1][1]*net[2][2])==0&&

((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==0)

level[i][j]=level[i][j]+x;

//单个O

if(((net[0][0]+net[1][1]+net[2][2])==2)&&(net[0][0]*net[1][1]*net[2][2])==0&&

((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==1)

level[i][j]=level[i][j]+o;

//空行,000

if(((net[0][0]+net[1][1]+net[2][2])==0)&&(net[0][0]*net[1][1]*net[2][2])==0&&

((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==-1)

level[i][j]=level[i][j]+nothing;

}

//副对角线

if((i==0&&j==2)||(i==2&&j==0)||(i==1&&j==1)){

//己方活二

if(((net[0][2]+net[1][1]+net[2][0])==4)&&(net[0][2]*net[1][1]*net[2][0])==0&&

((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==-1)

level[i][j]=level[i][j]+o2;

//对方活二

if(((net[0][2]+net[1][1]+net[2][0])==2)&&(net[0][2]*net[1][1]*net[2][0])==0&&

((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==0)

level[i][j]=level[i][j]+x2;

//单个X

if(((net[0][2]+net[1][1]+net[2][0])==1)&&(net[0][2]*net[1][1]*net[2][0])==0&&

((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==0)

level[i][j]=level[i][j]+x;

//单个O

if(((net[0][2]+net[1][1]+net[2][0])==2)&&(net[0][2]*net[1][1]*net[2][0])==0&&

((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==1)

level[i][j]=level[i][j]+o;

//空行,000

if(((net[0][2]+net[1][1]+net[2][0])==0)&&(net[0][2]*net[1][1]*net[2][0])==0&&

((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==-1)

level[i][j]=level[i][j]+nothing;

}//the end of for if

}//the end of if

}//the end of for j

}//the end of for j

//寻找最大权值的位置

int maxi = 0,maxj = 0,temp = 0;

for(int i=0;i<3;i++){

for(int j=0;j<3;j++){

if(level[i][j]>temp)

{

temp=level[i][j];

maxi=i;

maxj=j;

}

System.out.println("net[i][j]="+net[i][j]);

System.out.println("level[i][j]="+level[i][j]);

}

}

觉得作者不容易的话请顶一个(*^__^*) 谢谢

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