Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import chess
- def simplify_fen(fen):
- """Simplifies a FEN string by keeping only the position, turn, castling availability, and en passant target square."""
- return ' '.join(fen.split(' ')[:4])
- def add_descendants_iteratively(A, fen_to_node_id):
- queue = [(1, 0)]
- while queue:
- node_id, depth = queue.pop(0)
- board = chess.Board(A[node_id]['fen'] + " 0 1")
- for move in board.legal_moves:
- if move.promotion:
- move = chess.Move(move.from_square, move.to_square, promotion=chess.QUEEN)
- board.push(move)
- simplified_fen = simplify_fen(board.fen())
- if simplified_fen not in fen_to_node_id:
- new_node_id = len(A) + 1
- A[new_node_id] = {
- 'fen': simplified_fen,
- 'moves_to_mate': None,
- 'parent': node_id,
- 'color': chess.WHITE if simplified_fen.split()[1] == 'w' else chess.BLACK,
- 'result': None,
- 'processed': False,
- 'sequence': [],
- 'children': [],
- 'to_end': None,
- }
- fen_to_node_id[simplified_fen] = new_node_id
- A[node_id]['children'].append(new_node_id)
- queue.append((new_node_id, depth + 1))
- board.pop()
- def initialize_game_tree(initial_fen):
- simplified_fen = simplify_fen(initial_fen)
- A = {1: {'fen': simplified_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': [], 'to_end': None}}
- fen_to_node_id = {simplified_fen: 1}
- return A, fen_to_node_id
- def update_game_outcomes(A):
- for key, node in A.items():
- board = chess.Board(node['fen'] + " 0 1")
- if board.is_game_over():
- outcome = board.outcome()
- node['processed'] = True
- if outcome.termination == chess.Termination.CHECKMATE:
- node['result'] = 1 if outcome.winner == chess.WHITE else -1
- node['moves_to_mate'] = 0
- else:
- node['result'] = 0
- node['moves_to_mate'] = None
- node['to_end'] = 0
- # def update_parent_preferences(node_id, A):
- # node = A[node_id]
- # if node['processed']:
- # return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
- # best_child_id = None
- # # Initialize best_result with the current node result, ensuring it's an integer for comparison
- # best_result = node['result'] if node['result'] is not None else -float('inf')
- # best_path_length = float('inf')
- # for child_id in node['children']:
- # child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
- # # Ensure child_result is comparable
- # child_result = child_result if child_result is not None else -float('inf')
- # if child_to_end is not None:
- # path_length = 1 + child_to_end
- # if (child_result > best_result) or (child_result == best_result and path_length < best_path_length):
- # best_child_id = child_id
- # best_result = child_result
- # best_path_length = path_length
- # # After evaluating all children, update the node
- # if best_child_id is not None:
- # node['sequence'] = [best_child_id]
- # node['to_end'] = best_path_length
- # node['moves_to_mate'] = best_path_length if best_result in [1, -1] else None
- # node['result'] = best_result
- # else:
- # # If no viable children, mark this node accordingly
- # node['to_end'] = None if best_path_length == float('inf') else best_path_length
- # node['moves_to_mate'] = None
- # node['result'] = 0 if node['result'] is None else node['result']
- # node['processed'] = True
- # return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
- # def update_parent_preferences(node_id, A):
- # """
- # Recursively updates parent node preferences based on the best child outcomes.
- # Args:
- # - node_id: The ID of the current node in the game tree.
- # - A: The game tree, a dictionary mapping node IDs to node properties.
- # The function updates the following properties for each node:
- # - 'to_end': The number of moves to reach a determined game outcome.
- # - 'moves_to_mate': The number of moves to mate from the current position, if applicable.
- # - 'result': The game outcome from the current position (1 for White win, -1 for Black win, 0 for draw).
- # - 'sequence': The list of child node IDs leading to the best game outcome.
- # - 'processed': A flag indicating that the node has been processed.
- # """
- # node = A[node_id]
- # # Base case: If the node is already processed, return its values
- # if node['processed']:
- # return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
- # # Initialize variables to track the best child node and its outcomes
- # best_child_id = None
- # best_result = -float('inf') if node['color'] == chess.WHITE else float('inf')
- # best_to_end = None
- # # Iterate over all children to find the best outcome
- # for child_id in node['children']:
- # child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
- # # Determine if the current child node is preferable
- # is_preferable = False
- # if node['color'] == chess.WHITE:
- # # White's move: Prefer higher results and shorter paths to outcome
- # is_preferable = child_result > best_result or (child_result == best_result and (best_to_end is None or child_to_end < best_to_end))
- # else:
- # # Black's move: Prefer lower results and longer paths to delay outcome
- # is_preferable = child_result < best_result or (child_result == best_result and child_to_end > best_to_end)
- # if is_preferable:
- # best_child_id = child_id
- # best_result = child_result
- # best_to_end = child_to_end
- # # Update the current node based on the best child node found
- # if best_child_id is not None:
- # node['sequence'] = [best_child_id] # Update or append to the sequence based on your design choice
- # node['to_end'] = 1 + best_to_end if best_to_end is not None else None
- # node['moves_to_mate'] = 1 + best_to_end if best_to_end is not None else None
- # node['result'] = best_result
- # else:
- # # No preferable child found, or no children exist
- # node['to_end'] = None
- # node['moves_to_mate'] = None
- # # The result remains as initialized if no children influence the outcome
- # node['processed'] = True
- # return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
- # # Example usage:
- # # A = {1: {'fen': 'initial FEN here', 'children': [2, 3], 'color': chess.WHITE, 'processed': False, ...}}
- # # update_parent_preferences(1, A)
- # # print(A[1])
- def update_parent_preferences(node_id, A):
- node = A[node_id]
- # Return the current values if the node has already been processed
- if node['processed']:
- return node['to_end'], node['moves_to_mate'], node['result']
- best_child_id = None
- # Initialize best_result with an appropriate value based on the color to play
- best_result = float('-inf') if node['color'] else float('inf')
- best_to_end = None
- for child_id in node['children']:
- child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
- # Ensure comparisons are valid by checking for None
- if child_result is None:
- continue # Skip this child because it has no result, indicating it's not a terminal node or not evaluated yet
- # Handle the logic for updating the best choice based on the color to play
- if node['color']: # If it's White's turn to play
- if child_result > best_result or (child_result == best_result and (best_to_end is None or (child_to_end is not None and child_to_end < best_to_end))):
- best_child_id = child_id
- best_result = child_result
- best_to_end = child_to_end
- else: # If it's Black's turn to play
- if child_result < best_result or (child_result == best_result and (best_to_end is None or (child_to_end is not None and child_to_end > best_to_end))):
- best_child_id = child_id
- best_result = child_result
- best_to_end = child_to_end
- # Update the current node based on the best child node found
- if best_child_id is not None:
- node['sequence'] = [best_child_id]
- node['result'] = best_result
- node['to_end'] = 1 + (best_to_end if best_to_end is not None else 0)
- node['moves_to_mate'] = None if node['result'] == 0 else 1 + (best_to_end if best_to_end is not None else 0)
- else:
- node['to_end'] = None
- node['moves_to_mate'] = None
- node['processed'] = True
- return node['to_end'], node['moves_to_mate'], node['result']
- # Note: This function assumes the presence of an evaluate_board function or similar logic
- # that sets the initial 'result' for leaf nodes where the game is over.
- def print_sequence_from_root(A):
- current_node_id = 1
- while True:
- node = A[current_node_id]
- board = chess.Board(node['fen'] + " 0 1")
- print(f"Node ID: {current_node_id}, Moves to Mate: {node['moves_to_mate']}, Result: {node['result']}")
- print(board, "\n")
- if not node['sequence']:
- break
- current_node_id = node['sequence'][0]
- def main():
- initial_fen = "7Q/8/8/6k1/2K5/8/8/8 w - - 0 1"
- A, fen_to_node_id = initialize_game_tree(initial_fen)
- add_descendants_iteratively(A, fen_to_node_id)
- update_game_outcomes(A)
- update_parent_preferences(1, A)
- print("Final Output:")
- print(A[1])
- print_sequence_from_root(A)
- # for key in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]:
- for key in range(1,100):
- if A[key]['to_end'] != None: # and A[key]['to_end'] > 9:
- print(f"{key}:: {A[key]['to_end']} {A[key]}\n{chess.Board(A[key]['fen'])}<\n")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement