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

Reti残局Python IDDFS代码调试:如何获取白方唯一和棋走法Kg7?

Reti残局IDDFS代码修改问题

我正尝试用基于IDDFS的Python代码解决Reti残局,目标是让白方走出唯一能达成和棋的Kh8→Kg7走法,但当前代码输出如下:

Positions searched: 0, Time: 0d 00h 00m 00s, RAM: 81.44 MB
Draw found in 5 move(s), time taken: 0d 00h 00m 00s.
Positions searched: 3433

输出的走法序列:

初始棋盘状态:
. . . . . . . K
. . . . . . . .
k . P . . . . .
. . . . . . . p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Move Kh7:
. . . . . . . .
. . . . . . . K
k . P . . . . .
. . . . . . . p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Move Kb6:
. . . . . . . .
. . . . . . . K
. k P . . . . .
. . . . . . . p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Move Kh6:
. . . . . . . .
. . . . . . . .
. k P . . . . K
. . . . . . . p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Move Kxc6:
. . . . . . . .
. . . . . . . .
. . k . . . . K
. . . . . . . p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Move Kxh5:
. . . . . . . .
. . . . . . . .
. . k . . . . .
. . . . . . . K
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

我希望精准获取该关键王步,请问需要修改代码的哪一部分?


基于IDDFS的Python原代码

import chess
import time
import threading
import sys
import os
import psutil

positions_searched = 0
stop_timer = False

def format_time(seconds):
    """Convert seconds to a format of %dd %hh %mm %ss."""
    days, seconds = divmod(seconds, 86400)
    hours, seconds = divmod(seconds, 3600)
    minutes, seconds = divmod(seconds, 60)
    return f"{int(days)}d {int(hours):02d}h {int(minutes):02d}m {int(seconds):02d}s"

def update_position_counter():
    """Periodically updates the counter of positions searched and prints RAM usage."""
    global stop_timer
    process = psutil.Process(os.getpid())
    start_time = time.time()
    while not stop_timer:
        elapsed_time = time.time() - start_time
        ram_usage = process.memory_info().rss / 1024 ** 2  # Convert bytes to MB
        sys.stdout.write(f"\rPositions searched: {positions_searched}, Time: {format_time(elapsed_time)}, RAM: {ram_usage:.2f} MB\033[K")
        sys.stdout.flush()
        time.sleep(1)
    print()

def ddfs(board, depth, seeking_draw=False):
    global positions_searched
    positions_searched += 1

    if board.is_checkmate():
        return not seeking_draw, []
    
    if depth == 0 or board.is_game_over():
        # Consider draws excluding threefold repetition.
        return board.is_stalemate() or board.is_insufficient_material() or board.can_claim_fifty_moves(), []

    legal_moves = list(board.legal_moves)
    for move in legal_moves:
        board.push(move)
        found_goal, goal_path = ddfs(board, depth - 1, seeking_draw)
        board.pop()
        if found_goal:
            return True, [move] + goal_path
    
    return False, []

def iterative_deepening_dfs(board, seeking_draw=False):
    global stop_timer
    depth = 0
    while True:
        found_goal, goal_sequence = ddfs(board.copy(), depth, seeking_draw)
        if found_goal:
            stop_timer = True
            return depth, goal_sequence
        depth += 1
        if depth > 15:
            stop_timer = True
            print(f"Search stopped at depth {depth}. No solution found.")
            break
    stop_timer = True
    return None, []

def print_move_sequence(original_board, move_sequence):
    """Prints the board state and moves leading to mate or draw."""
    print("\nInitial board state:")
    print(original_board, "\n")
    
    board = original_board.copy()
    for move in move_sequence:
        san_move = board.san(move)
        board.push(move)
        print(f"\nMove {san_move}:")
        print(board, "\n")

def main():
    initial_fen = "7K/8/k1P5/7p/8/8/8/8 w - - 0 1"
    board = chess.Board(initial_fen)

    stronger = 'black'
    seeking_draw = (stronger == 'black')

    stop_timer = False
    timer_thread = threading.Thread(target=update_position_counter)
    timer_thread.start()

    start_time = time.time()
    mate_depth, goal_sequence = iterative_deepening_dfs(board, seeking_draw)
    elapsed_time = time.time() - start_time

    stop_timer = True
    timer_thread.join()

    outcome = "draw" if seeking_draw else "mate"
    print(f"\n{outcome.capitalize()} found in {mate_depth} move(s), time taken: {format_time(elapsed_time)}.")
    print(f"Positions searched: {positions_searched}")
    board.reset()
    board.set_fen(initial_fen)
    print_move_sequence(board, goal_sequence)

if __name__ == "__main__":
    main()

代码修改要点

1. 修正搜索目标的逻辑

当前代码中seeking_draw的判断逻辑错误,白方是需要主动寻找和棋的一方,应直接将其设为True:
在main函数中修改:

# 替换原有的stronger和seeking_draw定义
seeking_draw = True  # 明确白方目标是寻找和棋路径

2. 优先搜索关键走法

当前代码按默认顺序遍历合法走法,导致先找到Kh7的无效路径。可以在ddfs函数中调整走法排序,优先搜索Kg7这个关键走法:

legal_moves = list(board.legal_moves)
# 自定义走法优先级:优先白王走Kh8→Kg7
if board.turn == chess.WHITE:
    def move_priority(move):
        if move == chess.Move(chess.H8, chess.G7):
            return 0  # 最高优先级
        # 其次是白王向兵方向移动的走法
        elif move.from_square == chess.H8 and move.to_square in [chess.F7, chess.G8]:
            return 1
        else:
            return 2
    legal_moves.sort(key=move_priority)

3. 优化和棋判定逻辑

Reti残局的和棋核心是白王控制黑王通路,同时保留兵的升变威胁,而非直接在有限深度内达成和棋。修改ddfs函数的终止条件:

if depth == 0 or board.is_game_over():
    # 基础和棋判定
    is_draw = board.is_stalemate() or board.is_insufficient_material() or board.can_claim_fifty_moves()
    # 针对Reti残局的补充判定:白兵未被吃,且白王能牵制黑王
    if not is_draw:
        white_pawn = board.piece_at(chess.C6)
        if white_pawn and white_pawn.color == chess.WHITE:
            # 黑王无法一步吃掉白兵
            black_king_pos = board.king(chess.BLACK)
            if black_king_pos not in chess.SquareSet(chess.SquareDistance(chess.C6, 1)):
                # 白王在能支援兵升变的位置(如g7、g6、f7)
                white_king_pos = board.king(chess.WHITE)
                if white_king_pos in [chess.G7, chess.G6, chess.F7]:
                    is_draw = True
    return is_draw, []

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:14:52