HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

A small text adventure in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
textsmallpythonadventure

Problem

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 = '\nbox 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

def main_adventure():
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('. . .')

Solution

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.

Code Snippets

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 display_inventory(inventory):
    print("Inventory: {0}".format(", ".join(inventory) if inventory else "empty"))
>>> display_inventory([])
Inventory: empty
>>> display_inventory(['mallet', 'crowbar'])
Inventory: mallet, crowbar
if 'hammer' in inventory:
if item_use == 1:

Context

StackExchange Code Review Q#49415, answer score: 4

Revisions (0)

No revisions yet.