Home > Back-end >  Python Text based game trouble
Python Text based game trouble

Time:06-16

I have 3 issues with my code I haven't been able to figure out.

  1. I have trouble with my code when it loops it almost always says invalid command even when its valid and even completes the movement command.

  2. I need to have the items dictionary update when the item is picked up. I have tried pop(), popitem(), and del but I still have errors when I try to pick the item up again.

  3. I can't seem to get the split to work correctly for picking up items with two words. Such as 'fire spell' or 'health potion'.

rooms = {
        'Bedroom': {'South': 'Old Living Room'},
        'Old Living Room': {'South': 'Old Office', 'East': 'Old Kitchen', 'West': 'Old Garage'},
        'Old Garage': {'East': 'Old Living Room'},
        'Old Kitchen': {'West': 'Old Living Room', 'North': 'Pulsing Room', 'South': 'Freezer Room'},
        'Old Office': {'North': 'Old Living Room'},
        'Pulsing Room': {'West': 'Dining Room', 'South': 'Old Kitchen'},
        'Freezer Room': {'North': 'Old Kitchen'},
        'Evil Lair': {'Teleported here after all items gathered'}
    }
    
story = {
    'Old Living Room': {'text': 'You enter the old living room and the bedroom door disappears behind you. You see a stick that appears to be a wand on a coffee table.'},
    'Old Garage': {'text': 'You enter an old garage. On an old moving box you see a glowing red health potion'},
    'Old Kitchen': {'text': 'You are in an old familiar kitchen. On top of the oven you see a scroll for a fire spell'},
    'Old Office': {'text': 'You are in your fathers old office. On his old desk you see a blue glowing magic shield'},
    'Pulsing Room': {'text': 'You enter an unfamiliar purple pulsing room. In the center of the room you see a portal key'},
    'Freezer Room': {'text': 'You are in a freezer room. The cold appears to be coming from a scroll that has an ice spell written on it.'},
    'Evil Lair': {'text': 'You are teleported to the Evil Lair. You see Lazarus in front of you.'}
}

items = {
    'Old Living Room': {'contents': 'Wand'},
    'Old Garage': {'contents': 'Health Potion'},
    'Old Kitchen': {'contents': 'Fire Spell'},
    'Old Office': {'contents': 'Magic Shield'},
    'Pulsing Room': {'contents': 'Portal Key'},
    'Freezer Room': {'contents': 'Ice Spell'},
    'Evil Lair': {'contents': 'Lazarus, the Demon Mage'}
}

current_room = 'Bedroom'
story_text = 'Bedroom'
item_collection = 'Old Living Room'
inventory = []

def get_next_room(current_room, direction): # Defining the next room command
    next_room = current_room
    for x in rooms:  # Creating the loop
        if x == current_room:
            if direction in rooms[x]:
                next_room = rooms[x][direction] # Assign the next room
    return next_room

def move_instructions():
    # Print the movement commands the user can use.
    print('########################################################################')
    print('#                 Text based Adventure game                            #')
    print('#        Collect 6 items to face the final boss, Lazarus!!             #')
    print('# Use movement commands North, South, East, West to move between rooms #')
    print("#           'Add to inventory: get 'item name'                         #")
    print('########################################################################\n')

move_instructions()

input('Press Enter to begin your adventure!!')

print('####################################################################################################################')
print('You awaken in your childhood room, but something is different about it. It is dark and appears that the room is \n'
      'falling apart. There are cracks in the walls the glow purple. Unsure of how you got here you stand up and look out \n'
      'the only window in the room to see you are floating through what looks like a void. As you look out the window you \n'
      'see a mysterious figure begin to come toward the window. As it gets closer you realize it is not a person but a \n'
      'monster of some sort. It has tentacles for legs, human like upper body and arms. Its head is human like with no \n'
      'hair or eyes. It comes to the window and laughs as it says “You shall never leave this place. This is my domain. \n'
      'MUHAHAHA”. The figure suddenly disappears. Your task is to gather the items to access the portal that is protecting \n'
      'the creature. To do this, you must collect the items to battle the evil demon wizard Lazarus as well as the portal key. \n'
      'You will need a wand, magic shield, a fire spell, a ice spell, a health potion, and the pulsing purple portal key. \n'
      'Once all items are collected the key will begin pulsing and teleport the player to the Evil Lair.')
