pacai.search.food

 1import typing
 2
 3import pacai.core.board
 4import pacai.core.gamestate
 5import pacai.core.search
 6import pacai.pacman.board
 7
 8class FoodSearchNode(pacai.core.search.SearchNode):
 9    """
10    A search node for the food search problem.
11    The state for this search problem will be
12    the current position and the remaining food positions.
13    """
14
15    def __init__(self,
16            position: pacai.core.board.Position,
17            remaining_food: typing.Iterable[pacai.core.board.Position]) -> None:
18        self.position: pacai.core.board.Position = position
19        """ The current position being searched. """
20
21        self.remaining_food: tuple[pacai.core.board.Position, ...] = tuple(sorted(list(remaining_food)))
22        """
23        The food left to eat.
24        This is kept sorted to ensure that underlying comparison checks run cleanly.
25        """
26
27    def __lt__(self, other: object) -> bool:
28        if (not isinstance(other, FoodSearchNode)):
29            return False
30
31        return ((self.position, self.remaining_food) < (other.position, other.remaining_food))
32
33    def __eq__(self, other: object) -> bool:
34        if (not isinstance(other, FoodSearchNode)):
35            return False
36
37        return ((self.position == other.position) and (self.remaining_food == other.remaining_food))
38
39    def __hash__(self) -> int:
40        return hash((self.position, self.remaining_food))
41
42class FoodSearchProblem(pacai.core.search.SearchProblem[FoodSearchNode]):
43    """
44    A search problem associated with finding the a path that collects all of the "food" in a game.
45    """
46
47    def __init__(self,
48            game_state: pacai.core.gamestate.GameState,
49            start_position: pacai.core.board.Position | None = None,
50            **kwargs: typing.Any) -> None:
51        """
52        Create a food search problem.
53
54        If no start position is provided, the current agent's position will be used.
55        """
56
57        super().__init__()
58
59        self.state: pacai.core.gamestate.GameState = game_state
60        """ Keep track of the enire game state. """
61
62        if (start_position is None):
63            start_position = game_state.get_agent_position()
64
65        if (start_position is None):
66            raise ValueError("Could not find starting position.")
67
68        self.start_position = start_position
69        """ The position to start from. """
70
71    def get_starting_node(self) -> FoodSearchNode:
72        return FoodSearchNode(self.start_position, self.state.board.get_marker_positions(pacai.pacman.board.MARKER_PELLET))
73
74    def is_goal_node(self, node: FoodSearchNode) -> bool:
75        return (len(node.remaining_food) == 0)
76
77    def complete(self, goal_node: FoodSearchNode) -> None:
78        # Mark the final node in the history.
79        self.position_history.append(goal_node.position)
80
81    def get_successor_nodes(self, node: FoodSearchNode) -> list[pacai.core.search.SuccessorInfo]:
82        successors = []
83
84        # Check all the non-wall neighbors.
85        for (action, position) in self.state.board.get_neighbors(node.position):
86            new_remaining_food = list(node.remaining_food).copy()
87            if (position in new_remaining_food):
88                new_remaining_food.remove(position)
89
90            next_node = FoodSearchNode(position, new_remaining_food)
91            successors.append(pacai.core.search.SuccessorInfo(next_node, action, 1.0))
92
93        # Do bookkeeping on the states/positions we visited.
94        self.expanded_node_count += 1
95        if (node not in self.visited_nodes):
96            self.position_history.append(node.position)
97
98        return successors
class FoodSearchNode(pacai.core.search.SearchNode):
 9class FoodSearchNode(pacai.core.search.SearchNode):
10    """
11    A search node for the food search problem.
12    The state for this search problem will be
13    the current position and the remaining food positions.
14    """
15
16    def __init__(self,
17            position: pacai.core.board.Position,
18            remaining_food: typing.Iterable[pacai.core.board.Position]) -> None:
19        self.position: pacai.core.board.Position = position
20        """ The current position being searched. """
21
22        self.remaining_food: tuple[pacai.core.board.Position, ...] = tuple(sorted(list(remaining_food)))
23        """
24        The food left to eat.
25        This is kept sorted to ensure that underlying comparison checks run cleanly.
26        """
27
28    def __lt__(self, other: object) -> bool:
29        if (not isinstance(other, FoodSearchNode)):
30            return False
31
32        return ((self.position, self.remaining_food) < (other.position, other.remaining_food))
33
34    def __eq__(self, other: object) -> bool:
35        if (not isinstance(other, FoodSearchNode)):
36            return False
37
38        return ((self.position == other.position) and (self.remaining_food == other.remaining_food))
39
40    def __hash__(self) -> int:
41        return hash((self.position, self.remaining_food))

A search node for the food search problem. The state for this search problem will be the current position and the remaining food positions.

FoodSearchNode( position: pacai.core.board.Position, remaining_food: Iterable[pacai.core.board.Position])
16    def __init__(self,
17            position: pacai.core.board.Position,
18            remaining_food: typing.Iterable[pacai.core.board.Position]) -> None:
19        self.position: pacai.core.board.Position = position
20        """ The current position being searched. """
21
22        self.remaining_food: tuple[pacai.core.board.Position, ...] = tuple(sorted(list(remaining_food)))
23        """
24        The food left to eat.
25        This is kept sorted to ensure that underlying comparison checks run cleanly.
26        """

