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 test_grid_set_item(): grid = Grid(3, 4) pos = Position(0, 0) obj = Floor() assert grid[pos] is not obj grid[pos] = obj assert grid[pos] is obj
def test_grid_get_position(): grid = Grid(3, 4) # testing position -> grid_object -> position roundtrip for position in grid.positions(): obj = grid[position] assert grid.get_position(obj) == position # testing exception when object is not in grid with pytest.raises(ValueError): grid.get_position(Floor())
def test_floor_properties(): """ Basic stupid tests for floor grid object """ floor = Floor() assert floor.transparent assert not floor.blocks assert floor.color == Color.NONE assert not floor.can_be_picked_up assert floor.state_index == 0 assert floor.can_be_represented_in_state() assert floor.render_as_char() == ' ' assert floor.num_states() == 1
def test_box_basic_properties(): """Tests basic properties of box """ box = Box(Floor()) assert box.transparent assert box.blocks assert box.color == Color.NONE assert not box.can_be_picked_up assert box.state_index == 0 assert not box.can_be_represented_in_state() assert box.render_as_char() == 'b' assert box.num_states() == 1
def pickup_mechanics( state: State, action: Action, *, rng: Optional[rnd.Generator] = None, # pylint: disable=unused-argument ) -> None: """Implements the effect of the pickup and drop action Pickup applies to the item *in front* of the agent There are multiple scenarii * There is no (pick-up-able) item to pickup under the agent: * The agent is not holding any object -> No effect * The agent is holding an object: * Position in front of agent is floor -> drop current object * Position in front is not a floor -> No effect * There is a (pick-up-able) item to pickup under the agent: * The agent is not holding any object -> Pick up, put floor in stead * The agent is holding an object -> Swap items Args: state (`State`): action (`Action`): rng (`Generator, optional`) Returns: None: """ if action != Action.PICK_N_DROP: return obj_in_front_of_agent = state.grid[state.agent.position_in_front()] obj_holding = state.agent.obj can_pickup = obj_in_front_of_agent.can_be_picked_up can_drop = isinstance(obj_in_front_of_agent, Floor) or can_pickup if not can_pickup and not can_drop: return state.grid[state.agent.position_in_front()] = ( obj_holding if can_drop and not isinstance(obj_holding, NoneGridObject) else Floor() # We know we are picking up if not dropping ) # Know for sure that if not can_pickup then we have dropped state.agent.obj = obj_in_front_of_agent if can_pickup else NoneGridObject()
def test_grid_subgrid(area: Area, expected_objects: Sequence[Sequence[GridObject]]): # checkerboard pattern grid = Grid.from_objects([ [Wall(), Floor(), Wall(), Floor()], [Floor(), Wall(), Floor(), Wall()], [Wall(), Floor(), Wall(), Floor()], ]) expected = Grid.from_objects(expected_objects) assert grid.subgrid(area) == expected
def test_grid_change_orientation( orientation: Orientation, expected_objects: Sequence[Sequence[GridObject]]): # checkerboard pattern grid = Grid.from_objects([ [Wall(), Floor(), Wall(), Floor()], [Floor(), Wall(), Floor(), Wall()], [Wall(), Floor(), Wall(), Floor()], ]) expected = Grid.from_objects(expected_objects) assert grid.change_orientation(orientation) == 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 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 _change_grid(observation: Observation): """changes one object in the grid""" observation.grid[0, 0] = ( Wall() if isinstance(observation.grid[0, 0], Floor) else Floor() )
assert observation.grid.shape == Shape(6, 5) assert isinstance(observation.grid[3, 0], Wall) @pytest.mark.parametrize( 'agent,expected_objects', [ ( Agent((2, 1), Orientation.N), [ [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Wall(), Wall(), Wall(), Hidden()], [Hidden(), Floor(), Floor(), Floor(), Hidden()], ], ), ( Agent((0, 1), Orientation.S), [ [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Wall(), Wall(), Wall(), Hidden()], [Hidden(), Floor(), Floor(), Floor(), Hidden()], ], ), ( Agent((2, 1), Orientation.E),
factory, full_visibility, minigrid_visibility, partial_visibility, raytracing_visibility, ) from gym_gridverse.geometry import Position from gym_gridverse.grid import Grid from gym_gridverse.grid_object import Floor, GridObject, Wall @pytest.mark.parametrize( 'objects', [ [ [Floor(), Floor(), Floor()], [Floor(), Floor(), Floor()], [Floor(), Floor(), Floor()], ], [ [Wall(), Wall(), Wall()], [Wall(), Wall(), Wall()], [Wall(), Wall(), Wall()], ], ], ) def test_full_visibility(objects: Sequence[Sequence[GridObject]]): grid = Grid.from_objects(objects) for position in grid.positions(): visibility = full_visibility(grid, position)
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()), )
@pytest.mark.parametrize( 'area,expected_objects', [ ( Area((-1, 3), (-1, 4)), [ [Hidden(), Hidden(), Hidden(), Hidden(), Hidden(), Hidden()], [Hidden(), Wall(), Floor(), Wall(), Floor(), Hidden()], [Hidden(), Floor(), Wall(), Floor(), Wall(), Hidden()], [Hidden(), Wall(), Floor(), Wall(), Floor(), Hidden()], [Hidden(), Hidden(), Hidden(), Hidden(), Hidden(),
def reset_crossing( # pylint: disable=too-many-locals height: int, width: int, num_rivers: int, object_type: Type[GridObject], *, rng: Optional[rnd.Generator] = None, ) -> State: """An environment with "rivers" to be crosses Creates a height x width (including wall) grid with random rows/columns of objects called "rivers". The agent needs to navigate river openings to reach the goal. For example:: ######### #@ # # #### #### # # # ## ###### # # # # # # #G# ######### Args: height (`int`): odd height of grid width (`int`): odd width of grid num_rivers (`int`): number of `rivers` object_type (`Type[GridObject]`): river's object type rng: (`Generator, optional`) Returns: State: """ if height < 5 or height % 2 == 0: raise ValueError( f"Crossing environment height must be odd and >= 5, given {height}" ) if width < 5 or width % 2 == 0: raise ValueError( f"Crossing environment width must be odd and >= 5, given {width}") if num_rivers < 0: raise ValueError( f"Crossing environment number of walls must be >= 0, given {height}" ) rng = get_gv_rng_if_none(rng) state = reset_empty(height, width) assert isinstance(state.grid[height - 2, width - 2], Goal) # token `horizontal` and `vertical` objects h, v = object(), object() # all rivers specified by orientation and position rivers = list( itt.chain( ((h, i) for i in range(2, height - 2, 2)), ((v, j) for j in range(2, width - 2, 2)), )) # sample subset of random rivers rng.shuffle(rivers) # NOTE: faster than rng.choice rivers = rivers[:num_rivers] # create horizontal rivers without crossings rivers_h = sorted([pos for direction, pos in rivers if direction is h]) for y in rivers_h: draw_line_horizontal(state.grid, y, range(1, width - 1), object_type) # create vertical rivers without crossings rivers_v = sorted([pos for direction, pos in rivers if direction is v]) for x in rivers_v: draw_line_vertical(state.grid, range(1, height - 1), x, object_type) # sample path to goal path = [h] * len(rivers_v) + [v] * len(rivers_h) rng.shuffle(path) # create crossing limits_h = [0] + rivers_h + [height - 1] # horizontal river boundaries limits_v = [0] + rivers_v + [width - 1] # vertical river boundaries room_i, room_j = 0, 0 # coordinates of current "room" for step_direction in path: if step_direction is h: i = rng.integers(limits_h[room_i] + 1, limits_h[room_i + 1]) j = limits_v[room_j + 1] room_j += 1 elif step_direction is v: i = limits_h[room_i + 1] j = rng.integers(limits_v[room_j] + 1, limits_v[room_j + 1]) room_i += 1 else: assert False state.grid[i, j] = Floor() # Place agent on top left state.agent.position = (1, 1) # type: ignore state.agent.orientation = Orientation.E return state
('none_grid_object', {}), ('Hidden', {}), ('hidden', {}), ('Floor', {}), ('floor', {}), ('Wall', {}), ('wall', {}), ('Goal', {}), ('goal', {}), ('Door', {'status': 'LOCKED', 'color': 'RED'}), ('door', {'status': 'LOCKED', 'color': 'RED'}), ('Key', {'color': 'RED'}), ('key', {'color': 'RED'}), ('MovingObstacle', {}), ('moving_obstacle', {}), ('Box', {'obj': Floor()}), ('box', {'obj': Floor()}), ('Telepod', {'color': 'RED'}), ('telepod', {'color': 'RED'}), ], ) def test_factory_valid(name: str, kwargs): factory(name, **kwargs) @pytest.mark.parametrize( 'name,kwargs,exception', [ ('invalid', {}, ValueError), ('Door', {}, ValueError), ('door', {}, ValueError),
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 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)
with patch( 'gym_gridverse.envs.transition_functions._step_moving_obstacle', new=patched_step_moving_obstacle, ): step_moving_obstacles(state, Action.PICK_N_DROP) assert len(counts) == 4 assert all(count == 1 for count in counts.values()) @pytest.mark.parametrize( 'objects,expected_objects', [ ( [[Floor(), MovingObstacle(), MovingObstacle()]], [[MovingObstacle(), MovingObstacle(), Floor()]], ), ( [[MovingObstacle(), Floor(), MovingObstacle()]], [[Floor(), MovingObstacle(), MovingObstacle()]], ), ( [[MovingObstacle(), MovingObstacle(), Floor()]], [[MovingObstacle(), Floor(), MovingObstacle()]], ), ], ) def test_step_moving_obstacles( objects: Sequence[Sequence[GridObject]], expected_objects: Sequence[Sequence[GridObject]],