def test_agent_position_in_front( position: PositionOrTuple, orientation: Orientation, expected: PositionOrTuple, ): agent = Agent(position, orientation) assert agent.position_in_front() == expected
def test_agent_position_relative( position: PositionOrTuple, orientation: Orientation, delta_position: Position, expected: PositionOrTuple, ): agent = Agent(position, orientation) assert agent.position_relative(delta_position) == expected
def test_pickup_mechanics_swap(): grid = Grid(height=3, width=4) agent = Agent(position=(1, 2), orientation=Orientation.S) item_pos = (2, 2) agent.obj = Key(Color.BLUE) grid[item_pos] = Key(Color.GREEN) state = State(grid, agent) next_state = step_with_copy(state, Action.PICK_N_DROP) assert state.grid[item_pos] == next_state.agent.obj assert state.agent.obj == next_state.grid[item_pos]
def match_key_color( *, rng: Optional[rnd.Generator] = None, # pylint: disable=unused-argument ) -> State: """the agent has to pick the correct key to open a randomly colored door""" rng = get_gv_rng_if_none(rng) # necessary to use rng object! # only consider these colors colors = [Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW] # randomly choose location of keys key1, key2, key3, key4 = rng.permute([Key(color) for color in colors]) # randomly choose color of door door = Door(Door.Status.LOCKED, rng.choice(colors)) # grids can be constructed directly from objects grid = Grid.from_objects([ [Wall(), Wall(), Wall(), Wall(), Wall()], [Wall(), Wall(), Goal(), Wall(), Wall()], [Wall(), Wall(), door, Wall(), Wall()], [Wall(), key1, Floor(), key2, Wall()], [Wall(), key3, Floor(), key4, Wall()], [Wall(), Wall(), Wall(), Wall(), Wall()], ]) # positioning the agent in the above grid agent = Agent((4, 2), Orientation.N) return State(grid, agent)
def move_agent(agent: Agent, grid: Grid, action: Action) -> None: """Applies translation to agent (e.g. up/down/left/right) Leaves the state unaffected if any other action was taken instead Args: agent (`Agent`): grid (`Grid`): action (`Action`): Returns: None: """ if action not in TRANSLATION_ACTIONS: return next_pos = updated_agent_position_if_unobstructed(agent.position, agent.orientation, action) # exit if next position is not legal if next_pos not in grid or grid[next_pos].blocks: return agent.position = next_pos
def make_goal_state(agent_on_goal: bool) -> State: """makes a simple state with a wall in front of the agent""" grid = Grid(2, 1) grid[0, 0] = Goal() agent_position = (0, 0) if agent_on_goal else (1, 0) agent = Agent(agent_position, Orientation.N) return State(grid, agent)
def make_moving_obstacle_state(agent_on_obstacle: bool) -> State: """makes a simple state with goal object and agent on or off the goal""" grid = Grid(2, 1) grid[0, 0] = MovingObstacle() agent_position = (0, 0) if agent_on_obstacle else (1, 0) agent = Agent(agent_position, Orientation.N) return State(grid, agent)
def test_move_action_blocked_by_grid_object(): """ Puts an object on (2,0) and try to move there""" grid = Grid(height=3, width=2) agent = Agent(position=(2, 1), orientation=Orientation.N) grid[2, 0] = Door(Door.Status.CLOSED, Color.YELLOW) move_agent(agent, grid, action=Action.MOVE_LEFT) assert agent.position == (2, 1)
def test_pickup_mechanics_drop(): grid = Grid(height=3, width=4) agent = Agent(position=(1, 2), orientation=Orientation.S) item_pos = (2, 2) agent.obj = Key(Color.BLUE) state = State(grid, agent) # Can drop: next_state = step_with_copy(state, Action.PICK_N_DROP) assert isinstance(next_state.agent.obj, NoneGridObject) assert agent.obj == next_state.grid[item_pos] # Cannot drop: state.grid[item_pos] = Wall() next_state = step_with_copy(state, Action.PICK_N_DROP) assert isinstance(next_state.grid[item_pos], Wall) assert agent.obj == next_state.agent.obj
def test_move_action_can_go_on_non_block_objects(): grid = Grid(height=3, width=2) agent = Agent(position=(2, 1), orientation=Orientation.N) grid[2, 0] = Door(Door.Status.OPEN, Color.YELLOW) move_agent(agent, grid, action=Action.MOVE_LEFT) assert agent.position == (2, 0) grid[2, 1] = Key(Color.BLUE) move_agent(agent, grid, action=Action.MOVE_RIGHT) assert agent.position == (2, 1)
def rotate_agent(agent: Agent, action: Action) -> None: """Rotates agent according to action (e.g. turn left/right) Leaves the state unaffected if any other action was taken instead Args: agent (`Agent`): action (`Action`): Returns: None: """ if action not in ROTATION_ACTIONS: return if action == Action.TURN_LEFT: agent.orientation = agent.orientation.rotate_left() if action == Action.TURN_RIGHT: agent.orientation = agent.orientation.rotate_right()
def test_observation_hash(): wall_position = (0, 0) agent_position = (0, 1) agent_orientation = Orientation.N agent_object = None grid = Grid(2, 2) grid[wall_position] = Wall() agent = Agent(agent_position, agent_orientation, agent_object) observation = Observation(grid, agent) hash(observation)
def test_state_hash(): wall_position = (0, 0) agent_position = (0, 1) agent_orientation = Orientation.N agent_object = None grid = Grid(2, 2) grid[wall_position] = Wall() agent = Agent(agent_position, agent_orientation, agent_object) state = State(grid, agent) hash(state)
def test_move_action( position: PositionOrTuple, orientation: Orientation, actions: Sequence[Action], expected: PositionOrTuple, ): grid = Grid(height=3, width=2) agent = Agent(position=position, orientation=orientation) for action in actions: move_agent(agent, grid, action=action) assert agent.position == expected
def test_actuate_box( content: GridObject, orientation: Orientation, action: Action, expected: bool, ): grid = Grid(2, 1) grid[0, 0] = box = Box(content) agent = Agent((1, 0), orientation) state = State(grid, agent) actuate_box(state, action) assert (grid[0, 0] is box) != expected assert (grid[0, 0] is content) == expected
def test_actuate_door( door_state: Door.Status, door_color: Color, key_color: Color, action: Action, expected_state: Door.Status, ): # agent facing door grid = Grid(2, 1) grid[0, 0] = door = Door(door_state, door_color) agent = Agent((1, 0), Orientation.N, Key(key_color)) state = State(grid, agent) actuate_door(state, action) assert door.state == expected_state # agent facing away grid = Grid(2, 1) grid[0, 0] = door = Door(door_state, door_color) agent = Agent((1, 0), Orientation.S, Key(key_color)) state = State(grid, agent) actuate_door(state, action) assert door.state == door_state
def test_teleport( position_telepod1: Position, position_telepod2: Position, position_agent: Position, expected: Position, ): grid = Grid(2, 2) grid[position_telepod1] = Telepod(Color.RED) grid[position_telepod2] = Telepod(Color.RED) agent = Agent(position_agent, Orientation.N) state = State(grid, agent) step_telepod(state, Action.ACTUATE) assert state.agent.position == expected
def test_pickup_mechanics_nothing_to_pickup(): grid = Grid(height=3, width=4) agent = Agent(position=(1, 2), orientation=Orientation.S) item_pos = (2, 2) state = State(grid, agent) # Cannot pickup floor next_state = step_with_copy(state, Action.PICK_N_DROP) assert state == next_state # Cannot pickup door grid[item_pos] = Door(Door.Status.CLOSED, Color.GREEN) next_state = step_with_copy(state, Action.PICK_N_DROP) assert state == next_state assert isinstance(next_state.grid[item_pos], Door)
def test_pickup_mechanics_pickup(): grid = Grid(height=3, width=4) agent = Agent(position=(1, 2), orientation=Orientation.S) item_pos = (2, 2) grid[item_pos] = Key(Color.GREEN) state = State(grid, agent) # Pick up works next_state = step_with_copy(state, Action.PICK_N_DROP) assert grid[item_pos] == next_state.agent.obj assert isinstance(next_state.grid[item_pos], Floor) # Pick up only works with correct action next_state = step_with_copy(state, Action.MOVE_LEFT) assert grid[item_pos] != next_state.agent.obj assert next_state.grid[item_pos] == grid[item_pos]
def simplest_reset( *, rng: Optional[rnd.Generator] = None, # pylint: disable=unused-argument ) -> State: """smallest possible room with goal right in front of agent""" # constructed the grid directly from objects grid = Grid.from_objects([ [Wall(), Wall(), Wall()], [Wall(), Goal(), Wall()], [Wall(), Floor(), Wall()], [Wall(), Wall(), Wall()], ]) # positioning the agent in the above grid agent = Agent((2, 1), Orientation.N) return State(grid, agent)
def reset_empty( height: int, width: int, random_agent: bool = False, random_goal: bool = False, *, rng: Optional[rnd.Generator] = None, ) -> State: """An empty environment""" if height < 4 or width < 4: raise ValueError('height and width need to be at least 4') rng = get_gv_rng_if_none(rng) # TODO test creation (e.g. count number of walls, goals, check held item) grid = Grid(height, width) draw_wall_boundary(grid) if random_goal: goal_y = rng.integers(1, height - 2, endpoint=True) goal_x = rng.integers(1, width - 2, endpoint=True) else: goal_y = height - 2 goal_x = width - 2 grid[goal_y, goal_x] = Goal() if random_agent: agent_position = rng.choice([ position for position in grid.positions() if isinstance(grid[position], Floor) ]) agent_orientation = rng.choice(list(Orientation)) else: agent_position = (1, 1) agent_orientation = Orientation.E agent = Agent(agent_position, agent_orientation) return State(grid, agent)
def frontal_line_of_sight( state: State, *, observation_space: ObservationSpace, rng: Optional[rnd.Generator] = None, # pylint: disable=unused-argument ) -> Observation: """only tiles in front of the agent can be seen""" # get agent's POV grid area = state.agent.get_pov_area(observation_space.area) observation_grid = state.grid.subgrid(area).change_orientation( state.agent.orientation) # hiding all tiles which are not directly in front of agent for position in observation_grid.positions(): if ( # the tile is not in the same column as the agent position.x == observation_space.agent_position.x # or the tile is behind the agent or position.y < observation_space.agent_position.y): observation_grid[position] = Hidden() # boolean flag to detect whether the line of sight has run into a # non-transparent object found_non_transparent = False # for every y-coordinate in front of the agent for y in range(observation_space.agent_position.y - 1, -1, -1): position = Position(y, observation_space.agent_position.x) # hide object if we have already encountered a non-transparent object if found_non_transparent: observation_grid[position] = Hidden() # update the boolean flag if object is non-transparent found_non_transparent |= not observation_grid[position].transparent observation_agent = Agent(observation_space.agent_position, Orientation.N, state.agent.obj) return Observation(observation_grid, observation_agent)
def from_visibility( state: State, *, observation_space: ObservationSpace, visibility_function: VisibilityFunction, rng: Optional[rnd.Generator] = None, ): area = state.agent.get_pov_area(observation_space.area) observation_grid = state.grid.subgrid(area).change_orientation( state.agent.orientation) visibility = visibility_function(observation_grid, observation_space.agent_position, rng=rng) if Shape(*visibility.shape) != observation_space.grid_shape: raise ValueError('incorrect shape of visibility mask') for pos in observation_grid.positions(): if not visibility[pos.y, pos.x]: observation_grid[pos] = Hidden() observation_agent = Agent(observation_space.agent_position, Orientation.N, state.agent.obj) return Observation(observation_grid, observation_agent)
def reset_rooms( # pylint: disable=too-many-locals height: int, width: int, layout: Tuple[int, int], *, rng: Optional[rnd.Generator] = None, ) -> State: rng = get_gv_rng_if_none(rng) # TODO test creation (e.g. count number of walls, goals, check held item) layout_height, layout_width = layout y_splits = np.linspace( 0, height - 1, num=layout_height + 1, dtype=int, ) if len(y_splits) != len(set(y_splits)): raise ValueError( f'insufficient height ({height}) for layout ({layout})') x_splits = np.linspace( 0, width - 1, num=layout_width + 1, dtype=int, ) if len(x_splits) != len(set(x_splits)): raise ValueError( f'insufficient width ({height}) for layout ({layout})') grid = Grid(height, width) draw_room_grid(grid, y_splits, x_splits, Wall) # passages in horizontal walls for y in y_splits[1:-1]: for x_from, x_to in mitt.pairwise(x_splits): x = rng.integers(x_from + 1, x_to) grid[y, x] = Floor() # passages in vertical walls for y_from, y_to in mitt.pairwise(y_splits): for x in x_splits[1:-1]: y = rng.integers(y_from + 1, y_to) grid[y, x] = Floor() # sample agent and goal positions agent_position, goal_position = rng.choice( [ position for position in grid.positions() if isinstance(grid[position], Floor) ], size=2, replace=False, ) agent_orientation = rng.choice(list(Orientation)) grid[goal_position] = Goal() agent = Agent(agent_position, agent_orientation) return State(grid, agent)
observation.agent.orientation = observation.agent.orientation.rotate_back() def _change_agent_object(observation: Observation): """changes agent object""" observation.agent.obj = ( Key(Color.RED) if isinstance(observation.agent.obj, NoneGridObject) else NoneGridObject() ) @pytest.mark.parametrize( 'observation', [ Observation(Grid(2, 3), Agent((0, 0), Orientation.N)), Observation(Grid(3, 2), Agent((1, 1), Orientation.S, Key(Color.RED))), ], ) def test_observation_eq(observation: Observation): other_observation = deepcopy(observation) assert observation == other_observation other_observation = deepcopy(observation) _change_grid(other_observation) assert observation != other_observation other_observation = deepcopy(observation) _change_agent_position(other_observation) assert observation != other_observation
from gym_gridverse.agent import Agent from gym_gridverse.envs.observation_functions import ( factory, minigrid_observation, ) from gym_gridverse.geometry import Orientation, Shape from gym_gridverse.grid import Grid from gym_gridverse.grid_object import Floor, GridObject, Hidden, Wall from gym_gridverse.spaces import ObservationSpace from gym_gridverse.state import State @pytest.mark.parametrize( 'agent', [ Agent((7, 7), Orientation.N), Agent((3, 3), Orientation.S), Agent((7, 3), Orientation.E), Agent((3, 7), Orientation.W), ], ) def test_minigrid_observation(agent: Agent): grid = Grid(10, 10) grid[5, 5] = Wall() state = State(grid, agent) observation_space = ObservationSpace(Shape(6, 5), [], []) observation = minigrid_observation( state, observation_space=observation_space ) assert observation.agent.position == (5, 2)
def make_key_state(has_key: bool) -> State: """makes a simple state with a door""" grid = Grid(1, 1) obj = Key(Color.RED) if has_key else None agent = Agent((0, 0), Orientation.N, obj) return State(grid, agent)
def make_door_state(door_status: Door.Status) -> State: """makes a simple state with a door""" grid = Grid(2, 1) grid[0, 0] = Door(door_status, Color.RED) agent = Agent((1, 0), Orientation.N) return State(grid, agent)
def make_wall_state(orientation: Orientation = Orientation.N) -> State: """makes a simple state with goal object and agent on or off the goal""" grid = Grid(2, 1) grid[0, 0] = Wall() agent = Agent((1, 0), orientation) return State(grid, agent)
def make_5x5_goal_state() -> State: """makes a simple 5x5 state with goal object in the middle""" grid = Grid(5, 5) grid[2, 2] = Goal() agent = Agent((0, 0), Orientation.N) return State(grid, agent)