def get_valid_move_actions_(agent_direction: Grid4TransitionsEnum, agent_position: Tuple[int, int], rail: GridTransitionMap) -> Set[RailEnvNextAction]: """ Get the valid move actions (forward, left, right) for an agent. TODO https://gitlab.aicrowd.com/flatland/flatland/issues/299 The implementation could probably be more efficient and more elegant. But given the few calls this has no priority now. Parameters ---------- agent_direction : Grid4TransitionsEnum agent_position: Tuple[int,int] rail : GridTransitionMap Returns ------- Set of `RailEnvNextAction` (tuples of (action,position,direction)) Possible move actions (forward,left,right) and the next position/direction they lead to. It is not checked that the next cell is free. """ valid_actions: Set[RailEnvNextAction] = OrderedSet() possible_transitions = rail.get_transitions(*agent_position, agent_direction) num_transitions = np.count_nonzero(possible_transitions) # Start from the current orientation, and see which transitions are available; # organize them as [left, forward, right], relative to the current orientation # If only one transition is possible, the forward branch is aligned with it. if rail.is_dead_end(agent_position): action = RailEnvActions.MOVE_FORWARD exit_direction = (agent_direction + 2) % 4 if possible_transitions[exit_direction]: new_position = get_new_position(agent_position, exit_direction) valid_actions.add( RailEnvNextAction(action, new_position, exit_direction)) elif num_transitions == 1: action = RailEnvActions.MOVE_FORWARD for new_direction in [(agent_direction + i) % 4 for i in range(-1, 2)]: if possible_transitions[new_direction]: new_position = get_new_position(agent_position, new_direction) valid_actions.add( RailEnvNextAction(action, new_position, new_direction)) else: for new_direction in [(agent_direction + i) % 4 for i in range(-1, 2)]: if possible_transitions[new_direction]: if new_direction == agent_direction: action = RailEnvActions.MOVE_FORWARD elif new_direction == (agent_direction + 1) % 4: action = RailEnvActions.MOVE_RIGHT elif new_direction == (agent_direction - 1) % 4: action = RailEnvActions.MOVE_LEFT else: raise Exception("Illegal state") new_position = get_new_position(agent_position, new_direction) valid_actions.add( RailEnvNextAction(action, new_position, new_direction)) return valid_actions
def get_altpaths_from(a_pos, a_dir): # TODO depth next_actions = get_valid_move_actions_(a_dir, a_pos, distance_map.rail) if a_pos in cell_to_id_node: # if this is a switch, recursive case paths = [] for action in next_actions: first_step = WalkingElement( a_pos, a_dir, RailEnvNextAction(action.action, action.next_position, action.next_direction)) recursive_altpaths = get_altpaths_from(action.next_position, action.next_direction) for path in recursive_altpaths: paths.append([first_step] + path) return paths else: #Move Forward, I'm on a rail assert len(next_actions) == 1 # get shortest path for action in next_actions: first_step = WalkingElement( a_pos, a_dir, RailEnvNextAction(action.action, action.next_position, action.next_direction)) ret = [] if a_pos == agent.target: ret = [[first_step]] else: shortest = get_shortest_paths(distance_map=distance_map, max_depth=max_depth, agent_handle=handle, position=action.next_position, direction=action.next_direction) if shortest[handle] != None: ret = [[first_step] + shortest[handle]] return ret
def _shortest_path_for_agent(agent, a_position, a_direction): if a_position == None: if agent.status == RailAgentStatus.READY_TO_DEPART: a_position = agent.initial_position elif agent.status == RailAgentStatus.ACTIVE: a_position = agent.position elif agent.status == RailAgentStatus.DONE: a_position = agent.target else: shortest_paths[agent.handle] = None return if a_direction == None: a_direction = agent.direction shortest_paths[agent.handle] = [] distance = math.inf depth = 0 while (a_position != agent.target and (max_depth is None or depth < max_depth)): next_actions = get_valid_move_actions_(a_direction, a_position, distance_map.rail) best_next_action = None for next_action in next_actions: next_action_distance = distance_map.get()[ agent.handle, next_action.next_position[0], next_action.next_position[1], next_action.next_direction] if next_action_distance < distance: best_next_action = next_action distance = next_action_distance shortest_paths[agent.handle].append( WalkingElement(a_position, a_direction, best_next_action)) depth += 1 # if there is no way to continue, the rail must be disconnected! # (or distance map is incorrect) if best_next_action is None: shortest_paths[agent.handle] = None return a_position = best_next_action.next_position a_direction = best_next_action.next_direction if max_depth is None or depth < max_depth: shortest_paths[agent.handle].append( WalkingElement( a_position, a_direction, RailEnvNextAction(RailEnvActions.STOP_MOVING, a_position, a_direction)))
def get_altpaths(handle, distance_map, max_depth, cell_to_id_node): # TODO max_depth agent = distance_map.agents[handle] if agent.status == RailAgentStatus.READY_TO_DEPART: position = agent.initial_position elif agent.status == RailAgentStatus.ACTIVE: position = agent.position elif agent.status == RailAgentStatus.DONE: position = agent.target else: #Agent arrived return [] direction = agent.direction distance = math.inf depth = 0 assert position != agent.target def get_altpaths_from(a_pos, a_dir): # TODO depth next_actions = get_valid_move_actions_(a_dir, a_pos, distance_map.rail) if a_pos in cell_to_id_node: # if this is a switch, recursive case paths = [] for action in next_actions: first_step = WalkingElement( a_pos, a_dir, RailEnvNextAction(action.action, action.next_position, action.next_direction)) recursive_altpaths = get_altpaths_from(action.next_position, action.next_direction) for path in recursive_altpaths: paths.append([first_step] + path) return paths else: #Move Forward, I'm on a rail assert len(next_actions) == 1 # get shortest path for action in next_actions: first_step = WalkingElement( a_pos, a_dir, RailEnvNextAction(action.action, action.next_position, action.next_direction)) ret = [] if a_pos == agent.target: ret = [[first_step]] else: shortest = get_shortest_paths(distance_map=distance_map, max_depth=max_depth, agent_handle=handle, position=action.next_position, direction=action.next_direction) if shortest[handle] != None: ret = [[first_step] + shortest[handle]] return ret next_actions = get_valid_move_actions_(direction, position, distance_map.rail) ret = [] for action in next_actions: new_position = action.next_position new_direction = action.next_direction first_action = WalkingElement( position, direction, RailEnvNextAction(RailEnvActions.MOVE_FORWARD, new_position, new_direction)) altpaths = get_altpaths_from(new_position, new_direction) for altpath in altpaths: ret.append([first_action] + altpath) return ret