You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

极小极大(Minimax)算法:如何实现回合跳过功能?

为极小极大(Minimax)算法添加“无合法移动则跳过回合”的功能

我来帮你搞定这个问题——在井字棋、黑白棋这类存在「无合法移动需跳过回合」规则的游戏里,修改Minimax算法的核心是处理当前玩家无棋可走的分支逻辑,下面一步步拆解:

核心问题分析

原Minimax算法默认每个玩家在自己的回合都有至少一个合法移动(比如井字棋前期),但像黑白棋这类游戏,经常会出现某一方没有可落子的位置,必须跳过回合的情况。如果不处理这种场景,算法会因为没有子节点可遍历,返回错误的极值(比如最大化玩家会一直返回-∞),导致决策完全失效。

修改步骤与代码实现

1. 先实现辅助判断函数

首先需要一个工具函数,用来判断当前玩家在给定节点(棋盘状态)下是否有合法移动:

def has_valid_moves(node, player):
    # 根据具体游戏规则(比如黑白棋的翻转规则、井字棋的空位规则)
    # 检查player是否有至少一个合法的落子位置
    # 示例逻辑(黑白棋):遍历所有空位,判断落子后是否能翻转对方棋子
    for row in range(len(node.board)):
        for col in range(len(node.board[row])):
            if is_valid_move(node.board, row, col, player):
                return True
    return False

2. 修改Minimax主函数

在原算法的基础上,添加对「无合法移动」场景的处理,同时还要考虑连续跳过回合的极端情况(比如双方都没棋可走,游戏直接结束):

def minimax(node, depth, maximizingPlayer):
    # 终端节点判断:depth为0,或者游戏结束(包括双方都无合法移动)
    if depth == 0 or is_terminal_node(node):
        return heuristic_value(node)
    
    if maximizingPlayer:
        best_value = -float('inf')
        # 检查当前最大化玩家是否有合法移动
        if has_valid_moves(node, MAX_PLAYER):
            # 有合法移动,遍历所有子节点
            for child in generate_children(node, MAX_PLAYER):
                v = minimax(child, depth - 1, False)
                best_value = max(best_value, v)
        else:
            # 无合法移动,生成「跳过回合」的节点:棋盘不变,切换为最小化玩家回合
            # 注意:要创建新节点,避免修改原节点状态(递归中节点应保持不可变)
            skip_node = Node(node.board.copy(), turn=MIN_PLAYER)
            v = minimax(skip_node, depth - 1, False)
            best_value = max(best_value, v)
        return best_value
    else:
        best_value = float('inf')
        # 检查当前最小化玩家是否有合法移动
        if has_valid_moves(node, MIN_PLAYER):
            for child in generate_children(node, MIN_PLAYER):
                v = minimax(child, depth - 1, True)
                best_value = min(best_value, v)
        else:
            # 无合法移动,跳过回合,切换为最大化玩家
            skip_node = Node(node.board.copy(), turn=MAX_PLAYER)
            v = minimax(skip_node, depth - 1, True)
            best_value = min(best_value, v)
        return best_value

3. 完善终端节点判断

is_terminal_node函数需要补充「双方都无合法移动」的判断:

def is_terminal_node(node):
    # 游戏结束的条件:
    # 1. 棋盘已满(比如井字棋)
    # 2. 一方获胜(比如黑白棋某一方无棋子)
    # 3. 双方都没有合法移动
    return (is_board_full(node.board) or 
            has_winner(node.board) or 
            (not has_valid_moves(node, MAX_PLAYER) and not has_valid_moves(node, MIN_PLAYER)))

关键细节说明

  • 跳过节点的状态:跳过回合时,棋盘状态完全不变,只是切换当前玩家,所以要创建新的节点对象,避免修改原节点的状态(递归中节点应该是不可变的,防止状态污染)。
  • 连续跳过的处理:如果双方都没有合法移动,is_terminal_node会判定为终端节点,直接返回启发式值,避免无限递归。
  • 启发式函数的适配:如果游戏支持跳过回合,启发式函数不需要额外修改,因为它只评估当前棋盘状态的优劣,不管是正常走棋还是跳过得到的状态。

针对黑白棋的特殊提示

在黑白棋中,跳过回合的规则是:如果当前玩家无合法移动,必须跳过,由对方继续;如果对方也无合法移动,则游戏结束。上面的代码已经完美覆盖了这个逻辑——当一方跳过之后,递归会进入对方的回合,对方如果也没棋走,就会触发终端节点判断。

内容的提问来源于stack exchange,提问作者Valeria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:02:22