0

I have started development on a text-based adventure game. The environment behaves like a Sierra game, but there's no graphic interface and all commands are text.

Currently, any objects in the game (such as characters, rooms, items, etc) are defined by a dictionary. The keys are the name of the data value (name, description, etc) like this:

flash_light={
'name':'Flashlight',
'desc':'A flashlight, probably belonging to an eningeer on the ship.',
'consumable':False
}

The player's inventory and the global inventory are dictionaries where the key is the 'codename' string to call the item by, and the item is the dictionary referencing it. If you wanted to, say, take an item you found in the room, the dictionary of the room has a property that tracks the inventory of the room as a list. This list contains strings that are 'codenames' for the items in it.

my_room={
'name':'My Room',
'codename':'my_room',
'desc':'A hot, stuffy room shared with 3 other passengers. My trunk is   here.\
The door is on the NORTH wall.',
'access':True,
'direc':{'north':'st_hall_1'},
'inven':['flashlight']
}

After the command has decided the item you asked to take is actually IN the room, it runs:

current_pos.inven().remove(target)
player_inv.update({target:global_inv[target]})

These lines remove the string from the room's inventory list, then add a key and item to the player's inventory dictionary. The key is the string name of the object you tried to take, and the item is defined as the dictionary in the GLOBAL inventory at the string name.

The reason I have so many calls around the program is that I kept running into problems when I gave dictionaries references to other dictionaries (i.e. A room has a list of the rooms it connects to), and those dictionaries may not be defined yet. I kept the functions as general as possible, and use the string-to-call-a-dict thing to avoid giving something undefined names as a parameter.

My main question is this: How could I make this more efficient, if possible? Or, the way I built the system, would it take major restructuring to improve?

DankHill
  • 5
  • 3
  • 1
    My only suggestion would be to make your objects and rooms into classes, so that you could tie the code to update them to the objects directly. – Blckknght Oct 29 '15 at 19:15

1 Answers1

0

You should use classes instead of dicts. Start by making a generic item class that looks something like that:

class Item(object):
    def __init__(self, name, codename, description, is_consumable):
        self._name = name
        self._description = description
        self._is_consumable = is_consumable

And then create a class for each type of item:

class Flashlight(Item):
    def __init__(self, codename):
        super(Flashlight, self).__init__('Flashlight', codename,
            'A flashlight, probably belonging to an eningeer on the ship', False)

Consider creating a separate item for consumables which has a consume() method that processes the consumption of the item.

Create a Room class that looks something like that:

class Room(object):
    def __init__(self, name, codename, description, access, directions, inventory):
        self._name = name
        self._codename = codename
        self._description = description
        self._access = access
        self._directions = directions.copy()
        self._inventory = inventory[:]

I used copy in the definition of self._directions and [:] in the definition of self._inventory to create a copy of each object, instead of using the original.

Instantiate it for each room you want.

my_room = Room('My Room', 'my_room', 
'A hot, stuffy room shared with 3 other passengers. My trunk is here. The door is on the NORTH wall.',
True, {'north': 'st_hall_1'}, [Flashlight('flashlight')])

And then you could add methods that enable the players to do whatever the game allows them to do inside the room. You should also create a Character class, a Player class and so on.

So classes are the key to making your game more efficient. Instead of including all the game's logic inside the same function (or a few of them), each class should contain its own things.

EDIT: Now that I see your code, there are some things you can do to make it better: In your "main", use a function-dict that just picks the right action according to the command instead of a long chain of if statements (also, you did it without using else! that means that each of those statements is still evaluated after the action has been taken), like this: https://softwareengineering.stackexchange.com/questions/182093/why-store-a-function-inside-a-python-dictionary Your classes only contain getter functions, which can be defined using the @property decorator (How does the @property decorator work?)

In your room definitions you can clearly see how classes are better: instead of writing the same fields over and over again (and hoping you didn't have a typo anywhere), you could just instantiate them using the class you've defined. The same goes for the item definitions. You could also create a consume() method, which applies whatever effect the specific consumable has, use() for usables (such as your flashlight and screwdriver), etc.

Community
  • 1
  • 1
  • That's more or less a faster way to do what I did. I DO use classes, and mostly in the same manner, it's just when I call Room, I call it upon a dictionary of data. If I understand, you suggest make an item class, then make classes which are OF TYPE item. Then for rooms, instead of the class functions referencing the dictionaries, just define a room as class room, which has been passed the data it needs? Also, I am unclear on what the .copy() is supposed to do. Finally, would you like a pastebin of the current code? I just want to be sure my explanation actually explains the program. – DankHill Oct 30 '15 at 01:37
  • The main reason I suggested you to use classes is that classes can have methods to contain the logic of their operation. I did not specify any method in my examples, because I didn't know what kind of operations can be performed on general items or rooms in your game. But now that I think of it, a `toggle` function in class Flashlight could be a good example. And yes, a pastebin could help me to better understand your game. – SwedishOwlSerpent Oct 30 '15 at 05:32
  • http://pastebin.com/jSyAridz is the program as of now. Also, I appreciate the help. I mean, it is what I came for, but really, thanks. If you need anything clarified, I can oblige. – DankHill Oct 30 '15 at 08:42
  • Alright, I've edited my answer after going through the code. Hope that helps. – SwedishOwlSerpent Oct 30 '15 at 12:14
  • But again though, what would the .copy() function be for? – DankHill Oct 30 '15 at 21:09
  • In order not to reference the original object, but create a copy of it. It's good practice to do so. – SwedishOwlSerpent Oct 31 '15 at 16:14
  • For traveling between rooms, it currently keys the given direction to a string codename. This codename leads to a master dictionary where the string is the key, and the value is the actual room object. Is there a better way? – DankHill Nov 02 '15 at 00:36
  • Also, why do I need the codename in the item? I tried removing everything that defines codename for a test item and it won't work properly... – DankHill Nov 02 '15 at 00:57