☰
五子棋AI算法
2026/9/30 2:41:03 网站建设 项目流程

目录

  • 数据结构
  • 八个方向的权重计算
    • 基本逻辑
    • 代码实现
    • 空位两边连子处理

为了实现人机对战,我们在软件包中新建一个AI类,AI类承担计算八个方向的棋子连子权重,并找到权重最大(最优)位置,返回棋子的功能。

数据结构

  • 键值对存储连子和权重
  • 初始化代码块,设置权重
`intarr[][]=newint[16][16];HashMap<String,Integer>map=newHashMap<>();{map.put("010",10);map.put("0110",100);map.put("01110",1000);map.put("011110",10000);map.put("020",10);map.put("0220",100);map.put("02220",1000);map.put("022220",10000);map.put("01",7);map.put("011",70);map.put("0111",700);map.put("01111",10000);map.put("02",7);map.put("022",70);map.put("0222",700);map.put("02222",10000);}

八个方向的权重计算

基本逻辑

  • 当该位置上有棋子–不计算
  • 当空位旁边无棋子–不计算
  • 当持续遇到相同颜色的棋子–记录
  • 当空位向一个方向遇到不同颜色的棋子时–打破循环
  • 当空位向一个方向遇到了空位时–记录并打破循环
  • 数组越界检查

代码实现

以向左为例

publicvoidtoLeft(intchessArr[][],intr,intc){//如果第一位是0,退出循环if(c-1<0||chessArr[r][c-1]==0)return;intmyFlag=chessArr[r][c-1];StringBuildersb=newStringBuilder("0");//向左遍历,判断棋子数符合哪种情况,加上对应权重for(inti=c-1;i>=0;i--){if(chessArr[r][i]==myFlag){sb.append(myFlag);}else{if(chessArr[r][i]==0){sb.append(0);}break;}//存储进字符串,拿来取出哈希表中对应权重}intscore=map.get(sb.toString());arr[r][c]+=score;}

由于八个方向的基本逻辑一样,只是方向不同,因此我们可以提炼出buildLine方法:

privateStringbuildLine(int[][]arr,intr,intc,intdr,intdc,intmyFlag){StringBuildersb=newStringBuilder("0");//从该位置的下一步长开始inti=r+dr;intj=c+dc;while(i>=0&&i<16&&j>=0&&j<16){if(arr[i][j]==myFlag){sb.append(myFlag);}else{//如果遇到0,记录后打破循坏if(arr[i][j]==0){sb.append("0");}break;//如果遇到其他颜色的棋子,直接打破循环}i+=dr;j+=dc;//下一步}returnsb.toString();}

优化后的toLeft:

publicvoidtoLeft(int[][]chessArr,intr,intc){//如果第一位是0,退出循环if(c-1<0||chessArr[r][c-1]==0)return;intmyFlag=chessArr[r][c-1];StringlStr=buildLine(chessArr,r,c,0,-1,myFlag);intscore=map.get(lStr);arr[r][c]+=score;}

其余几个方向:

publicStringtoRight(intchessArr[][],intr,intc){if(c+1>=16||chessArr[r][c+1]==0){returnnull;}intmyFlag=chessArr[r][c+1];StringrStr=buildLine(chessArr,r,c,0,1,myFlag);intscore=map.get(rStr);arr[r][c]+=score;returnrStr;}publicvoidtoUp(int[][]chessArr,intr,intc){if(r-1<0||chessArr[r-1][c]==0){return;}intmyFlag=chessArr[r-1][c];StringuStr=buildLine(chessArr,r,c,-1,0,myFlag);intscore=map.get(uStr);arr[r][c]+=score;}publicStringtoDown(int[][]chessArr,intr,intc){if(r+1>=16||chessArr[r+1][c]==0){returnnull;}intmyFlag=chessArr[r+1][c];StringdStr=buildLine(chessArr,r,c,1,0,myFlag);intscore=map.get(dStr);arr[r][c]+=score;returndStr;}publicvoidtoLeftUp(int[][]chessArr,intr,intc){if(r-1<0||c-1<0||chessArr[r-1][c-1]==0){return;}intmyFlag=chessArr[r-1][c-1];StringluStr=buildLine(chessArr,r,c,-1,-1,myFlag);intscore=map.get(luStr);arr[r][c]+=score;}publicStringtoLeftDown(int[][]chessArr,intr,intc){if(r+1>=16||c+1>=16||chessArr[r+1][c+1]==0){returnnull;}intmyFlag=chessArr[r+1][c+1];StringldStr=buildLine(chessArr,r,c,1,1,myFlag);intscore=map.get(ldStr);arr[r][c]+=score;returnldStr;}publicvoidtoRightUp(int[][]chessArr,intr,intc){if(r-1<0||c+1>=16||chessArr[r-1][c+1]==0){return;}intmyFlag=chessArr[r-1][c+1];StringruStr=buildLine(chessArr,r,c,-1,1,myFlag);intscore=map.get(ruStr);arr[r][c]+=score;}publicStringtoRightDown(int[][]chessArr,intr,intc){if(r+1>=16||c-1<0||chessArr[r+1][c-1]==0){returnnull;}intmyFlag=chessArr[r+1][c-1];StringrdStr=buildLine(chessArr,r,c,1,-1,myFlag);intscore=map.get(rdStr);arr[r][c]+=score;returnrdStr;}

空位两边连子处理

现在计算机可以处理形如此表中的连子情况:

map.put("010",10);
map.put("0110",100); map.put("01110",1000); map.put("011110",10000); map.put("020", 10); map.put("0220", 100); map.put("02220", 1000); map.put("022220", 10000); map.put("01", 7); map.put("011", 70); map.put("0111", 700); map.put("01111", 10000); map.put("02", 7); map.put("022", 70); map.put("0222", 700); map.put("02222", 10000);

但是若遇到“101110”或“01101”,计算机则会把它们当作简单的二连三连和一连相加,从而导致误判输局。
为此,我们采用在一个方向方法中调用一次反向,取出同一条线上的连子情况再做判断。

调整反向返回类型为String

StringrStr=toRight(chessArr,r,c);intrFlag=chessArr[r][c+1];//如果两个方向棋子颜色不一样,结束方法if(rFlag!=myFlag){return;}if(rStr!=null){//计算两边的有效棋子数intlc=countChess(lStr);intrc=countChess(rStr);//中间有空位的情况分别当作活二 活三 活四处理if(lc+rc==2)arr[r][c]+=100;elseif(lc+rc==3)arr[r][c]+=1000;elseif(lc+rc>=4)arr[r][c]+=10000;}

计算除空位外的连子方法:

privateIntegercountChess(Stringstr){intcount=0;//如果不为0,增加计数for(charc:str.toCharArray()){//toCharArray()将字符串转为char类型数组,便于遍历if(c!='0')count++;}returncount;}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询