def __init__(self, owner, x, y, size, img_path): """ Constructs all neccesary attributes for the Wall Object Parameters ---------- owner : None, hidenseek.objects.controllable.Hiding, hidenseek.objects.controllable.Seeker Wall owner, None for game environment x : float center of the rectangle in 'x' axis for absolute coordinate system (game screen) y : float center of the rectangle in 'y' axis for absolute coordinate system (game screen) size : tuple Wall size, at least 2x2 """ super().__init__() self.owner = owner self.width = size[0] self.height = size[1] self.pos = Point((x, y)) image = pygame.Surface((self.width, self.height)) image.fill((0, 0, 0, 0)) image.set_colorkey((0, 0, 0)) self.image = image self.filling = [ pygame.image.load(os.path.join(os.getcwd(), 'wall', img_path, file)) for file in os.listdir(os.path.join(os.getcwd(), 'wall', img_path)) ] self.rect = self.image.get_rect() self.rect.center = (self.pos.x, self.pos.y) filling_width = self.filling[0].get_width() filling_height = self.filling[0].get_height() img_full_size_w = self.width / filling_width img_rounded_size_w = math.ceil(img_full_size_w) img_full_size_h = self.height / filling_height img_rounded_size_h = math.ceil(img_full_size_h) blit_list = [(self.filling[0], (filling_width * i, j * filling_height)) for i in range(0, img_rounded_size_w) for j in range(0, img_rounded_size_h)] image.blits(blit_list) self.polygon_points = [ Point((self.rect.left, self.rect.top)), Point((self.rect.right, self.rect.top)), Point((self.rect.right, self.rect.bottom)), Point((self.rect.left, self.rect.bottom)) ]
def _rotate(self, angle, position): """ Rotates the sprite by creating new Rectangle and updates its polygon points Parameters ---------- angle : float player direction in radians position : Point center of the wall Returns ------- None """ # Copy and then rotate the original image. copied_image = self.image.copy() self.image = pygame.transform.rotozoom(copied_image, -angle * 180 / math.pi, 1) self.image.set_colorkey((0, 0, 0)) # Create a new rect with the center of the sprite. self.rect = self.image.get_rect() self.rect.center = (position.x, position.y) self.width = self.rect.width self.height = self.rect.height # Update the polygon points for collisions self.polygon_points = [ Point.triangle_unit_circle_relative(angle, self.pos, polygon_point) for polygon_point in self.polygon_points ]
def _determine_new_ray_points(self, wall_edges): """ Algorithm which calculates new possible ray points based on the current Agent Position and Agent Direction Parameters ---------- None Returns ------- ray_points : list of Point list of new, standard Ray Points """ ray_points = [] dir_t = self.direction - 2 * math.pi if self.direction > math.pi else self.direction point_angle_0 = self.pos + Point((self.vision_radius, 0)) angles = np.linspace(dir_t - self.vision_rad / 2, dir_t + self.vision_rad / 2, num=11, endpoint=True) # counter-clockwise angles_min, angles_max = min(angles), max(angles) for p in [pnt for wall_edge in wall_edges for pnt in wall_edge]: delta = p - self.pos theta_radians = math.atan2(delta.y, delta.x) # 3rd quartet (2nd in math, 3rd in Y being from top to bottom), fixes 2nd; from [-PI; PI] to [-2PI; 0] if angles_min < -math.pi and theta_radians > 0: theta_radians = theta_radians - 2 * math.pi # 2nd quartet (3rd in math, 2nd in Y being from top to bottom), fixes 3rd; from [-PI; PI] to [0; 2PI] elif angles_max > math.pi and theta_radians < 0: theta_radians = theta_radians + 2 * math.pi if theta_radians not in angles and theta_radians > angles_min and theta_radians < angles_max: angles = np.append(angles, theta_radians) angles = np.sort(angles) for angle in angles: ray_point = Point.triangle_unit_circle_relative( angle, self.pos, point_angle_0) ray_points.append(ray_point) return ray_points
def update_vision(self, local_env): """ Updates Agent Vision Parameters ---------- local_env : dict contains Player Local Environment Returns ------- None """ new_point = Point.triangle_unit_circle(self.direction, side_size=self.vision_radius) self.vision_top = self.pos + new_point wall_edges = self.reduce_wall_edges(local_env['walls']) self.ray_points = self._determine_new_ray_points(wall_edges) # without center self.ray_points = self._find_intersections(wall_edges)[1:] # creates triangles self.ray_objects = [[ self.pos, self.ray_points[i], self.ray_points[i + 1] ] for i in range(len(self.ray_points) - 1) if self.ray_points[i] != self.ray_points[i + 1]] # adds Agent Rectangle to Agent Ray Objects speed_dist_w = self.speed + 1 + self.width / 2 speed_dist_h = self.speed + 1 + self.height / 2 self.ray_objects.append([ Point((self.pos.x - speed_dist_w, self.pos.y - speed_dist_h)), Point((self.pos.x + speed_dist_w, self.pos.y - speed_dist_h)), Point((self.pos.x + speed_dist_w, self.pos.y + speed_dist_h)), Point((self.pos.x - speed_dist_w, self.pos.y + speed_dist_h)), ])
def _add_wall(self): """ Adds Wall Parameters ---------- None Returns ------- None """ if self.player_hide.walls_counter < self.player_hide.walls_max and not self.player_hide.wall_timer: logger_hiding.info( f"\tAdding Wall #{self.player_hide.walls_counter + 1}") wall_pos = copy.deepcopy(self.player_hide.pos) wall_size = (max(int(self.player_hide.width / 10), 2), max(int(self.player_hide.height / 2), 2)) # minimum 2x2 Wall vision_arc_range = np.sqrt( (self.player_hide.vision_top.x - self.player_hide.pos.x) * (self.player_hide.vision_top.x - self.player_hide.pos.x) + (self.player_hide.vision_top.y - self.player_hide.pos.y) * (self.player_hide.vision_top.y - self.player_hide.pos.y)) # vision arc range - 1.5 wall width, so the wall is always created inside PoV. wall_pos.x = wall_pos.x + vision_arc_range - \ (1.5 * wall_size[0]) wall_pos = Point.triangle_unit_circle_relative( self.player_hide.direction, self.player_hide.pos, wall_pos) wall = Wall(self.player_hide, wall_pos.x, wall_pos.y, wall_size, self.cfg['GRAPHICS_PATH_WALL_OWNER']) logger_hiding.info(f"\t\tPosition: {wall_pos}") wall._rotate(self.player_hide.direction, wall_pos) if self._can_create_wall(wall, self.agent_env['p_hide']['enemy']): self.player_hide.walls_counter += 1 logger_hiding.info( f"\tAdded wall #{self.player_hide.walls_counter}") self.walls_group.add(wall) self.player_hide.wall_timer = copy.deepcopy( self.player_hide.wall_timer_init) else: del wall
def _find_intersections(self, wall_edges): """ Algorithm which looks for new Ray Points, which are closer to the Agent Center than radius-distance Ray Points Parameters ---------- wall_edges : list of [Point, Point] list of Wall Edges in Agent Local Environment Returns ------- temp_ray_points : list of Point list of new Ray Points """ edges_bounding_boxes = [{ 'center': (edge[0] + edge[1]) / 2, 'size': (abs(edge[1].x - edge[0].x), abs(edge[1].y - edge[0].y)) } for edge in wall_edges] temp_ray_points = [Point(self.rect.center)] for vertex in self.ray_points: # first must be the center point line_segment = [self.pos.round(4), vertex.round(4)] new_point = copy.deepcopy(vertex.round(4)) new_point_dist = self.pos.distance(new_point) bounding_box = { 'center': (line_segment[0] + line_segment[1]) / 2, 'size': (abs(line_segment[1].x - line_segment[0].x), abs(line_segment[1].y - line_segment[0].y)) } for edge, edge_bounding_box in zip(wall_edges, edges_bounding_boxes): if not Collision.aabb(bounding_box['center'], bounding_box['size'], edge_bounding_box['center'], edge_bounding_box['size']): continue p = Collision.line_intersection(line_segment, edge) if p and self.pos.distance(p) <= new_point_dist: new_point = p new_point_dist = self.pos.distance(p) temp_ray_points.append(new_point) return temp_ray_points
def update(self, new_action, local_env, logger): """ Takes and performs the action Parameters ---------- new_action : dict action taken by Agent local_env : dict contains Player Local Environment logger : logging logging instance, i.e. logger_hiding, logger_seeker Returns ------- None """ if new_action['type'] == 'NOOP': self.image_index = 0 logger.info("NOOP! NOOP!") elif new_action['type'] == 'movement': x = math.cos(self.direction) * self.speed * new_action['content'] y = math.sin(self.direction) * self.speed * new_action['content'] old_pos = copy.deepcopy(self.pos) new_pos = self.pos + Point((x, y)) logger.info(f"Moving to {new_pos}") logger.info(f"\tChecking collisions with other Objects") for wall in local_env['walls']: if Collision.aabb(new_pos, (self.width, self.height), wall.pos, (wall.width, wall.height)): self._move_action(new_pos) if Collision.sat(self.get_abs_vertices(), wall.get_abs_vertices()): logger.info( "\tCollision with some Wall! Not moving anywhere") self._move_action(old_pos) return self._move_action(new_pos) elif new_action['type'] == 'rotation': self._rotate(new_action['content'], local_env)
def get_abs_vertices(self): """ Returns absolute coordinates of Vertices in Polygon Parameters ---------- None Returns ------- points : list of hidenseek.ext.supportive.Point self.pylogon_points mapped to the absolute coordinates system """ return [ Point((polygon_point.x + self.rect.left, polygon_point.y + self.rect.top)) for polygon_point in self.polygon_points ]
def __init__(self, cfg, size, pos_ratio, SCREEN_WIDTH, SCREEN_HEIGHT): """ Constructs all neccesary attributes for the Player Object Parameters ---------- cfg : configparser Object Agent Config Object size : tuple Agent size pos_ratio : tuple used to calculate initial position of the Player in absolute coordinate system (game screen); if value < 1 then it's ratio in percentage, otherwise it's coord SCREEN_WIDTH : int width of the game window SCREEN_HEIGHT : int height of the game window """ super().__init__() self.width = size[0] self.height = size[1] tmp_pos = list(pos_ratio) if tmp_pos[0] < 1: tmp_pos[0] *= SCREEN_WIDTH if tmp_pos[1] < 1: tmp_pos[1] *= SCREEN_HEIGHT self.pos = Point(tmp_pos) self.SCREEN_WIDTH = SCREEN_WIDTH self.SCREEN_HEIGHT = SCREEN_HEIGHT self.speed = cfg.getfloat('SPEED_RATIO', fallback=1.0) self.speed_rotate = cfg.getfloat('SPEED_ROTATE_RATIO', fallback=0.1) self.wall_timer_init = cfg.getint('WALL_ACTION_TIMEOUT', fallback=5) self.wall_timer = cfg.getint('WALL_ACTION_TIMEOUT', fallback=5) self.vision_radius = self.width * 2 self.vision_top = None self.ray_objects = None self.vision_rad = math.pi self.ray_points = [] self.direction = 0 # radians from which vision_rad is added/substracted """ OCTAGON > 0.15 on every side because we need to cover only 0.7 of space, to be able to freely rotate without making bigger rectangle > 2*x / sqrt(2) + x = 0.7 > x ~= 0.29 > x / sqrt(2) ~= 0.205 x/sqrt(2) x x/sqrt(2) ........---------........ ....../ \...... ...../ \..... ..../ \.... .../ \... ..| |.. ..| |.. ..| |.. ..| |.. ..| |.. ...\ /... ....\ /.... .....\ /..... ......\ /...... ........---------........ """ self.polygon_points = [ Point((self.width * .355, self.height * .15)), Point((self.width * .645, self.height * .15)), Point((self.width * .85, self.height * .355)), Point((self.width * .85, self.height * .645)), Point((self.width * .645, self.height * .85)), Point((self.width * .355, self.height * .85)), Point((self.width * .15, self.height * .645)), Point((self.width * .15, self.height * .355)), ] self.sprites = [ pygame.image.load( os.path.join(os.getcwd(), 'people', cfg.get('GRAPHICS_PATH', fallback='bald'), file)) for file in os.listdir( os.path.join(os.getcwd(), 'people', cfg.get('GRAPHICS_PATH', fallback='bald'))) ] surface = pygame.Surface((self.width, self.height)) surface.set_colorkey((0, 0, 0)) self.image_index = 0 self.image = surface self.rect = self.image.get_rect() self.rect.center = (self.pos.x, self.pos.y) # base class Player actions self.actions = [ { 'type': 'NOOP', # do nothing }, { 'type': 'movement', 'content': -1, }, { 'type': 'movement', 'content': 1, }, { 'type': 'rotation', 'content': -1 }, { 'type': 'rotation', 'content': 1 }, ]
class Player(pygame.sprite.Sprite): """ Parent Player Class for Hide'n'Seek Game, inherits from pygame.sprite.Sprite. Shouldn't be used because it doesn't have implementation of few methods Attributes ---------- width : int width of the Player Rectangle height : int height of the Player Rectangle SCREEN_WIDTH : int width of the game window SCREEN_HEIGHT : int height of the game window pos : hidenseek.ext.supportive.Point object position on the game display speed : int speed ratio for Player movement (in ticks) speed_rotate : float speed ratio for Player rotate wall_timer_init : int init cooldown (in frames) for any wall-specific action wall_timer : int cooldown (in frames)for any wall-specific action vision_radius : float Player POV radius vision_rad : float Player POV angle vision_top : Point Player Top POV Point ray_points : list of Point Player Ray POV in Points representation ray_objects : list of Objects (3-el list of Point) Player Ray POV in Triangles representation direction : float POV angle in radians (Z = 2 * PI) image_index : int determines which image should be drawn images : list of pygame.Surface objects with sprite/images from which the proper one will be drawn image : pygame.Surface object with sprite/image, chosen by 'image_index' rect : pygame.Rect object Rectangle, to be drawn polygon_points : list of tuples Agent vertices, used for collision check in SAT actions : list of dict contains all possible Player actions Methods ------- _rotate(turn, local_env): rotates the object, accordingly to the value, along its axis get_abs_vertices(): returns absolute vertices coordinates (in game screen coordinates system) _move_action(new_pos): algorithm which moves the Player object to given poisition update_vision(local_env): updates Agent POV update(local_env): Not implemented in Parent Class """ def __init__(self, cfg, size, pos_ratio, SCREEN_WIDTH, SCREEN_HEIGHT): """ Constructs all neccesary attributes for the Player Object Parameters ---------- cfg : configparser Object Agent Config Object size : tuple Agent size pos_ratio : tuple used to calculate initial position of the Player in absolute coordinate system (game screen); if value < 1 then it's ratio in percentage, otherwise it's coord SCREEN_WIDTH : int width of the game window SCREEN_HEIGHT : int height of the game window """ super().__init__() self.width = size[0] self.height = size[1] tmp_pos = list(pos_ratio) if tmp_pos[0] < 1: tmp_pos[0] *= SCREEN_WIDTH if tmp_pos[1] < 1: tmp_pos[1] *= SCREEN_HEIGHT self.pos = Point(tmp_pos) self.SCREEN_WIDTH = SCREEN_WIDTH self.SCREEN_HEIGHT = SCREEN_HEIGHT self.speed = cfg.getfloat('SPEED_RATIO', fallback=1.0) self.speed_rotate = cfg.getfloat('SPEED_ROTATE_RATIO', fallback=0.1) self.wall_timer_init = cfg.getint('WALL_ACTION_TIMEOUT', fallback=5) self.wall_timer = cfg.getint('WALL_ACTION_TIMEOUT', fallback=5) self.vision_radius = self.width * 2 self.vision_top = None self.ray_objects = None self.vision_rad = math.pi self.ray_points = [] self.direction = 0 # radians from which vision_rad is added/substracted """ OCTAGON > 0.15 on every side because we need to cover only 0.7 of space, to be able to freely rotate without making bigger rectangle > 2*x / sqrt(2) + x = 0.7 > x ~= 0.29 > x / sqrt(2) ~= 0.205 x/sqrt(2) x x/sqrt(2) ........---------........ ....../ \...... ...../ \..... ..../ \.... .../ \... ..| |.. ..| |.. ..| |.. ..| |.. ..| |.. ...\ /... ....\ /.... .....\ /..... ......\ /...... ........---------........ """ self.polygon_points = [ Point((self.width * .355, self.height * .15)), Point((self.width * .645, self.height * .15)), Point((self.width * .85, self.height * .355)), Point((self.width * .85, self.height * .645)), Point((self.width * .645, self.height * .85)), Point((self.width * .355, self.height * .85)), Point((self.width * .15, self.height * .645)), Point((self.width * .15, self.height * .355)), ] self.sprites = [ pygame.image.load( os.path.join(os.getcwd(), 'people', cfg.get('GRAPHICS_PATH', fallback='bald'), file)) for file in os.listdir( os.path.join(os.getcwd(), 'people', cfg.get('GRAPHICS_PATH', fallback='bald'))) ] surface = pygame.Surface((self.width, self.height)) surface.set_colorkey((0, 0, 0)) self.image_index = 0 self.image = surface self.rect = self.image.get_rect() self.rect.center = (self.pos.x, self.pos.y) # base class Player actions self.actions = [ { 'type': 'NOOP', # do nothing }, { 'type': 'movement', 'content': -1, }, { 'type': 'movement', 'content': 1, }, { 'type': 'rotation', 'content': -1 }, { 'type': 'rotation', 'content': 1 }, ] def _rotate(self, turn, local_env): """ Rotates the object, accordingly to the value, along its axis. Parameters ---------- turn : int, [-1,1] in which direction should agent rotate (clockwise or counterclockwise) local_env : dict contains Player Local Environment Returns ------- None """ self.image_index = 0 self.direction += self.speed_rotate * turn # base 2PI, because it's circle self.direction = self.direction % (2 * math.pi) def get_abs_vertices(self): """ Returns absolute coordinates of Vertices in Polygon Parameters ---------- None Returns ------- points : list of hidenseek.ext.supportive.Point self.pylogon_points mapped to the absolute coordinates system """ return [ Point((polygon_point.x + self.rect.left, polygon_point.y + self.rect.top)) for polygon_point in self.polygon_points ] def _move_action(self, new_pos): """ Algorithm which moves the Player object to given direction, if not outside map (game screen) Parameters ---------- new_pos : hidenseek.ext.supportive.Point Point object of the new position Returns ------- None """ old_pos = copy.deepcopy(self.pos) self.pos = new_pos if old_pos != self.pos: # if moving self.image_index = (self.image_index + 1) % len(self.sprites) if not self.image_index: self.image_index += 1 self.rect.center = (self.pos.x, self.pos.y) else: # if not moving self.image_index = 0 def _determine_new_ray_points(self, wall_edges): """ Algorithm which calculates new possible ray points based on the current Agent Position and Agent Direction Parameters ---------- None Returns ------- ray_points : list of Point list of new, standard Ray Points """ ray_points = [] dir_t = self.direction - 2 * math.pi if self.direction > math.pi else self.direction point_angle_0 = self.pos + Point((self.vision_radius, 0)) angles = np.linspace(dir_t - self.vision_rad / 2, dir_t + self.vision_rad / 2, num=11, endpoint=True) # counter-clockwise angles_min, angles_max = min(angles), max(angles) for p in [pnt for wall_edge in wall_edges for pnt in wall_edge]: delta = p - self.pos theta_radians = math.atan2(delta.y, delta.x) # 3rd quartet (2nd in math, 3rd in Y being from top to bottom), fixes 2nd; from [-PI; PI] to [-2PI; 0] if angles_min < -math.pi and theta_radians > 0: theta_radians = theta_radians - 2 * math.pi # 2nd quartet (3rd in math, 2nd in Y being from top to bottom), fixes 3rd; from [-PI; PI] to [0; 2PI] elif angles_max > math.pi and theta_radians < 0: theta_radians = theta_radians + 2 * math.pi if theta_radians not in angles and theta_radians > angles_min and theta_radians < angles_max: angles = np.append(angles, theta_radians) angles = np.sort(angles) for angle in angles: ray_point = Point.triangle_unit_circle_relative( angle, self.pos, point_angle_0) ray_points.append(ray_point) return ray_points def reduce_wall_edges(self, walls): """ Algorithm which reduces wall edges from 4 per Wall to only 2 (closest ones) Parameters ---------- walls : list of Wall list of Walls in Agent Local Environment Returns ------- proper_walls_lines : list of [Point, Point] list of closest wall edges """ walls_lines = [[[ wall.get_abs_vertices()[i % 4], wall.get_abs_vertices()[(i + 1) % 4] ] for i in range(4)] for wall in walls] # get only closer parallel wall edge, reduces computation by half proper_walls_lines = [] for wall_lines in walls_lines: if self.pos.distance( wall_lines[0][0] + (wall_lines[0][1] - wall_lines[0][0]) / 2) < self.pos.distance( wall_lines[2][0] + (wall_lines[2][1] - wall_lines[2][0]) / 2): proper_walls_lines.append(wall_lines[0]) else: proper_walls_lines.append(wall_lines[2]) if self.pos.distance( wall_lines[1][0] + (wall_lines[1][1] - wall_lines[1][0]) / 2) < self.pos.distance( wall_lines[3][0] + (wall_lines[3][1] - wall_lines[3][0]) / 2): proper_walls_lines.append(wall_lines[1]) else: proper_walls_lines.append(wall_lines[3]) return proper_walls_lines def _find_intersections(self, wall_edges): """ Algorithm which looks for new Ray Points, which are closer to the Agent Center than radius-distance Ray Points Parameters ---------- wall_edges : list of [Point, Point] list of Wall Edges in Agent Local Environment Returns ------- temp_ray_points : list of Point list of new Ray Points """ edges_bounding_boxes = [{ 'center': (edge[0] + edge[1]) / 2, 'size': (abs(edge[1].x - edge[0].x), abs(edge[1].y - edge[0].y)) } for edge in wall_edges] temp_ray_points = [Point(self.rect.center)] for vertex in self.ray_points: # first must be the center point line_segment = [self.pos.round(4), vertex.round(4)] new_point = copy.deepcopy(vertex.round(4)) new_point_dist = self.pos.distance(new_point) bounding_box = { 'center': (line_segment[0] + line_segment[1]) / 2, 'size': (abs(line_segment[1].x - line_segment[0].x), abs(line_segment[1].y - line_segment[0].y)) } for edge, edge_bounding_box in zip(wall_edges, edges_bounding_boxes): if not Collision.aabb(bounding_box['center'], bounding_box['size'], edge_bounding_box['center'], edge_bounding_box['size']): continue p = Collision.line_intersection(line_segment, edge) if p and self.pos.distance(p) <= new_point_dist: new_point = p new_point_dist = self.pos.distance(p) temp_ray_points.append(new_point) return temp_ray_points def update_vision(self, local_env): """ Updates Agent Vision Parameters ---------- local_env : dict contains Player Local Environment Returns ------- None """ new_point = Point.triangle_unit_circle(self.direction, side_size=self.vision_radius) self.vision_top = self.pos + new_point wall_edges = self.reduce_wall_edges(local_env['walls']) self.ray_points = self._determine_new_ray_points(wall_edges) # without center self.ray_points = self._find_intersections(wall_edges)[1:] # creates triangles self.ray_objects = [[ self.pos, self.ray_points[i], self.ray_points[i + 1] ] for i in range(len(self.ray_points) - 1) if self.ray_points[i] != self.ray_points[i + 1]] # adds Agent Rectangle to Agent Ray Objects speed_dist_w = self.speed + 1 + self.width / 2 speed_dist_h = self.speed + 1 + self.height / 2 self.ray_objects.append([ Point((self.pos.x - speed_dist_w, self.pos.y - speed_dist_h)), Point((self.pos.x + speed_dist_w, self.pos.y - speed_dist_h)), Point((self.pos.x + speed_dist_w, self.pos.y + speed_dist_h)), Point((self.pos.x - speed_dist_w, self.pos.y + speed_dist_h)), ]) def update(self, new_action, local_env, logger): """ Takes and performs the action Parameters ---------- new_action : dict action taken by Agent local_env : dict contains Player Local Environment logger : logging logging instance, i.e. logger_hiding, logger_seeker Returns ------- None """ if new_action['type'] == 'NOOP': self.image_index = 0 logger.info("NOOP! NOOP!") elif new_action['type'] == 'movement': x = math.cos(self.direction) * self.speed * new_action['content'] y = math.sin(self.direction) * self.speed * new_action['content'] old_pos = copy.deepcopy(self.pos) new_pos = self.pos + Point((x, y)) logger.info(f"Moving to {new_pos}") logger.info(f"\tChecking collisions with other Objects") for wall in local_env['walls']: if Collision.aabb(new_pos, (self.width, self.height), wall.pos, (wall.width, wall.height)): self._move_action(new_pos) if Collision.sat(self.get_abs_vertices(), wall.get_abs_vertices()): logger.info( "\tCollision with some Wall! Not moving anywhere") self._move_action(old_pos) return self._move_action(new_pos) elif new_action['type'] == 'rotation': self._rotate(new_action['content'], local_env)