当前位置: 首页 > Web前端 > HTML

FE.GAME-五子棋AI游戏算法实践

时间:2023-03-28 00:07:18 HTML

最终目标是使用nodejs实现控制台人机对战五子棋,人先走,一方获胜后停止交互。(如下图gif)人机游戏的程序主要构成了一种在机器上表示游戏的方法,让程序知道游戏的状态。生成合法移动的规则,以便游戏公平进行,并可以确定人类对手是否无赖。从所有合法着法中选择最佳着法的技术。一种评估情况利弊的方法,与上述技术结合使用以做出明智的选择。可以使用该程序的接口。本程序主要组成本文从易到难依次介绍以下主要部分的实现drawBoard棋盘局势绘制isEnd游戏结束判断局势绘制通过映射1输出到控制台:'●','-1':'○',0:'+'functiondrawBoard(board,cursor){if(typeofboard==='string')board=board.replace(/(\d{16})/g,"$1,").slice(0,-1).split(',').map(v=>v.split('').map(v=>v==2?'-1':v))console.log((cursor?"person":"machine")+"0123456789ABCDEF")for(leti=0;i9?i:''+i)+''+board[i].map((v,j)=>{if(cursor&&cursor.x===j&&cursor.y===i)return'◎'return({1:'●','-1':'○',0:'+'})[v]}).join(''))}人出手时,用方向键控制'◎'表示移动的位置,回车确认移动过程。stdin.on('keypress',(str,key)=>{if(key.name==='返回'){}else{switch(key.name){case'up':cursor.y=cursor.y-1;休息;case'down':cursor.y=cursor.y+1;休息;case'left':cursor.x=cursor.x-1;休息;案例“右”:光标。x=cursor.x+1;休息;}cursor.x=Math.min(15,Math.max(0,cursor.x))cursor.y=Math.min(15,Math.max(0,cursor.y))drawBoard(chessBoard.join(''),cursor)}isEnd判断游戏是否结束,每放一个棋子,通过计算从当前位置开始的4条线(横竖笔画)是否连续有5个棋子函数isEnd(x,y,chessBoard){letvect=[[-1,0],[-1,1],[0,1],[1,1]]letqi=chessBoard[y][x]for(让我=0;我<4;我++){让a=1;让b=1;while(chessBoard[y+vect[i][0]*a]&&chessBoard[y+vect[i][0]*a][x+vect[i][1]*a]===qi)a++while(chessBoard[y-vect[i][0]*b]&&chessBoard[y-vect[i][0]*b][x-vect[i][1]*b]===qi)b++if(a+b>5)returntrue}returnfalse;}getMark现状评价遍历每个格子的4条线(横竖直连的条数的得分之和)作为打分的参考情势点数:连片得分连片现场评分51<<16睡眠51<<15实时41<<12睡眠41<<11实时31<<8睡眠31<<7实时21<<6睡眠21<<5其他1functiongetScore(cnt,flag){旗帜=旗帜?0:1;switch(cnt){案例5:返回1<<(15+标志)案例4:返回1<<(11+标志)案例3:返回1<<(7+标志)案例2:返回1<<(5+flag)default:return1}}minimax决策算法可以直接看视频https://www.bilibili.com/video...学习下面描述nodejs实现的关于节点的数据结构(由moves生成)Nod类属性描述棋盘位置信息对应棋盘位置信息curjustlastmovenxtnextmovedeep当前节点深度pos记录走棋位置标记当前位置分数children()childnodeclassNod{constructor({board,cur,nxt,deep,pos}){this.board=board;这个.cur=cur;这个.nxt=nxt;this.deep=深;这个.pos=pos;this.mark=getMark(this.board);}children(){constarr=[];constreg=/0/g;while(reg.exec(this.board)!=null){arr.push(newNod({board:this.board.slice(0,reg.lastIndex-1)+this.nxt+this.board.slice(reg.lastIndex),cur:this.nxt,nxt:this.cur,deep:this.deep+1,正:[...this.pos,reg.lastIndex-1]}));}返回arr;}}minimax,也称为minimax算法,是一种在最大失败可能性中寻找最小值的算法,该算法是一种树状结构的递归算法。每个节点的子节点和父节点都是对手玩家,所有节点分为最大值(我方)节点和最小值(对手)节点。也就是说,在每次对方玩家做出最佳决策的决策路径下,我方仍然是优势最大的一方functionminimax(node,MAXDEEP){if(node.deep>=MAXDEEP)return节点;让arr=node.children().map(v=>minimax(v,MAXDEEP));if(node.deep%2)//minreturnarr.sort((a,b)=>a.mark-b.mark)[0]elsereturnarr.sort((a,b)=>b.mark-a.mark)[0]}negamax《Negamax算法》是在《MiniMax算法》将近20年后做了一个小小的改进。程序功能和效率没有什么区别……唯一的区别是前者更简洁(后者一会儿取最大值,一会儿取最小值)。可以发现NegaMax在传参的时候使用了-alpha来起到反向取最大值的作用(也就是负最大值),所以不需要判断取最大值和判断去取最小值。其实也是在“正最大值”和“负最大值”交替出现,原理相同但实现方法不同。functionnegamax(node,MAXDEEP){if(node.deep>=MAXDEEP)返回节点;让arr=node.children();让bestV=arr.map(v=>{constn=negamax(v,MAXDEEP);n.mark=-n.mark返回n;}).sort((a,b)=>b.mark-a.标记)[0];returnbestV;}minimax在上面的极点做alpha-beta剪枝在big-minimum算法中,MIN和MAX过程将所有的可能性保存在搜索树中,然后从端点的估计值向后计算,即效率很低。α-β算法的引入可以提高运算效率,丢弃一些不需要的估计值。它的策略是执行深度优先搜索。当生成的节点到达指定深度时,立即进行静态估计。一旦某个非端节点能够确定后向值,就立即为其赋值,节省了将其他分支扩展到节点的成本。常量MAXN=1<<28;constMINN=-MAXN;functionabminimax(node,MAXDEEP,a,b){if(node.deep>=MAXDEEP)返回节点letarr=node.childrenit();让最好的V;if(node.deep%2){//minbestV={mark:MAXN};for(letchildofarr){constval=abminimax(child,MAXDEEP,a,b)if(val.mark=b)中断;}}}else{bestV={标记:MINN};for(letchildofarr){constval=abminimax(child,MAXDEEP,a,b)if(val.mark>bestV.mark){bestV=val;b=bestV.markif(a>=b)中断;}}}returnbestV;}negamax做alpha-beta剪枝结合两者的优点,代码简化和剪枝优化constMINN=-(1<<28);constMAXDEEP=2;functionabnegamax(node,a,b){if(node.deep>=MAXDEEP)返回节点让arr=node.childrenit();让bestV={标记:MINN};for(letchildofarr){constval=abnegamax(child,-b,-Math.max(a,bestV.mark));val.mark=-val.markif(val.mark>bestV.mark){bestV=val;如果(bestV.mark>=b)中断;}}returnbestV;}源码https://github.com/Seasonley/...