def add_bed(builder: WorldBuilder, top_loc, room):
    """ Add one bed to the MATRX world

    Parameters
    ----------
    builder
        The MATRX world builder
    top_loc
        the coordinate of the top part of the bed
    room
        the hospital room in which the bed is located

    """
    # Add top half of bed with the room
    builder.add_object(location=top_loc,
                       is_traversable=False,
                       is_movable=False,
                       name="Bed_top",
                       assigned_patient='free',
                       img_name="bed_top.png",
                       room=room,
                       customizable_properties=['assigned_patient'])
    # Add bottom half of bed
    bot_loc = [top_loc[0], top_loc[1] + 1]
    builder.add_object(location=bot_loc,
                       is_traversable=False,
                       is_movable=False,
                       name="Bed_bottom",
                       img_name="bed_bottom.png")
Esempio n. 2
0
def create_builder():
    # Some BW4T settings
    block_colours = ['#ff0000', '#ffffff', '#ffff00', '#0000ff', '#00ff00', '#ff00ff']
    block_sense_range = 10  # the range with which agents detect blocks
    other_sense_range = np.inf  # the range with which agents detect other objects (walls, doors, etc.)
    agent_memory_decay = (10 / tick_duration)  # we want to memorize states for (seconds / tick_duration ticks) ticks

    # Set numpy's random generator
    np.random.seed(random_seed)

    # The world size, with plenty of space for agents to move between rooms
    world_size = (30, 44)

    # Create our world builder
    builder = WorldBuilder(shape=world_size, tick_duration=tick_duration, random_seed=random_seed, run_matrx_api=True,
                           run_matrx_visualizer=True, verbose=verbose, visualization_bg_clr="#f0f0f0",
                           visualization_bg_img="")

    # Add the world bounds (not needed, as agents cannot 'walk off' the grid, but for visual effect)
    builder.add_room(top_left_location=(0, 0), width=world_size[0], height=world_size[1], name="world_bounds")

    # Create the rooms
    room_locations = add_rooms(builder)

    # Add the blocks the agents need to collect, we do so probabilistically so each world will contain different blocks
    add_blocks(builder, room_locations, block_colours)

    # Create the drop-off zones, this includes generating the random colour/shape combinations to collect.
    add_drop_off_zone(builder, world_size, block_colours, nr_blocks_to_collect=2)

    # Add the agents and human agents to the top row of the world
    add_agents(builder, block_sense_range, other_sense_range, agent_memory_decay)

    # Return the builder
    return builder
Esempio n. 3
0
    def __init__(self,
                 agents: List[dict],
                 worldsettings: dict = DEFAULT_WORLDSETTINGS):
        '''
           @param agents a list like 
            [
            {'name':'agent1', 'botclass':PatrollingAgent, 'settings':{'slowdown':3}},
            {'name':'human1', 'botclass':Human, 'settings':{'slowdown':1}}
            ]
            Names must all be unique.
            Check BW4TBrain for more on the agents specification.
        '''
        self._worldsettings = worldsettings
        self._agents = agents

        np.random.seed(worldsettings['random_seed'])
        world_size = self.world_size()

        # Create the goal
        goal = CollectionGoal(worldsettings['deadline'])

        # Create our world builder
        self._builder = WorldBuilder(
            shape=world_size,
            tick_duration=worldsettings['tick_duration'],
            random_seed=worldsettings['random_seed'],
            run_matrx_api=worldsettings['run_matrx_api'],
            run_matrx_visualizer=worldsettings['run_matrx_visualizer'],
            verbose=worldsettings['verbose'],
            simulation_goal=goal)

        # Hacky? But this is apparently the way to do this.
        # Also note the extra underscore, maybe that's a buig in matrx?
        self._builder.api_info['_matrx_paused'] = worldsettings['matrx_paused']

        # Add the world bounds (not needed, as agents cannot 'walk off' the grid, but for visual effects)
        self._builder.add_room(top_left_location=(0, 0),
                               width=world_size[0],
                               height=world_size[1],
                               name="world_bounds")
        room_locations = self._addRooms()
        self._addBlocks(room_locations)
        self._addDropOffZones(world_size)

        # Add the agents and human agents to the top row of the world
        self._addAgents()

        media_folder = os.path.dirname(
            os.path.join(os.path.realpath(__file__), "media"))
        self._builder.startup(media_folder=media_folder)
        self._builder.add_logger(BW4TLogger, save_path='.')

        self._gridworld = self._builder.worlds(nr_of_worlds=1).__next__()
