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")
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
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 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
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