Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

jayj
jayj
2,515 Points

Just finished the dungeon game on my own. I think I went overboard, but it works!

So I pretty much spent all day on this. I really wanted to give it a try on my own after seeing a few other users had managed to do so. So I went all out and used git as well, on my first working python script!

Then I went a bit overboard and decided on a visual map. I know it's probably unoptimized and there are likely easier ways to do a lot of these things, but I tried not to research anything new aside from .isdigit() to figure out how to tell what was an int.

I started with tuples for the dungeon and monster/door location, but the mutable/immutable types started getting me confused and causing errors. I decided to simplify it and use all lists. Comments are welcome! :)

Edit: After watching the videos describing how to build it I saw a lot of things I should have probably done different, like returns more efficiently.

# Dungeon Game made by JayJ for Teamtreehouse Python course!

import random

# Initialize some variables
dungeon, dungeon_x, dungeon_y, player_history, player_loc, monster_loc, door_loc = [], '', '', [], [], [], []

# Configuration. Allow us to choose the size of the dungeon. 3 x 1, or 1 x 3 is the minimum.
while True:
    dungeon_x = input('Please enter the width of your dungeon: [1-100]\n> ')
    dungeon_y = input('Please enter the height of your dungeon: [1-100]\n> ')
    # Check to make sure the input is an integer.
    if not dungeon_x.isdigit() or not dungeon_y.isdigit():
        print('ERROR: Only numbers are allowed!\n')
        continue
    # Convert our strings from input into actual integers
    dungeon_x = int(dungeon_x)
    dungeon_y = int(dungeon_y)
    # Error checking for dungeon X, dungeon Y and total dungeon size.
    if dungeon_x < 1 or dungeon_x > 100:
        print('ERROR: The width of the dungeon must be greater than 1 and less than 100.\n')
        continue
    elif dungeon_y < 1 or dungeon_y > 100:
        print('ERROR: The height of the dungeon must be greater than 1 and less than 100.\n')
        continue
    # Just a little error checking to make sure we have at least 3 areas.
    elif dungeon_x * dungeon_y < 3:
        print('ERROR: Board must be at least 3 areas large to play.\n')
        continue
    else:
     break

# Now we will create our dungeon.
# To create a dungeon sized by arguments, we must generate each row of the dungeon.
# In order to do this, we should start by generating a range of numbers from 0 to X and 0 to Y.
# For each X, we will loop through the entirety of y, to generate one row. We will store each row using lists.
# Once we reach the end of X, we will end the creation function.

for a in range(0, dungeon_x):
    for b in range(0, dungeon_y):
        dungeon.append((a, b))
print('\nA {} x {} dungeon has been created successfully. Board size: {}\n'.format(dungeon_x, dungeon_y, dungeon_x * dungeon_y))

# Now let's figure out our player, monster, and door location.
# We want to make sure that they are all different, or we restart.

while True:
    # Pick some random choices from the dungeon
    monster_loc = list(random.choice(dungeon))
    door_loc = list(random.choice(dungeon))
    player_loc = list(random.choice(dungeon))
    # If monster, door, or start are the same, do it again
    if monster_loc == door_loc or door_loc == player_loc or player_loc == monster_loc:
        continue
    else:
        player_history.append(player_loc[:])  # Start up our move history list
        break


# Display a visual dungeon to the player
def show_dungeon():
    buffer = '    '
    # Add numbering to top dungeon row
    for a in range(0, dungeon_x):
        if a < 9:
            buffer += str(a) + '  '
        else:
            buffer += str(a) + ' '
    print(buffer)
    buffer, buffer_icon = '', ''
    # Pull in the range of y and x to generate our columns.
    for a in range(0, dungeon_y):
        for b in range(0, dungeon_x):
            # First determine the room type and hold it for later
            if [b, a] == player_loc:
                buffer_icon = '[P]'  # Player in Room
            elif [b, a] in player_history:
                buffer_icon = '[ ]'  # Discovered Room
            else:
                buffer_icon = '[?]'  # Undiscovered Room
            # Figure out start of line by checking for x = 0, also format for longer numbers.
            if b == 0 and a < 10:
                buffer += str(a) + '  ' + buffer_icon
                # Quick fix for 1 width dungeons formatting
                if dungeon_x == 1:
                    buffer += '\n'
            elif b == 0 and a >= 10:
                buffer += str(a) + ' ' + buffer_icon
                # Quick fix for 1 width dungeons formatting
                if dungeon_x == 1:
                    buffer += '\n'
            # Find out if end of line by checking for x being equal to our max dungeon X size.
            elif b == dungeon_x - 1:
                buffer += buffer_icon + '\n'
            # If none of the above, just a normal icon
            else:
                buffer += buffer_icon
    print(buffer)
    print('Coordinates: {} : {}'.format(*player_loc))
    print('Moves taken: {}\n'.format(len(player_history) - 1))
    show_moves(player_loc[0], player_loc[1])

