Reti残局Python IDDFS代码调试:如何获取白方唯一和棋走法Kg7?
我正尝试用基于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

