无第三方库实现国际象棋对局树结构及分支识别咨询
构建国际象棋多局对局树结构的实现方案
一、核心类的正确设计
先明确Node和Branch的职责边界,避免逻辑混淆:
Node:代表对局中的一个状态节点,存储回合数和当前执棋方,同时维护所有从该节点出发的分支选项。Branch:代表从某个节点出发的一步具体走法,存储走法字符串(比如e4、Nf3),并指向该走法后的下一个Node。
代码示例:
class Node: def __init__(self, turn_number, player): self.turn_number = turn_number # 根节点设为0,代表开局前状态 self.player = player # 用'W'代表白方,'B'代表黑方 self.branches = [] # 存储当前节点的所有分支(Branch对象) class Branch: def __init__(self, move, next_node): self.move = move # 具体走法,如"e4" self.next_node = next_node # 该走法对应的下一个Node
二、树的构建与节点/分支添加逻辑
构建树的核心是复用已有路径,仅在差异点创建新分支,流程如下:
- 初始化根节点:回合数0,执棋方设为
None - 遍历每一局的走法序列,逐个处理每一步走法:
- 从当前节点(初始为根节点)开始
- 检查当前节点的
branches中是否存在对应走法的Branch - 若存在:直接跳转到该
Branch的next_node,继续处理下一步 - 若不存在:创建新的
Node(回合数+1,执棋方切换),创建新的Branch绑定走法和新Node,将Branch加入当前节点的branches列表,再跳转到新Node
实现代码(添加单局/多局对局)
def add_game_to_tree(root_node, game_moves): current_node = root_node current_player = 'W' # 国际象棋默认白方先走 for idx, move in enumerate(game_moves): # 检查当前节点是否已有该走法的分支 existing_branch = next((b for b in current_node.branches if b.move == move), None) if existing_branch: # 复用已有路径 current_node = existing_branch.next_node else: # 创建新节点:回合数为idx+1,执棋方切换 next_turn = idx + 1 next_player = 'B' if current_player == 'W' else 'W' new_node = Node(next_turn, next_player) new_branch = Branch(move, new_node) current_node.branches.append(new_branch) current_node = new_node # 切换下一轮执棋方 current_player = 'B' if current_player == 'W' else 'W' # 示例:添加两局对局 root = Node(0, None) # 第一局:e4 e5 Nf3 Nc6 game1 = ["e4", "e5", "Nf3", "Nc6"] # 第二局:e4 c5 Nf3 Nc6(第二步产生分支) game2 = ["e4", "c5", "Nf3", "Nc6"] add_game_to_tree(root, game1) add_game_to_tree(root, game2)
三、识别对局分支点
分支点的本质是存在多个可选走法的Node,有两种识别方式:
- 遍历树结构,找出所有
len(node.branches) > 1的Node,这些节点就是分支点(从这里开始出现了不同走法) - 在添加对局的过程中实时检测:当处理某一步走法时,当前节点没有对应分支,说明当前节点是一个新的分支点(因为已有其他对局从该节点走了不同的路)
分支点检测代码
def find_branch_points(root_node): branch_points = [] stack = [root_node] while stack: node = stack.pop() if len(node.branches) > 1: branch_points.append({ "turn_number": node.turn_number, "player": node.player, "available_moves": [b.move for b in node.branches] }) # 遍历所有子节点 for branch in node.branches: stack.append(branch.next_node) return branch_points # 检测示例中的分支点 points = find_branch_points(root) for p in points: print(f"分支点:回合{p['turn_number']},执棋方{p['player']},可选走法:{p['available_moves']}")
输出结果会显示回合1、执棋方B的节点是分支点,可选走法为e5和c5,符合两局对局的差异点。
四、树的遍历与展示
可以用递归或迭代方式遍历树,展示所有对局路径:
def print_tree(node, path=""): if node.turn_number == 0: print("开局") else: print(f"回合{node.turn_number} {node.player}: {path}") for branch in node.branches: new_path = path + " " + branch.move if path else branch.move print_tree(branch.next_node, new_path) # 打印整个树 print_tree(root)
内容的提问来源于stack exchange,提问作者marfin
相关产品推荐
相关产品推荐

