1

I have asked a similar question elsewhere and I have detected where roughly is a problem. It is in this function which gets processed for node "1" only, see the output section below: (I'm trying to put the node 6109 into A[1]['sequence'] but I cannot) Can someone help to me fix this function def evaluate_and_partition(A, node_id=1):

def evaluate_and_partition(A, node_id=1):
    node = A[node_id]
    # Debugging line to track the function calls
    print(f"Evaluating Node ID: {node_id}")

    # Return previously calculated result if this node has been processed
    if node['processed']:
        print(f"Returning processed Node ID: {node_id} with result: {node['result']}, moves to mate: {node['moves_to_mate']}")
        return node['result'], node['moves_to_mate']

    # Initialize variables to store the best result and path found so far
    optimal_result = -float('inf')  # Assume worst case scenario
    optimal_moves_to_mate = None  # Initialize as None, to be updated
    optimal_child_id = None  # Keep track of which child leads to the optimal result

    # Iterate through each child of the current node
    for child_id in node['children']:
        print(child_id)
        # Recursively evaluate each child
        child_result, child_moves_to_mate = evaluate_and_partition(A, child_id)
        
        # Check if the current child's result improves upon the best result found so far
        if child_result is not None and (
            child_result > optimal_result or 
            (child_result == optimal_result and optimal_moves_to_mate is not None and 
             child_moves_to_mate is not None and child_moves_to_mate < optimal_moves_to_mate)):
            # Update optimal values based on the current child's results
            optimal_result = child_result
            optimal_moves_to_mate = child_moves_to_mate
            optimal_child_id = child_id

    # After evaluating all children, update the current node with the best result and path found
    node['result'] = optimal_result
    if optimal_moves_to_mate is not None:
        # If a path to victory or draw is found, increment moves to mate as we move up the tree
        node['moves_to_mate'] = optimal_moves_to_mate + 1
    else:
        # If no path improves the position, moves to mate remains None
        node['moves_to_mate'] = None
    node['sequence'] = [optimal_child_id] if optimal_child_id is not None else []
    node['processed'] = True  # Mark the node as processed

    # Return the best result and path found for the current node
    return node['result'], node['moves_to_mate']

END OF THE WRONG FUNCTION, the code follows

import chess

def initialize_game_tree(initial_fen):
    """Initializes the game tree with the root node based on the initial FEN."""
    return {
        1: {
            'fen': initial_fen,
            'moves_to_mate': None,
            'parent': None,
            'color': chess.WHITE if initial_fen.split(' ')[1] == 'w' else chess.BLACK,
            'result': None,
            'processed': False,
            'sequence': [],
            'children': []
        }
    }

def add_descendants(node_id, depth, A):
    """Recursively adds descendant nodes to the game tree up to a specified depth."""
    if depth == 0:
        return
    board = chess.Board(A[node_id]['fen'])
    for move in board.legal_moves:
        board.push(move)
        new_node_id = len(A) + 1
        A[new_node_id] = {
            'fen': board.fen(),
            'moves_to_mate': None,
            'parent': node_id,
            'color': chess.WHITE if board.turn else chess.BLACK,
            'result': None,
            'processed': False,
            'sequence': [],
            'children': []
        }
        A[node_id]['children'].append(new_node_id)
        add_descendants(new_node_id, depth - 1, A)
        board.pop()


def evaluate_and_partition(A, node_id=1):
    node = A[node_id]
    # Debugging line to track the function calls
    print(f"Evaluating Node ID: {node_id}")

    # Return previously calculated result if this node has been processed
    if node['processed']:
        print(f"Returning processed Node ID: {node_id} with result: {node['result']}, moves to mate: {node['moves_to_mate']}")
        return node['result'], node['moves_to_mate']

    # Initialize variables to store the best result and path found so far
    optimal_result = -float('inf')  # Assume worst case scenario
    optimal_moves_to_mate = None  # Initialize as None, to be updated
    optimal_child_id = None  # Keep track of which child leads to the optimal result

    # Iterate through each child of the current node
    for child_id in node['children']:
        print(child_id)
        # Recursively evaluate each child
        child_result, child_moves_to_mate = evaluate_and_partition(A, child_id)
        
        # Check if the current child's result improves upon the best result found so far
        if child_result is not None and (
            child_result > optimal_result or 
            (child_result == optimal_result and optimal_moves_to_mate is not None and 
             child_moves_to_mate is not None and child_moves_to_mate < optimal_moves_to_mate)):
            # Update optimal values based on the current child's results
            optimal_result = child_result
            optimal_moves_to_mate = child_moves_to_mate
            optimal_child_id = child_id

    # After evaluating all children, update the current node with the best result and path found
    node['result'] = optimal_result
    if optimal_moves_to_mate is not None:
        # If a path to victory or draw is found, increment moves to mate as we move up the tree
        node['moves_to_mate'] = optimal_moves_to_mate + 1
    else:
        # If no path improves the position, moves to mate remains None
        node['moves_to_mate'] = None
    node['sequence'] = [optimal_child_id] if optimal_child_id is not None else []
    node['processed'] = True  # Mark the node as processed

    # Return the best result and path found for the current node
    return node['result'], node['moves_to_mate']


# Main execution block
initial_fen = "4k3/8/8/3K2Q1/8/8/8/8 w - - 6 4"
A = initialize_game_tree(initial_fen)
add_descendants(1, 5, A)  # Adjust the depth as needed
evaluate_terminal_positions(A)
evaluate_and_partition(A, 1)

# Print the root node to see the analysis result
print(A[1])

# Function to print boards for children of a given node
def print_boards_for_children(A, parent_key):
    children_keys = A[parent_key].get('children', [])
    for key in children_keys:
        if key in A:
            fen = A[key]['fen']
            board = chess.Board(fen)
            print(f"Board for child {key}:\n{board}\n")

# Display the initial board and boards for first-level children
print(chess.Board(initial_fen))
print_boards_for_children(A, 1)

The output is like this

Evaluating Node ID: 1
Returning processed Node ID: 1 with result: None, moves to mate: None
{'fen': '4k3/8/8/3K2Q1/8/8/8/8 w - - 6 4', 'moves_to_mate': None, 'parent': None, 'color': True, 'result': None, 'processed': True, 'sequence': [], 'children': [2, 3697, 6109, 8685, 9041, 20864, 32046, 34967, 44777, 50093, 60983, 70685, 83639, 94018, 111578, 126490, 142939, 161014, 178208, 196205, 197783, 202648, 209235, 216611, 225572, 236906, 248111]}
. . . . k . . .
. . . . . . . .
. . . . . . . .
. . . K . . Q .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
Board for child 2:
. . . . k . Q .
. . . . . . . .
. . . . . . . .
. . . K . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Board for child 3697:
. . . Q k . . .
. . . . . . . .
. . . . . . . .
. . . K . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

Board for child 6109:
. . . . k . . .
. . . . . . Q .
. . . . . . . .
. . . K . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.