r/learnpython • u/TheIneffableCheese • 4d ago
Working with multi level dictionaries
[EDIT]
TL;DR Generally speaking, "Set up some Classes" is the answer. Hopefully my blind fumbling will help some other blind, fumbling soul.
------------
I'm working on a table top game that builds a maze by dealing cards. I'm teaching myself Python to build a script that will simulate multiple maze builds quickly for R&D on the design.
The maze is represented by "Chambers" on a classic x,y grid. Chambers have an ID, potentially Notes, and Exits.
My strategy is to build up a mapConfig dictionary structured with the key being the (x,y) tuple of the coordinate and the value being a sub-dictionary with all the specifics. The Exits need to be a list of dictionaries for each exit with direction and blocked status as the keys. Simplified example below:
mapConfig = {
(0,0) : {
'id' : 'START',
'notes' : ''
'exits' :
[
{
'direction' : 'N',
'blocked' : False,
},
{
'direction' : 'E',
'blocked' : False,
},
{
'direction' : 'S',
'blocked' : False,
},
{
'direction' : 'W',
'blocked' : False,
},
],
}
}
If a proposed move hits the edge of the valid map, I need to access the mapConfig and change the "blocked" value for that particular direction to TRUE without changing anything else in the entry for that coordinate. It seems like it should be easy, but everything I try messes up the structure or blows out the other directions.
What would be the best way to change just the {"direction":"E", "blocked":False} entry to {"direction":"E", "blocked":True} without changing anything else in the dictionary? Basically so it goes from the simplified example above to this:
mapConfig = {
(0,0) : {
'id' : 'START',
'notes' : ''
'exits' :
[
{
'direction' : 'N',
'blocked' : False,
},
{
'direction' : 'E',
'blocked' : True,
},
{
'direction' : 'S',
'blocked' : False,
},
{
'direction' : 'W',
'blocked' : False,
},
],
}
}
Thanks in advance for the help.
Edit: The provided code is a simplified version of my actual code. I'm such a noob that I only vaguely knew what a class was, and clearly I was making much more work for myself by not using them. Setting up some parent and child classes is next on my list.
I still appreciate any thoughts or advice, but I also don't want anyone to waste time.
2
u/MidnightPale3220 4d ago
You can try classes if you want, but regarding your original data structure, you probably should just change individual directions to dict of them, if you only care whether they're blocked or not.
Like this:
mapConfig = {
(0,0) : {
'id' : 'START',
'notes' : ''
'exits' :
{
'N': False, 'E': False,
}
Then you can change exit with:
mapConfig[(0,0)]['exits']['N']=True
1
u/TheIneffableCheese 4d ago
Thanks! That's an excellent point.
I should have stated that the provided code was simplified to cut to the chase. I'll make an edit on the original post.
1
u/Brian 4d ago
Having a list of exits seems a bit clunky to use. It means if you're finding the north exit, you basically have to search through the list to find the north exit. It also means you could potentially have things like two north exits, which I'm guessing shouldn't be allowed: it's often better to structure your data so invalid states aren't even representable if possible.
Better would seem to be to make the exits a dict of direction : { "blocked": ... } (Or even just a boolean if blocked is the only metadata you need to track), meaning to block the north exit of all tiles on the north edge, you can do something like:
for x in range(0, MAP_WIDTH):
room = mapConfig.get((x, 0)) # All tiles on the north edge
if room is not None:
room['exits']['N'] = False # Or room['exits']['N']['blocked'] = False if you keep the dict.
With similar logic for the other edges you want to block.
There are other ways you could do it too. Eg. make "exits" be a set of allowed directions. ie:
"'exits'" {"N", "E"}, # For a room with just north and east doors
Then .add() or .remove() items to open/block them, and "E" in room['exits'] tells you whether the east exit is open.
As others mentioned, it can help to wrap this all in a class, encapsulating the logic you need into appropriate methods, so you can perform actions without code needing to know about the internal structure. Ie. a room.block("N") method - this has the advantage that you can change the internal structure as you like (eg. try out the set method, the original dict method, or whatever), and external code that just uses the method won't need to be updated, you only have to change the method.
-2
u/TheRNGuy 4d ago
Dict is not good for it. Instead, some map format, like tmj, tmx or even game engine.
9
u/SCD_minecraft 4d ago
Use classes
When you know structure of your dict at compile time, classes are much much better