Assimilation
Assimilation

Reputation: 3

Python - function that c

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

Answers (4)

user890167
user890167

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

ssice
ssice

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).

What if you wanted to make a copy and not a reference?

Well, you can do that via the deepcopy and copy functions from the copy module.

The problem with NameErrors 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.

Reminder

If you want to refer to other objects via their names, they have to be named before that reference happens.

Upvotes: 0

unutbu
unutbu

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

jramirez
jramirez

Reputation: 8685

You referencing the dict1 within dict2, but dict1 doesn't exist yet.

Upvotes: 0

Related Questions