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 attempt at the Dungeon Game

I tried my best to figure this out before watching Kenneth's solution, and ended up getting carried away in the process. Here are the additional features of my version:

  • Variable map size
  • Introduced a character who will guide you to himself. If you get to him, he gives you a map, but also wakes the dragon
  • Dragon will move towards player once map initiated

My code is definitely a lot more convoluted than Kenneth's. Any feedback on what I could do to improve would be greatly appreciated! What a fun challenge.

Kenneth Love

import random
import os
import sys

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

# Name your character
def name():
    char_name = input("What's your name?: ")
    return char_name

# Help text
def help():
    print("""
Your goal is to reach the door without being eaten by the dragon.
Navigate using "W" (up), "A" (left), "S" (down), "D" (right).
Type HELP to view this help again.
Enter QUIT to quit.
    """)

# Draw a grid for the dungeon using Tuples as coordinates
def DUNGEON_MAP(map_size):
    map_coordinates = []
    y_index = 1
    x_index = 1
    while y_index < map_size+1:
        while x_index < map_size+1:
            coord = (y_index, x_index)
            map_coordinates.append(coord)
            x_index += 1
        y_index += 1
        x_index = 1
    return map_coordinates

# Define locations of characters          
def locations(map_coordinates, map_size):
    coord_choices = map_coordinates
# Create a hero and place him on the map
    hero_location = random.choice(coord_choices)
    hero_y, hero_x = hero_location
    # Remove hero location from options for dragon/door/bob
    coord_choices.remove(hero_location)
# Create a dragon and place it on the map
    dragon_location = random.choice(coord_choices)
    # Remove dragon location from options for door/bob
    coord_choices.remove(dragon_location)
# Create a door and place it on the map
    door_location = random.choice(coord_choices)
    # Remove door location from options for bob
    coord_choices.remove(door_location)
# Create Bob and place him on the map
    bob_location = random.choice(coord_choices)
# Return characters
    return hero_location, dragon_location, door_location, bob_location

# Define movement functions for the character:
def move_hero(hero, move, map_size):
    # If move is "A" (left), x -1
    if move == "A":  # left
        hero_y, hero_x = hero['location']
        if hero_x - 1 < 0:
            print("You try to proceed, but a mysterious force pushes you back...")
        else:
            hero_x -= 1
            hero['location'] = (hero_y, hero_x)
            hero['x'] = hero_x
            print(immersive())
    # If move is "W" (up), y -1
    elif move == "W":  # up
        hero_y, hero_x = hero['location']
        if hero_y - 1 < 0:
            print("You try to proceed, but a mysterious force pushes you back...")
        else:
            hero_y -= 1
            hero['location'] = (hero_y, hero_x)
            hero['y'] = hero_y
            print(immersive())
    # If move is "D" (right), x +1
    elif move == "D":  # right
        hero_y, hero_x = hero['location']
        if hero_x + 1 > map_size + 1:
            print("You try to proceed, but a mysterious force pushes you back...")
        else:
            hero_x += 1
            hero['location'] = (hero_y, hero_x)
            hero['x'] = hero_x
            print(immersive())
    # If move is "S" (down), y +1
    elif move == "S":  # down
        hero_y, hero_x = hero['location']
        if hero_y + 1 > map_size + 1:
            print("You try to proceed, but a mysterious force pushes you back...")
        else:
            hero_y += 1
            hero['location'] = (hero_y, hero_x)
            hero['y'] = hero_y
            print(immersive())
    return hero

# Draw the map
def draw_map(hero, dragon, door_location, map_coordinates, map_size):

    # Prep tiles
    tile = "|{}"
    top_line_count = map_size
    while top_line_count:
        print(" _", end="")
        top_line_count -= 1
    print("")

    # Define right wall
    right_wall = []
    for coord in map_coordinates:
        x, y = coord
        if y == map_size:
            right_wall.append(coord)

    # Loop through map cells    
    # print(map_coordinates) # Uncomment if you want to see the coords of the map
    for cell in map_coordinates:
        if cell not in right_wall:
            if cell == hero['location']:
                print(tile.format("X"), end="")
            elif cell == dragon['location']:
                print(tile.format("&"), end="")
            elif cell == door_location:
                print(tile.format("D"), end="")
            else:
                print(tile.format("_"), end="")
        else:
            if cell == hero['location']:
                print(tile.format("X|"))
            elif cell == dragon['location']:
                print(tile.format("&|"))
            elif cell == door_location:
                print(tile.format("D|"))
            else:
                print(tile.format("_|"))
    print("")

