# A small text adventure in Python

I've been teaching myself programming in Python for about three months now using How To Think Like a Computer Scientist and a bit of the internet with the intention of being able to create video games someday (nothing huge, but something/stuff worth playing). What I'm looking for is an assessment on how I'm doing and if I should change anything. Here's what I made with what I've learned. It's nothing much, but I'm pretty proud for coming this far:

# Right side of room dialogue:
box_see = '\nI see a box.'
box_q = 'I think I can open this. Should I?'
box_open = '\n*box opening sounds*'
box_easy = 'I opened the box with ease.'
crowbar_get = 'A crowbar? This will help.\n'
# Left side of room dialogue:
bookshelf = "\nThere's a bookshelf."
bookshelf_q = 'Should I move it?'
boarded_hole = '\nHuh, a boarded up hole...'
pry = "Let's try to pry this wood off with the crowbar."
mallet_get = 'A mallet? Should come in handy.\n'
# Back side of room dialogue:
crack = '\nI see something in a small crack on this wall.'
crack_q = 'Should I try to get it?'
crack_complementing = '\nMaybe if I. . .'
crack_smash = '*crash*'
key_get = "A key? This could be my ticket out of here!\n"
# General dialogue:
cant = "That won't work.\n"
no_dice = '\nNothing of interest here.\n'
leave_alone = "\nI'll leave it alone for now.\n"
hand = 1
crowbar = 0
mallet = 0
key = 0

beginning()
main_hub()

def beginning():
name = input('My name is...\n')
if not name:
name = 'Not important, I guess'
name_line = ". . . {0}. (Press Enter to advance)".format(name)
else:
name_line = "it's. . . {0}. Yeah, that's right. (Press Enter to advance)".format(name)
input(name_line)
input('Hm, I have no idea how I got here.')
input('Last thing I remember was going to')
input("sleep, and now I'm here. . .")
input('*tries to open the door*')
input("What the. . .!? it's locked!")
input('Anybody out there? Help!')
input('. . .')
input("Nothing.")
input("Damn, guess I'll have to break out of here. . .\n")

def main_hub():
print('What to do. . .')
inventory()
print("(Input 'left' to look left,")
print("'right' to look right,")
print("'back' to look behind you,")
look = input("or 'door' to go to the door.)\n")
if not look:
main_hub()
elif look == 'left' or look == 'Left':
room_sides(mallet, bookshelf, bookshelf_q, crowbar, boarded_hole, pry, mallet_get)
elif look == 'right' or look == 'Right':
room_sides(crowbar, box_see, box_q, hand, box_open, box_easy, crowbar_get)
elif look == 'back' or look == 'Back':
room_sides(key, crack, crack_q, mallet, crack_complementing, crack_smash, key_get )
elif look == 'door' or look == 'Door':
game_end()
else:
main_hub()

def inventory():
if crowbar == 0:
print('Inventory: empty')
elif crowbar == 1 and mallet == 0:
print('Inventory: crowbar')
elif crowbar == 1 and mallet == 1 and key == 0:
print('Inventory: crowbar, mallet')
else:
print('Inventory: crowbar, mallet, key')

def room_sides(item_get, string1, string2, item_use, string3, string4, string5):
global crowbar
global mallet
global key
if item_get == 1:
input(no_dice)
return main_hub()
input(string1)
print(string2)
action = input('(1 for yes, 2 for no)\n')
if not action:
input(leave_alone)
main_hub()
if action == '1' and item_use == 0:
input(string3)
input(cant)
main_hub()
elif action == '2':
input(leave_alone)
main_hub()
elif action == '1' and item_use == 1:
input(string3)
input(string4)
input(string5)
if item_get == crowbar:
crowbar =+ 1
return main_hub()
elif item_get == mallet:
mallet =+ 1
return main_hub()
elif item_get == key:
key =+ 1
return main_hub()

def game_end():
global key
if key == 1:
input("\nHope this works. . .")
input('*key fits and turns perfectly, unlocking the door*')
input("Awesome, I'm free!")
input('Thanks for playing!')
else:
input("Can't do much with the door for now.\n")
main_hub()



If it helps to know, I attempt to put in at least a few hours a day of practice, and I'm not interested in working in the video game industry, so this would remain as a hobby over anything. Any input is appreciated!

The most obvious thing you are missing is any use of Python's various container types, relying instead on too many individual variables. Two examples spring immediately to mind, using the most common containers: list and dict.

## Inventory

At the moment, you are using global variables for your inventory, which is a bad sign. The function for displaying the inventory:

def inventory():
if crowbar == 0:
print('Inventory: empty')
elif crowbar == 1 and mallet == 0:
print('Inventory: crowbar')
elif crowbar == 1 and mallet == 1 and key == 0:
print('Inventory: crowbar, mallet')
else:
print('Inventory: crowbar, mallet, key')


is also somewhat awkward. Contrast this with:

def display_inventory(inventory):
print("Inventory: {0}".format(", ".join(inventory) if inventory else "empty"))


How have I made it so neat? By making inventory a list of the items your character has, e.g.:

>>> display_inventory([])
Inventory: empty
>>> display_inventory(['mallet', 'crowbar'])
Inventory: mallet, crowbar


Checking whether the user has the item needed is now the relatively clear:

if 'hammer' in inventory:


as opposed to:

if item_use == 1:


This has also removed reliance on the order in which things are collected, so if you later decide to extend your game it will be much easier.

## Rooms

Second, you have the function room_sides which gets passed lots of arguments, each corresponding to the same variables for different rooms. Compare to:

def perform_action():
choices = {1: True, 2: False}
while True:
try:
choice = int(input('(1 for yes, 2 for no)\n'))
except ValueError:
print("Not valid input")
else:
if choice in choices:
return choices[choice]
print("Not valid input")

def room_sides(room, inventory):
if room['completed']:
input('\nNothing of interest here.\n')
else:
input(room['intro'])
print(room['question'])
if perform_action():
if room['item needed'] is None or room['item needed'] in inventory:
for key in ['process', 'outcome', 'item found']:
input(room[key])
inventory.append(room['item'])
room['completed'] = True
else:
print("That won't work.\n")
else:
input("\nI'll leave it alone for now.\n")
main_hub()


Again, how have I achieved this? Firstly, using the inventory already defined, rather than the global variables. Secondly, by moving the logic required to take user input out to a separate function (you could so something similar in main_hub, too). Finally, by making each room_side a dictionary, rather than a series of variables:

side1 = {'intro': '\nI see a box.',
'question': 'I think I can open this. Should I?',
'item needed': None,
'process': '\n*box opening sounds*',
'outcome': 'I opened the box with ease.',
'item found': 'A crowbar? This will help.\n',
'item': 'crowbar',
'completed': False}


Again, note that the reliance on the collection order has been factored out - we don't care about the order items are collected in, just whether the player has what is needed right now.

• I would probably go one step further and make the room a class instance rather than a simple dictionary. If you returned the next place to go in each function you could have a loop which asked for input, handled the choice, and went to the next location. May 12 '14 at 23:19
• @SeanPerry I considered a class, but it was a big jump from where the OP was; I thought containers was a logical next step. May 12 '14 at 23:24
• I totally understand @jonrsharpe. I just wanted to mention that the path kept going without making a "me too plus more" answer. May 12 '14 at 23:35
• @SeanPerry ah, I see; and certainly agree! Thanks for the input. May 12 '14 at 23:41