Esempio n. 4
0
    def get_room_content(self, room_name):
        # Locate method to identify room content
        def is_content(obj):
            if 'class_inheritance' in obj.keys():
                chain = obj['class_inheritance']
                if not (Wall.__name__ in chain or Door.__name__ in chain or AreaTile in chain):
                    return obj
            else:  # the object is a Wall, Door or AreaTile
                return None

        # Get all walls of the room
        walls = self.get_with_property(["room_name", "class_inheritance"], [room_name, "Wall"], combined=True)

        # Get the top left corner and width and height of the room based on the found walls (and assuming the room is
        # rectangle).
        xs = [wall['location'][0] for wall in walls]
        ys = [wall['location'][1] for wall in walls]
        top_left = (min(xs), min(ys))
        width = max(xs) - top_left[0] + 1
        height = max(ys) - top_left[1] + 1
        content_locs = WorldBuilder.get_room_locations(top_left, width, height)

        # Get all objects with those content locations
        content = self.get_with_property('location', content_locs)

        # Get all room objects
        room_objs = self.get_room_objects(room_name)

        # Filter out all area's, walls and doors
        content = map(is_content, room_objs)
        content = [c for c in content if c is not None]

        return content
def create_builder():
    # Create our builder, here we specify the world size and a nice background image
    builder = WorldBuilder(shape=[14, 13],
                           run_matrx_api=True,
                           run_matrx_visualizer=True,
                           visualization_bg_img="",
                           tick_duration=0.1)

    # Add the walls surrounding the maze
    builder.add_room(top_left_location=[0, 0],
                     width=14,
                     height=13,
                     name="Borders")

    # Add the walls to our maze
    builder.add_line(start=[2, 2], end=[6, 2], name="Maze wall")
    builder.add_line(start=[8, 2], end=[11, 2], name="Maze wall")
    builder.add_line(start=[2, 3], end=[2, 5], name="Maze wall")
    builder.add_line(start=[11, 3], end=[11, 5], name="Maze wall")
    builder.add_line(start=[6, 4], end=[8, 4], name="Maze wall")
    builder.add_line(start=[9, 4], end=[9, 7], name="Maze wall")
    builder.add_line(start=[6, 5], end=[6, 6], name="Maze wall")
    builder.add_line(start=[4, 4], end=[4, 8], name="Maze wall")
    builder.add_line(start=[5, 8], end=[9, 8], name="Maze wall")
    builder.add_line(start=[2, 7], end=[2, 9], name="Maze wall")
    builder.add_line(start=[11, 7], end=[11, 9], name="Maze wall")
    builder.add_line(start=[2, 10], end=[5, 10], name="Maze wall")
    builder.add_line(start=[7, 10], end=[11, 10], name="Maze wall")

    # Add our treasure chest!
    builder.add_object(location=[7, 5],
                       name="Treasure!",
                       visualize_colour="#fcba03",
                       is_traversable=True)

    # Add a human controllable agent with certain controls and a GIF
    key_action_map = {
        'w': MoveNorth.__name__,
        'd': MoveEast.__name__,
        's': MoveSouth.__name__,
        'a': MoveWest.__name__,
    }
    brain = HumanAgentBrain()
    builder.add_human_agent(location=[1, 1],
                            agent=brain,
                            name="Human",
                            key_action_map=key_action_map,
                            img_name="/static/images/agent.gif")

    # Return the builder
    return builder
