最近有个朋友来找我问井字棋的下棋逻辑怎么用编程表示,搜了一下网上的资料,发现了minimax这个算法,研究了一下发现蛮有意思的,就写一篇文章记录一下
minimax通常是用于那些满足“零和博弈”(指参与博弈的各方,在严格竞争下,一方的收益必然意味着另一方的损失,博弈各方的收益和损失相加总和永远为“零”,故双方不存在合作的可能)的棋类算法。
其核心是对每一种可能的局面进行打分,在我方回合总是会选择分数更高的分支,而敌方回合总是会显示分数更低的分支。
如图所示。方块为我方回合,三角为敌方回合,最后的圈为游戏结束情况及其对应的得分,可以看到方块就是从所有子节点中取分数最高的,而三角则是从所有子节点中取分数最低的。话不多说,直接上代码
def minimax(board, player_mine, player_you, mine_or_you, bestAction, depth=0):
if mine_or_you:
bestVal = -10
else:
bestVal= 10
if complete(board,player_mine,player_you):
if is_win(board,player_you):
show_board(board)
print('分数是'+str(-10 + depth))
return -10 + depth, None
elif is_win(board,player_mine):
show_board(board)
print('分数是'+str(10 - depth))
return 10 - depth, None
else:
show_board(board)
print('分数是'+'0')
return 0,None
for action in [i for i in range(9) if board[i] == 0]:
if mine_or_you:
board=place(board,action,player_mine)
else:
board = place(board, action, player_you)
val, _ = minimax(board, player_mine, player_you, not mine_or_you, bestAction, depth + 1)
board=remove(board,action)
if mine_or_you:
if val > bestVal:
bestVal, bestAction = val, action
else:
if val < bestVal:
bestVal, bestAction = val, action
return bestVal, bestAction
传参中
1、board是个长度为9的数组,代表了棋盘,其中为0的代表空着的点,为1的代表是玩家1下的,为2的代表是玩家2下的
2、player_mine代表函数调用者,先手的为1,后手的为2
3、player_you代表对手,值为3-plyaer_mine
4、mine_or_you为布尔值,因为minimax需要模拟对手(对手是想方设法让得分变低),为true代表自己,为false代表对手
5、bestAction为当前的最优操作,是用来做棋牌回退的
6、depth代表当前走了多少步,从0开始,depth越高,最终计算的分数越接近0