diff --git a/.DS_Store b/.DS_Store index 0ff2cc6..e8417f2 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/simple_virtual_world/__pycache__/runner.cpython-38.pyc b/simple_virtual_world/__pycache__/runner.cpython-38.pyc new file mode 100644 index 0000000..9e8062e Binary files /dev/null and b/simple_virtual_world/__pycache__/runner.cpython-38.pyc differ diff --git a/simple_virtual_world/__pycache__/virtual_world.cpython-38.pyc b/simple_virtual_world/__pycache__/virtual_world.cpython-38.pyc new file mode 100644 index 0000000..697b6ff Binary files /dev/null and b/simple_virtual_world/__pycache__/virtual_world.cpython-38.pyc differ diff --git a/simple_virtual_world/runner.py b/simple_virtual_world/runner.py index ceffe5e..ca243c4 100644 --- a/simple_virtual_world/runner.py +++ b/simple_virtual_world/runner.py @@ -9,12 +9,11 @@ class RunnerAgent(Agent): def __init__(self, unique_id, model): super().__init__(unique_id, model) - self.type = 'type1' - # self.type = self.random.choice(['type1', 'type2']) + # self.type = 'type1' + self.type = self.random.choice(['type1', 'type2']) if self.type == 'type2': self.on_road = True self.on_trail = False - # self.on_way_running = True self.on_way_home = False self.entrance_trail_pos = None self.exit_trail_pos = None @@ -22,13 +21,11 @@ def __init__(self, unique_id, model): self.ready_to_exit_trail = False self.start_the_trail_run = False self.exit_the_trail_going_home = False - # self.get_to_the_first_intersection = False self.direction = None self.count = 0 self.distance_goal = 160 self.want_to_go_home = False # for type 1 & TYPE 2 - # {(x,y):[(),(),(),..] self.intersection_memory = {} # for type 1 & TYPE 2 self.memory_on_way_home = {} # for type 1 & TYPE 2 self.num_intersection_from_going_home_point = 0 # for type 1 & TYPE 2 @@ -45,7 +42,6 @@ def step(self): self.count += 1 - # try: if self.type == 'type1': if self.state == '_continue_forward': self.continue_forward() @@ -58,9 +54,6 @@ def step(self): elif self.state == '_decide_way_go_home': self.decide_way_go_home() - # elif self.state == 'rest': - # print('ID: ', self.unique_id, 'DONE\n\n\next_pos') - if self.type == 'type2': if self.state == '_decide_way_to_get_to_trail_entrance': self.decide_way_to_get_to_trail_entrance() @@ -76,8 +69,6 @@ def step(self): self.decide_way_to_get_to_trail_exit() elif self.state == '_decide_way_go_home': self.decide_way_go_home() - # elif self.state == 'rest': - # print('ID: ', self.unique_id, 'DONE\n\n\next_pos') if self.pos == self.init_position and self.count >= self.distance_goal: self.state = 'rest' @@ -85,7 +76,6 @@ def step(self): def continue_forward(self): '''MOVING FORWARD''' # Initially, start with no direction - # print('continue - type 1') if self.direction == None: # if start at a dead end, then runner memorize to mark road out of intersection @@ -122,13 +112,10 @@ def _check_to_change_state(self): # CHANGE STATE IF NECESSARY # facing trail, dead end if len(self._get_road_cell_around()) == 1: - # print('CHANGE STATE 1') self.state = '_dead_end' # at the corner of road elif len(self._get_road_cell_around()) == 2 and self._get_road_cell_forward() == False: - # print('CHANGE STATE 2') if self.count >= self.distance_goal and self.want_to_go_home == False: - # print('corner and want to go home') self.state = '_decide_way_go_home' self.want_to_go_home = True self.num_intersection_from_going_home_point += 1 @@ -136,18 +123,13 @@ def _check_to_change_state(self): self.state = '_corner_of_road' # at the intersection and have to turn elif len(self._get_road_cell_around()) > 2: - # print('CHANGE STATE 3') - - # print(self.intersection_memory) # STORE DEAD END ROAD if on the way getting out of it and at intersection if self.getting_out_of_deadend: self.road_to_dead_end.append(self._get_road_cell_behind()) self.getting_out_of_deadend = False - # print(self.road_to_dead_end) if self.count >= self.distance_goal: - # print('FIND WAY HOME') self.state = '_decide_way_go_home' self.want_to_go_home = True self.num_intersection_from_going_home_point += 1 @@ -159,37 +141,23 @@ def _check_to_change_state(self): # Continue forward for type 2 def continue_forward_type2(self): - # THIS PART IS USED FOR TYPE 2 - # At the entrance of trail, enter it if self.ready_to_enter_trail: next_position = self._get_trail_cell_around()[0] self.exit_trail_pos = next_position - # print('Exit trail position: ', self.exit_trail_pos) self.ready_to_enter_trail = False - # self.on_way_running = False self.start_the_trail_run = True - # self.get_to_the_first_intersection = True self.on_road = False self.on_trail = True # At the exit of trail, READY TO ENTERING ROAD AGAIN TO GO HOME elif self.ready_to_exit_trail: - # print('Get position') next_position = self._get_road_cell_around()[0] self.ready_to_exit_trail = False self.exit_the_trail_going_home = True self.on_road = True self.on_trail = False - # # Go forward after entering the trail - # elif self.ready_to_enter_trail == False and self.on_trail: - # next_position = self._get_trail_cell_forward() - - # # Go forward after exiting the trail - # elif self.ready_to_enter_trail == False and self.on_trail: - # next_position = self._get_trail_cell_forward() - # on road, start, haven't got to trail yet (NORMAL) elif self.on_road: next_position = self._get_road_cell_forward() @@ -202,17 +170,13 @@ def continue_forward_type2(self): if self.getting_out_of_deadend == True and self.pos == self.init_position: self.getting_out_of_deadend = False self.start_from_dead_end_road = True - # print('Set to False again') # at the entrance trail, about to start the trail running if self.pos == self.entrance_trail_pos and self.count < self.distance_goal: - # print('READY TO Enter') self.ready_to_enter_trail = True - # self.on_road = False # at the exit trail, about to get on the road and go home if self.pos == self.exit_trail_pos and self.count >= self.distance_goal: - # print('READY TO EXIT') self.ready_to_exit_trail = True self._check_to_change_state_type2() @@ -226,24 +190,19 @@ def _check_to_change_state_type2(self): self.state = '_continue_forward_type2' # just start going home from the entrance elif len(self._get_trail_cell_around()) == 1 and self.exit_the_trail_going_home: - # print('Change state to go forward') self.state = '_continue_forward_type2' self.exit_the_trail_going_home = False # facing dead end elif len(self._get_road_cell_around()) == 1: - # print('CHANGE STATE to dead end') self.state = '_dead_end' # still on road elif len(self._get_road_cell_around()) == 2 and self._get_road_cell_forward() != False: - # print('CHANGE STATE to CONTINUE FORWARD') self.state = '_continue_forward_type2' # at the corner of road elif len(self._get_road_cell_around()) == 2 and self._get_road_cell_forward() == False: - # print('CHANGE STATE to CORNER of road') self.state = '_corner_of_road' # at intersection on road elif len(self._get_road_cell_around()) > 2: - # print('KEEP') # on way home, at intersection, need the closest way to home if self.count >= self.distance_goal: @@ -258,7 +217,6 @@ def _check_to_change_state_type2(self): # store the dead end road if on the way getting out of it and at intersection if self.getting_out_of_deadend: - # print('RUN') if self._get_road_cell_behind() not in self.road_to_dead_end: self.road_to_dead_end.append( self._get_road_cell_behind()) @@ -274,20 +232,16 @@ def _check_to_change_state_type2(self): # just start running at the trail elif len(self._get_trail_cell_around()) == 1 and self.start_the_trail_run: - # print('Change state to go forward') self.state = '_continue_forward_type2' self.start_the_trail_run = False # facing dead end elif len(self._get_trail_cell_around()) == 1: - # print('Change state to dead end') self.state = '_dead_end' # still on trail elif len(self._get_trail_cell_around()) == 2 and self._get_trail_cell_forward() != False: - # print('Change state to continue forward') self.state = '_continue_forward_type2' # at the corner of trail elif len(self._get_trail_cell_around()) == 2 and self._get_trail_cell_forward() == False: - # print('Change state to corner of road') # Pass the distance goal if self.count >= self.distance_goal and self.num_intersection_from_going_home_point == 0: @@ -302,7 +256,6 @@ def _check_to_change_state_type2(self): # at intersection on trail elif len(self._get_trail_cell_around()) > 2: - # print('KEEP') # Pass the distance goal if self.count >= self.distance_goal: @@ -315,13 +268,9 @@ def _check_to_change_state_type2(self): else: # Normally self.state = '_intersection_on_trail' - # if self.get_to_the_first_intersection: - # self.trail_cell_behind_first_intersection = self._get_trail_cell_behind() - # self.get_to_the_first_intersection = False # store the dead end road if on the way getting out of it and at intersection if self.getting_out_of_deadend: - # print('RUN') if self._get_trail_cell_behind() not in self.road_to_dead_end: self.road_to_dead_end.append( self._get_trail_cell_behind()) @@ -339,8 +288,6 @@ def dead_end(self): elif self.type == 'type2' and self.on_trail: next_position = self._get_trail_cell_behind() - # print('TYPE2 ', self.pos, ' ', self.exit_trail_pos) - # let runner memorize this is dead end to store infor once getting to the intersection self.getting_out_of_deadend = True @@ -401,7 +348,6 @@ def decide_way_go_home(self): direction = self._check_direction_of_point( self.pos, self.init_position) road_cells = self._get_road_cell_around() - # print('ROAD CELLS: ', road_cells) prefer_roads = [] # set a prefer roads list to take consideration @@ -409,7 +355,6 @@ def decide_way_go_home(self): # choose a road randomly from the prefer road, if don't have prefer road, choose one of the other non-prefer roads # without considering roads leading to dead end and road just passed - # print(direction) # remove roads leading to dead_end but not home if len(self.road_to_dead_end) > 0: @@ -418,7 +363,6 @@ def decide_way_go_home(self): prefer_roads.remove(cell) if cell in road_cells: road_cells.remove(cell) - # print('ROAD TO DEAD END: ', self.road_to_dead_end) road_consider = road_cells.copy() @@ -430,8 +374,6 @@ def decide_way_go_home(self): if cell in road_consider: road_consider.remove(cell) - # print('PREFER ROAD: ', prefer_roads) - if len(prefer_roads) > 0: next_position = self.random.choice(prefer_roads) # print('CHOOSE: ', next_position) @@ -439,9 +381,6 @@ def decide_way_go_home(self): next_position = self.random.choice(road_consider) elif len(road_cells) > 0: next_position = self.random.choice(road_cells) - # else: - # next_position = self.random.choice(self._get_road_cell_around()) - # self._get_road_cell_around()) # place agent, set new direction, change state self._set_new_direction_place_agent(next_position) @@ -456,38 +395,17 @@ def decide_way_go_home(self): def intersection_on_trail(self): # CHOOSE PREFER TRAIL: STRAIGHT, RIGHT, LEFT, THEN CHOOSE ONE FIRST USE TO ENTER INTERS - if not self.on_way_home: # still running and experiencing the trail - if self._get_trail_cell_forward() and self._get_trail_cell_forward() not in self.intersection_memory[self.pos]: - next_position = self._get_trail_cell_forward() - elif self._get_trail_cell_right() and (self._get_trail_cell_right() not in self.intersection_memory[self.pos]): - next_position = self._get_trail_cell_right() - elif self._get_trail_cell_left() and (self._get_trail_cell_left() not in self.intersection_memory[self.pos]): - next_position = self._get_trail_cell_left() - # elif (self.intersection_memory[self.pos][0] not in self.road_to_dead_end) and (self.intersection_memory[self.pos][0] not in self.mark_road_to_home_dead_end): - # next_position = self.intersection_memory[self.pos][0] - else: - possible_steps = self._get_trail_cell_around() - possible_steps.remove(self._get_trail_cell_behind()) - - next_position = self.random.choice(possible_steps) - - # elif self.on_way_to_home: - # if self._get_trail_cell_forward() and self._get_trail_cell_forward() not in self.intersection_memory[self.pos]: - # next_position = self._get_trail_cell_forward() - # elif self._get_trail_cell_right() and (self._get_trail_cell_right() not in self.intersection_memory[self.pos]): - # next_position = self._get_trail_cell_right() - # elif self._get_trail_cell_left() and (self._get_trail_cell_left() not in self.intersection_memory[self.pos]): - # next_position = self._get_trail_cell_left() - # elif (self.intersection_memory[self.pos][0] not in self.road_to_dead_end) and (self.intersection_memory[self.pos][0] not in self.mark_road_to_home_dead_end): - # next_position = self.intersection_memory[self.pos][0] - # else: - # possible_steps = self._get_trail_cell_around() - - # if self._get_trail_cell_behind() != self.intersection_memory[self.pos][0]: - # possible_steps.remove(self._get_trail_cell_behind()) - # possible_steps.remove(self.intersection_memory[self.pos][0]) + if self._get_trail_cell_forward() and self._get_trail_cell_forward() not in self.intersection_memory[self.pos]: + next_position = self._get_trail_cell_forward() + elif self._get_trail_cell_right() and (self._get_trail_cell_right() not in self.intersection_memory[self.pos]): + next_position = self._get_trail_cell_right() + elif self._get_trail_cell_left() and (self._get_trail_cell_left() not in self.intersection_memory[self.pos]): + next_position = self._get_trail_cell_left() + else: + possible_steps = self._get_trail_cell_around() + possible_steps.remove(self._get_trail_cell_behind()) - # next_position = self.random.choice(possible_steps) + next_position = self.random.choice(possible_steps) # set new direction and move agent self._set_new_direction_place_agent(next_position) @@ -576,7 +494,6 @@ def decide_way_to_get_to_trail_entrance(self): # Start at entrance trail (rare case but possible) if self.pos == self.entrance_trail_pos: self.ready_to_enter_trail = True - # self.on_road = False # Otherwise, do normal else: @@ -595,10 +512,7 @@ def decide_way_to_get_to_trail_entrance(self): direction = self._check_direction_of_point( self.pos, self.target_point) road_cells = self._get_road_cell_around() - # print('ROAD CELLS: ', road_cells) prefer_roads = [] - # print('Select entrance: ', self.entrance_trail_pos) - # print(direction) # set a prefer roads list to take consideration self._set_prefer_roads(prefer_roads, direction, road_cells) @@ -610,7 +524,6 @@ def decide_way_to_get_to_trail_entrance(self): prefer_roads.remove(cell) if cell in road_cells: road_cells.remove(cell) - # print('ROAD TO DEAD END: ', self.road_to_dead_end) road_consider = road_cells.copy() @@ -621,13 +534,9 @@ def decide_way_to_get_to_trail_entrance(self): prefer_roads.remove(cell) if cell in road_consider: road_consider.remove(cell) - # print('AFTER REMOVE ROADS HAVE BEEN USED') - - # print('PREFER ROAD: ', prefer_roads) if len(prefer_roads) > 0: next_position = self.random.choice(prefer_roads) - # print('CHOOSE: ', next_position) elif len(road_consider) > 0: next_position = self.random.choice(road_consider) elif len(road_cells) > 0: @@ -639,7 +548,6 @@ def decide_way_to_get_to_trail_entrance(self): # get to entrance trail at step 2 (rare case but possible) if self.pos == self.entrance_trail_pos: self.ready_to_enter_trail = True - # self.on_road = False # check and update intersection memory that has been passed self._set_memory_over_intersection_one_step() @@ -657,10 +565,7 @@ def decide_way_to_get_to_trail_exit(self): direction = self._check_direction_of_point( self.pos, self.exit_trail_pos) trail_cells = self._get_trail_cell_around() - # print('TRAIL CELLS AROUND: ', trail_cells) prefer_trails = [] - # print('Trail exit: ', self.exit_trail_pos) - # print(direction) # set a prefer roads list to take consideration self._set_prefer_roads(prefer_trails, direction, trail_cells) @@ -672,7 +577,6 @@ def decide_way_to_get_to_trail_exit(self): prefer_trails.remove(cell) if cell in trail_cells: trail_cells.remove(cell) - # print('ROAD TO DEAD END: ', self.road_to_dead_end) trail_consider = trail_cells.copy() @@ -688,7 +592,6 @@ def decide_way_to_get_to_trail_exit(self): if len(prefer_trails) > 0: next_position = self.random.choice(prefer_trails) - # print('CHOOSE: ', next_position) # consider roads with that no dead end, no road used before elif len(trail_consider) > 0: next_position = self.random.choice(trail_consider) @@ -715,7 +618,6 @@ def _select_closest_trail(self): if min_distance == None or (estimate_distance < min_distance): min_distance = estimate_distance prefer_entrance = entrance_pos - # print(prefer_entrance) return prefer_entrance @@ -847,7 +749,6 @@ def _get_trail_cell_around(self): # List contains position of road cells that are from those 4 cells above possible_trails = [] for pos in cells_around: - # x, y = pos for cell_object in self.model.background_cells: if cell_object.pos == pos and cell_object.type == 'trail': possible_trails.append(pos) diff --git a/simple_virtual_world/runner_sample.py b/simple_virtual_world/runner_sample.py new file mode 100644 index 0000000..e9fc3d8 --- /dev/null +++ b/simple_virtual_world/runner_sample.py @@ -0,0 +1,332 @@ +from mesa import Agent, Model +from mesa.space import MultiGrid + + +class RunnerAgent(Agent): + ''' This class will represent runners in this model ''' + + def __init__(self, unique_id, model): + super().__init__(unique_id, model) + self.type = 'runner' + self.direction = None + self.count = 0 + self.distance_goal = 100 + self.want_to_go_home = True + # {(x,y):[(),(),(),..] + self.intersection_memory = {} + self.road_to_dead_end = [] + self.getting_out_of_deadend = False + self.state = '_continue_forward' + + def step(self): + + if self.state == '_continue_forward': + self.continue_forward() + elif self.state == '_intersection': + self.intersection() + elif self.state == '_corner_of_road': + self.corner_of_road() + elif self.state == '_dead_end': + self.dead_end() + elif self.state == '_decide_way_go_home': + self.decide_way_go_home() + + elif self.state == 'rest': + pass + + self.count += 1 + + if self.pos == self.init_position and self.count >= self.distance_goal: + self.state = 'rest' + print('FINISH') + + def continue_forward(self): + '''MOVING FORWARD''' + # Initially, start with no direction + if self.direction == None: + + # if start at a dead end, then runner memorize and set memory once get to intersection + if len(self._get_road_cell_around()) == 1: + self.getting_out_of_deadend = True + # if start at intersection, then create memory at that intersection + if len(self._get_road_cell_around()) > 2: + self.intersection_memory[self.pos] = [] + + next_position = self.random.choice(self._get_road_cell_around()) + + # check and update intersection memory just passed + if self.pos in self.intersection_memory: + self.intersection_memory[self.pos].append(next_position) + + self._set_new_direction_place_agent(next_position) + + # Already having a direction and have road ahead + elif self._get_road_cell_forward(): + next_position = self._get_road_cell_forward() + self._set_new_direction_place_agent(next_position) + + # CHANGE STATE IF NECESSARY + # facing trail, dead end + if len(self._get_road_cell_around()) == 1: + print('CHANGE STATE 1') + self.state = '_dead_end' + # at the corner of road + elif len(self._get_road_cell_around()) == 2 and self._get_road_cell_forward() == False: + print('CHANGE STATE 2') + self.state = '_corner_of_road' + # at the intersection and have to turn + elif len(self._get_road_cell_around()) > 2: + print('CHANGE STATE 3') + # key: intersection center cell - is not created yet + self._set_memory_at_intersection() + if self.count >= self.distance_goal: + print('FIND WAY HOME') + self.state = '_decide_way_go_home' + self.want_to_go_home = True + else: + self.state = '_intersection' + + def dead_end(self): + ''' make a U-turn since this type of runner avoids trail, also avoid dead end ''' + + next_position = self._get_road_cell_behind() + print('U TURN: ', next_position) + # let runner memorize this is dead end to store infor once getting to the intersection + self.getting_out_of_deadend = True + # set new direction and move agent + self._set_new_direction_place_agent(next_position) + # after making a U-turn, set state back to _continue_forward + self.state = '_continue_forward' + + def intersection(self): + ''' Prefer turn right, then left, if both roads have been gone, choose the one first used to enter this intersection to get out ''' + + # store the dead end road if on the way getting out of it + if self.getting_out_of_deadend: + self.road_to_dead_end.append(self._get_road_cell_behind()) + self.getting_out_of_deadend = False + + # CHOOSE PREFER ROAD: STRAIGHT, RIGHT, LEFT, THEN CHOOSE ONE FIRST USE TO ENTER INTERS. + if self._get_road_cell_forward() and self._get_road_cell_forward() not in self.intersection_memory[self.pos]: + next_position = self._get_road_cell_forward() + elif self._get_road_cell_right() and (self._get_road_cell_right() not in self.intersection_memory[self.pos]): + next_position = self._get_road_cell_right() + elif self._get_road_cell_left() and (self._get_road_cell_left() not in self.intersection_memory[self.pos]): + next_position = self._get_road_cell_left() + else: + next_position = self.intersection_memory[self.pos][0] + + # check and update intersection memory just passed + if next_position not in self.intersection_memory[self.pos]: + self.intersection_memory[self.pos].append(next_position) + + # set new direction and move agent + self._set_new_direction_place_agent(next_position) + # after making a turn, set state back to _continue_forward + self.state = '_continue_forward' + print(self.intersection_memory) + + def decide_way_go_home(self): + ''' Try to direct runner to home as close as possible ''' + # x, y = self.pos + + # Find prefer direction based on the 2 position (currrent and initial) + direction = self._check_direction_of_point( + self.pos, self.init_position) + road_cells = self._get_road_cell_around() + print('ROAD CELLS: ', road_cells) + prefer_roads = [] + + # append prefer road based on the direction toward init pos + if direction == 'up': + if self._get_cell('up') in road_cells: + prefer_roads.append(self._get_cell('up')) + elif direction == 'up_right': + if self._get_cell('up') in road_cells: + prefer_roads.append(self._get_cell('up')) + if self._get_cell('right') in road_cells: + prefer_roads.append(self._get_cell('right')) + elif direction == 'right': + if self._get_cell('right') in road_cells: + prefer_roads.append(self._get_cell('right')) + elif direction == 'down_right': + if self._get_cell('down') in road_cells: + prefer_roads.append(self._get_cell('down')) + if self._get_cell('right') in road_cells: + prefer_roads.append(self._get_cell('right')) + elif direction == 'down': + if self._get_cell('down') in road_cells: + prefer_roads.append(self._get_cell('down')) + elif direction == 'down_left': + if self._get_cell('down') in road_cells: + prefer_roads.append(self._get_cell('down')) + if self._get_cell('left') in road_cells: + prefer_roads.append(self._get_cell('left')) + elif direction == 'left': + if self._get_cell('left') in road_cells: + prefer_roads.append(self._get_cell('left')) + elif direction == 'up_left': + if self._get_cell('up') in road_cells: + prefer_roads.append(self._get_cell('up')) + if self._get_cell('left') in road_cells: + prefer_roads.append(self._get_cell('left')) + + # choose a road randomly from the prefer road, if don't have prefer road, choose one of the other non-prefer roads + # without considering roads leading to dead end + print(direction) + print('PREFER ROAD: ', prefer_roads) + + if len(self.road_to_dead_end) > 0: + for cell in self.road_to_dead_end: + if cell in prefer_roads: + prefer_roads.remove(cell) + if cell in road_cells: + road_cells.remove(cell) + + if len(prefer_roads) > 0: + next_position = self.random.choice(prefer_roads) + print('CHOOSE: ', next_position) + else: + next_position = self.random.choice(road_cells) + + # place agent, set new direction, change state + self._set_new_direction_place_agent(next_position) + self.state = '_continue_forward' + + def corner_of_road(self): + ''' Have to turn at the corner of road ''' + + possible_steps = self._get_road_cell_around() + possible_steps.remove(self._get_road_cell_behind()) + + next_position = possible_steps[0] + print(next_position) + # set new direction and move agent + self._set_new_direction_place_agent(next_position) + # after making a turn, set state back to _continue_forward + self.state = '_continue_forward' + + def _set_memory_at_intersection(self): + # create a key as the intersection center cell if it's created yet, then append road cell passed + if self.pos not in self.intersection_memory: + self.intersection_memory[self.pos] = [] + if self._get_road_cell_behind() not in self.intersection_memory[self.pos]: + self.intersection_memory[self.pos].append( + self._get_road_cell_behind()) + + def _set_new_direction_place_agent(self, next_pos): + # Unpack tuple position + x, y = self.pos + a, b = next_pos + # Set new direction + if a > x: + self.direction = 'right' + elif a < x: + self.direction = 'left' + elif b > y: + self.direction = 'up' + else: + self.direction = 'down' + # Place agent to new position + self.model.grid.move_agent(self, next_pos) + + def _get_road_cell_around(self): + # List contains position of 4 cells around (top, bottom, left, right) + cells_around = self.model.grid.get_neighborhood( + self.pos, moore=False, include_center=False) + # List contains position of road cells that are from those 4 cells above + possible_roads = [] + for pos in cells_around: + # x, y = pos + for cell_object in self.model.background_cells: + if cell_object.pos == pos and cell_object.type == 'road': + possible_roads.append(pos) + return possible_roads + + def _get_road_cell_behind(self): + if self.direction == 'right': + return (self.pos[0] - 1, self.pos[1]) + elif self.direction == 'left': + return (self.pos[0] + 1, self.pos[1]) + elif self.direction == 'up': + return (self.pos[0], self.pos[1] - 1) + elif self.direction == 'down': + return (self.pos[0], self.pos[1] + 1) + + def _get_road_cell_forward(self): + if self.direction == 'right' and self._check_cell_is_road((self.pos[0] + 1, self.pos[1])): + return (self.pos[0] + 1, self.pos[1]) + elif self.direction == 'left' and self._check_cell_is_road((self.pos[0] - 1, self.pos[1])): + return (self.pos[0] - 1, self.pos[1]) + elif self.direction == 'up' and self._check_cell_is_road((self.pos[0], self.pos[1] + 1)): + return (self.pos[0], self.pos[1] + 1) + elif self.direction == 'down' and self._check_cell_is_road((self.pos[0], self.pos[1] - 1)): + return (self.pos[0], self.pos[1] - 1) + else: + return False + + def _get_road_cell_right(self): + if self.direction == 'right' and self._check_cell_is_road((self.pos[0], self.pos[1] - 1)): + return (self.pos[0], self.pos[1] - 1) + elif self.direction == 'left' and self._check_cell_is_road((self.pos[0], self.pos[1] + 1)): + return (self.pos[0], self.pos[1] + 1) + elif self.direction == 'up' and self._check_cell_is_road((self.pos[0] + 1, self.pos[1])): + return (self.pos[0] + 1, self.pos[1]) + elif self.direction == 'down' and self._check_cell_is_road((self.pos[0] - 1, self.pos[1])): + return (self.pos[0] - 1, self.pos[1]) + else: + return False + + def _get_road_cell_left(self): + if self.direction == 'right' and self._check_cell_is_road((self.pos[0], self.pos[1] + 1)): + return (self.pos[0], self.pos[1] + 1) + elif self.direction == 'left' and self._check_cell_is_road((self.pos[0], self.pos[1] - 1)): + return (self.pos[0], self.pos[1] - 1) + elif self.direction == 'up' and self._check_cell_is_road((self.pos[0] - 1, self.pos[1])): + return (self.pos[0] - 1, self.pos[1]) + elif self.direction == 'down' and self._check_cell_is_road((self.pos[0] + 1, self.pos[1])): + return (self.pos[0] + 1, self.pos[1]) + else: + return False + + def _get_cell(self, type): + x, y = self.pos + if type == 'up': + return (x, y + 1) + elif type == 'down': + return (x, y - 1) + elif type == 'left': + return (x - 1, y) + elif type == 'right': + return (x + 1, y) + + def _check_cell_is_road(self, cell_position): + possible_roads = self._get_road_cell_around() + if cell_position in possible_roads: + return True + else: + return False + + def _check_direction_of_point(self, current_pos, init_position): + x, y = current_pos + a, b = init_position + + distance_x = a - x + distance_y = b - y + + if distance_y > 0 and distance_x == 0: + return 'up' + elif distance_y > 0 and distance_x > 0: + return 'up_right' + elif distance_y == 0 and distance_x > 0: + return 'right' + elif distance_y < 0 and distance_x > 0: + return 'down_right' + elif distance_y < 0 and distance_x == 0: + return 'down' + elif distance_y < 0 and distance_x < 0: + return 'down_left' + elif distance_y == 0 and distance_x < 0: + return 'left' + elif distance_y > 0 and distance_x < 0: + return 'up_left' diff --git a/simple_virtual_world/server.py b/simple_virtual_world/server.py index 642cce7..eb40e21 100644 --- a/simple_virtual_world/server.py +++ b/simple_virtual_world/server.py @@ -22,12 +22,7 @@ def cell(agent): elif agent.type == 'grass': portrayal['Color'] = '#4ECA24' - -<< << << < Updated upstream - elif agent.type == 'runner': -== == == = elif agent.type == 'type1': ->>>>>> > Stashed changes portrayal['Shape'] = 'circle' portrayal['r'] = '0.7' portrayal['Layer'] = 1 @@ -43,14 +38,8 @@ def cell(agent): grid = CanvasGrid(cell, 50, 50, 600, 600) -# chart = ChartModule([{'Label': 'Num_mov_agents', 'Color': 'Black'}]) - -<<<<<<< Updated upstream -server = ModularServer(VirtualWorldModel, [grid], "Virtual World", {'N': 1, -======= -server = ModularServer(VirtualWorldModel, [grid], "Virtual World", {'N': 10, ->>>>>>> Stashed changes - 'width': 50, 'height': 50}) +server = ModularServer(VirtualWorldModel, [grid], "Virtual World", { + 'N': 50, 'width': 50, 'height': 50}) server.port = 8000 server.launch() diff --git a/simple_virtual_world/virtual_world.py b/simple_virtual_world/virtual_world.py index 15ccada..17a41fd 100644 --- a/simple_virtual_world/virtual_world.py +++ b/simple_virtual_world/virtual_world.py @@ -1,287 +1,10 @@ from mesa import Agent, Model from mesa.space import MultiGrid from mesa.time import RandomActivation - - -class RunnerAgent(Agent): - ''' This class will represent runners in this model ''' - - def __init__(self, unique_id, model): - super().__init__(unique_id, model) - self.type = 'runner' - self.direction = None - self.count = 0 - # {(x,y):[(),(),(),..] - self.intersection_memory = {} - self.state = 'run' - - def step(self): - - if self.state == 'run': - self.go_forward() - - def go_forward(self): - # List contains position of 4 cells around (top, bottom, left, right) - cells_around = self.model.grid.get_neighborhood( - self.pos, moore=False, include_center=False) - # List contains position of road cells that are from those 4 cells above - possible_steps = [] - for pos in cells_around: - # x, y = pos - for cell_object in self.model.background_cells: - if cell_object.pos == pos and cell_object.type == 'road': - possible_steps.append(pos) - - # Runner has to choose a direction at first - if self.direction == None: - next_position = self.random.choice(possible_steps) - - # Runner already had a direction - else: - x, y = self.pos # unpack current position - - # In the right (east) direction - if self.direction == 'right': - - # continue forward if having road and that road haven't been gone through - if (((x + 1, y) in possible_steps) and (self.pos not in self.intersection_memory)) or (((x + 1, y) in possible_steps) and (self.pos in self.intersection_memory) and ((x + 1, y) not in self.intersection_memory[self.pos])): - next_position = (x + 1, y) - # At the intersection, or over the center 1 cell, store a center cell, and the cells around that have been gone through - if len(possible_steps) > 2: - # create key-value inside - if self.pos not in self.intersection_memory: - # key: center cell's position, value: list of around road cells position that have been gone through - self.intersection_memory[self.pos] = [] - - self.intersection_memory[self.pos].append((x - 1, y)) - - # Append the current pos once passed the intersection - elif (self.pos[0] - 1, self.pos[1]) in self.intersection_memory: - self.intersection_memory[( - self.pos[0] - 1, self.pos[1])].append(self.pos) - - # either one-way road or at the intersection that runner must turn - else: - # facing trail or dead end --> make a U-turn - if len(possible_steps) == 1: - next_position = (x - 1, y) - # at the corner and have to turn either left or right - elif len(possible_steps) == 2: - # remove the behind step and assign the turning road - possible_steps.remove((x - 1, y)) - next_position = possible_steps[0] - # at intersection and have to turn and also avoid repeated route - else: - # Create key memory for that intersection if not yet created - if self.pos not in self.intersection_memory: - self.intersection_memory[self.pos] = [] - # Prefer turn right first - if ((x, y - 1) in possible_steps) and ((x, y - 1) not in self.intersection_memory[self.pos]): - next_position = (x, y - 1) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x - 1, y)) - # Turn left instead if already turned right - elif ((x, y + 1) in possible_steps) and (x, y + 1) not in self.intersection_memory[self.pos]: - next_position = (x, y + 1) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x - 1, y)) - # Choose the first route that the runner used to enter this intersection to get out of this loop - else: - num_routes = len( - self.intersection_memory[self.pos]) - for i in range(num_routes - 1): - self.intersection_memory[self.pos].pop() - # set position by the remained position (first route) - next_position = self.intersection_memory[self.pos][0] - - # In the left (west) direction - elif self.direction == 'left': - - # continue forward if having road and that road haven't been gone through - if (((x - 1, y) in possible_steps) and (self.pos not in self.intersection_memory)) or (((x - 1, y) in possible_steps) and (self.pos in self.intersection_memory) and ((x - 1, y) not in self.intersection_memory[self.pos])): - next_position = (x - 1, y) - # At the intersection, or over the center 1 cell, store a center cell, and the cells around that have been gone through - if len(possible_steps) > 2: - # create key-value inside - if self.pos not in self.intersection_memory: - # key: center cell's position, value: list of around road cells position that have been gone through - self.intersection_memory[self.pos] = [] - - self.intersection_memory[self.pos].append((x + 1, y)) - - # Append the current pos once passed the intersection - elif (self.pos[0] + 1, self.pos[1]) in self.intersection_memory: - self.intersection_memory[( - self.pos[0] + 1, self.pos[1])].append(self.pos) - - # either one-way road or at the intersection that runner must turn - else: - # facing trail or dead end --> make a U-turn - if len(possible_steps) == 1: - next_position = (x + 1, y) - # at the corner and have to turn either left or right - elif len(possible_steps) == 2: - # remove the behind step and assign the turning road - possible_steps.remove((x + 1, y)) - next_position = possible_steps[0] - # at intersection and have to turn and also avoid repeated route - else: - # create key memory for that intersection if not yet created - if self.pos not in self.intersection_memory: - self.intersection_memory[self.pos] = [] - # Prefer turn right first - if ((x, y + 1) in possible_steps) and ((x, y + 1) not in self.intersection_memory[self.pos]): - next_position = (x, y + 1) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x + 1, y)) - # Turn left instead if already turned right - elif ((x, y - 1) in possible_steps) and (x, y - 1) not in self.intersection_memory[self.pos]: - next_position = (x, y - 1) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x + 1, y)) - # choose the first route that the runner used to enter this intersection to get out of this loop - else: - num_routes = len( - self.intersection_memory[self.pos]) - for i in range(num_routes - 1): - self.intersection_memory[self.pos].pop() - # set position by the remained position (first route) - next_position = self.intersection_memory[self.pos][0] - - # In the up (north) direction - elif self.direction == 'up': - # continue forward if having road and that road haven't been gone through - if (((x, y + 1) in possible_steps) and (self.pos not in self.intersection_memory)) or (((x, y + 1) in possible_steps) and (self.pos in self.intersection_memory) and ((x, y + 1) not in self.intersection_memory[self.pos])): - next_position = (x, y + 1) - # At the intersection, or over the center 1 cell, store a center cell, and the cells around that have been gone through - if len(possible_steps) > 2: - # create key-value inside - if self.pos not in self.intersection_memory: - # key: center cell's position, value: list of around road cells position that have been gone through - self.intersection_memory[self.pos] = [] - - self.intersection_memory[self.pos].append((x, y - 1)) - - # Append the current pos once passed the intersection - elif (self.pos[0], self.pos[1] - 1) in self.intersection_memory: - self.intersection_memory[( - self.pos[0], self.pos[1] - 1)].append(self.pos) - - # either one-way road or at the intersection that runner must turn - else: - # facing trail or dead end --> make a U-turn - if len(possible_steps) == 1: - next_position = (x, y - 1) - # at the corner and have to turn either left or right - elif len(possible_steps) == 2: - # remove the behind step and assign the turning road - possible_steps.remove((x, y - 1)) - next_position = possible_steps[0] - # at intersection and have to turn and also avoid repeated route - else: - # create key memory for that intersection if not yet created - if self.pos not in self.intersection_memory: - self.intersection_memory[self.pos] = [] - # Prefer turn right first - if ((x + 1, y) in possible_steps) and ((x + 1, y) not in self.intersection_memory[self.pos]): - next_position = (x + 1, y) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x, y - 1)) - # Turn left instead if already turned right - elif ((x - 1, y) in possible_steps) and (x - 1, y) not in self.intersection_memory[self.pos]: - next_position = (x - 1, y) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x, y - 1)) - else: # choose the first route that the runner used to enter this intersection to get out of this loop - num_routes = len( - self.intersection_memory[self.pos]) - for i in range(num_routes - 1): - self.intersection_memory[self.pos].pop() - # set position by the remained position (first route) - next_position = self.intersection_memory[self.pos][0] - - # In the down (south) direction - elif self.direction == 'down': - # continue forward if having road and that road haven't been gone through - if (((x, y - 1) in possible_steps) and (self.pos not in self.intersection_memory)) or (((x, y - 1) in possible_steps) and (self.pos in self.intersection_memory) and ((x, y - 1) not in self.intersection_memory[self.pos])): - next_position = (x, y - 1) - # At the intersection, or over the center 1 cell, store a center cell, and the cells around that have been gone through - if len(possible_steps) > 2: - # create key-value inside - if self.pos not in self.intersection_memory: - # key: center cell's position, value: list of around road cells position that have been gone through - self.intersection_memory[self.pos] = [] - - self.intersection_memory[self.pos].append((x, y + 1)) - - # Append the current pos once passed the intersection - elif (self.pos[0], self.pos[1] + 1) in self.intersection_memory: - self.intersection_memory[( - self.pos[0], self.pos[1] + 1)].append(self.pos) - - # either one-way road or at the intersection that runner must turn - else: - # facing trail or dead end --> make a U-turn - if len(possible_steps) == 1: - next_position = (x, y + 1) - # at the corner and have to turn either left or right - elif len(possible_steps) == 2: - # remove the behind step and assign the turning road - possible_steps.remove((x, y + 1)) - next_position = possible_steps[0] - # at intersection and have to turn and also avoid repeated route - else: - # create key memory for that intersection if not yet created - if self.pos not in self.intersection_memory: - self.intersection_memory[self.pos] = [] - # Prefer turn right first - if ((x - 1, y) in possible_steps) and ((x - 1, y) not in self.intersection_memory[self.pos]): - next_position = (x - 1, y) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x, y + 1)) - # Turn left instead if already turned right - elif ((x + 1, y) in possible_steps) and (x + 1, y) not in self.intersection_memory[self.pos]: - next_position = (x + 1, y) - # append the cell behind which just passed through before entering this center - self.intersection_memory[self.pos].append( - (x, y + 1)) - # choose the first route that the runner used to enter this intersection to get out of this loop - else: - num_routes = len( - self.intersection_memory[self.pos]) - for i in range(num_routes - 1): - self.intersection_memory[self.pos].pop() - # set position by the remained position (first route) - next_position = self.intersection_memory[self.pos][0] - - # Update direction for every step - self.direction = self.set_direction(self.pos, next_position) - self.model.grid.move_agent(self, next_position) - self.count += 1 - if self.pos == self.init_position: - print('NUMBER OF STEP TO COMPLETE THIS LOOP RUN: ', self.count) - - # print(self.intersection_memory) - - def set_direction(self, current_pos, next_pos): - # Unpack tuple position - x, y = current_pos - a, b = next_pos - if a > x: - return 'right' - elif a < x: - return 'left' - elif b > y: - return 'up' - else: - return 'down' +from runner import RunnerAgent +import numpy as np +from matplotlib import pyplot as plt +import seaborn as sns class CellAgent(Agent): @@ -299,22 +22,13 @@ class VirtualWorldModel(Model): def __init__(self, N, width, height): self.width = width self.height = height + self.num_agents = N self.schedule = RandomActivation(self) + self.heatmap_data = np.zeros((self.height, self.width)) self.grid = MultiGrid(self.width, self.height, True) - # Create a list of lists to store attribute of each cell (house, trail, road,...) - # Further, this will be also used for agents/people's initial position and to direct in this map - # self.cell_attribute = [] self.background_cells = [] - # for x in range(self.width): - # # a number of list corresponding with a number of x cells (column) - # self.cell_attribute.append(list()) - # for inside_list in self.cell_attribute: - # for y in range(self.height): - # # a number of list corresponding with a number of y cells (row) for each column - # inside_list.append(list()) - # Create agent for cell and set its attribute count = 0 # for unique_id for x in range(self.width): @@ -328,8 +42,7 @@ def __init__(self, N, width, height): # Set attribute for each cell self.set_attribute_cell(cell_object, x, y) - # Set corresponding position in the attribute list to this type - # self.cell_attribute[x][y] = cell_object.type + # Append to the list containing all background cells self.background_cells.append(cell_object) count += 1 @@ -338,55 +51,54 @@ def __init__(self, N, width, height): self.roads = [ cell.pos for cell in self.background_cells if cell.type == 'road'] # Create runner agents - for i in range(N): + self.agent_objects = [] + for i in range(self.num_agents): runner = RunnerAgent(i, self) # store the inital position as attribte runner.init_position = self.random.choice(self.roads) - -<< << << < Updated upstream print('Initial position: ', runner.init_position) -== == == = - # runner.init_position = (46, 21) - # print('Initial position: ', runner.init_position) ->>>>>> > Stashed changes + self.grid.place_agent(runner, runner.init_position) self.schedule.add(runner) + self.agent_objects.append(runner) + + # update heatmap data + x, y = runner.init_position + self.heatmap_data[self.height - 1 - y][x] += 1 # Attribute running for visualization self.running = True + # Trail entrance point + self.trail_entrance_point = [(3, 32), (30, 40)] + + self.num_agents_complete_running = 0 + def step(self): ''' Activate the step for all runner agents at once ''' self.schedule.step() -<<<<<<< Updated upstream -======= # stop once all agents finish running for agent in self.agent_objects: if agent.state == 'rest': self.num_agents_complete_running += 1 if self.num_agents_complete_running == self.num_agents: self.running = False - print('ALL AGENTS COMPLETED THEIR RUNNING') + print('ALL AGENTS COMPLETED THEIR RUNS') # HEAT MAP - fig, ax = plt.subplots() sns.set_theme() - xlabels = [i for i in range(self.width)] - ax = sns.heatmap(self.heatmap_data, xticklabels=10, yticklabels=10) plt.tight_layout() plt.show() - else: self.num_agents_complete_running = 0 ->>>>>>> Stashed changes def set_attribute_cell(self, cell_object, x, y): # Attribute 'HOUSE' for cells if y >= 5 and y <= 7 and x >= 35 and x <= 37: @@ -485,17 +197,3 @@ def set_attribute_cell(self, cell_object, x, y): # GRASS else: cell_object.type = 'grass' - - # Find all road cells and return a list of multiple tuple positions of roads - def find_road_cells(self, list_cells, width, height): - position_roads = [] - for x in range(width): - for y in range(height): - if list_cells[x][y] == 'road': - position_roads.append((x, y)) - return position_roads - - -# world = VirtualWorldModel(51, 51) -# # # # # print(len(world.cell_attribute[49])) -# print(world.cell_attribute)