def __mapBlockSurrounding(self, block, blocks): """ Maps the surrounding of the block given """ encoded_map = bitmap.BitMap(8) #8 Surrounding blocks total_walls = 0 #Make list of all surrounding blocks in board bx, by = block surrounding = [ (sur_x, sur_y) for sur_x in range(bx - self.size, bx + self.size * 2, self.size) for sur_y in range(by - self.size, by + self.size * 2, self.size) if sur_x != bx or sur_y != by ] #Encode the surroundings into the bitmap for index, (x, y) in enumerate(surrounding): if (snake.Block(self.size, x, y) in blocks or x <= self.leftBoundry or y <= 0 or x >= self.rightBoundry or y >= self.gameHeight): encoded_map.set(index) return encoded_map
def isSafe(self): """ Determine if the food is in a reachable location OVERRIDE """ return (super().isSafe() and snake.Block(self.width, self.x, self.y) not in self.game.redirection_blocks)
def __closest2Walls(self, block): """ Returns the two closest walls to the given point on the grid """ #Add error checking walls = [ snake.Block(block.width, block.x, 0), snake.Block(block.width, self.leftBoundry, block.x), snake.Block(block.width, block.x, self.gameHeight), snake.Block(block.width, block.rightBoundry, block.y) ] distances = sorted( [self.__gridDistanceBetweenBlocks(block, x) for x in walls]) return distances[:2]
def __blockSafety(self, block, blocks): """ Examines if the block is safely placed """ #Check blocks L R U and D from current block and enocde that area all_surroundings = [(block.x - block.width, block.y), (block.x + block.width, block.y), (block.x, block.y - block.width), (block.x, block.y + block.width)] #Encode each surrounding for surrounding in all_surroundings: encoded_map = self.__mapBlockSurrounding(surrounding, blocks) #Check for conflict if encoded_map.count( ) >= 3: #If it's less, theres no possibility of conflict #Check for -_- shape (impossible to escape) if ((encoded_map[3] and encoded_map[4] and (encoded_map[1] or encoded_map[6])) or ((encoded_map[1] and encoded_map[6]) and (encoded_map[3] or encoded_map[4]))): return False #Not valid, conflict exists #Add the corners so we can find the edges #Doesn't get corners that don't exist (ie: "fake" corner) # ### <- This ## # # # # # # -> # # # # ## # # # # # # #Thought: if we have 3 corners we can find the 4th corner_blocks = self.__addCorners(blocks) blocks_with_corners = blocks + corner_blocks #if len(blocks) >= 3: if False: #This isn't working edges = self.__findEdges(blocks_with_corners) if len(edges) == 3: x_values = [x.x for x in edges] y_values = [x.y for x in edges] missing_x = [m for m in x_values if x_values.count(m) == 1] missing_y = [m for m in y_values if y_values.count(m) == 1] edges += [snake.Block(self.size, missing_x, missing_y)] elif len(edges) > 4: raise RunTimeError("More than 4 edges") elif len(edges) < 4: return True return self.__distanceInEdges(edges, blocks) < 2 else: return True
def hitRedirect(self, newX, newY): """ Checks if the move about to be made will collide with any of the blocks that will redirect the snake. """ newBlock = snake.Block(self.width, newX, newY) for block in self.game.redirection_blocks: if block.colliderect(newBlock): self.hit_redirect = True break
def move(self): """ Move the snake. The snake moves by shifting the entire array of the tail to the left (removing the last element) and putting a new Block where the head used to be. """ self.hit_self = False self.hit_wall = False self.hit_redirect = False if self.tail: self.tail = self.tail[1:] self.tail.append(snake.Block(self.game.size, self.x, self.y)) for block in self.tail[1:]: block.resetColor() self.tail[0].color = (255, 250, 205) newY = self.dy + self.y newX = self.dx + self.x self.hitWall(newX, newY) if self.hit_wall: if self.game.noBoundry: self.__goThroughWall(newX, newY) self.checkEat(self.x, self.y) elif self.game.assist: self.assist() else: self.die() return self.hitRedirect(newX, newY) if self.hit_redirect: self.die() #self.assist(tail=True) #self.checkEat(self.x, self.y) #return if not self.checkEat(newX, newY): # Only check if the snake hits itself if it didn't eat, # eating causes another block to be placed exactly where the snake is self.hitSelf(newX, newY) if self.hit_self: if self.game.assist: self.assist() else: self.die() self.hit_self = False return #Don't update the snake if bad move self.y = newY self.x = newX
def __encodeSurrounding(cls, bmap, minimum_value, snake_obj, bit_start=0): global redirection_blocks surrounding = cls.__mapSurrounding(snake_obj, minimum_value) encoded_map = bmap # Checks each block in the surrounding and checks if it is near a wall, or near a piece of the tail bit_position = bit_start for (index, (x, y, block)) in enumerate(surrounding): if index % minimum_value == 0 and index != 0: # Don't increment immediately bit_position += 1 if (x < snake_obj.game.leftBoundry or y < 0 or x == snake_obj.game.rightBoundry or y == constant.WINDOW_HEIGHT or snake.Block(snake_obj.width, x, y) in redirection_blocks or (block != None and block.colliderect(snake.Block(constant.BLOCK_SIZE, x, y))) and not encoded_map.test(bit_position)): encoded_map.set(bit_position)
def __distanceInEdges(self, edges, blocks): sorted_edges = sorted(edges, key=lambda e: (e.x, e.y)) same_x = [[sorted_edges[:2]], [sorted_edges[2:]]] same_y = [[sorted_edges[::2]], [sorted_edges[1::1]]] total_distance = 0 distance_between_x = self.__gridDistanceBetweenBlocks(*same_x) for x in range(distance_between_x): check_block = snake.Block(x.width, same_x[0].x + x * self.size, same_x[1]) if check_block not in blocks: total_distance += 1 distance_between_y = self.__gridDistanceBetweenBlocks(*same_y) for y in range(distance_between_y): check_block = snake.Block(x.width, same_x[0].x, same_x[1] + y * self.size) if check_block not in blocks: total_distance += 1 return total_distance
def __touchingOtherBlock(self, block, blocks): """ Retruns a list of blocks that are touching the given block Argument List: blocks - List of blocks on the board """ directions = [ snake.Direction.UP, snake.Direction.DOWN, snake.Direction.LEFT, snake.Direction.RIGHT ] blocks_touching = [] for direction in directions: dx, dy = map(lambda x: x * block.width, direction.value) newBlock = snake.Block(block.width, block.x + block.dx, block.y + block.dy) if newBlock in blocks: blocks_touching += [newBlock] return blocks_touching
def __createBlocks(self): """ Creates the blocks that will push away and place them on the baord. TODO: Place the blocks, randomly, but check that they don't limit an area? Or place the blocks in the same place every time? """ block_coordinates = [] for i in range(10): safe = False while not safe: block_coordinates.append( snake.Block(self.size, random.randint(self.leftBoundry / self.size, self.rows) * self.size, random.randint(0, self.cols) * self.size, color=(220, 220, 220))) if self.__isSafe(block_coordinates): safe = True else: block_coordinates.pop() return block_coordinates
def __searchEdge(self, origin, blocks, last_direction=None, block=None, distance_travelled=0): if block == origin: return True if distance_travelled >= 2: return block if block == None: block = origin directions = [ snake.Direction.UP, snake.Direction.DOWN, snake.Direction.LEFT, snake.Direction.RIGHT ] if last_direction: #We won't undo the last move directions.remove(~last_direction) for direction in directions: dx, dy = map(lambda x: x * block.width, direction.value) newBlock = snake.Block(block.width, block.x + dx, block.y + dy) if newBlock in blocks: further = self.__searchEdge(origin, blocks, direction, newBlock, distance_travelled) else: further = self.__searchEdge(origin, blocks, direction, newBlock, distance_travelled + 1) return False
def __addCorners(self, blocks): temp_blocks = [] for block in blocks: # We have to take into account the new blocks we have added so we # Don't double add encoded_map = self.__mapBlockSurrounding((block.x, block.y), blocks + temp_blocks) if encoded_map[1] and encoded_map[3] and not encoded_map[0]: temp_blocks += [ snake.Block(block.width, block.x - block.width, block.y - block.width) ] encoded_map.set(0) if encoded_map[1] and encoded_map[4] and not encoded_map[3]: temp_blocks += [ snake.Block(block.width, block.x - block.width, block.y + block.width) ] encoded_map.set(3) if encoded_map[6] and encoded_map[3] and not encoded_map[5]: temp_blocks += [ snake.Block(block.width, block.x + block.width, block.y - block.width) ] encoded_map.set(5) if encoded_map[6] and encoded_map[4] and not encoded_map[7]: temp_blocks += [ snake.Block(block.width, block.x + block.width, block.y + block.width) ] encoded_map.set(7) if encoded_map[0]: if not encoded_map[1]: temp_blocks += [ snake.Block(block.width, block.x - block.width, block.y) ] encoded_map.set(1) if not encoded_map[3]: temp_blocks += [ snake.Block(block.width, block.x, block.y - block.width) ] encoded_map.set(3) if encoded_map[2]: if not encoded_map[1]: temp_blocks += [ snake.Block(block.width, block.x - block.width, block.y) ] encoded_map.set(1) if not encoded_map[4]: temp_blocks += [ snake.Block(block.width, block.x, block.width + block.y) ] encoded_map.set(4) if encoded_map[5]: if not encoded_map[3]: temp_blocks += [ snake.Block(block.width, block.x, block.y - block.width) ] encoded_map.set(3) if not encoded_map[6]: temp_blocks += [ snake.Block(block.width, block.x + block.width, block.y) ] encoded_map.set(6) if encoded_map[7]: if not encoded_map[4]: temp_blocks += [ snake.Block(block.width, block.x, block.width + block.y) ] if not encoded_map[6]: temp_blocks += [ snake.Block(block.width, block.x + block.width, block.y) ] encoded_map.set(6) return temp_blocks