Reputation: 3
I'm working on a choose-your-own-adventure project whose main function accepts 3 paramters.
Example.
text1 = 'This is the scenario'
text2 = 'These are the choices'
dict2 = {'1':[text2, text1, dict1]}
dict1 = {'1':[text1, text2, dict2]}
def mainloop(scenario, choice, consequence):
print scenario
print choice
answer = raw_input('Please input 1, 2 or 3>>> ')
if answer in consequence.keys():
mainloop(*consequence[answer])
mainloop(text3, text2, dict1)
I thought this would be a good way to design my project, however I am running into a problem with the dictionary parameter. Because the dictionary values contain a list of arguments, which include other dictionaries I keep getting the error:
NameError: name 'dict1' is not defined
Flipflopping the order I define the dictionaries in expectedly results in the same error, only with 'dict2' not being defined. Any advice on how I can get this concept to work? Or is it time to take a completely different approach?
Upvotes: 0
Views: 134
Reputation:
There are a couple of things that I would suggest rethinking about the approach as a whole.
As others pointed out, mainloop()
isn't actually a loop; it's a recursive function. Ideally, if this is a game loop, you'd want it to be more like…
def myGameLoop():
gameRunning = True
while gameRunning:
# code that displays your rooms, gets user input,
#and checks to make sure that gameRunning is not False.
#for an example, something like:
if somethingAwfulHappened
gameRunning = False
In this way you don't have to call the mainloop
more than once, and there's no reason for it to call itself.
Additionally, the reason your room dicts/lists keep telling you they don't exist is because, well, they don't :) This is actually a fairly good example of why it's a good idea to separate your concerns!
Think of it this way: why does a 'room' object - whether it is a dict, a list, an object, etc - need to contain any data about other rooms? Your kitchen might lead to your bathroom, sure - but does your kitchen KNOW that it leads to the bathroom? Does it serve a new purpose by leading to the bathroom instead of your bedroom? In the same way that your kitchen does not "care" that it is connected to your bathroom, neither do your dicts need to "know" that they are connected by explicitly naming each other in their own data.
An ideal approach might be instead to go and define all your rooms, and then create a 'map' which describes the relationship between your rooms. So for example:
kitchen = {
"name":"Kitchen",
"description": "This is the kitchen! It's nice and clean.",
"exits": "S", "E"
}
bathroom = {
"name":"Bathroom",
"description":"This is the bathroom. Someone left a towel on the floor.",
"exits":"W", "S"
}
#and so on, creating rooms
Now create a map dict that just holds all this info and describes how those exits work.
mapOfHouse = {
"kitchen": kitchen,
"leadsTo": {
"S": bathroom,
"E": someOtherRoom ##some other place you've defined
},
"bathroom": bathroom,
"leadsTo": {
"S": otherAwesomePlaces,
"E": kitchen
},
#and so on for other rooms in the house/on the map/etc
}
Once you sketch all this out, you then set your gameloop to get your player's input, check it against the room's exits, and if there's a match, as long as the loop is still True
it heads back up to the top, displaying the updated information.
It seems like a lot more work, but really this gives you an immense amount of freedom. It lets you focus strictly on rooms as you design them, then focus strictly on the map as you update it, and then lets you design a game loop which doesn't really care a lot about the contents of what it's looping over, as long as it stays True
the whole time and gets good instructions from the player.
Upvotes: 1
Reputation: 3683
Your problem is the following:
dict2 = {'1':[text2, text1, dict1]} # NameError: Here dict1 does not exist yet
dict1 = {'1':[text1, text2, dict2]}
You can only solve this by defining the objects before referencing them. In order to achieve that, you can do as follows:
dict1, dict2 = {}, {} # Define both objects
dict1[1] = [text2, text1, dict2] # Here dict2 is already defined, no NameError
dict1[2] = None # ...
dict2[1] = [text1, text2, dict1] # And here is dict1 already defined too
dict2[2] = None # ...
The question we could ask is: does referencing an object and later changing it alter the reference? The answer is yes, it does; provided you're using references and not copies (asigning dictonaries always references them).
Well, you can do that via the deepcopy
and copy
functions from the copy
module.
The problem with NameError
s is that there is no such name defined; Python does not use names to track variables: the same name can correspond to different variables (in different scopes, or at different times) and the same variable can be accessed via different names (by assigning one name's value to the other).
When you do del x
, you unlink a variable from its name, but you don't always eliminate the object.
For example, the following code works and prints stash
correctly, altough via the del
operator we unlinked the str
object 'hello'
from the object x
that contained it.
x = {1: 'hello'}
stash = x[1]
del x[1]
print stash
By deleting the stash
object too the 'hello'
object may be now prone to be garbage-collected at some point.
If you want to refer to other objects via their names, they have to be named before that reference happens.
Upvotes: 0
Reputation: 880927
I'm not quite sure why you need two dicts, but assuming you do, it is possible to define dicts with circular references:
text1 = 'This is the scenario'
text2 = 'These are the choices'
dict1, dict2 = {}, {}
dict2['1'] = [text2, text1, dict1]
dict1['1'] = [text1, text2, dict2]
Upvotes: 3
Reputation: 8685
You referencing the dict1 within dict2, but dict1 doesn't exist yet.
Upvotes: 0