# Prevent character from moving off the map
def get_moves(hero, map_size):
    moves = ["A (left)", "W (up)", "S (down)", "D (right)"]
    # if player's y is 0, remove "W" (up)
    if hero['y'] == 0:
        moves.remove("W (up)")
    # if player's y is map_size+1, remove "S" (down)
    if hero['y'] == map_size + 1:
        moves.remove("S (down)")
    # if player's x is 0, remove "A" (left)
    if hero['x'] == 0:
        moves.remove("A (left)")
    # if player's x is map_size+1, remove "D" (right)
    if hero['x'] == map_size + 1:
        moves.remove("D (right)")
    return moves

# Immersive experience
def immersive():
    return random.choice([
        "\n",
        "You stumble through the undergrowth, roots clawing at your ankles.\n",
        "The forest closes in around you, dark and foreboding.\n",
        "A jackal calls out into the night.\n",
        "The wind rattles the tree branches above your head.\n"])

# Define Bob whisper
def bob_whisper(hero, bob, dragon):
    if bob['whisper'] == True:
        if bob['location'] == hero['location']:
            bob_encounter(hero, bob, dragon)
        elif hero['x'] > bob['x']:
            print("A voice whispers on the breeze: 'go left...'")
        elif hero['x'] < bob['x']:
            print("A voice whispers on the breeze: 'go right...'")
        elif hero['y'] > bob['y']:
            print("A voice whispers on the breeze: 'head north...'")
        elif hero['y'] < bob['y']:
            print("A voice whispers on the breeze: 'head south...'")

# Define Bob encounter
def bob_encounter(hero, bob, dragon):
    clear_screen()
    print("""
You break into a clearing and find Bob, your inexplicably
magical friend who went missing a few months ago.

Bob stares at you strangely...
    """)
    input("""Get his attention:

> """)

    clear_screen()
    print("""
'Oh, {}! I almost didn't recognize you. So you got
stuck in these woods too, huh?'

Bob grins and produces a wand from his khaki shorts.

'Well, fear not! I can light your way...'

Bob waves his wand.
""".format(hero['name']))
    bob['whisper'] = False
    input("> ")
    clear_screen()
# Generate map    
    print("""
'There you go. Just find your way to the village and
you'll be okay.'

A rumble seems to come from Bob's stomach.

'Uh oh...'

Bob looks uncomfortable. 'You might want to move
quickly. There's a dragon in these woods, and...'

Bob shifts from toe to toe, avoiding eye contact.

'Well, I might have accidentally just woken him up
with my magic. And accidentally locked his killing
senses onto your location. But don't worry! I'm sure
you won't come to harm...

You should probably leave my clearing now. See you around!'
""")

# Initiate dragon movement
    dragon['active'] = True
    return bob, dragon

# Define dragon movement
def dragon_move(dragon, hero):
    direction = random.choice([1,2])
    dragon_y, dragon_x = dragon['location']
    if direction == 1 and dragon['x'] > hero['x']:
        dragon['x'] = dragon_x -1
        dragon['location'] = (dragon_y, dragon_x -1)
    elif direction == 1 and dragon['x'] < hero['x']:
        dragon['x'] = dragon_x +1
        dragon['location'] = (dragon_y, dragon_x +1)
    elif direction == 2 and dragon['y'] < hero['y']:
        dragon['y'] = dragon_y +1
        dragon['location'] = (dragon_y +1, dragon_x)
    elif direction == 2 and dragon['y'] < hero['y']:
        dragon['y'] = dragon_y -1
        dragon['location'] = (dragon_y -1, dragon_x)
    else:
        print("The dragon roars, chilling your feeble, snappable, flame-grillable bones.")
        print("")

