The Reti endgame

49 Views Asked by At

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()
0

There are 0 best solutions below