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

My Dungeon Game

I know there's already a ton of these out there but I just wanted to share my version of the Dungeon Game with all of the extra credit challenges expect for multiple monsters completed. Here is a snapshot of the workspace as well. If you have any questions or comments, I'd love to hear them!

import random
import os
import time


def create_cells():
    """Return a list of cells from size"""

    print("* Setup *")
    size = int(input("How big would you like the map to be?\n> "))
    return size, [(x, y) for y in range(size) for x in range(size)]


def clear_screen():
    """Clear screen function"""
    os.system('cls' if os.name == 'nt' else 'clear')


def get_locations():
    """Return locations for monster, door, player"""

    return random.sample(CELLS, 3)


def move_player(player, move):
    """Move the player and update past location"""

    player['past'].append(player['current'])
    x, y = player['current']

    if move == "LEFT":
        x -= 1
    elif move == "RIGHT":
        x += 1
    elif move == "DOWN":
        y += 1
    elif move == "UP":
        y -= 1

    player['current'] = (x, y)
    return player


def draw_map(player, monster): 
    """Draw map for players current location, past locations
    and monster's current location"""

    sep = "---".join("+" * (SIZE + 1))

    rows = [sep]
    for j in range(SIZE):
        row = "|"
        for i in range(SIZE):
            if (i, j) == monster:
                row += " M "
            elif (i, j) == player['current']:
                row += " X "
            elif (i, j) in player['past']:
                row += " . "
            else:
                row += "   "
            row += "|"
        rows.extend([row, sep])
    return "\n".join((rows))


def get_moves(player):
    """Return list of valid moves"""

    x, y = player['current']
    moves = []
    if x != 0:
        moves.append("LEFT")
    if x != (SIZE - 1):
        moves.append("RIGHT")
    if y != 0:
        moves.append("UP")
    if y != (SIZE - 1):
        moves.append("DOWN")

    return moves

def game_loop():
    """Game loop"""

    monster, door, player_loc = get_locations()

    player = {"current": player_loc, "past": []}
    playing = True
    DEBUG = False

    while playing:
        clear_screen()
        valid_moves = get_moves(player)

        print(f"** WINS: {SCORE['wins']}; LOSSES: {SCORE['losses']} **")
        print(f"You're currently in room {player['current']}")
        if DEBUG:
            print(f"Monster: {monster}, Door: {door}")

        print(draw_map(player, monster))
        print(f"You can move {', '.join(valid_moves)}")
        print("Enter QUIT to quit")
        print("Enter DEBUG to debug")


        move = input("> ").upper()

        # Quitting
        if move.startswith("Q"):
            print("\n ** See you next time! ** \n")
            break
        # Debugging
        elif move == "DEBUG":
            DEBUG = not DEBUG
        # Invalid key entry
        elif move not in VALID_MOVE_KEYS:
            print(f"\n ** Please enter one: {VALID_MOVE_KEYS} **")
            time.sleep(2)
        # Move player and monster if valid move
        elif move in valid_moves:
            player = move_player(player, move)
            monster = random.choice(CELLS)

            # Check for win/lose status
            if player['current'] == door:
                print(draw_map(player, monster))
                print("\n ** You escaped! Congratulations! :-) **\n")
                SCORE["wins"] += 1
                playing = False
            elif player['current'] == monster:
                print(draw_map(player, monster))
                print("\n ** Oh no! The monster got you! Better luck next time! :-( **\n")
                SCORE["losses"] += 1
                playing = False
        # Invalid move        
        else:
            print("\n ** Walls are hard! Don't run into them! **\n")
            time.sleep(2)
    # Prompt for re-play if game ended from win/lose
    else:
        if not input("> Play again? [Y/n] ").upper().startswith("N"):
            game_loop()


# Global variables
VALID_MOVE_KEYS = ["LEFT", "RIGHT", "DOWN", "UP", "QUIT", "DEBUG"]
SCORE = {"wins": 0, "losses": 0}
SIZE, CELLS = create_cells()

# Starting Messages
print("Welcome to the dungeon!")
input("Press return to start!\n> ")

game_loop()

1 Answer

Steven Parker
Steven Parker
243,134 Points

I don't recall if it was suggested by the instructor, but the "breadcrumbs" are a really nice touch!

And I didn't expect to see the monster when DEBUG wasn't on. That gave me the idea to also show the door. So I made "DEBUG" a global, and passed "door" (along with "monster" and "player") to "draw_map", plus made a few changes to the output:

            if DEBUG and (i, j) == monster:
                row += " M "
            elif (i, j) == player['current']:
                row += " X "
            elif DEBUG and (i, j) == door:
                row += " D "

Great job, keep up the good work, and happy coding!

Thank you! Yeah, I think my logic became flawed with the DEBUG being separate from the monster being displayed and I should combine those two ideas.

I came across this issue with setting the DEBUG variable to be global and trying to change the value of DEBUG in my game_loop function which is why I kept my DEBUG variable in the game_loop function before the while loop. Did you use the global keyword to change the value of DEBUG?

Steven Parker
Steven Parker
243,134 Points

Yes, I just added "global DEBUG" on the line right before where it is created. Alternatively, you could pass it as an argument along with "door" and the others.