def create_builder(test_subject_id=None):
    world_size = [24, 28]
    bg_color = "#ebebeb"
    wall_color = "#adadad"
    tdp = "tdp_decision_support_explained"
    timestamp = setTimestamp()

    config_path = os.path.join(os.path.realpath("mhc"), 'cases',
                               'experiment_3_tdp_dss.json')

    config = json.load(open(config_path))
    print("Loaded config file:", config_path)

    np.random.seed(config['random_seed'])
    print("Set random seed:", config['random_seed'])

    # Create our builder instance
    builder = WorldBuilder(shape=world_size,
                           run_matrx_api=True,
                           run_matrx_visualizer=False,
                           visualization_bg_clr=bg_color,
                           visualization_bg_img="",
                           tick_duration=config['world']['tick_duration'],
                           simulation_goal=AllPatientsTriaged(
                               config['patients']['max_patients']))

    #################################################################
    # Rooms
    ################################################################
    add_mhc_rooms(builder, config, world_size, wall_color)

    #################################################################
    # Beds
    ################################################################
    add_mhc_chairs_beds(builder)

    #################################################################
    # Other objects
    ################################################################
    add_mhc_extras(builder, config)

    # add settings object
    builder.add_object(location=[0, 0],
                       is_traversable=True,
                       is_movable=False,
                       name="Settings",
                       visualize_size=0,
                       tdp=tdp,
                       visualize_your_vs_patient_robots=True,
                       start_timestamp=timestamp,
                       show_agent_predictions=True,
                       trial_completed=False,
                       config=config,
                       end_message=config['world']['trial_end_message'],
                       customizable_properties=['trial_completed'])

    #################################################################
    # Loggers
    ################################################################
    log_folder = tdp + "_" + timestamp
    if test_subject_id is not None:
        log_folder = f"test_subject_{test_subject_id}_{log_folder}"

    builder.add_logger(
        LogPatientStatus,
        save_path=os.path.join('Results', log_folder),
        file_name_prefix="patient_status",
    )

    builder.add_logger(LogNewPatients,
                       save_path=os.path.join('Results', log_folder),
                       file_name_prefix="new_patients")

    builder.add_logger(LogTriageDecision,
                       save_path=os.path.join('Results', log_folder),
                       file_name_prefix="triage_decisions")

    #################################################################
    # Actors
    ################################################################

    # create the patient planner (god agent) that spawns patients over time, as described in the config
    builder.add_agent(location=[0, 0],
                      is_traversable=True,
                      is_movable=False,
                      agent_brain=PatientPlanner(config=config, tdp=tdp),
                      name="Patient planner",
                      visualize_size=0)

    # add the test subject: the human doctor
    builder.add_human_agent(location=config['human_doctor']['location'],
                            is_traversable=True,
                            is_movable=False,
                            agent=HumanDoctor(),
                            name="human_doctor",
                            visualize_size=0)

    # add the hospital manager (god agent) that takes care of removing deceased patients
    builder.add_agent(location=[0, 0],
                      is_traversable=True,
                      is_movable=False,
                      agent_brain=HospitalManager(),
                      name="hospital_manager",
                      visualize_size=0)

    # Return the builder
    return builder
