def __init__(self, filename): """ Initialise maze The Maze object has given attributes: :var bool status: False = End of game (file error, end of game or quit) :var int COL_NB: column number of the maze :var int RANGE: string range :var int MAX_ITEMS: number of items :var str string: contain maze without EOL in astring :param filename: maze filename """ # Loading maze file if os.path.isfile(filename) is False: self.status = False print(ERR_FILE.format(filename)) else: with open(filename, "r") as maze_data: splited_maze = maze_data.read().splitlines() if self.check_file(splited_maze): # Builds a square maze (end-line spaces are missing in file) self.string = '\n'.join( (self.check_line(line) for line in splited_maze)) # Place randomly 'item' on the maze for symbol_to_place in elmt_val('symbol', 'item', True): position = random.choice([ idx for (idx, value) in enumerate(self.string) if value == elmt_val('symbol', 'name', 'floor', 0) ]) self.set_symbol(symbol_to_place, position) self.MAX_ITEMS = sum(1 for _ in elmt_val('name', 'item', True)) self.COL_NB = MAZE_SIZE + 1 # List starts to zero self.RANGE = range(self.COL_NB * MAZE_SIZE - 1) # remove last EOL self.status = True else: self.status = False
def update(self, player): """ Updates GUI after a move :param obj player: a Player object """ changed_tiles = [ (elmt_val('tile', 'symbol', player.ground, 0), player.old_position), (elmt_val('tile', 'name', 'player', 0), player.current_position), ] [ self.blit(tile[0], self.coord_from_index(tile[1])) for num, tile in enumerate(changed_tiles) if None not in tile ] # Refresh pygame.display.flip()
def check_line(line): """ Checks if a line has a good length (configured in MAZE_SIZE const). Fill it if it's too small, truncate if it's too long. """ differance = MAZE_SIZE - len(str(line)) if differance < 0: return line[:MAZE_SIZE] elif differance > 0: return line + (differance * elmt_val('symbol', 'name', 'floor', 0)) else: return line
def __init__(self, maze): """ Creates a player in the given maze :param obj maze: Maze object """ self.maze = maze self.current_position = maze.string.find( elmt_val('symbol', 'name', 'player', 0)) self.old_position = None # Element under player, default 'floor' self.ground = elmt_val('symbol', 'name', 'floor', 0) # Colleted items self.stock = [] self.stock_num = 0 # Contextual messages to display on each turn self.status_message = {} self.status_message['title'] = HEAD_MESSAGES['title'] self.status_message['status'] = HEAD_MESSAGES['status'] self.status_message['items'] = HEAD_MESSAGES['items'].format( self.stock_num, maze.MAX_ITEMS)
def draw(self, maze, messages): """ Take a maze string and generate a graphic maze :param obj maze: a Maze object :param list/str messages: list of messages for header """ for cell, element in enumerate(maze.string.replace('\n', '')): img = elmt_val('tile', 'symbol', element, 0) x = (cell % MAZE_SIZE) * CELL_SIZE y = (cell // MAZE_SIZE) * CELL_SIZE + HEAD_SIZE_H if img is False: self.blit(UNKNOWN_FILE, (x, y)) else: self.blit(img, (x, y)) self.set_header(messages) # Refresh pygame.display.flip()
def move_to(self, next_position): """ Next position treatment For each movement, it checks the next symbol on the maze and apply the corresponding rule: - set the new position - updates messages - collect item (if any) - set symbol of the leaved position - stop the game (win or lose) :param int next_position: index in self.maze.string """ # in the string range if next_position in self.maze.RANGE: next_symbol = self.maze.string[next_position] self.old_position = self.current_position # 'floor' element if next_symbol == elmt_val('symbol', 'name', 'floor', 0): self.current_position = next_position self.status_message['status'] = MSG_OK # 'item' element elif next_symbol in elmt_val('symbol', 'item', True): self.current_position = next_position self.stock.append(elmt_val('name', 'symbol', next_symbol, 0)) self.stock_num += 1 self.status_message['status'] = MSG_COLLECT.format( elmt_val('name', 'symbol', next_symbol, 0)) self.status_message['items'] \ = HEAD_MESSAGES['items'].format( self.stock_num, self.maze.MAX_ITEMS ) # 'guard' element elif next_symbol == elmt_val('symbol', 'name', 'guard', 0): self.maze.status = False # all 'item' are collected : player wins if sorted(self.stock) == sorted(elmt_val('name', 'item', True)): self.status_message['status'] = MSG_WINNER # player lose else: missed_item_flist = ', '.join( (item for item in elmt_val('name', 'item', True) if item not in self.stock)) self.status_message['status'] = MSG_LOSER.format( missed_item_flist) # for all other element (wall or nline) else: self.status_message['status'] = MSG_WALL self.old_position = None # out the string range else: self.status_message['status'] = MSG_WALL self.old_position = None # Replaces player symbol in maze.string by 'ground' value self.maze.string = self.maze.string.replace( elmt_val('symbol', 'name', 'player', 0), self.ground) # Sets the player's new position in maze.string self.maze.set_symbol(elmt_val('symbol', 'name', 'player', 0), self.current_position)