def get_neighbor_move_position( current_position: position.Position, current_rotation: rotation.Rotation ) -> Tuple[position.Position, position.Position]: back_rotation: rotation.Rotation = rotation.rotate_clockwise( rotation.rotate_clockwise(rotation.rotate_clockwise(current_rotation))) facing_position: position.Position = None behind_position: position.Position = None if current_position.y % 2 == 0: for offset, rot in EVEN_ROTATIONS.items(): if rot == current_rotation: facing_position = position.Position( current_position.x + offset[0], current_position.y + offset[1]) elif rot == back_rotation: behind_position = position.Position( current_position.x + offset[0], current_position.y + offset[1]) else: for offset, rot in ODD_ROTATIONS.items(): if rot == current_rotation: facing_position = position.Position( current_position.x + offset[0], current_position.y + offset[1]) elif rot == back_rotation: behind_position = position.Position( current_position.x + offset[0], current_position.y + offset[1]) return facing_position, behind_position
def rotation_possibilities( start_position: position.Position, end_position: position.Position, agent_rotation: rotation.Rotation ) -> List[Tuple[List[agent_actions.AgentAction], rotation.Rotation]]: current_rotation: rotation.Rotation = copy.deepcopy(agent_rotation) num_rotations: int = get_num_rotations(start_position, end_position, current_rotation) if num_rotations == 0: return [([agent_actions.AgentAction.MF], current_rotation)] elif num_rotations == 1: return [([agent_actions.AgentAction.RR, agent_actions.AgentAction.MF], rotation.rotate_clockwise(current_rotation)), ([ agent_actions.AgentAction.RL, agent_actions.AgentAction.RL, agent_actions.AgentAction.MB ], rotation.rotate_counterclockwise( rotation.rotate_counterclockwise(current_rotation)))] elif num_rotations == 2: return [([ agent_actions.AgentAction.RR, agent_actions.AgentAction.RR, agent_actions.AgentAction.MF ], rotation.rotate_clockwise( rotation.rotate_clockwise(current_rotation))), ([agent_actions.AgentAction.RL, agent_actions.AgentAction.MB], rotation.rotate_counterclockwise(current_rotation))] elif num_rotations == 3: return [([agent_actions.AgentAction.MB], current_rotation), ([ agent_actions.AgentAction.RR, agent_actions.AgentAction.RR, agent_actions.AgentAction.RR, agent_actions.AgentAction.MF ], rotation.rotate_clockwise( rotation.rotate_clockwise( rotation.rotate_clockwise(current_rotation))))] elif num_rotations == 4: return [([agent_actions.AgentAction.RR, agent_actions.AgentAction.MB], rotation.rotate_clockwise(current_rotation)), ([ agent_actions.AgentAction.RL, agent_actions.AgentAction.RL, agent_actions.AgentAction.MF ], rotation.rotate_counterclockwise( rotation.rotate_counterclockwise(current_rotation)))] elif num_rotations == 5: return [([agent_actions.AgentAction.RL, agent_actions.AgentAction.MF], rotation.rotate_counterclockwise(current_rotation)), ([ agent_actions.AgentAction.RR, agent_actions.AgentAction.RR, agent_actions.AgentAction.MB ], rotation.rotate_clockwise( rotation.rotate_clockwise(current_rotation)))] else: raise ValueError('Can\'t rotate ' + str(num_rotations) + ' times.')
def get_new_player_orientation( player: agent.Agent, action: agent_actions.AgentAction, obstacle_positions: List[position.Position] ) -> Tuple[position.Position, rotation.Rotation]: new_position: position.Position = player.get_position() new_rotation: rotation.Rotation = player.get_rotation() if action == agent_actions.AgentAction.MF: facing_position: position.Position = get_neighbor_move_position( player.get_position(), player.get_rotation())[0] if facing_position in obstacle_positions: raise ValueError('Cannot MF ' + str(player.get_type()) + ' from ' + str(player.get_position()) + ' rotating ' + str(player.get_rotation()) + ' to position ' + str(facing_position)) new_position = facing_position elif action == agent_actions.AgentAction.MB: behind_position: position.Position = get_neighbor_move_position( player.get_position(), player.get_rotation())[1] if behind_position in obstacle_positions: raise ValueError('Cannot MB ' + str(player.get_type()) + ' from ' + str(player.get_position()) + ' rotating ' + str(player.get_rotation()) + ' to position ' + str(behind_position)) new_position = behind_position elif action == agent_actions.AgentAction.RR: new_rotation = rotation.rotate_clockwise(player.get_rotation()) elif action == agent_actions.AgentAction.RL: new_rotation = rotation.rotate_counterclockwise(player.get_rotation()) return new_position, new_rotation
def get_num_rotations(start_position: position.Position, end_position: position.Position, start_rotation: rotation.Rotation) -> int: num_rotations: int = 0 start_depth = start_position.y move_vector: Tuple[int, int] = (end_position.x - start_position.x, end_position.y - start_position.y) temp_rot: rotation.Rotation = copy.deepcopy(start_rotation) if start_depth % 2 == 0: while not temp_rot == planner.EVEN_ROTATIONS[move_vector]: num_rotations += 1 temp_rot = rotation.rotate_clockwise(temp_rot) else: while not temp_rot == planner.ODD_ROTATIONS[move_vector]: num_rotations += 1 temp_rot = rotation.rotate_clockwise(temp_rot) return num_rotations
def find_path_between_positions( avoid_locations: List[position.Position], start_config: agent.Agent, target_config: agent.Agent, ignore_target_rotation: bool = False ) -> Optional[List[Tuple[agent.Agent, agent_actions.AgentAction]]]: """Finds a path between two positions in the map. Args: avoid_locations: A list of locations to avoid, including obstacles and cards that should not be touched. start_config: The starting configuration (position/rotation) of the agent. target_config: The target configuration (position/rotation) of the agent. ignore_target_rotation: Whether the final rotation of the agent matters. """ queue: PositionRotationQueue = PositionRotationQueue() queue.put(start_config.get_position(), start_config.get_rotation(), 0) paths: Dict[Tuple[position.Position, rotation.Rotation], Optional[Tuple[Tuple[position.Position, rotation.Rotation], List[agent_actions.AgentAction]]]] = dict() paths[(start_config.get_position(), start_config.get_rotation())] = None total_dist: Dict[Tuple[position.Position, rotation.Rotation], int] = dict() total_dist[(start_config.get_position(), start_config.get_rotation())] = 0 has_ended: bool = False current_pos_and_rot: Tuple[Optional[position.Position], Optional[rotation.Rotation]] = (None, None) while not queue.is_empty(): current_pos_and_rot: Tuple[position.Position, rotation.Rotation] = queue.get() current_position: position.Position = current_pos_and_rot[0] current_rotation: rotation.Rotation = current_pos_and_rot[1] if current_position == target_config.get_position(): has_ended = True break for next_position in position.get_neighbors( current_position, environment_util.ENVIRONMENT_WIDTH, environment_util.ENVIRONMENT_DEPTH): if next_position not in avoid_locations: action_rot_pairs: List[Tuple[ List[agent_actions.AgentAction], rotation. Rotation]] = rotation_planner.rotation_possibilities( current_position, next_position, current_rotation) # There could be several ways to get from one hex to another by rotation. Iterate through all of them, # considering the cost of backwards moves. for move_possibility in action_rot_pairs: actions: List[ agent_actions.AgentAction] = move_possibility[0] resulting_rotation: rotation.Rotation = move_possibility[1] new_dist: int = total_dist[ current_pos_and_rot] + follower_action_cost(actions) move_pair: Tuple[position.Position, rotation.Rotation] = (next_position, resulting_rotation) if new_dist < total_dist.get(move_pair, sys.maxsize): total_dist[move_pair] = new_dist paths[move_pair] = (current_pos_and_rot, actions) priority: int = new_dist + metric.manhattan_distance( target_config.get_position(), next_position) queue.put(next_position, resulting_rotation, priority) if not has_ended: return None final_rotation: rotation.Rotation = current_pos_and_rot[1] path_positions: List[position.Position] = [] actions: List[agent_actions.AgentAction] = [] while current_pos_and_rot != (start_config.get_position(), start_config.get_rotation()): segment_actions = paths[current_pos_and_rot][1] segment_actions.reverse() actions += segment_actions path_positions.append(current_pos_and_rot[0]) current_pos_and_rot = paths[current_pos_and_rot][0] actions.reverse() path_positions.reverse() if not ignore_target_rotation and target_config.get_rotation( ) != final_rotation: num_right: int = 0 temp_right_rotation: rotation.Rotation = final_rotation while temp_right_rotation != target_config.get_rotation(): num_right += 1 temp_right_rotation = rotation.rotate_clockwise( temp_right_rotation) if num_right <= 3: actions.extend( [agent_actions.AgentAction.RR for _ in range(num_right)]) else: actions.extend( [agent_actions.AgentAction.RL for _ in range(6 - num_right)]) path_positions = [start_config.get_position()] + path_positions # Now create an actual list of states and actions position_action_list: List[Tuple[agent.Agent, agent_actions.AgentAction]] = list() pos_idx: int = 0 current_rotation: rotation.Rotation = start_config.get_rotation() for action in actions: position_action_list.append( (agent.Agent(environment_objects.ObjectType.FOLLOWER, path_positions[pos_idx], current_rotation), action)) if action in { agent_actions.AgentAction.MF, agent_actions.AgentAction.MB }: pos_idx += 1 elif action in { agent_actions.AgentAction.RR, agent_actions.AgentAction.RL }: if action == agent_actions.AgentAction.RR: current_rotation = rotation.rotate_clockwise(current_rotation) else: current_rotation = rotation.rotate_counterclockwise( current_rotation) else: raise ValueError('Action should not be generated: ' + str(action)) # Should end up in the expected rotation. if not ignore_target_rotation: assert current_rotation == target_config.get_rotation() return position_action_list