Untitled

 avatar
unknown
python
5 months ago
3.2 kB
8
Indexable
import chess

def a_star_search(board: chess.Board, goal_position: chess.Square):
    """
    Implements the A* search algorithm to find the final path for the Knight's quest.
    
    Parameters:
    - board: The chess board that the knight is moving upon.
    - goal_position: The target square where the knight needs to move (H8).
    
    Returns:
    A list containing the final path from start to goal, represented by square IDs.
    """
    # Priority queue: stores (f(n), g(n), current_square, path_to_current_square)
    priority_queue = []
    
    # g_score: cost to reach a square from the start
    g_score = {i: float('inf') for i in range(64)}  # Initialize with infinity
    g_score[0] = 0  # The knight starts at A1 (square 0)
    
    # Start position and push it to the list with initial f(n) = g(n) + h(n)
    start_position = 0
    priority_queue.append((0 + chess.square_knight_distance(start_position, goal_position), 0, start_position, [start_position]))
    
    # Set to track visited nodes
    visited = set()
    
    while priority_queue:
        # Sort the queue manually by f(n) to always pick the best option
        priority_queue.sort(key=lambda x: x[0])  # Sort by f(n)
        f_current, g_current, current_square, path_to_current = priority_queue.pop(0)
        
        # If the current square is the goal, return the path
        if current_square == goal_position:
            return path_to_current
        
        # If we've already visited this node, skip it
        if current_square in visited:
            continue
        
        # Mark this node as visited
        visited.add(current_square)
        
        # Place the knight at the current square
        board.clear()  # Clear the board
        board.set_piece_at(current_square, chess.Piece(chess.KNIGHT, chess.WHITE))  # Place the knight
        
        # Get all legal moves for the knight from the current square
        legal_moves = list(board.legal_moves)
        
        # Prepare the list of possible moves sorted by f(n)
        for move in legal_moves:
            next_square = move.to_square
            
            # Skip already visited squares
            if next_square in visited:
                continue
            
            # Calculate g(n): the cost to reach next_square
            tentative_g_score = g_current + 1
            
            # Only proceed if this new g(n) is better (shorter path) than what we have for the next square
            if tentative_g_score < g_score[next_square]:
                # Update g(n) for next_square
                g_score[next_square] = tentative_g_score
                
                # Calculate h(n): heuristic cost to the goal
                h_score = chess.square_knight_distance(next_square, goal_position)
                
                # Calculate f(n) = g(n) + h(n)
                f_score = tentative_g_score + h_score
                
                # Add the move to the priority queue
                priority_queue.append((f_score, tentative_g_score, next_square, path_to_current + [next_square]))
    
    # If we exhaust the priority queue without finding the goal, return an empty list (shouldn't happen)
    return []
Editor is loading...
Leave a Comment