From b8ba772993560a0c3438b1423fe44a680fa0ec5e Mon Sep 17 00:00:00 2001 From: Sean Sawyer Date: Wed, 9 Oct 2019 23:40:27 -0400 Subject: [PATCH] Procedurally-generated map and a smidge of color --- pmrl.py | 112 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/pmrl.py b/pmrl.py index c31ebb9..5aef7be 100644 --- a/pmrl.py +++ b/pmrl.py @@ -9,59 +9,80 @@ class Coordinates(NamedTuple): x: int y: int -map_s = [ - '##########', - '#........#', - '#........#', - '#........#', - '#........#', - '#........#', - '#........#', - '#........#', - '#........#', - '##########', -] -map = [list(r) for r in map_s] -map_width = len(map[0]) -map_height = len(map) +screen_width = 80 +screen_height = 50 +map_width = screen_width +map_height = screen_height - 2 + +def generate_map(): + # start with all walls + map_tiles = [['#'] * map_width for y in range(map_height)] + # choose a random starting point + x = random.randint(1, map_width - 2) + y = random.randint(1, map_height - 2) + # walk in a random direction + possible_moves = [ + (0, -1), # up + (0, 1), # down + (-1, 0), # left + (1, 0), # right + ] + map_tiles[y][x] = '.' + for i in range(10000): + choice = random.randint(0, len(possible_moves) - 1) + dx, dy = possible_moves[choice] + if 0 < x + dx < map_width - 2 and 0 < y + dy < map_height - 2: + x = x + dx + y = y + dy + map_tiles[y][x] = '.' + return map_tiles + def is_mob(coords: Coordinates, mobs_coords: List[Coordinates]): return coords in mobs_coords -def is_wall(coords: Coordinates, map_coords: Coordinates): +def is_wall(coords: Coordinates, map_tiles: List[List[str]]): # Is it even in the map? - if not map_coords.x <= coords.x < map_coords.x + map_width: + if not 0 <= coords.x < map_width: return True - if not map_coords.y <= coords.y < map_coords.y + map_height: + if not 0 <= coords.y < map_height: return True # Is it a wall tile? - tile = map[coords.y][coords.x] + tile = map_tiles[coords.y][coords.x] return tile == '#' def draw_status( - map_coords: Coordinates, + status_y: Coordinates, player_hp: int ): msg = f'HP: {player_hp:2}' - libtcod.console_print(0, 0, map_coords.y + map_height, msg) + libtcod.console_set_default_foreground(0, libtcod.blue) + libtcod.console_print(0, 0, status_y, msg) + libtcod.console_set_default_foreground(0, libtcod.white) def draw_map( - map_coords: Coordinates, + map_tiles: List[List[str]], exit_coords: Coordinates, player_coords: Coordinates, mobs_coords: List[Coordinates] ): - y = map_coords.y - for row in map: - x = map_coords.x + y = 0 + for row in map_tiles: + x = 0 for tile in row: + color = libtcod.white if x == player_coords.x and y == player_coords.y: tile = '@' + color = libtcod.yellow elif Coordinates(x, y) in mobs_coords: tile = 'o' + color = libtcod.red elif x == exit_coords.x and y == exit_coords.y: tile = '<' + color = libtcod.green + libtcod.console_set_default_foreground(0, color) libtcod.console_put_char(0, x, y, tile, libtcod.BKGND_NONE) + libtcod.console_set_default_foreground(0, libtcod.white) x += 1 y += 1 @@ -84,22 +105,35 @@ def keypress_to_command(key: libtcod.Key): return key_char_command_map.get(chr(key.c), {}) return key_vk_command_map.get(key.vk, {}) +def choose_random_open_tile(map_tiles: List[List[str]], occupied_coords: List[Coordinates]): + coords = None + tile = '#' + while tile != '.' and coords not in occupied_coords: + x = random.randint(1, map_width - 2) + y = random.randint(1, map_height - 2) + tile = map_tiles[y][x] + coords = Coordinates(x, y) + occupied_coords.append(coords) + return coords + def main(): - screen_width = map_width - screen_height = map_height + 2 - map_coords = Coordinates(0, 0) - exit_coords = Coordinates(8, 8) + map_tiles = generate_map() + # pick a random tile to place the exit + occupied_coords = [] + exit_coords = choose_random_open_tile(map_tiles, occupied_coords) mobs_coords = [ - Coordinates(3, 4), - Coordinates(6, 5), - Coordinates(2, 7), + choose_random_open_tile(map_tiles, occupied_coords), + choose_random_open_tile(map_tiles, occupied_coords), + choose_random_open_tile(map_tiles, occupied_coords), ] mobs_hp = [ 5, 4, 3, ] - player_coords = Coordinates(1, 1) + # pick a random tile to place the player + tile = '#' + player_coords = choose_random_open_tile(map_tiles, occupied_coords) player_hp = 10 libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GRAYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'pmrl', False) @@ -115,13 +149,15 @@ def main(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse) libtcod.console_set_default_foreground(0, libtcod.white) # update the screen - draw_map(map_coords, exit_coords, player_coords, mobs_coords) - draw_status(map_coords, player_hp) + draw_map(map_tiles, exit_coords, player_coords, mobs_coords) + draw_status(map_height, player_hp) libtcod.console_flush() # endgame sequence if dying or winning: - msg_y = map_coords.y + map_height + 1 + msg_y = map_height + 1 msg = 'You win!' if winning else 'You die.' + color = libtcod.green if winning else libtcod.red + libtcod.console_set_default_foreground(0, color) libtcod.console_print(0, 0, msg_y, msg) libtcod.console_flush() running = False @@ -154,7 +190,7 @@ def main(): mobs_hp[mob_i] -= 1 if mobs_hp[mob_i] == 0: dead_mobs.add(mob_i) - elif not is_wall(new_mob_coords, map_coords): + elif not is_wall(new_mob_coords, map_tiles): # check if it's another mob try: is_other_mob = mob_i == mobs_coords.index(new_mob_coords) @@ -173,7 +209,7 @@ def main(): try: mob_i = mobs_coords.index(new_player_coords) except ValueError: - if not is_wall(new_player_coords, map_coords): + if not is_wall(new_player_coords, map_tiles): player_coords = new_player_coords else: player_hp -= 1