pacai.capture.agents
1import typing 2 3import pacai.agents.greedy 4import pacai.core.action 5import pacai.core.agent 6import pacai.core.gamestate 7import pacai.core.features 8import pacai.search.distance 9 10GHOST_IGNORE_RANGE: float = 2.5 11 12class DefensiveAgent(pacai.agents.greedy.GreedyFeatureAgent): 13 """ 14 A capture agent that prioritizes defending its own territory. 15 """ 16 17 def __init__(self, 18 override_weights: dict[str, float] | None = None, 19 **kwargs: typing.Any) -> None: 20 kwargs['feature_extractor_func'] = _extract_baseline_defensive_features 21 super().__init__(**kwargs) 22 23 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 24 """ Precompute distances. """ 25 26 # Set base weights. 27 self.weights['on_home_side'] = 100.0 28 self.weights['stopped'] = -100.0 29 self.weights['reverse'] = -2.0 30 self.weights['num_invaders'] = -1000.0 31 self.weights['distance_to_invader'] = -10.0 32 33 if (override_weights is None): 34 override_weights = {} 35 36 for (key, weight) in override_weights.items(): 37 self.weights[key] = weight 38 39 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 40 self._distances.compute(initial_state.board) 41 42class OffensiveAgent(pacai.agents.greedy.GreedyFeatureAgent): 43 """ 44 A capture agent that prioritizes defending its own territory. 45 """ 46 47 def __init__(self, 48 override_weights: dict[str, float] | None = None, 49 **kwargs: typing.Any) -> None: 50 kwargs['feature_extractor_func'] = _extract_baseline_offensive_features 51 super().__init__(**kwargs) 52 53 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 54 """ Precompute distances. """ 55 56 # Set base weights. 57 self.weights['score'] = 100.0 58 self.weights['distance_to_food'] = -1.0 59 60 if (override_weights is None): 61 override_weights = {} 62 63 for (key, weight) in override_weights.items(): 64 self.weights[key] = weight 65 66 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 67 self._distances.compute(initial_state.board) 68 69def _extract_baseline_defensive_features( 70 state: pacai.core.gamestate.GameState, 71 action: pacai.core.action.Action, 72 agent: pacai.core.agent.Agent | None = None, 73 **kwargs: typing.Any) -> pacai.core.features.FeatureDict: 74 agent = typing.cast(DefensiveAgent, agent) 75 state = typing.cast(pacai.capture.gamestate.GameState, state) 76 77 features: pacai.core.features.FeatureDict = pacai.core.features.FeatureDict() 78 79 current_position = state.get_agent_position(agent.agent_index) 80 if (current_position is None): 81 # We are dead and waiting to respawn. 82 return features 83 84 # Note the side of the board we are on. 85 features['on_home_side'] = int(state.is_ghost(agent_index = agent.agent_index)) 86 87 # Prefer moving over stopping. 88 features['stopped'] = int(action == pacai.core.action.STOP) 89 90 # Prefer not turning around. 91 # Remember that the state we get is already a successor, so we have to look two actions back. 92 agent_actions = state.get_agent_actions(agent.agent_index) 93 if (len(agent_actions) > 1): 94 features['reverse'] = int(action == state.get_reverse_action(agent_actions[-2])) 95 96 # We don't like any invaders on our side. 97 invader_positions = state.get_invader_positions(agent_index = agent.agent_index) 98 features['num_invaders'] = len(invader_positions) 99 100 # Hunt down the closest invader! 101 if (len(invader_positions) > 0): 102 invader_distances = [agent._distances.get_distance(current_position, invader_position) for invader_position in invader_positions.values()] 103 features['distance_to_invader'] = min(distance for distance in invader_distances if (distance is not None)) 104 105 return features 106 107def _extract_baseline_offensive_features( 108 state: pacai.core.gamestate.GameState, 109 action: pacai.core.action.Action, 110 agent: pacai.core.agent.Agent | None = None, 111 **kwargs: typing.Any) -> pacai.core.features.FeatureDict: 112 agent = typing.cast(OffensiveAgent, agent) 113 state = typing.cast(pacai.capture.gamestate.GameState, state) 114 115 features: pacai.core.features.FeatureDict = pacai.core.features.FeatureDict() 116 features['score'] = state.get_normalized_score(agent.agent_index) 117 118 # Note the side of the board we are on. 119 features['on_home_side'] = int(state.is_ghost(agent_index = agent.agent_index)) 120 121 # Prefer moving over stopping. 122 features['stopped'] = int(action == pacai.core.action.STOP) 123 124 # Prefer not turning around. 125 # Remember that the state we get is already a successor, so we have to look two actions back. 126 agent_actions = state.get_agent_actions(agent.agent_index) 127 if (len(agent_actions) > 1): 128 features['reverse'] = int(action == state.get_reverse_action(agent_actions[-2])) 129 130 current_position = state.get_agent_position(agent.agent_index) 131 if (current_position is None): 132 # We are dead and waiting to respawn. 133 return features 134 135 food_positions = state.get_food(agent_index = agent.agent_index) 136 if (len(food_positions) > 0): 137 food_distances = [agent._distances.get_distance(current_position, food_position) for food_position in food_positions] 138 features['distance_to_food'] = min(distance for distance in food_distances if (distance is not None)) 139 else: 140 # There is no food left, give a large score. 141 features['distance_to_food'] = -100000 142 143 ghost_positions = state.get_nonscared_opponent_positions(agent_index = agent.agent_index) 144 if (len(ghost_positions) > 0): 145 ghost_distances = [agent._distances.get_distance(current_position, ghost_position) for ghost_position in ghost_positions.values()] 146 features['distance_to_ghost'] = min(distance for distance in ghost_distances if (distance is not None)) 147 if (features['distance_to_ghost'] > GHOST_IGNORE_RANGE): 148 features['distance_to_ghost'] = 1000 149 150 features['distance_to_ghost_squared'] = features['distance_to_ghost'] ** 2 151 else: 152 features['distance_to_ghost'] = 0 153 154 return features
GHOST_IGNORE_RANGE: float =
2.5
13class DefensiveAgent(pacai.agents.greedy.GreedyFeatureAgent): 14 """ 15 A capture agent that prioritizes defending its own territory. 16 """ 17 18 def __init__(self, 19 override_weights: dict[str, float] | None = None, 20 **kwargs: typing.Any) -> None: 21 kwargs['feature_extractor_func'] = _extract_baseline_defensive_features 22 super().__init__(**kwargs) 23 24 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 25 """ Precompute distances. """ 26 27 # Set base weights. 28 self.weights['on_home_side'] = 100.0 29 self.weights['stopped'] = -100.0 30 self.weights['reverse'] = -2.0 31 self.weights['num_invaders'] = -1000.0 32 self.weights['distance_to_invader'] = -10.0 33 34 if (override_weights is None): 35 override_weights = {} 36 37 for (key, weight) in override_weights.items(): 38 self.weights[key] = weight 39 40 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 41 self._distances.compute(initial_state.board)
A capture agent that prioritizes defending its own territory.
DefensiveAgent(override_weights: dict[str, float] | None = None, **kwargs: Any)
18 def __init__(self, 19 override_weights: dict[str, float] | None = None, 20 **kwargs: typing.Any) -> None: 21 kwargs['feature_extractor_func'] = _extract_baseline_defensive_features 22 super().__init__(**kwargs) 23 24 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 25 """ Precompute distances. """ 26 27 # Set base weights. 28 self.weights['on_home_side'] = 100.0 29 self.weights['stopped'] = -100.0 30 self.weights['reverse'] = -2.0 31 self.weights['num_invaders'] = -1000.0 32 self.weights['distance_to_invader'] = -10.0 33 34 if (override_weights is None): 35 override_weights = {} 36 37 for (key, weight) in override_weights.items(): 38 self.weights[key] = weight
40 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 41 self._distances.compute(initial_state.board)
Notify this agent that the game is about to start. The provided agent index is the game's index/id for this agent. The state represents the initial state of the game. Any precomputation for this game should be done in this method. Calls to this method may be subject to a timeout.
Inherited Members
43class OffensiveAgent(pacai.agents.greedy.GreedyFeatureAgent): 44 """ 45 A capture agent that prioritizes defending its own territory. 46 """ 47 48 def __init__(self, 49 override_weights: dict[str, float] | None = None, 50 **kwargs: typing.Any) -> None: 51 kwargs['feature_extractor_func'] = _extract_baseline_offensive_features 52 super().__init__(**kwargs) 53 54 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 55 """ Precompute distances. """ 56 57 # Set base weights. 58 self.weights['score'] = 100.0 59 self.weights['distance_to_food'] = -1.0 60 61 if (override_weights is None): 62 override_weights = {} 63 64 for (key, weight) in override_weights.items(): 65 self.weights[key] = weight 66 67 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 68 self._distances.compute(initial_state.board)
A capture agent that prioritizes defending its own territory.
OffensiveAgent(override_weights: dict[str, float] | None = None, **kwargs: Any)
48 def __init__(self, 49 override_weights: dict[str, float] | None = None, 50 **kwargs: typing.Any) -> None: 51 kwargs['feature_extractor_func'] = _extract_baseline_offensive_features 52 super().__init__(**kwargs) 53 54 self._distances: pacai.search.distance.DistancePreComputer = pacai.search.distance.DistancePreComputer() 55 """ Precompute distances. """ 56 57 # Set base weights. 58 self.weights['score'] = 100.0 59 self.weights['distance_to_food'] = -1.0 60 61 if (override_weights is None): 62 override_weights = {} 63 64 for (key, weight) in override_weights.items(): 65 self.weights[key] = weight
67 def game_start(self, initial_state: pacai.core.gamestate.GameState) -> None: 68 self._distances.compute(initial_state.board)
Notify this agent that the game is about to start. The provided agent index is the game's index/id for this agent. The state represents the initial state of the game. Any precomputation for this game should be done in this method. Calls to this method may be subject to a timeout.