在蒙特卡洛树搜索(MCTS)中如何考量对手的可能走法?
双人交替视角蒙特卡洛树搜索(MCTS)的胜率计算与最优走法实现方案
我刚好有不少双人零和游戏MCTS的开发经验,针对你提到的交替视角节点+基于深层节点胜率选走法的需求,这里分享几个核心要点和实现思路:
核心逻辑:视角交替下的胜率反转
因为你的节点是交替视角(根节点玩家1,子节点玩家2,以此类推),所以不同视角节点的胜率含义完全相反:
- 玩家1视角的节点胜率:代表玩家1在该节点下获胜的概率
- 玩家2视角的节点胜率:代表玩家2在该节点下获胜的概率,对玩家1来说,这个值的补集(1 - 玩家2胜率)才是自己的胜率
举个你提到的例子:假设根节点有两个合法走法对应的子节点(玩家2视角):
- 第一个子节点经过大量模拟后,玩家2胜率70% → 对玩家1来说,这个走法的胜率是30%
- 第二个子节点玩家2胜率40% → 玩家1胜率60%
这时候显然要选第二个走法。
关键实现步骤
1. 给节点标记视角信息
每个节点必须明确记录当前属于哪个玩家的回合,这样回溯更新胜率时才不会出错。比如给节点类加一个player_turn字段:
class MCTSNode: def __init__(self, player_turn, move=None): self.player_turn = player_turn # 1 或 2 self.move = move # 该节点对应的走法 self.wins = 0 self.visits = 0 self.children = [] self.parent = None
2. 模拟与回溯的胜率更新逻辑
模拟(rollout)结束后,要明确返回结果:比如1代表玩家1胜,-1代表玩家2胜,0代表平局。回溯时根据节点视角更新胜率:
- 若当前节点是玩家1视角:如果模拟结果是
1,则胜场+1;平局则胜场+0.5 - 若当前节点是玩家2视角:如果模拟结果是
-1,则胜场+1;平局则胜场+0.5
对应的回溯函数示例:
def backpropagate(node, result): current_node = node while current_node is not None: current_node.visits += 1 if result == 1: if current_node.player_turn == 1: current_node.wins += 1 elif result == -1: if current_node.player_turn == 2: current_node.wins += 1 else: # 平局 current_node.wins += 0.5 current_node = current_node.parent
3. 最优走法的选择逻辑
遍历根节点的所有子节点(玩家2视角),将每个子节点的胜率转换为玩家1的胜率,然后选择胜率最高的走法:
def select_best_move(root_node): best_win_rate = -1.0 best_move = None for child in root_node.children: if child.visits == 0: # 未被模拟的节点暂时胜率设为0.5(或根据需求调整) player1_rate = 0.5 else: # 转换为玩家1的胜率:1 - 玩家2的胜率 player1_rate = 1 - (child.wins / child.visits) if player1_rate > best_win_rate: best_win_rate = player1_rate best_move = child.move return best_move
额外注意事项
- 探索与利用的平衡:在选择扩展节点时,不能只看胜率,要结合UCB1公式平衡探索(访问少的节点)和利用(胜率高的节点),公式示例:
import math def ucb1(child, parent): win_rate = child.wins / child.visits if child.visits > 0 else 0.5 exploration_term = math.sqrt(math.log(parent.visits) / (child.visits + 1e-6)) return win_rate + math.sqrt(2) * exploration_term - 模拟的随机性:rollout阶段要保证动作选择的随机性,避免固定路径导致胜率偏差;如果游戏有确定性策略,也可以在模拟后期加入启发式优化。
- 平局处理:根据游戏规则调整平局的权重,比如有些游戏平局对双方价值相同,就按各加0.5处理;如果平局对某方更有利,可以调整权重。
内容的提问来源于stack exchange,提问作者Bastiaan Reinink
相关产品推荐
相关产品推荐