# Display available moves to the player
def show_moves(x, y):
    # Default moves available
    moves = ['NORTH', 'SOUTH', 'EAST', 'WEST']
    # Remove any invalid moves
    if y == 0:
        moves.remove('NORTH')
    if y == dungeon_y - 1:
        moves.remove('SOUTH')
    if x == dungeon_x - 1:
        moves.remove('EAST')
    if x == 0:
        moves.remove('WEST')
    # Print out the available moves without a bracket
    print('Available moves: {}\n'.format(', '.join(moves)))


# Handle player movement and checking
def move_player(direction, x, y):
    # Check to make sure each direction is first available, then change the player location.
    if direction == 'NORTH' and y != 0:
        player_loc[1] -= 1
    elif direction == 'SOUTH' and y != dungeon_y - 1:
        player_loc[1] += 1
    elif direction == 'EAST' and x != dungeon_x - 1:
        player_loc[0] += 1
    elif direction == 'WEST' and x != 0:
        player_loc[0] -= 1
    else:
        print('INVALID DIRECTION: Type "MAP" for available directions.')
        return  # Break this function if the move is not allowed
    # Also make sure to add the new location to the players move history.
    player_history.append(player_loc[:])
    show_dungeon()
    check_move(direction)


# Check every move to see if the player has won or lost the game.
def check_move(direction):
    # Player found the monster! :( LOSE!
    if [player_loc[0], player_loc[1]] == monster_loc:
        print("> " + direction)
        print('\n*******************************************************************')
        print('\nYou fall head first into the Monster, who first removes your head.')
        print('\nYOU LOSE')
        print('\nTotal Moves: {}'.format(len(player_history) - 1))
        print('\n*******************************************************************')
        quit()
    # Player found the door! :) WIN!
    if [player_loc[0], player_loc[1]] == door_loc:
        print("> " + direction)
        print('\n*******************************************************************')
        print('\nYou discover the door and enter, inside you find a lost treasure!')
        print('\nYOU WIN')
        print('\nTotal Moves: {}'.format(len(player_history) - 1))
        print('\n*******************************************************************')
        quit()


# Easy function to call help for the player
def show_help():
    print('\nWelcome to Dungeon Game, the goal of the game is to find the door. Watch out for the monster!\n')
    print('KEYBOARD SHORTCUTS: N(NORTH), S(SOUTH), E(EAST), W(WEST), M(MAP), H(HELP), Q(QUIT)\n')
    print('MAP LEGEND: [P] = PLAYER,  [?] = UNEXPLORED AREA, [ ] = EXPLORED AREA\n')
    show_dungeon()

# Main Game Loop and input
show_help()

while True:
    # Get a command from the player
    player_command = input('Which direction would you like to go?\n> ').upper()
    # Find the players command in a list, or return invalid.
    if player_command == 'MAP' or player_command == 'M':
        show_dungeon()
    elif player_command == 'HELP' or player_command == 'H':
        show_help()
    elif player_command == 'QUIT' or player_command == 'Q':
        print('\nThank you for playing the dungeon game!')
        exit()
    elif player_command == 'NORTH' or player_command == 'N':
        move_player('NORTH', player_loc[0], player_loc[1])
    elif player_command == 'SOUTH' or player_command == 'S':
        move_player('SOUTH', player_loc[0], player_loc[1])
    elif player_command == 'EAST' or player_command == 'E':
        move_player('EAST', player_loc[0], player_loc[1])
    elif player_command == 'WEST' or player_command == 'W':
        move_player('WEST', player_loc[0], player_loc[1])
    else:
        print('INVALID COMMAND: Type "HELP" for assistance.\n')

Going overboard is an excellent way to learn the material.