예제 #1
0
def test_agent_position_in_front(
    position: PositionOrTuple,
    orientation: Orientation,
    expected: PositionOrTuple,
):
    agent = Agent(position, orientation)
    assert agent.position_in_front() == expected
예제 #2
0
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
예제 #3
0
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]
예제 #4
0
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)
예제 #5
0
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
예제 #6
0
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)
예제 #7
0
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)
예제 #8
0
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)
예제 #9
0
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
예제 #10
0
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)
예제 #11
0
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()
예제 #12
0
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)
예제 #13
0
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)
예제 #14
0
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
예제 #15
0
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
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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)
예제 #19
0
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)
예제 #21
0
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)
예제 #22
0
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)
예제 #23
0
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)
예제 #24
0
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)
예제 #25
0
    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)
예제 #27
0
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)
예제 #28
0
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)
예제 #29
0
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)
예제 #30
0
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)