def test_step_moving_obstacles( objects: Sequence[Sequence[GridObject]], expected_objects: Sequence[Sequence[GridObject]], ): state = State(Grid.from_objects(objects), MagicMock()) expected_state = State(Grid.from_objects(expected_objects), MagicMock()) action = MagicMock() step_moving_obstacles(state, action) assert state.grid == expected_state.grid
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 creeping_walls( state: State, action: Action, # pylint: disable=unused-argument *, rng: Optional[rnd.Generator] = None, ) -> None: """randomly chooses a Floor tile and turns it into a Wall tile""" rng = get_gv_rng_if_none(rng) # necessary to use rng object! # all positions associated with a Floor object floor_positions = [ position for position in state.grid.positions() if isinstance(state.grid[position], Floor) ] try: # floor_positions could be an empty list position = rng.choice(floor_positions) except ValueError: # there are no floor positions pass else: # if we were able to sample a position, change the corresponding Floor # into a Wall state.grid[position] = Wall()
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 actuate_box( state: State, action: Action, *, rng: Optional[rnd.Generator] = None, ) -> None: """Attempts to open door When not holding correct key with correct color: `open` or `closed` -> `open` `locked` -> `locked` When holding correct key: any state -> `open` """ if action is not Action.ACTUATE: return position = state.agent.position_in_front() try: box = state.grid[position] except IndexError: return if not isinstance(box, Box): return state.grid[position] = box.content
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_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 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_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_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) assert observation.agent.orientation == Orientation.N assert observation.agent.obj == state.agent.obj assert observation.grid.shape == Shape(6, 5) assert isinstance(observation.grid[3, 0], Wall)
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_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_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 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_minigrid_observation_partially_observable( agent: Agent, expected_objects: Sequence[Sequence[GridObject]] ): grid = Grid.from_objects( [ [Floor(), Floor(), Floor()], [Wall(), Wall(), Wall()], [Floor(), Floor(), Floor()], ] ) state = State(grid, agent) observation_space = ObservationSpace(Shape(6, 5), [], []) observation = minigrid_observation( state, observation_space=observation_space ) expected = Grid.from_objects(expected_objects) assert observation.grid == expected
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 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)
def make_moving_obstacle_state(): grid = Grid(3, 3) grid[1, 1] = MovingObstacle() agent = MagicMock() return State(grid, agent)
def _change_agent_orientation(state: State): """changes agent orientation""" state.agent.orientation = state.agent.orientation.rotate_back() def _change_agent_object(state: State): """changes agent object""" state.agent.obj = (Key(Color.RED) if isinstance( state.agent.obj, NoneGridObject) else NoneGridObject()) @pytest.mark.parametrize( 'state', [ State(Grid(2, 3), Agent((0, 0), Orientation.N)), State(Grid(3, 2), Agent((1, 1), Orientation.S, Key(Color.RED))), ], ) def test_state_eq(state: State): other_state = deepcopy(state) assert state == other_state other_state = deepcopy(state) _change_grid(other_state) assert state != other_state other_state = deepcopy(state) _change_agent_position(other_state) assert state != other_state
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 _change_grid(state: State): """changes one object in the grid""" state.grid[0, 0] = (Wall() if isinstance(state.grid[0, 0], Floor) else Floor())
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)
def simple_state_without_object() -> State: """ Returns a 2x2 (empty) grid with an agent without an item """ return State( Grid(height=2, width=2), Agent(position=(0, 0), orientation=Orientation.N, obj=Floor()), )