def __init__(self, settings): """Initiallize game simulator with settings""" self.settings = settings self.size = self.settings["world_size"] # make 4 walls self.walls = [ LineSegment2(Point2(0, 0), Point2(0, self.size[1])), LineSegment2(Point2(0, self.size[1]), Point2(self.size[0], self.size[1])), LineSegment2(Point2(self.size[0], self.size[1]), Point2(self.size[0], 0)), LineSegment2(Point2(self.size[0], 0), Point2(0, 0)) ] # make hero object self.hero = GameObject(Point2(*self.settings["hero_initial_position"]), Vector2(*self.settings["hero_initial_speed"]), "hero", self.settings) if not self.settings["hero_bounces_off_walls"]: self.hero.bounciness = 0.0 # now hero has no bounciness self.objects = [] # spawn 25 friends, 25 enemy for obj_type, number in settings["num_objects"].items(): # 2 times run for _ in range(number): self.spawn_object(obj_type) # generate 32 number of antennas self.observation_lines = self.generate_observation_lines() self.object_reward = 0 self.collected_rewards = [] # every observation_line sees one of objects or wall and # two numbers representing speed of the object (if applicable) self.eye_observation_size = len( self.settings["objects"] ) + 3 # 2+3 --> maybe [friend, enemy, wall, speed X, Y] # additionally there are two numbers representing agents own speed. self.observation_size = self.eye_observation_size * len( self.observation_lines ) + 2 # (5 * 32) + 2 ==> 2 is hero's own speed self.directions = [ Vector2(*d) for d in [[1, 0], [0, 1], [-1, 0], [0, -1]] ] # there are 4 directions. up down left right self.num_actions = len(self.directions) # so num_actions is 4 self.objects_eaten = defaultdict(lambda: 0)
def __init__(self, settings, gpsFile): """Initiallize game simulator with settings""" self.settings = settings self.GPS = gpsFile self.timeStep = 0 self.previousOffset = 0 self.deltaT = 0 self.size = self.settings["world_size"] self.walls = [ LineSegment2(Point2(0, 0), Point2(0, self.size[1])), LineSegment2(Point2(0, self.size[1]), Point2(self.size[0], self.size[1])), LineSegment2(Point2(self.size[0], self.size[1]), Point2(self.size[0], 0)), LineSegment2(Point2(self.size[0], 0), Point2(0, 0)) ] self.hero = GameObject(Point2(*self.settings["hero_initial_position"]), Vector2(*self.settings["hero_initial_speed"]), "hero", self.settings, 0) if not self.settings["hero_bounces_off_walls"]: self.hero.bounciness = 0.0 self.objects = [] count = 0 for obj_type, number in settings["num_objects"].items(): count = count + 2 for _ in range(number): self.spawn_object(obj_type, count) self.observation_lines = self.generate_observation_lines() self.object_reward = 0 self.collected_rewards = [] # every observation_line sees one of objects or wall and # two numbers representing speed of the object (if applicable) self.eye_observation_size = len(self.settings["objects"]) + 3 # additionally there are two numbers representing agents own speed and position. self.observation_size = self.eye_observation_size * len( self.observation_lines) + 2 + 2 self.directions = [ Vector2(*d) for d in [[1, 0], [0, 1], [-1, 0], [0, -1], [0.0, 0.0]] ] self.num_actions = len(self.directions) self.objects_eaten = defaultdict(lambda: 0)
def __init__(self, settings): """Initialize game simulator with settings""" self.settings = settings self.size = self.settings["world_size"] self.walls = [LineSegment2(Point2(0,0), Point2(0,self.size[1])), LineSegment2(Point2(0,self.size[1]), Point2(self.size[0], self.size[1])), LineSegment2(Point2(self.size[0], self.size[1]), Point2(self.size[0], 0)), LineSegment2(Point2(self.size[0], 0), Point2(0,0))] self.hero = GameObject(Point2(*self.settings["hero_initial_position"]), Vector2(*self.settings["hero_initial_speed"]), "hero", self.settings["hero_radius"], self.settings) # Hero direction is a number between 0 and num_observation_lines_total - 1 (0 is directly right) self.hero_direction = self.settings["hero_initial_direction"] self.unit_vectors = [] for angle in np.linspace(0, 2*np.pi, self.settings["num_observation_lines_total"], endpoint=False): u_vector = Point2(math.cos(angle), math.sin(angle)) self.unit_vectors.append(u_vector) self.objects = [] for obj_type, number in settings["num_objects"].items(): for _ in range(number): self.spawn_object(obj_type) self.observation_lines = self.generate_observation_lines() self.object_reward = 0 self.collected_rewards = [] self.just_shot = False self.just_got_hit = False # every observation_line sees one of objects and # two numbers representing speed of the object (if applicable) self.eye_observation_size = len(self.settings["objects"]) + 2 # additionally there are two numbers representing agents own speed. self.observation_size = self.eye_observation_size * len(self.observation_lines) + 2 # self.directions = [Vector2(*d) for d in [[1,0], [0,1], [-1,0],[0,-1]]] self.num_actions = 4 # Accelerate, turn clockwise, turn anticlockwise, shoot self.objects_eaten = defaultdict(lambda: 0) self.objects_shot = defaultdict(lambda: 0)
def generate_observation_lines(self): """Generate observation segments in settings["num_observation_lines"] directions""" result = [] for i in range(self.hero_direction - (self.settings["num_observation_lines"] / 2), self.hero_direction + (self.settings["num_observation_lines"] / 2) + 1): if i < 0: j = 40 + i elif i >= 40: j = i - 40 else: j = i result.append( LineSegment2(Point2(0.0, 0.0), self.unit_vectors[j] * self.settings["observation_line_length"]) ) return result
def generate_observation_lines(self): """Generate observation segments in settings["num_observation_lines"] directions""" result = [] start = Point2(0.0, 0.0) end = Point2(self.settings["observation_line_length"], self.settings["observation_line_length"]) for angle in np.linspace(0, 2*np.pi, self.settings["num_observation_lines"], endpoint=False): rotation = Point2(math.cos(angle), math.sin(angle)) current_start = Point2(start[0] * rotation[0], start[1] * rotation[1]) current_end = Point2(end[0] * rotation[0], end[1] * rotation[1]) result.append( LineSegment2(current_start, current_end)) return result
def update_observation_lines(self): observable_distance = self.settings["observable_distance"] relevant_objects = [ obj for obj in self.objects if obj.position.distance(self.hero.position) < observable_distance and obj is not self.hero ] # objects sorted from closest to furthest relevant_objects.sort( key=lambda x: x.position.distance(self.hero.position)) for observation_line in self.observation_lines: # shift to hero position l = LineSegment2( self.hero.position + Vector2(*observation_line.p1), self.hero.position + Vector2(*observation_line.p2)) start_l, end_l = l.p1, l.p2 observed_object = None # if end of observation line is outside of walls, we see the wall. if end_l.x < 0.0 or end_l.x > 1.0 or end_l.y < 0.0 or end_l.y > 1.0: observed_object = "wall" for obj in relevant_objects: if l.distance(obj.position) < obj.radius: observed_object = obj break intersection = end_l if observed_object == "wall": # wall seen # best candidate is intersection between # l and a wall, that's # closest to the hero for wall in self.walls: candidate = l.intersect(wall) if candidate is not None: if (intersection is None or intersection.distance(self.hero.position) > candidate.distance(self.hero.position)): intersection = candidate elif observed_object is not None: # agent seen intersection_segment = obj.as_circle().intersect(l) if intersection_segment is not None: if (intersection_segment.p1.distance(self.hero.position) < intersection_segment.p2.distance( self.hero.position)): intersection = intersection_segment.pl else: intersection = intersection_segment.p2 self.line_end_where[observation_line] = intersection self.line_end_who[observation_line] = observed_object
def _is_hit(self, ray, theta, tank): radius = self._calculate_scan_radius(theta) center_line = LineSegment2(ray.p, ray.v, radius) center_vector = ray.v target_line = LineSegment2(ray.p, tank.position) tank_circle = Circle(tank.position, float(tank.radius)) bounds = theta / 2. if theta == 0.: left = right = center_line else: left = LineSegment2(ray.p, center_vector.rotate(bounds), radius) right = LineSegment2(ray.p, center_vector.rotate(-bounds), radius) LOG.debug( "Checking if %r is inside sector between %r and %r with radius %r", tank.position, left, right, radius) if self._debug: from ibidem.codetanks.server.debug_util import ScanPlot ScanPlot(self.arena.width, self.arena.height, left, right, center_line, radius, tank).plot() if target_line.length > radius: LOG.debug( "Outside because %r is %r from center, which is more than radius %r", tank.position, target_line.length, radius) return False for side in left, right: intersect = side.intersect(tank_circle) if intersect: LOG.debug( "Inside because tank intersects side vector (%r) at %r", side, intersect) return True if target_line.v.angle(center_line.v) > bounds: LOG.debug( "Outside because %r is further from the center line than %r", target_line.v, bounds) return False LOG.debug("Inside sector") return True
def __init__(self, points): self.points = np.array(points) self.line_segments = np.array([ LineSegment2(points[i], points[(i + 1) % len(points)]) for i in range(len(points)) ]) for seg_a in self.line_segments: for seg_b in self.line_segments: if seg_a is not seg_b: intersect_point = seg_a.intersect(seg_b) if intersect_point and intersect_point not in (seg_a.p1, seg_a.p2): raise IntersectingPolygonError( "{0} intersects {1}".format(seg_a, seg_b))
def __init__(self, settings): super(HeroSimulator, self).__init__(settings) self.walls = [ LineSegment2(Point2(0, 0), Point2(0, 1.0)), LineSegment2(Point2(0, 1.0), Point2(1.0, 1.0)), LineSegment2(Point2(1.0, 1.0), Point2(1.0, 0)), LineSegment2(Point2(1.0, 0), Point2(0, 0)) ] self.observation_lines = self.generate_observation_lines() self.line_end_where = {l: l.p2 for l in self.observation_lines} self.line_end_who = {l: None for l in self.observation_lines} self.hero = GameObject(Point2(0.5, 0.5), Vector2(0.0, 0.0), "hero", radius=self.settings['obj_radius']) self.add(self.hero) self.update_observation_lines() self.observation_size = self.settings["num_observation_lines"] * ( len(self.settings["observable_objects"]) + 4)
def perform_action(self, action_id): """Change speed or direction of hero""" assert 0 <= action_id < self.num_actions if action_id == 0: # Accelerate in direction hero is facing self.just_shot = False self.hero.speed *= self.settings["hero_momentum"] self.hero.speed += self.unit_vectors[self.hero_direction] * self.settings["delta_v"] if action_id == 1: # Turn clockwise self.just_shot = False self.hero_direction += 1 if self.hero_direction > 39: self.hero_direction = 0 self.observation_lines = self.generate_observation_lines() if action_id == 2: # Turn anticlockwise self.just_shot = False self.hero_direction -= 1 if self.hero_direction < 0: self.hero_direction = 39 self.observation_lines = self.generate_observation_lines() if action_id == 3: # Shoot laser self.just_shot = True shooting_distance = self.settings["laser_line_length"] relevant_objects = [obj for obj in self.objects if obj.position.distance(self.hero.position) < shooting_distance] shooting_line = LineSegment2(self.hero.position, self.hero.position + (self.unit_vectors[self.hero_direction] * shooting_distance)) # Sort relevant objects from closest to hero to farthest relevant_objects.sort(key=lambda x: x.position.distance(self.hero.position)) for obj in relevant_objects: if shooting_line.distance(obj.position) < obj.radius: self.objects_shot[obj.obj_type] += 1 if obj.obj_type == 'asteroids': # Split up large asteroids and spawn gems if (obj.radius / 2) > self.settings["min_asteroid_radius"]: self.spawn_cluster(2, 2, obj.radius, obj.position, obj.speed) self.objects.remove(obj) respawnable = ['asteroids'] if (obj.obj_type in respawnable and len([thing for thing in self.objects if thing.obj_type == obj.obj_type]) < self.settings["num_objects"][obj.obj_type]): self.spawn_object(obj.obj_type) break
def observe(self): """Return observation vector. For all the observation directions it returns representation of the closest object to the hero - might be nothing or an object. Representation of observation for all the directions will be concatenated. """ num_obj_types = len(self.settings["objects"]) max_speed_x, max_speed_y = self.settings["maximum_speed"] max_speed = ((max_speed_x ** 2) + (max_speed_y ** 2)) ** 0.5 observable_distance = self.settings["observation_line_length"] relevant_objects = [obj for obj in self.objects if obj.position.distance(self.hero.position) < observable_distance] # objects sorted from closest to furthest relevant_objects.sort(key=lambda x: x.position.distance(self.hero.position)) observation = np.zeros(self.observation_size) observation_offset = 0 for i, observation_line in enumerate(self.observation_lines): # shift to hero position observation_line = LineSegment2(self.hero.position + Vector2(*observation_line.p1), self.hero.position + Vector2(*observation_line.p2)) # Unit vector for observation line: line_direction = self.hero_direction - (self.settings["num_observation_lines"] / 2) + i if line_direction < 0: line_direction += self.settings["num_observation_lines_total"] elif line_direction >= self.settings["num_observation_lines_total"]: line_direction -= self.settings["num_observation_lines_total"] line_vector = self.unit_vectors[line_direction] # Get unit vector perpendicular to observation line: p_line_direction = line_direction + (self.settings["num_observation_lines_total"] / 4) if p_line_direction < 0: p_line_direction += self.settings["num_observation_lines_total"] elif p_line_direction >= self.settings["num_observation_lines_total"]: p_line_direction -= self.settings["num_observation_lines_total"] p_line_vector = self.unit_vectors[p_line_direction] observed_object = None for obj in relevant_objects: if observation_line.distance(obj.position) < obj.radius: observed_object = obj break object_type_id = None speed_x, speed_y = 0, 0 rel_speed_along_line = 0.0 rel_speed_across_line = 0.0 proximity = 0 if observed_object is not None: # object seen object_type_id = self.settings["objects"].index(observed_object.obj_type) speed_x, speed_y = tuple(observed_object.speed) rel_speed_along_line = line_vector.dot(Vector2(speed_x - self.hero.speed[0], speed_y - self.hero.speed[1])) rel_speed_across_line = p_line_vector.dot(Vector2(speed_x - self.hero.speed[0], speed_y - self.hero.speed[1])) intersection_segment = obj.as_circle().intersect(observation_line) assert intersection_segment is not None try: proximity = min(intersection_segment.p1.distance(self.hero.position), intersection_segment.p2.distance(self.hero.position)) except AttributeError: proximity = observable_distance for object_type_idx_loop in range(num_obj_types): observation[observation_offset + object_type_idx_loop] = 1.0 if object_type_id is not None: observation[observation_offset + object_type_id] = proximity / observable_distance # rel_speed_across_line = ((speed_x ** 2) + (speed_y ** 2) - (rel_speed_along_line ** 2)) ** 0.5 observation[observation_offset + num_obj_types] = rel_speed_along_line / max_speed observation[observation_offset + num_obj_types + 1] = rel_speed_across_line / max_speed assert num_obj_types + 2 == self.eye_observation_size, "{} and {}".format(num_obj_types, self.eye_observation_size) observation_offset += self.eye_observation_size # Realign hero speed to be relative to the direction it is facing: facing_uv = self.unit_vectors[self.hero_direction] sideways_dir = self.hero_direction + (self.settings["num_observation_lines_total"] / 4) if sideways_dir >= self.settings["num_observation_lines_total"]: sideways_dir -= self.settings["num_observation_lines_total"] sideways_uv = self.unit_vectors[sideways_dir] forward_v = facing_uv.dot(self.hero.speed) sideways_v = sideways_uv.dot(self.hero.speed) # sideways_v = ((self.hero.speed[0] ** 2) + (self.hero.speed[1] ** 2) - (forward_v ** 2)) ** 0.5 observation[observation_offset] = forward_v / max_speed observation[observation_offset + 1] = sideways_v / max_speed assert observation_offset + 2 == self.observation_size return observation
def observe(self): """Return observation vector. For all the observation directions it returns representation of the closest object to the hero - might be nothing, another object or a wall. Representation of observation for all the directions will be concatenated. """ num_obj_types = len( self.settings["objects"]) + 1 # 3 == (friend, enemy and wall) max_speed_x, max_speed_y = self.settings["maximum_speed"] observable_distance = self.settings[ "observation_line_length"] # length of antenna == 120 relevant_objects = [ obj for obj in self.objects if obj.position.distance(self.hero.position) < observable_distance ] # recall the objects near from hero with given that length # objects sorted from closest to furthest relevant_objects.sort( key=lambda x: x.position.distance(self.hero.position)) observation = np.zeros( self.observation_size ) # 32*5 (objects * features) + 2 ( hero's speed) observation_offset = 0 for i, observation_line in enumerate( self.observation_lines): # for 32 lines # shift the antenna's center to hero position observation_line = LineSegment2( self.hero.position + Vector2(*observation_line.p1), self.hero.position + Vector2(*observation_line.p2)) observed_object = None # if end of observation line is outside of walls, we see the wall. if not self.inside_walls( observation_line.p2): # p1 is start, p2 is end of the line observed_object = "**wall**" # defaulyt see the wall, for obj in relevant_objects: # for near objects from hero, sorted from nearst to furtherst if observation_line.distance(obj.position) < self.settings[ "object_radius"]: # the distance between line and point < radius # this means, the line touch that object observed_object = obj # so that is observed_object break # this mean, one line can see only one object object_type_id = None speed_x, speed_y = 0, 0 proximity = 0 # closetness if observed_object == "**wall**": # wall is seen object_type_id = num_obj_types - 1 # object type id of all == 2 # a wall has fairly low speed... speed_x, speed_y = 0, 0 # best candidate is intersection between observation_line and a wall, that's closest to the hero best_candidate = None for wall in self.walls: # for all wall about each lines (32 * 4 times) candidate = observation_line.intersect( wall) # LineSegment2 has intersect function # so this calculate the intersected point with wall if candidate is not None: if (best_candidate is None or best_candidate.distance(self.hero.position) > candidate.distance(self.hero.position)): best_candidate = candidate # change the best candidate if best_candidate is None: # assume it is due to rounding errors and wall is barely touching observation line proximity = observable_distance else: proximity = best_candidate.distance(self.hero.position) elif observed_object is not None: # agent seen object_type_id = self.settings["objects"].index( observed_object.obj_type ) # index of that obj_type, -> 0:friend, 1:enemy speed_x, speed_y = tuple( observed_object.speed) # speed is 2dim vector intersection_segment = obj.as_circle().intersect( observation_line) # what is obj? relevant obj? assert intersection_segment is not None try: proximity = min( intersection_segment.p1.distance(self.hero.position), intersection_segment.p2.distance(self.hero.position)) except AttributeError: proximity = observable_distance for object_type_idx_loop in range( num_obj_types): # for (friend, enemy, wall) observation[ observation_offset + object_type_idx_loop] = 1.0 # initialize each object's distance ratio feature with 1 ( 1 is maximum ) if object_type_id is not None: # this is always true observation[observation_offset + object_type_id] = proximity / observable_distance # the ratio of distance with hero on observed object # the 4th -> speed X ratio / 5th -> speed Y ratio of observed object observation[observation_offset + num_obj_types] = speed_x / max_speed_x observation[observation_offset + num_obj_types + 1] = speed_y / max_speed_y assert num_obj_types + 2 == self.eye_observation_size # maximum feature for each object is 5 observation_offset += self.eye_observation_size # this means feature of observed object == 5 # the last two observation is hero's own speed ratio observation[observation_offset] = self.hero.speed[0] / max_speed_x observation[observation_offset + 1] = self.hero.speed[1] / max_speed_y assert observation_offset + 2 == self.observation_size return observation
def __init__(self, settings): """Initiallize game simulator with settings""" self.settings = settings self.size = self.settings["world_size"] self.walls = [ LineSegment2(Point2(0, 0), Point2(0, self.size[1])), LineSegment2(Point2(0, self.size[1]), Point2(self.size[0], self.size[1])), LineSegment2(Point2(self.size[0], self.size[1]), Point2(self.size[0], 0)), LineSegment2(Point2(self.size[0], 0), Point2(0, 0)) ] self.num_active = [ self.settings['num_objects_active']['prey'], self.settings['num_objects_active']['pred'] ] #number of [prey, pred] controlling movement self.objects = [] for obj_type, number in settings["num_objects"].items(): for _ in range(number): self.objects.append(self.spawn_object(obj_type)) self.observation_lines = self.generate_observation_lines() self.object_reward = np.zeros(self.num_active[0] + self.num_active[1]) self.collected_rewards = [] # every observation_line sees one of objects or wall and # two numbers representing velocity of the object (if applicable) self.eye_observation_size = len(self.settings["objects"]) + 3 # additionally there are two numbers representing agents own velocity and position. self.observation_size = self.eye_observation_size * len( self.observation_lines) + 2 + 2 #Four possible movement directions plus stationary self.directions = [ Vector2(*d) for d in [[1, 0], [0, 1], [-1, 0], [0, -1], [0.0, 0.0]] ] self.num_actions = len(self.directions) print('num_actions ', self.num_actions) #self.objects_eaten = defaultdict(lambda: 0) self.objects_eaten = { 'prey': { 'prey': 0, 'pred': 0 }, 'pred': { 'prey': 0, 'pred': 0 } } self.num_acts_so_far = 0 self.list_to_remove = [] tests = float(self.settings["maximum_velocity"]['prey']) self.max_velocity = max( float(self.settings["maximum_velocity"]['prey']), float(self.settings["maximum_velocity"]['pred']))
def observe(self, obj_type): """Return observation vector. For all the observation directions it returns representation of the closest object to the hero - might be nothing, another object or a wall. Representation of observation for all the directions will be concatenated. """ num_obj_types = len(self.settings["objects"]) + 1 # and wall #max_velocity_x, max_velocity_y = self.settings["maximum_velocity"] observable_distance = self.settings["observation_line_length"] observation = np.zeros( (self.num_active[obj_type], self.observation_size), dtype=float) for ind, active_ind in enumerate(self.get_list(obj_type)): #test = self.objects[active_ind].position[0] #to delete relevant_objects = [ obj for obj in self.objects[:active_ind] + self.objects[active_ind + 1:] if obj.position.distance( self.objects[active_ind].position) < observable_distance ] # objects sorted from closest to furthest relevant_objects.sort(key=lambda x: x.position.distance( self.objects[active_ind].position)) observation_offset = 0 for i, observation_line in enumerate( self.generate_observation_lines()): # shift to hero position observation_line = LineSegment2( self.objects[active_ind].position + Vector2(*observation_line.p1), self.objects[active_ind].position + Vector2(*observation_line.p2)) observed_object = None # if end of observation line is outside of walls, we see the wall. if not self.inside_walls(observation_line.p2): observed_object = "**wall**" for obj in relevant_objects: if observation_line.distance( obj.position) < self.settings["object_radius"]: observed_object = obj break object_type_id = None velocity_x, velocity_y = 0, 0 proximity = 0 if observed_object == "**wall**": # wall seen object_type_id = num_obj_types - 1 # a wall has no velocity velocity_x, velocity_y = 0, 0 # best candidate is intersection between # observation_line and a wall, that's # closest to the individual best_candidate = None for wall in self.walls: candidate = observation_line.intersect(wall) if candidate is not None: if (best_candidate is None or best_candidate.distance( self.objects[active_ind].position) > candidate.distance( self.objects[active_ind].position)): best_candidate = candidate if best_candidate is None: # assume it is due to rounding errors # and wall is barely touching observation line proximity = observable_distance else: proximity = best_candidate.distance( self.objects[active_ind].position) elif observed_object is not None: # agent seen object_type_id = self.settings["objects"].index( observed_object.obj_type) velocity_x, velocity_y = tuple(observed_object.velocity) intersection_segment = obj.as_circle().intersect( observation_line) assert intersection_segment is not None try: proximity = min( intersection_segment.p1.distance( self.objects[active_ind].position), intersection_segment.p2.distance( self.objects[active_ind].position)) except AttributeError: proximity = observable_distance for object_type_idx_loop in range(num_obj_types): observation[ind, observation_offset + object_type_idx_loop] = 1.0 if object_type_id is not None: observation[ ind, observation_offset + object_type_id] = proximity / observable_distance observation[ ind, observation_offset + num_obj_types] = velocity_x / self.max_velocity #constant velocities now observation[ind, observation_offset + num_obj_types + 1] = velocity_y / self.max_velocity assert num_obj_types + 2 == self.eye_observation_size observation_offset += self.eye_observation_size #add velocity information about the focal individual observation[ind, observation_offset] = self.objects[ active_ind].velocity[0] / self.max_velocity observation[ ind, observation_offset + 1] = self.objects[active_ind].velocity[1] / self.max_velocity observation_offset += 2 # add normalized locaiton of the focal individual in environment observation[ ind, observation_offset] = self.objects[active_ind].position[0] / ( self.size[0] / 2) - 1.0 #originally was / 350.0 observation[ind, observation_offset + 1] = self.objects[active_ind].position[1] / ( self.size[1] / 2) - 1.0 # orginally was / 250.0 assert observation_offset + 2 == self.observation_size return observation
def test_intersect(self): line_segment = LineSegment2(Point2(1, 5), Point2(5, 1)) square = Polygon(self.points) intersect_points = square.intersect(line_segment) desired = [Point2(2, 4), Point2(4, 2)] self.assertListEqual(desired, intersect_points)
def observe(self): """Return observation vector. For all the observation directions it returns representation of the closest object to the hero - might be nothing, another object or a wall. Representation of observation for all the directions will be concatenated. """ num_obj_types = len(self.settings["objects"]) + 1 # and wall max_speed_x, max_speed_y = self.settings["maximum_speed"] observable_distance = self.settings["observation_line_length"] relevant_objects = [ obj for obj in self.objects if obj.position.distance(self.hero.position) < observable_distance ] # objects sorted from closest to furthest relevant_objects.sort( key=lambda x: x.position.distance(self.hero.position)) observation = np.zeros(self.observation_size) observation_offset = 0 for i, observation_line in enumerate(self.observation_lines): # shift to hero position observation_line = LineSegment2( self.hero.position + Vector2(*observation_line.p1), self.hero.position + Vector2(*observation_line.p2)) observed_object = None # if end of observation line is outside of walls, we see the wall. if not self.inside_walls(observation_line.p2): observed_object = "**wall**" for obj in relevant_objects: if observation_line.distance( obj.position) < self.settings["object_radius"]: observed_object = obj break object_type_id = None speed_x, speed_y = 0, 0 proximity = 0 if observed_object == "**wall**": # wall seen object_type_id = num_obj_types - 1 # a wall has fairly low speed... speed_x, speed_y = 0, 0 # best candidate is intersection between # observation_line and a wall, that's # closest to the hero best_candidate = None for wall in self.walls: candidate = observation_line.intersect(wall) if candidate is not None: if (best_candidate is None or best_candidate.distance(self.hero.position) > candidate.distance(self.hero.position)): best_candidate = candidate if best_candidate is None: # assume it is due to rounding errors # and wall is barely touching observation line proximity = observable_distance else: proximity = best_candidate.distance(self.hero.position) elif observed_object is not None: # agent seen object_type_id = self.settings["objects"].index( observed_object.obj_type) speed_x, speed_y = tuple(observed_object.speed) intersection_segment = obj.as_circle().intersect( observation_line) assert intersection_segment is not None try: proximity = min( intersection_segment.p1.distance(self.hero.position), intersection_segment.p2.distance(self.hero.position)) except AttributeError: proximity = observable_distance for object_type_idx_loop in range(num_obj_types): observation[observation_offset + object_type_idx_loop] = 1.0 if object_type_id is not None: observation[observation_offset + object_type_id] = proximity / observable_distance observation[observation_offset + num_obj_types] = speed_x / max_speed_x observation[observation_offset + num_obj_types + 1] = speed_y / max_speed_y assert num_obj_types + 2 == self.eye_observation_size observation_offset += self.eye_observation_size observation[observation_offset] = self.hero.speed[0] / max_speed_x observation[observation_offset + 1] = self.hero.speed[1] / max_speed_y observation_offset += 2 # add normalized locaiton of the hero in environment observation[observation_offset] = self.hero.position[0] / 350.0 - 1.0 observation[observation_offset + 1] = self.hero.position[1] / 250.0 - 1.0 assert observation_offset + 2 == self.observation_size return observation
def line(p1, p2): return LineSegment2(point(p1), point(p2))