Esempio n. 7
0
class BW4TWorld:
    '''
    Creates a single GridWorld to be run. 
    The idea was that this extends GridWorld, however
    it seems we need to create these through the WorldBuilder
    and therefore this approach seems not possible.
    Instead, this only supports the 'run' function and
    internally creates the gridworld using WorldBuilder.
    
    '''
    def __init__(self,
                 agents: List[dict],
                 worldsettings: dict = DEFAULT_WORLDSETTINGS):
        '''
           @param agents a list like 
            [
            {'name':'agent1', 'botclass':PatrollingAgent, 'settings':{'slowdown':3}},
            {'name':'human1', 'botclass':Human, 'settings':{'slowdown':1}}
            ]
            Names must all be unique.
            Check BW4TBrain for more on the agents specification.
        '''
        self._worldsettings = worldsettings
        self._agents = agents

        np.random.seed(worldsettings['random_seed'])
        world_size = self.world_size()

        # Create the goal
        goal = CollectionGoal(worldsettings['deadline'])

        # Create our world builder
        self._builder = WorldBuilder(
            shape=world_size,
            tick_duration=worldsettings['tick_duration'],
            random_seed=worldsettings['random_seed'],
            run_matrx_api=worldsettings['run_matrx_api'],
            run_matrx_visualizer=worldsettings['run_matrx_visualizer'],
            verbose=worldsettings['verbose'],
            simulation_goal=goal)

        # Hacky? But this is apparently the way to do this.
        # Also note the extra underscore, maybe that's a buig in matrx?
        self._builder.api_info['_matrx_paused'] = worldsettings['matrx_paused']

        # Add the world bounds (not needed, as agents cannot 'walk off' the grid, but for visual effects)
        self._builder.add_room(top_left_location=(0, 0),
                               width=world_size[0],
                               height=world_size[1],
                               name="world_bounds")
        room_locations = self._addRooms()
        self._addBlocks(room_locations)
        self._addDropOffZones(world_size)

        # Add the agents and human agents to the top row of the world
        self._addAgents()

        media_folder = os.path.dirname(
            os.path.join(os.path.realpath(__file__), "media"))
        self._builder.startup(media_folder=media_folder)
        self._builder.add_logger(BW4TLogger, save_path='.')

        self._gridworld = self._builder.worlds(nr_of_worlds=1).__next__()

    def run(self):
        '''
        run the world till termination
        @return this 
        '''
        self._gridworld.run(self._builder.api_info)
        return self

    def getLogger(self) -> BW4TLogger:
        '''
        @return the logger. We assume there is only 1: BW4TLogger
        '''
        return self._gridworld._GridWorld__loggers[0]

    def world_size(self):
        '''
        returns (width,height) (number of tiles)
        '''
        worldsettings = self._worldsettings
        nr_room_rows = np.ceil(worldsettings['nr_rooms'] /
                               worldsettings['rooms_per_row'])

        # calculate the total width
        world_width = max(
            worldsettings['rooms_per_row'] * worldsettings['room_size'][0] +
            2 * worldsettings['hallway_space'],
            (worldsettings['nr_drop_zones'] + 1) *
            worldsettings['hallway_space'] +
            worldsettings['nr_drop_zones']) + 2

        # calculate the total height
        world_height = nr_room_rows * worldsettings['room_size'][1] + (
            nr_room_rows + 1) * worldsettings['hallway_space'] + worldsettings[
                'nr_blocks_needed'] + 2

        return int(world_width), int(world_height)

    def _addBlocks(self, room_locations):
        '''
        Add blocks to all given room locations
        '''
        for room_name, locations in room_locations.items():
            for loc in locations:
                # Get the block's name
                name = f"Block in {room_name}"

                # Get the probability for adding a block so we get the on average the requested number of blocks per room
                prob = min(
                    1.0, self._worldsettings['average_blocks_per_room'] /
                    len(locations))

                # Create a MATRX random property of shape and color so each block varies per created world.
                # These random property objects are used to obtain a certain value each time a new world is
                # created from this builder.
                colour_property = RandomProperty(
                    values=self._worldsettings['block_colors'])
                shape_property = RandomProperty(
                    values=self._worldsettings['block_shapes'])

                # Add the block; a regular SquareBlock as denoted by the given 'callable_class' which the
                # builder will use to create the object. In addition to setting MATRX properties, we also
                # provide a `is_block` boolean as custom property so we can identify this as a collectible
                # block.
                self._builder.add_object_prospect(
                    loc,
                    name,
                    callable_class=CollectableBlock,
                    probability=prob,
                    visualize_shape=shape_property,
                    visualize_colour=colour_property,
                    block_size=self._worldsettings['block_size'])

    def _addAgents(self):
        '''
        Add bots as specified, starting top left corner. 
        All bots have the same sense_capability.
        '''
        sense_capability = SenseCapability({
            AgentBody:
            self._worldsettings['agent_sense_range'],
            CollectableBlock:
            self._worldsettings['block_sense_range'],
            None:
            self._worldsettings['other_sense_range']
        })

        loc = (0, 1)  # agents start in horizontal row at top left corner.
        team_name = "Team 1"  # currently this supports 1 team
        for agent in self._agents:
            brain = agent['botclass'](agent['settings'])
            loc = (loc[0] + 1, loc[1])
            if agent['botclass'] == Human:
                self._builder.add_human_agent(
                    loc,
                    brain,
                    team=team_name,
                    name=agent['name'],
                    key_action_map=self._worldsettings['key_action_map'],
                    sense_capability=sense_capability)
            else:
                self._builder.add_agent(loc,
                                        brain,
                                        team=team_name,
                                        name=agent['name'],
                                        sense_capability=sense_capability)

    def _addRooms(self):
        '''
        @return room locations
        '''
        room_locations = {}
        for room_nr in range(self._worldsettings['nr_rooms']):
            room_top_left, door_loc = self.get_room_loc(room_nr)

            # We assign a simple random color to each room. Not for any particular reason except to brighting up the place.
            room_color = random.choice(self._worldsettings['room_colors'])

            # Add the room
            room_name = f"room_{room_nr}"
            self._builder.add_room(
                top_left_location=room_top_left,
                width=self._worldsettings['room_size'][0],
                height=self._worldsettings['room_size'][1],
                name=room_name,
                door_locations=[door_loc],
                wall_visualize_colour=self._worldsettings['wall_color'],
                with_area_tiles=True,
                area_visualize_colour=room_color,
                area_visualize_opacity=0.1)

            # Find all inner room locations where we allow objects (making sure that the location behind to door is free)
            room_locations[room_name] = self._builder.get_room_locations(
                room_top_left, self._worldsettings['room_size'][0],
                self._worldsettings['room_size'][1])

        return room_locations

    def get_room_loc(self, room_nr):
        '''
        @return room location (room_x, room_y), (door_x, door_y) for given room nr
        '''
        row = np.floor(room_nr / self._worldsettings['rooms_per_row'])
        column = room_nr % self._worldsettings['rooms_per_row']

        # x is: +1 for the edge, +edge hallway, +room width * column nr, +1 off by one
        room_x = int(1 + self._worldsettings['hallway_space'] +
                     (self._worldsettings['room_size'][0] * column))

        # y is: +1 for the edge, +hallway space * (nr row + 1 for the top hallway), +row * room height, +1 off by one
        room_y = int(1 + self._worldsettings['hallway_space'] * (row + 1) +
                     row * self._worldsettings['room_size'][1] + 1)

        # door location is always center bottom
        door_x = room_x + int(np.ceil(self._worldsettings['room_size'][0] / 2))
        door_y = room_y + self._worldsettings['room_size'][1] - 1

        return (room_x, room_y), (door_x, door_y)

    def _addDropOffZones(self, world_size):
        x = int(np.ceil(world_size[0] / 2)) - \
            (int(np.floor(self._worldsettings['nr_drop_zones'] / 2)) * \
                (self._worldsettings['hallway_space'] + 1))
        y = world_size[
            1] - 1 - 1  # once for off by one, another for world bound
        for nr_zone in range(self._worldsettings['nr_drop_zones']):
            # Add the zone's tiles. Area tiles are special types of objects in MATRX that simply function as
            # a kind of floor. They are always traversable and cannot be picked up.
            self._builder.add_area(
                (x, y - self._worldsettings['nr_blocks_needed'] + 1),
                width=1,
                height=self._worldsettings['nr_blocks_needed'],
                name=f"Drop off {nr_zone}",
                visualize_colour=self._worldsettings['drop_off_color'],
                drop_zone_nr=nr_zone,
                is_drop_zone=True,
                is_goal_block=False,
                is_collectable=False)

            # Go through all needed blocks
            for nr_block in range(self._worldsettings['nr_blocks_needed']):
                # Create a MATRX random property of shape and color so each world contains different blocks to collect
                colour_property = RandomProperty(
                    values=self._worldsettings['block_colors'])
                shape_property = RandomProperty(
                    values=self._worldsettings['block_shapes'])

                # Add a 'ghost image' of the block that should be collected. This can be seen by both humans and agents to
                # know what should be collected in what order.
                loc = (x, y - nr_block)
                self._builder.add_object(
                    loc,
                    name="Collect Block",
                    callable_class=GhostBlock,
                    visualize_colour=colour_property,
                    visualize_shape=shape_property,
                    drop_zone_nr=nr_zone,
                    block_size=self._worldsettings['block_size'])

            # Change the x to the next zone
            x = x + self._worldsettings['hallway_space'] + 1