Python: Dictionary of Dictionaries

Started by
18 comments, last by Zahlman 17 years, 9 months ago
I'm having some trouble creating a dictionary of dictionaries in python. I can understand how to create a singular dictionary, but the syntax of a dictionary of dictionaries confuse me. Anyone have any advice on how I can go about creating one? Thanks very much!
Advertisement
Simply create the dictionaries one at a time. Python dictionaries do not care about what kind of values they contain.

a = {}a["banana"] = {}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Right. Hmm, what Im trying to do is this:

Im trying to create a text based game in python. Lets say I have rooms and players, and each room and player is kept track of by a roomID and playerID. Now, the players can move around in the rooms, and at any time, the user can execute a command (lets say this command is called "Look") to display where the player is. Also, the roomID will contain the room name, and a room description. The playerID will contain the player name, and player description (ie Zelda, A Beautiful Princess). Also, every time the "Look" command is executed, it will display the room name and description, and the player name and description.

What I was thinking of doing was something like this:

player dictionary: - key: roomID
- value: playerID
- key: playerID
- value: playerName, playerDescription

So, in essense...a dictionary of a dictionary?

Like Fruny said, Python dictionaries (and lists and tuples) don't care about what they contain: they are 'heterogenous containers'. So if you really wanted a dictionary of dictionaries, you could do that quite easily, because a dictionary is a kind of object, and any object can be a dictionary value.

That said, it sounds like your confusion has more to do with modelling the situation than the syntax of implementing that model :)

First off, when you talk about "IDs", this implies a separate object from the thing being ID'd. That's fine, but you probably only want a name in the ID, leaving the description in the thing being IDd.

We have four sorts of things:

- player
- player ID
- room
- room ID

Because the IDs are just names, we could just use strings for them. The player and room both aggregate some information and will have some behaviour, so it makes sense to define classes for them.

Now, a room might contain players, and similarly a player knows about the room that s/he's in. We don't actually need IDs to handle this, because what we'll do is make each room track a list of the contained players, and have each player remember the containing room directly. There's a bit of a trick here: because of how Python stores objects, you don't really distinguish between object members that are "contained" and object members that are "known about" in the syntax - it's a matter of semantics.

So, we do something like:

class Room:  def __init__(self):    self.players = [] # will be Players that are "contained"class Player:  def __init__(self, location):    self.location = location # will be a Room that is "known about" (containing)


Note that the Room won't *actually* "contain" Players, but instead points to them, in the same way that the Player points to its containing room. Hence the semantics. :)

Now, we just add the functionality to move a Player from one room to the next. We should also make sure that the Player's initial Room knows about the Player, so we'll adjust the constructor as well. We can make this more foolproof by setting an invalid location first, and then "moving" the player into the initial Room.

class Room:  def __init__(self):    self.players = []  def removePlayer(self, player):    # I don't remember if this throws an exception or returns -1 for not found    # So adjust as needed :)    index = self.players.find(player)    if (index != -1) : del self.players[index]  def addPlayer(self, player):    self.players.append(player)class Player:  def __init__(self, location):    self.location = None    self.moveTo(location)  def moveTo(self, location):    if self.location is not None:      # excuse myself from the current room, if any      self.location.removePlayer(self)      # and go to the new one.      location.addPlayer(self)      self.location = location
Quote:
    # I don't remember if this throws an exception or returns -1 for not found    # So adjust as needed :)    index = self.players.find(player)    if (index != -1) : del self.players[index]


There is no list.find routine. list.index does what you want and throws an exception, although it'd just be easier to use list.remove, which is what you're doing.
Hmmm... Dictionaries have time complexity of O(1) and lists have O(n). It would make sense to make a dictionary of dictionaries but the PyNumeric extension has a hardware Array function that would probably work for the inner dictionary thus effectively making it a dictionary of arrays. That might make your code simpler. The only catch is that a Numeric Array is of fixed size so the PlayerName and PlayerDescription would only be elements in the array.

If you want to enumerate the fields of the array so you could refer to them by name rather than by number just make the name a single element tuple (by putting a comma after the constant you are assigning it to) and the tuple will be a constant in your code:

PlayerName=1,
arrayname[PlayerName]="Lancelot"

