Minimax算法

Minimax算法被广泛应用在棋类游戏中,是一种找出失败的最大可能性中的最小值的算法(Wikipedia)。

博弈树(game tree)

以“tic tac toe”游戏为例。从当前状态或初始状态开始,根据可以采取的行动(actions)和可以到达的状态(s),绘制子节点,再对子节点绘制子节点。直到游戏结束的状态。如下图这种树称为game tree。

game_tree

Minimax算法

先从一个简单的场景入手,介绍Minimax的思想。

假设有一个游戏,只有两个玩家参与,两轮便定出胜负。我们称两个玩家为MAX和MIN。每个玩家在各自的回合中,都有2个到1个行动(actions)可选。MAX先手。下图中,圆形表示MAX的回合,方形表示MIN的回合,每条连线表示当前状态下可以采取的行动。因为假设游戏只有两轮,所以游戏进行到图中标号为4的层时,游戏的胜负就已经知道了,我们可以评估该层各个状态的效用值(utility),来表示玩家MAX的胜负多少,对于这一层的结果,MIN和MAX双方都是知道的。

minimax

假设现在我们就是MAX,我们的对手就是MIN。MIN为了赢得游戏,一定会想办法让MAX的得分最低。游戏双方都会从游戏的结果开始回溯,来指导相应的状态下,自己该采取何种行动来最大化自己的目标。

假设现在处在标号为3的层,是MIN的回合。MIN在所有可选的actions中,一定会选择使得MAX的得分最少的行动。所以将子节点较小的效用值填写到第3层中,表示游戏进行到相应的状态,MAX能达到的最大效用。

接着回溯到第2层,这层是MAX的回合,MAX知道了第3层各种状态下自己的效用值,MAX当然会选择使自己效用最大的行动。所以选取子节点效用最大的填入第2层。

接着回溯第1层,是MIN的回合,与第3层同理。

最后回溯到第0层,MAX的回合,与第2层同理。

MAX从游戏结束的状态开始回溯,知道了自己能够达到的最大效用是-7。

上述过程就是Minimax算法的主要流程。

多玩家场景

前面考虑的都是只有两个玩家参与的场景。如果是多玩家场景,可以将单个的效用值扩展到向量的形式。

multiplayer minimax

总结

算法的实现可以通过递归的方式,从当前状态开始搜索,一直到游戏结束,然后回溯。但是当游戏的状态和可采取的步骤变多,game tree的深度变深时,博弈树的节点数量就会指数爆炸。所以根据minimax搜索整棵树的行为,对大多数游戏是不现实的。但是Minimax的思想是其他算法的基础。

### Minimax算法的代码实现 以下是Minimax算法的一个简单实现,以井字棋为例: ```python import math def minimax(board, depth, is_maximizing): """ 实现Minimax算法的核心逻辑。 参数: board (list): 当前棋盘状态表示为列表形式。 depth (int): 搜索树的深度。 is_maximizing (bool): 是否是最大化玩家。 返回值: int: 表示最佳得分。 """ scores = { 'X': 10, 'O': -10, 'tie': 0 } result = check_winner(board) if result != None: return scores[result] if is_maximizing: best_score = -math.inf for i in range(9): if board[i] == '': board[i] = 'X' score = minimax(board, depth + 1, False) board[i] = '' best_score = max(score, best_score) return best_score else: best_score = math.inf for i in range(9): if board[i] == '': board[i] = 'O' score = minimax(board, depth + 1, True) board[i] = '' best_score = min(score, best_score) return best_score def find_best_move(board): """ 找到当前局面下的最优走法。 参数: board (list): 当前棋盘状态表示为列表形式。 返回值: int: 最优位置索引。 """ best_score = -math.inf optimal_move = 0 for i in range(9): if board[i] == '': board[i] = 'X' # 假设 X 是最大化玩家 move_score = minimax(board, 0, False) board[i] = '' # 还原棋盘 if move_score > best_score: best_score = move_score optimal_move = i return optimal_move def check_winner(board): """ 检查是否有获胜者或者平局。 参数: board (list): 当前棋盘状态表示为列表形式。 返回值: str or None: 获胜者的标志 ('X', 'O') 或 平局('tie'), 如果没有结束返回None。 """ winning_combinations = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ] for combo in winning_combinations: if board[combo[0]] == board[combo[1]] == board[combo[2]]: if board[combo[0]] != '': return board[combo[0]] if '' not in board: return 'tie' return None ``` 上述代码实现了Minimax算法并应用于井字棋游戏中。通过递归的方式计算每一步的最佳得分,并最终找到最优解[^4]。 ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值