def set_map_size(self, width, height): if isinstance(width, int) and isinstance(height, int): if width < 2: width = 2 elif width > 119: width = 119 if height < 2: height = 2 elif height > 30: height = 30 self.map_size = [width, height] my_logger.debug("Map size has been stored successfully") return True else: my_logger.error("Wrong size type! Please, check the input") return False
def generate_map(self): width = self.map_size[0] height = self.map_size[1] cells_count = width * height treasures_count = ceil((cells_count) / 20) trap_count = ceil((cells_count) / 10) my_logger.debug("Traps and treasures quantity has been calculated") my_logger.debug("Generating map...") self.dungeon_map = ['T' for x in range(0, treasures_count)] self.dungeon_map.extend(['X' for x in range(0, trap_count)]) self.dungeon_map.extend([ '-' for x in range(0, cells_count - treasures_count - trap_count) ]) shuffle(self.dungeon_map) self.dungeon_map = [ self.dungeon_map[x * width:x * width + width] for x in range(0, height) ]
def setup_game(self): """ Game startup method: user should choose between playing new game or loading save """ my_logger.debug("Game start choice") start_game_choice = input( 'Enter "y" if you want to play a new game or\n"load" if you want to load existing game:\n' ) my_logger.debug("Game start choice handling") if start_game_choice == "load": try: self.load_game() except (FileNotFoundError, pickle.UnpicklingError) as file_error: my_logger.exception(file_error) if isinstance(file_error, FileNotFoundError): my_logger.error( "There is no dungeon.sav file! Start a new game instead!" ) elif isinstance(file_error, pickle.UnpicklingError): my_logger.error( "dungeon.sav file is corrupted! Start a new game instead!" ) self.setup_new_game() else: self.setup_new_game() self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map() self.is_game_ongoing = True self.enemy_last_position = [self.enemy.enemy_x, self.enemy.enemy_y] self.enemy_thread = threading.Thread(target=self.enemy_update) self.enemy_thread.start()
def setup_game(self): """ Game startup method: user should choose between playing new game or loading save """ my_logger.debug("Game start choice") start_game_choice = input( 'Enter "y" if you want to play a new game or\n"load" if you want to load existing game:\n' ) my_logger.debug("Game start choice handling") if start_game_choice == "load": self.load_game() else: map_request = input( 'Enter preferable map size in format "width:height", or just press enter to play with default map:\n' ) my_logger.info("Generating map...") if not len(map_request): map_size = [20, 10] else: map_size = [int(token) for token in map_request.split(':')] self.dungeon_map.set_map_size(*map_size) self.dungeon_map.generate_map() my_logger.info("Map has been generated successfully!") self.player_map.set_map_size(*map_size) self.player_map.init_map() self.player.reset() self.player.randomize_initial_position(self.dungeon_map) self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map()
def randomize_initial_position(self, dungeon_map): my_logger.debug("Trying to find empty place for palyer...") while True: self.player_x = randint(0, dungeon_map.map_size[0] - 1) self.player_y = randint(0, dungeon_map.map_size[1] - 1) if dungeon_map.get_cell_content(self.player_y, self.player_x) != '-': continue else: break my_logger.debug("Empty place for palyer has been found") return None
def set_map_size(self, width, height): if isinstance(width, int) and isinstance(height, int): try: if width < 5: raise MapSizeError("", width, height) width = 5 elif width > 119: raise MapSizeError("", width, height) width = 119 elif height < 5: raise MapSizeError("", width, height) height = 5 elif height > 30: raise MapSizeError("", width, height) height = 30 except MapSizeError as map_size_error: my_logger.exception(map_size_error) my_logger.error("Map size will be resetted to default value!") self.reset_map_size() return False self.map_size = [width, height] my_logger.debug("Map size has been stored successfully") return True else: my_logger.error("Wrong size type! Please, check the input") return False
def randomize_initial_position(self, dungeon_map): """ Enemy position randomize. Used at start and after biting player """ my_logger.debug("Trying to find empty place for enemy...") while True: self.enemy_x = randint(0, dungeon_map.map_size[0] - 1) self.enemy_y = randint(0, dungeon_map.map_size[1] - 1) if dungeon_map.get_cell_content(self.enemy_y, self.enemy_x) != '-': continue else: break my_logger.debug("Empty place for enemy has been found") return None
def spawn_player(width, height, dungeon_map): """ Parameters corresponds to map size """ my_logger.debug("Trying to find empty place for palyer...") while True: player_x = randint(0, width - 1) player_y = randint(0, height - 1) if dungeon_map[player_y][player_x] != '-': continue else: break my_logger.debug("Empty place for palyer has been found") return [player_x, player_y]
def update_map(self, real_map, player_x, player_y): my_logger.debug("Checking for wall near player...") min_row_index = player_y - 1 if player_y - 1 > 0 else 0 max_row_index = player_y + 2 if player_y + 1 < self.map_size[ 1] else self.map_size[1] row_range = range(min_row_index, max_row_index) min_column_index = player_x - 1 if player_x - 1 > 0 else 0 max_column_index = player_x + 2 if player_x + 1 < self.map_size[ 0] else self.map_size[0] column_range = range(min_column_index, max_column_index) my_logger.debug("Wall check done") my_logger.debug("Checking for treasures and traps around") is_treasure = False is_trap = False for y in row_range: for x in column_range: if real_map.get_cell_content(x, y) == 'T': is_treasure = True elif real_map.get_cell_content(x, y) == 'X': is_trap = True if is_treasure and is_trap: cell_filler = '!' elif is_treasure: cell_filler = 't' elif is_trap: cell_filler = 'x' else: cell_filler = '-' my_logger.debug("Treasures and traps check done") my_logger.debug("Making output for player") for y in row_range: for x in column_range: if self.dungeon_map[y][x] == '@': self.dungeon_map[y][x] = '-' elif not self.dungeon_map[y][x] == '-': self.dungeon_map[y][x] = cell_filler self.dungeon_map[player_y][player_x] = '@' if is_treasure: my_logger.info('There is a treasure!') elif is_trap: my_logger.info('There is a trap!') my_logger.debug("Player output finished") return None
from dungeon_game import Game from dungeon_logger import my_logger game_instance = Game() while True: game_instance.setup_game() while game_instance.run_farame(): pass decision = input('Do you want to play again? y/n:\n') if decision == 'y': my_logger.debug("Restarting game") continue else: my_logger.debug("Abandoning game") break
def dungeon_map_generator(width=20, height=10): """ Generates random map with at least 10% cells occupied with traps and 5% with treasures. Rounding quantity of special cells performed to higher value (ceil) """ my_logger.debug("Checking correctness of input...") if not (isinstance(width, int) and isinstance(height, int)): my_logger.info( 'Wrong cell size! Width and height should be positive integers\n') return None if width < 2: width = 2 elif width > 119: width = 119 if height < 2: height = 2 elif height > 30: height = 30 my_logger.debug("Input check done") my_logger.debug("Calculating amount of traps and treasures...") cells_count = width * height treasures_count = ceil((cells_count) / 20) trap_count = ceil((cells_count) / 10) my_logger.debug("Traps and treasures quantity has been calculated") my_logger.debug("Generating map...") dungeon_map = ['T' for x in range(0, treasures_count)] dungeon_map.extend(['X' for x in range(0, trap_count)]) dungeon_map.extend( ['-' for x in range(0, cells_count - treasures_count - trap_count)]) shuffle(dungeon_map) dungeon_map = [ dungeon_map[x * width:x * width + width] for x in range(0, height) ] my_logger.debug("Map has been generated") return dungeon_map
def make_move(self, move_direction, width, height): """ Used to change coordinates of enemy A little bit redundant method, however clear enough. Enemy moves in any case, through repelling from walls if the way has been blocked by the wall """ if move_direction == 'w': if self.enemy_y > 0: self.enemy_y -=1 my_logger.debug('Enemy have moved up') else: self.enemy_y +=1 my_logger.debug('Enemy have moved down') elif move_direction == 'd': if self.enemy_x < width - 1: self.enemy_x +=1 my_logger.debug('Enemy have moved right') else: self.enemy_x -=1 my_logger.debug('Enemy have moved left') elif move_direction == 's': if self.enemy_y < height - 1: self.enemy_y +=1 my_logger.debug('Enemy have moved down') else: self.enemy_y -=1 my_logger.debug('Enemy have moved up') elif move_direction == 'a': if self.enemy_x > 0: self.enemy_x -=1 my_logger.debug('Enemy have moved left') else: self.enemy_x +=1 my_logger.debug('Enemy have moved right') return None
from game_functions import game_loop from dungeon_logger import my_logger from dungeon_logger import log_decorator while True: my_logger.debug("Entering main game function") game_loop() my_logger.debug("Main game function has finished") decision = input('Do you want to play again? y/n:\n') if decision == 'y': my_logger.debug("Restarting game") continue else: my_logger.debug("Abandoning game") break
def check_around(player_x, player_y, map_size, dungeon_map, player_map): """ This function performs check for treasures/traps in surrounding cells """ is_treasure = False is_trap = False my_logger.debug("Checking for wall near player...") min_row_index = player_y - 1 if player_y - 1 > 0 else 0 max_row_index = player_y + 2 if player_y + 1 < map_size[1] else map_size[1] row_range = range(min_row_index, max_row_index) min_column_index = player_x - 1 if player_x - 1 > 0 else 0 max_column_index = player_x + 2 if player_x + 1 < map_size[ 0] else map_size[0] column_range = range(min_column_index, max_column_index) my_logger.debug("Wall check done") my_logger.debug("Checking for treasures and traps around") for y in row_range: for x in column_range: if dungeon_map[y][x] == 'T': is_treasure = True elif dungeon_map[y][x] == 'X': is_trap = True if is_treasure and is_trap: fill_cells = '!' elif is_treasure: fill_cells = 't' elif is_trap: fill_cells = 'x' else: fill_cells = '-' my_logger.debug("Treasures and traps check done") my_logger.debug("Making output for player") for y in row_range: for x in column_range: if not player_map[y][x] == '-': player_map[y][x] = fill_cells player_map[player_y][player_x] = '@' for row in player_map: my_logger.info("".join(row)) if is_treasure: my_logger.info('There is a treasure!') elif is_trap: my_logger.info('There is a trap!') my_logger.debug("Player output finished") return (is_treasure, is_trap)
def game_loop(): """ Main game function contains game loop and some surrounding stuff """ my_logger.debug("Game start choice") start_game_choice = input( 'Enter "y" if you want to play a new game or\n"load" if you want to load existing game:\n' ) my_logger.debug("Game start choice handling") if start_game_choice == "load": my_logger.info("Loading game...") in_file = open('dungeon.sav', 'rb') data = pickle.load(in_file) game_map = data[0] player_map = data[1] player_position = data[2] map_size = data[3] my_logger.info("Game has been loaded!") else: map_request = input( 'Enter preferable map size in format "width:height", or just press enter to play with default map:\n' ) my_logger.info("Generating map...") if not len(map_request): map_size = [20, 10] else: map_size = [int(token) for token in map_request.split(':')] game_map = dungeon_map_generator(*map_size) player_map = [['?' for x in range(0, map_size[0])] for y in range(0, map_size[1])] player_position = spawn_player(*map_size, game_map) my_logger.info("Map has been generated successfully!") my_logger.debug("Checking around...") check_around(*player_position, map_size, game_map, player_map) my_logger.debug("Check around has been done") my_logger.debug("Entering main game loop...") while True: move = input( '\nEnter your move, please (w - up, d - right, s - down, a - left), or "save" for save game:\n' ) if move == "save": data = [game_map, player_map, player_position, map_size] out_file = open('dungeon.sav', 'wb') pickle.dump(data, out_file) break player_map[player_position[1]][player_position[0]] = '-' make_move(move, player_position, map_size) check_around(*player_position, map_size, game_map, player_map) if game_map[player_position[1]][player_position[0]] == 'T': my_logger.info("\n>>>This is a treasure! You are victorious!<<<\n") break elif game_map[player_position[1]][player_position[0]] == 'X': my_logger.info("\n}}}This is a trap! You loose!{{{\n") break else: continue my_logger.debug("Main game loop has stopped") my_logger.debug("Printing game map...") for row in game_map: my_logger.info("".join(row)) my_logger.debug("Game map has been printed")