BTW, I'm not sure about the array syntax since it's been a while since I used Python.
Quote:Original post by bytecoder
Quote:
    # I don't remember if this throws an exception or returns -1 for not found    # So adjust as needed :)    index = self.players.find(player)    if (index != -1) : del self.players[index]


There is no list.find routine. list.index does what you want and throws an exception, although it'd just be easier to use list.remove, which is what you're doing.


Er, yes. Wow, I'm way out of practice :/ Been doing C++ at work :(
Ok wow, thanks Zahlman. Hmm, I think your correct in that Im more confused about how to model the situation than the syntax. I just recently started learning Python, so its still a little confusing...and even though the solution you provided is probably most ingenius, Im still not quite sure what is going on with it. XD

Also some clarification, I am also looking to have a "create" function, to allow me to create rooms, players, or items as I am within the game.

So what will happen is this, say I am within the game (all commands to the game are input from the command line):

>>> create room 10 Basement A dark and scary basement

create is the command, room would be referring to the room dictionary, 10 is the room number (key in the room dictionary), Basement is the room name (value in the room dictionary), and "A dark..." is the room description (which, I guess would also be a value in a dictionary, but with the room name as the key for this dictionary).

That would be why I am thinking to use a dictionary of dictionaries for this implementation.

Btw, how do you post code in the posts? XD

Thanks again for your responses. Forgive my newbieness XD
Quote:Original post by fengxSo what will happen is this, say I am within the game (all commands to the game are input from the command line):

>>> create room 10 Basement A dark and scary basement



The room name and description are most logical as members of a Room class. The dictionary can simply map from ID number to instances of this class. A simplified example:

rooms = {}class Room:    def __init__(self, roomname, roomdesc):        self.roomname = roomname        self.roomdesc = roomdescdef create(dict, id, roomname, roomdesc):    dict[id] = Room(roomname, roomdesc)create(rooms, 1234, "Basement", "A dark and scary basement.")



Quote:Btw, how do you post code in the posts? XD

http://www.gamedev.net/community/forums/faq.asp#tags

[Edited by - Hollower on July 4, 2006 9:42:06 PM]
Thanks for everyone's help so far!

Ok, so I have started an early implementation of my game. What I have done so far is to read the commmand line to create a new room for the game.
The command line structure for room creation is explained breifly in an earlier post.

So far, I can successfully read in and parse the command from the command line using regular expressions. However, when I try to assign the parsed variables to a dictionary (in this case, the room dictionary), I get an error saying the key is not found. I have a print statement in the if loop just for testing. And, it will not print anything and give me an error saying the key is not found.

For testing purposes, I am using this as the command:
<Adventure> create room 23 basement A cool basement

import sysimport reroom = {}player = {}item = {}class Room:        def __init__(self, roomname, roomdesc):                self.roomname = roomname                self.roomdesc = roomdescclass Player:        def __init__(self, playername, desc):                self.playername = playername                self.playerdesc = playerdescclass Item:        def __init__(self, itemname, desc):                self.itemname = itemname                self.itemdesc = itemdescdef createRoom(dict, id, roomname, roomdesc):        dict[id] = Room(roomname, roomdesc)def createPlayer(dict, id, playername, playerdesc):        dict[id] = Player(playername, playerdesc)def createItem(dict, id, itemname, itemdesc):        dict[id] = Item(itemname, itemdesc)def prompt():        line = re.compile('(\d+)\s+(\w+)\s+(\w+)')        while 1:                try:                        cmd = raw_input("<Adventure> ")                except:                        print "Done"                        break                if re.search("create room", cmd):                        print "Room create"                        data = line.search(cmd)                        if data:                                type_id, name, desc = data.group(1, 2, 3)                                createRoom(room, type_id, name, desc)                        print "ID: %s, name: %s, desc: %s" % (type_id, name, desc)                        print room[23]                elif re.search("create item", cmd):                        print "item create"                elif re.search("create player", cmd):                        print "player create"                else:                        print "Unknown command!"prompt()


Also, I am not able to take in the entire line of "A cool basement" I can only take in "A". I know I should not be using \w to parse the regular expression, but I cant think of what to use in place of that...

This topic is closed to new replies.

Advertisement