print('####################################################################################################################\n')

print('You see your old childhood bedroom and a mysterious door.')  # Print current room
while True:
    print('Inventory: ', inventory)
    movement = input('What would you like to do?')  # Ask for user movement input
    movement = movement.capitalize()  # Makes first letter capital
    if movement == 'Exit':  # Exit command to end game
        print('Game ended')
        exit(0)  # Exit to end game
    if movement == 'North' or movement == 'South' or movement == 'East' or movement == 'West':  # Assign movement commands
        next_room = get_next_room(current_room, movement)  # Calls function
        if next_room == current_room:  # Used if user enters movement that
            print('There is a wall there. Try a different movement command.')
        else:
            current_room = next_room  # Move user to next room
            story_text = current_room
            print(*story[story_text].values())
    if movement.lower().split()[0] == 'get':
        item = movement.lower().split()[1]
        item_collection = current_room
        if item in [x.lower() for x in items[item_collection].values()]:
            inventory.append(item)
            print('You have obtained the', item)
        else:
            print('Invalid item')
    else:
        print('Invalid Command')  # Print if invalid movement command

CodePudding user response:

Addressing your first issue:

if movement == 'Exit':
    ...
if movement == 'North' or movement == 'South' or movement == 'East' or movement == 'West':
    ...
if movement.lower().split()[0] == 'get':
    ...
else:
    print('Invalid Command')

Let's say your command is Exit. The first if clause evaluates to True, and the contents of that stanza is executed. Your code proceeds to the next if, evaluates as false, and then moves on to the comparison if with get. This evaluates as false, so it moves to the else branch and executes that. Thus, you get an 'Invalid Command' response, even though you also execute the 'Exit' command.

It's not clear what errors you're getting with your second issue, but you're not using a dictionary - you're using a list. It's not clear that you're removing the item from the room when it is picked up. Without seeing that code or what you're doing to replace it (drop it) it's hard to know where you're going wrong.

Similarly, with your third problem, you say 'it doesn't work right' without saying what is wrong. If you have a string fire wand and .split()[1] it should give you wand. That said, what you probably want to do is split your sentence out into tokens, handling them in a sub-function and returning an object or value that you can use more clearly to manipulate the game state. For instance, a function that takes the string "get wand" and returns an object Get("wand") that has relevant methods attached to it (say, update_inventory()).

Essentially, your approach ought to be something like this:

class Command:
   ...

class Move(Command):  # Subclasses Command
   ...

class Get(Command):
   ...

def parse_command(inp: str) -> Command:
   tokens = inp.split()
   if len(tokens) == 1 and tokens[0] in ["west", "south", "north", "east"]:
       return Move(tokens[0])
   elif len(tokens) == 2 and tokens[0] is "get":
       return Get(tokens[1])
   ... # etc.

# in the game loop
inp = input("What would you like to do?")
cmd = parse_command(inp)
cmd.take_action()  # take_action() is defined individually on each class.

CodePudding user response:

There are some definite inconsistencies.

  1. I would start by making the main loop use elif. I assume only one command can be processed per input or per loop. There is no need to keep on matching. Using elif will only continue if it has not matched yet. You are also inconsistent on how you clean your input. Either capitalize always, or lower case always. Don't do both.
  2. You should consider using OO here. Each room should be an object with its own "state" (a set of properties associated with that room). When an object is collected, it should be removed from the inventory of that room and moved to the inventory of the character. If an object is discarded, the reverse should happen.
  3. use split with specified max splits...
item = movement.lower().split(' ', 1)[1]

The 1 in the split means split only once. item[0] should be the command "get". item[1] is everything after.

actually, using re.split is even better, I think...

re.split('\s ', movement.lower(), 1)

the \s is white space. With the , it matches on variable length white space. Sometimes user's will type an extra space, for example (this may be causing some of your issues). The 1, again, limits how many splits can happen.

  • Related