I'm trying to make my code in Python to solve correctly the Reti endgame by pushing Kh8 to Kg7, which is the only move leading to a draw for white. However the code given below keeps saying
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
But I wish to obtain the most accurate move by K. What line to touch ?
Initial board state:
. . . . . . . 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
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
The code in Python based on IDDFS
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()
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()