The current position being searched.

remaining_food: tuple[pacai.core.board.Position, ...]

The food left to eat. This is kept sorted to ensure that underlying comparison checks run cleanly.

43class FoodSearchProblem(pacai.core.search.SearchProblem[FoodSearchNode]):
44    """
45    A search problem associated with finding the a path that collects all of the "food" in a game.
46    """
47
48    def __init__(self,
49            game_state: pacai.core.gamestate.GameState,
50            start_position: pacai.core.board.Position | None = None,
51            **kwargs: typing.Any) -> None:
52        """
53        Create a food search problem.
54
55        If no start position is provided, the current agent's position will be used.
56        """
57
58        super().__init__()
59
60        self.state: pacai.core.gamestate.GameState = game_state
61        """ Keep track of the enire game state. """
62
63        if (start_position is None):
64            start_position = game_state.get_agent_position()
65
66        if (start_position is None):
67            raise ValueError("Could not find starting position.")
68
69        self.start_position = start_position
70        """ The position to start from. """
71
72    def get_starting_node(self) -> FoodSearchNode:
73        return FoodSearchNode(self.start_position, self.state.board.get_marker_positions(pacai.pacman.board.MARKER_PELLET))
74
75    def is_goal_node(self, node: FoodSearchNode) -> bool:
76        return (len(node.remaining_food) == 0)
77
78    def complete(self, goal_node: FoodSearchNode) -> None:
79        # Mark the final node in the history.
80        self.position_history.append(goal_node.position)
81
82    def get_successor_nodes(self, node: FoodSearchNode) -> list[pacai.core.search.SuccessorInfo]:
83        successors = []
84
85        # Check all the non-wall neighbors.
86        for (action, position) in self.state.board.get_neighbors(node.position):
87            new_remaining_food = list(node.remaining_food).copy()
88            if (position in new_remaining_food):
89                new_remaining_food.remove(position)
90
91            next_node = FoodSearchNode(position, new_remaining_food)
92            successors.append(pacai.core.search.SuccessorInfo(next_node, action, 1.0))
93
94        # Do bookkeeping on the states/positions we visited.
95        self.expanded_node_count += 1
96        if (node not in self.visited_nodes):
97            self.position_history.append(node.position)
98
99        return successors

A search problem associated with finding the a path that collects all of the "food" in a game.

FoodSearchProblem( game_state: pacai.core.gamestate.GameState, start_position: pacai.core.board.Position | None = None, **kwargs: Any)
48    def __init__(self,
49            game_state: pacai.core.gamestate.GameState,
50            start_position: pacai.core.board.Position | None = None,
51            **kwargs: typing.Any) -> None:
52        """
53        Create a food search problem.
54
55        If no start position is provided, the current agent's position will be used.
56        """
57
58        super().__init__()
59
60        self.state: pacai.core.gamestate.GameState = game_state
61        """ Keep track of the enire game state. """
62
63        if (start_position is None):
64            start_position = game_state.get_agent_position()
65
66        if (start_position is None):
67            raise ValueError("Could not find starting position.")
68
69        self.start_position = start_position
70        """ The position to start from. """

Create a food search problem.

If no start position is provided, the current agent's position will be used.

Keep track of the enire game state.

start_position

The position to start from.

def get_starting_node(self) -> FoodSearchNode:
72    def get_starting_node(self) -> FoodSearchNode:
73        return FoodSearchNode(self.start_position, self.state.board.get_marker_positions(pacai.pacman.board.MARKER_PELLET))

Get the starting node for the search problem.

def is_goal_node(self, node: FoodSearchNode) -> bool:
75    def is_goal_node(self, node: FoodSearchNode) -> bool:
76        return (len(node.remaining_food) == 0)

Check if this node is a valid goal node.

def complete(self, goal_node: FoodSearchNode) -> None:
78    def complete(self, goal_node: FoodSearchNode) -> None:
79        # Mark the final node in the history.
80        self.position_history.append(goal_node.position)

Notify this search problem that the solver choose this goal node.

def get_successor_nodes( self, node: FoodSearchNode) -> list[pacai.core.search.SuccessorInfo]:
82    def get_successor_nodes(self, node: FoodSearchNode) -> list[pacai.core.search.SuccessorInfo]:
83        successors = []
84
85        # Check all the non-wall neighbors.
86        for (action, position) in self.state.board.get_neighbors(node.position):
87            new_remaining_food = list(node.remaining_food).copy()
88            if (position in new_remaining_food):
89                new_remaining_food.remove(position)
90
91            next_node = FoodSearchNode(position, new_remaining_food)
92            successors.append(pacai.core.search.SuccessorInfo(next_node, action, 1.0))
93
94        # Do bookkeeping on the states/positions we visited.
95        self.expanded_node_count += 1
96        if (node not in self.visited_nodes):
97            self.position_history.append(node.position)
98
99        return successors

Get all the possible successors (successor nodes) to the current node. This action can be though of expanding a search node, or getting the children of a node in the search tree.