# Game start

while True:
    try:
        map_size = int(input("How big do you want to go? (Enter a number from 5 to 10): "))
        break
    except ValueError:
        print("Please enter a number.")
map_coordinates = DUNGEON_MAP(map_size)
# print(DUNGEON_MAP(map_size)) # Uncomment if you want to see the coords of the map
coord_choices = map_coordinates[:]
hero_location, dragon_location, door_location, bob_location = locations(coord_choices, map_size)
# The following lines can be uncommented for debugging purposes:
# print("Hero is at {}".format(hero_location))
# print("Dragon is at {}".format(dragon_location))
# print("Door is at {}".format(door_location))
# print("Bob is at {}".format(bob_location))

# Create dictionaries for characters
hero_y, hero_x = hero_location
hero = {'name': {}, 'x': hero_x,'y': hero_y, 'location': hero_location}
hero['name'] = name()
bob_y, bob_x = bob_location
bob = {'x': bob_x, 'y': bob_y, 'location': bob_location, 'whisper': True}
dragon_y, dragon_x = dragon_location
dragon = {'x': dragon_x, 'y': dragon_y, 'location': dragon_location, 'active': False}

# Clear screen and display intro help
clear_screen()
print("Nice to meet you, {}.".format(hero['name']))
help()
print("Press ENTER to begin.")
response = input("> ")
if response == "QUIT":
        quit()
clear_screen()
print("Okay, let's go!")
print("""
You wake up in a dark forest.
""")

# Core game loop
while True:

    # Define loss if character stumbles onto dragon
    if hero['location'] == dragon['location']:
        print("""You hear a loud noise, like a car being crushed in a junkyard.

A big shadow comes over your head...

You see a flash of teeth.


You got ate!
        """)
        break
    # Define win if character finds door
    elif hero['location'] == door_location:
        print("""You stagger, gasping for breath, round a tree.

There's light in the distance...

You move closer.

You push past an overgrown bush, jump over a
fallen oak, and emerge onto a lush, moonlit field.


You escaped the forest!
        """)
        break
    else:
        # Define near miss
        dragon_x, dragon_y = dragon['location']
        if hero['location'] == (dragon_x + 1, dragon_y) or hero['location'] == (dragon_x - 1, dragon_y) or hero['location'] == (dragon_x, dragon_y + 1) or hero['location'] == (dragon_x, dragon_y -1):
            print("""An unholy screech pierces the stillness, sending chills down your spine.

Is that fire you see in the distance?
            """)
        # Get hero's new location
        if dragon['active'] == True:
            draw_map(hero, dragon, door_location, map_coordinates, map_size)
        else:
            print("You are at {}.".format(hero['location']))
        print("You can move {}.".format(get_moves(hero, map_size)))
        print("")
        bob_whisper(hero, bob, dragon)

        # Tee up next move
        moves = ["A", "W", "S", "D"]
        move = input("> ")
        move = move.upper()
        clear_screen()
        if move == "QUIT":
            break
        elif move == "HELP":
            help()
        else:
            if move in moves:
                move_hero(hero, move, map_size)
                # Move dragon
                if dragon['active'] == True:
                    dragon_move(dragon, hero)
            else:
                print("You spin around in place, going a little crazy. Get it together, {}!".format(hero['name']))
                print("")
Jeff Muday
Jeff Muday
Treehouse Moderator 28,732 Points

This is very cool. The additional features are impressive. I wouldn't call your code "convoluted" at all, you included lots of thoughtful comments so anyone who wants to fork your code would know where to make modifications.

You may want to try your hand at refactoring your code to add a graphical user interface like PyGame!

http://www.pygame.org/

Thanks Jeff! Very kind of you to say. I will check out PyGame.

Really good game!!. Your code is very organised and easy to understand. I will try my own version with yours as a reference. Thanks very much!

2 Answers

I'm also very impressed

Thank you!

Impressive! It's a very interesting and fun short little game :)