Text Adventure: Mentioning the dictionary inside itself

Is there a way to accomplish this?

Dict = {'a': 'Python',
        'b': Dict['a']

Thanks!

Consider how you can add an item to an existing dictionary. That will help you figure out how to have a dictionary reference itself. Please post your code as you attempt to do this, so that we can help, and so that others can benefit from your work.

1 Like

You can do this:

Dict = {'a': 'Python', 'b': 'Python'}

Or you can do this:

Dict = {'a': 'Python'}
Dict['b'] = Dict['a']

Or you can do this:

Dict = dict.fromkeys(['a', 'b'], 'Python')

And probably many other ways to solve the same problem.

Hello, @Python_And_Ladders.

@steven.daprano has posted some solutions. But for practice, you can write some additional code.

As a challenge, try creating two dictionaries, dict_a, and dict_b, and then make them reference each other. Please post your solution, so as to benefit yourself as well as others who read this discussion. Also try using print to display the items in one of the dictionaries. Can you explain the output?

I have solved the problem. Thanks to all of you.

Dict = {'a': 'Python'
}
Dict['b'] = Dict['a']
print(Dict)

I am coding a text adventure game using a dictionary to store the out to its corresponding input.
In a form like this.

desc = 'description'
actions = 'actions'
object_desc = 'object_desc'
items = 'items'
n = ['n', 'north']
s = ['s', 'south']
e = ['e', 'east']
w = ['w', 'west']
sw = ['sw', 'southwest']
se = ['se', 'southeast']
nw = ['nw', 'northwest']
ne = ['ne', 'northwest']
u = ['u', 'up']
d = ['d', 'down']

Home: {
'Living Room': {
    actions: {      #specific moves
    'push book': {
        "print": 'You pushed the book. You hear a crank... a rumble. The shelf slides aside, revealing a lit stairway going down.',#prints this when inputed command
        'desc': Home[player.position][desc].replace('shelf and',
                                                    '') + ' There is a hidden passage to your southeast leading to a descending stairway.', # I am working on this
        'moves': [('se', 'Secret Chamber')] #makes the 'Secret Chamber' unlocked
                    },
    'unlock stand': {
            'print': 'The stand is unlocked. There is a mask and silver key inside it.',
            'items': ['mask', 'silver key'],
            'effects': Home[player.position][object_desc]['stand'].replace(' But it is locked.', '') #working on it!
                    }
            },
    items: ["brass key", 'book'],#objects in room (that can be picked up)
    object_desc: { #object and description of it
        'shelf': "It's a bookshelf. As you look closely you find a mysterious black book with no title.",
        'sofa': 'It seems very comfy, you really want to enjoy it, but you remind yourself that you still have something to do.',
        'tv': 'It is on an TV stand. There is nothing special about the TV.',
        'chairs': 'There are nothing special about them.',
        'table': 'It looks like any other table, as you look under it you find an brass key on the floor.',
        'stand': 'You see an mask and silver key inside the cabinet. But it is locked.',
                },
    desc: 'You are in the living room. There is a shelf and sofa behind you, on the opposite side of the sofa is the '
            'TV, there are some chairs beside a table to your right. The bathroom is to your northwest. ', # description of room
    's': 'Hallway', # available directions of travel
    'nw': 'Bathroom',
    }
}

Maybe someone could help point out some mistakes or give some suggestions?
Thanks!

What is the purpose of this line?:

Home: {

Now that you’ve laid down some code, you might want to take a fresh look at your data structure. It looks pretty complex and perhaps a bit organic (design-as-you-go). Computers work much better with a consistent structure. And programmers trying to maintain and extend a program–which includes you–also prefer good structure. Consider these definitions:

  • complex: a collection (system) of simple elements with simple relationships between them.
  • complicated: a “system” of arbitrary elements with arbitrary relationships between them.

Complex is okay, and you get there by thinking ‘simple’.

My suggestion is to design the data structure you plan to use before you try to program it. You might find, for example, that a master list containing separate dictionaries for {rooms} and {actions} (with each dictionary entry being a list of rooms, actions, etc.) is better than a single large dictionary.

Of course, if this project is to learn about how to design and program dictionaries, then continue programming. Just know that it’s very common to realize after you’ve programmed something how to optimize the program, because finishing the first version gave you a deep understanding of the system you’re creating.

A well-designed data structure can be enlarged for a very long time. For this reason, a best practice is to design the data structures that will give you the behavior you want and be as simple as possible to program.

The principle is: Design comes before build. If this is an exercise to learn Python, then that’s a great thing. The more interest you have in completing a project, the more you’ll get out of the project and the more fun it will be.

Consider this data structure:
[EDITED to correct the nested Room lists and replace the poor choice of map, which is a Python function (now ‘BOARD’)]

  1. BOARD[]
    This might need to be a grid list[] with Y rows of map locations and X rooms per row, each containing `Room[]` (see item 'B' below)
  2. Room[]
    1. roomName' (string)
    2. exits[] (N, E, S, W)
    3. Contents/Objects
    4. Puzzles
    5. etc. ...
  3. ACTIONS[]
    1. move
    2. open
    3. take
    4. drop
    5. etc. ...

See this post for how to create a grid of lists. Once you have a grid, you can reference the coordinates of the grid with BOARD[Y][X]. (Note the reversed coordinates. The grid origin is at top left and goes DOWN then RIGHT. The origin is map[0][0].

2 Likes

Home is a segment. There are other segments such as Street, Mall, Port…

Hey there. If I am not mistaken, is this what you mean?

            #Room               Objects                             Exits                     Puzzles
BOARD = [[['Bathroom', ['toothbrush', 'toothpaste', 'mirror'], [('e', 'Bedroom')], 'Not sure what will I be doing here yet.'],
        
        ['Bedroom',  ['phone', 'book'], [('w', 'Bathroom'), ('s', 'Living Room')], 'PUZZLES']],
        [['Garden', ['shovel', 'flowers'], [('e', 'Living Room')], 'PUZZLES'],
         ['Living Room', ['keys', 'computer', 'sofa'], [('w', 'Garden'), ('n', 'Bedroom')], 'PUZZLES']]]

It’s a bit messy I admit, but could you please clarify on ACTIONS[] please?
Thanks

1 Like

Hi Python_And_Ladders,

This topic is moving away from the original title, so if you like, it may be better to create another thread.
As Leland said, the design of the data structure is quite essential in programming.
I will recommend a design using FSM for your game application.

To describe a gatekeeper problem shown as an example in Wikipedia, first determine the states, inputs, transitions, and actions. Here’s a snippet and what the application looks like.

Locked, Unlocked = 'Locked', 'Unlocked' # states

Coin, Pass = 'coin', 'pass' # inputs

gatekeeper = FSM({
    Locked : {
        Coin : (Unlocked, lambda: print("\tGate is unlocked.")),
        Pass : (Locked,   lambda: print("\tWait! :(")),
    },
    Unlocked : {
        Coin : (Unlocked, lambda: print("\tThanks! :)")),
        Pass : (Locked,   lambda: print("\tGate is locked.")),
    },
})

while 1:
    gatekeeper(input("> ")) # input coin or pass

I don’t show the detail of the implementation of FSM here, however, it is a very simple and good practice for you. :wink:

You’ll need to get an input from the player and determine what action they’d like to do. It could be move a direction’ or take an object’ or open a door’. A list of actions would help you scan through their command and respond to the action and the object they entered, like “move N” or “open Door”.

Here’s a reflowed breakout of your BOARD list so the Rooms and Room Elements are easier to see. This should make it easier to design your board (changed from ‘map’ because map() is a Python function.)

BOARD = [[
        ['Bathroom', 
                    ['toothbrush', 'toothpaste', 'mirror'],
                    [('e', 'Bedroom')],
                    'Not sure what I will be doing here yet.'],
        ['Bedroom',
                    ['phone', 'book'],
                    [('w', 'Bathroom'),
                    ('s', 'Living Room')],
                    'PUZZLES']],
        ['Garden',
                    ['shovel', 'flowers'],
                    [('e', 'Living Room')],
                    'PUZZLES'],
        ['Living Room',
                    ['keys', 'computer', 'sofa'],
                    [('w', 'Garden'), ('n', 'Bedroom')],
                    'PUZZLES']
        ]] #I deleted an extra '[' in front of 'Garden'

Right now, your BOARD[] layout is one-dimensional (a list of rooms and features of that room). Would you like to keep the one-dimensional list or use a 2-dimensional list as a grid? The double square brackets at the beginning and end can go away if you’d like to keep the one-dimensional list.

P.S. If you use a 2-dimensional grid, you can drop the room name paired with the exit since N,E,S,W can move to the next location on the BOARD[] without having to know the destination. This is simpler than scanning the board for the room name in order to navigate to it. To go North for example, you can just go to ROOM[currentY-1][currentX].

Let’s finish the BOARD[] design and then you can work on filling in the rooms and navigation.

SUGGESTION: If you choose the 2-dimensional grid, then you can make a 2x2 grid from the four rooms above, program the navigation, then expand the grid and make sure the navigation still works (it should but you’ll want to program in a modular way and constantly test the modules as you go.)

P.P.S. I threw PUZZLES into the room[] list in case you would like to ask the player to do something extra like solve a riddle.

@Python_And_Ladders, Kazuya’s recommendation is a good one for a complex adventure if you’ve already done a few with basic data structures and aren’t trying to learn Finite State Machines (a professional-level concept) while you’re learning about Python lists or basic Python.

What is your level of experience with programming? Have you programmed a function using def, for example? If “yes”, then what’s the most complex project you’ve successfully completed?

def navigate(currY, currX, dir):
    if dir == 'n':  #only one direction here as a sample
        newY = currY - 1
        return newY, currX

Well… I think naming a thread “Could anyone give suggestions for a text adventure game design?” would be too awkward would it :slight_smile: ? I will be considering using FSM for the “Puzzles” design.
I don’t really have a good understanding about lambda but could you please clarify on how would lambda: print("\tGate is unlocked.") be used later on?

I think I’d use the one dimensional layout as there might be rooms below and above also. I will be working on the puzzles design before I move on. I think I am still a beginner. I use def. The most complex project that was not made by watching a tutorial is… probably this project. :smiley:

This would be a good reason to use a 2-dimensional grid for your game board.

[EDIT: ] @Python_And_Ladders, actually, you’d want to use a 3-dimensional grid to capture multiple floors of a building. Start with a single, one-story house or other building, though. Rome wasn’t built in a day and if you try to build out a town or city to start with, you’ll never finish the minimally-working system that allows you to build from a foundation. [1]

Adding a third dimension to a working 2D system is fairly trivial–if the 2D system is properly designed. The navigation will be the same except with the addition of up and down, which only apply at staircases, holes, etc. (and Chutes and Ladders, to reference your user name here. :wink: )

Cool. :sunglasses: What did you use it for? (What functions did you create with def?)


  1. A minimum viable product has just enough core features to effectively deploy the product, and no more. ↩︎

That part would be perfect as a topic title, actually.

If you hurry, you’ll still be able to revise it. The edit window on that post will close soon if it hasn’t already.

Lambda is also called Anonymous function - Wikipedia

It is a function that does not have a name. The following two ways of preparing a value[1] for the open_gate variable are (almost) the same in the final effect:

def open_gate():
    print("\tGate is unlocked.")

# as lambda:
open_gate = lambda: print("\tGate is unlocked.")

Later you perform the action by calling the variable open_gate as a function. For both the cases above it is exactly the same:

open_gate()

Why is it useful? In the example by Kazuya you store the actions to be performed later as functions. Without lambda you would need to define the functions first, giving them names. Then you insert them into the data structure by using their names.

def unlock_gate():
    print("\tGate is unlocked.")

def wait():
    print("\tWait! :(")
...
    {
        Coin : (Unlocked, unlock_gate),
        Pass : (Locked, wait),
    }
...

But it is too verbose and makes the code less clear. So you define the (short and single-use) functions as anonymous directly in the place where you need them - inside the data structure:

Later when you need to perform the stored action you call it - as a function:

state = Locked     # we are in Locked state
stimulus = Coin    # input stimulus is Coin

FSM_diagram[state][stimulus][1]()

The operator () causes the function (our anonymous lambda: print("\tGate is unlocked.")) to be called. Parentheses are empty because we give no arguments to the function. As a result print("\tGate is unlocked.") is executed.

Lambdas are often used in different cases. Here we did not talk about very important things like function arguments, return value, side-effects, functional programming. See the Wikipedia article at the beginning for more information.


  1. Yes, function is a value in Python. In Python everything is an object. ↩︎

2 Likes

Also with apologies to the OP for posting an aside.
A member of our Python User Group has requested (an intro to) FSMs be covered during a future meeting. Would (one, or more of) you care to volunteer a talk, demo, coding exercise, … please?
Even before COVID-19, we have been running virtual meetings (web-conference) in the UTC+12 time-zone (based in Auckland New Zealand) and enjoy meeting local and international speakers and attendees.
More info upon request…
Regards =dn (NZPUG@etelligence.info)

1 Like

Sadly I am not able to edit the topic anymore. Is it alright if I create an new topic and continue there?

Is this how to create a 3 dimensional grid? I never made one.

BOARD = [
    [[['Bathroom',
     ['toothbrush', 'toothpaste', 'mirror'],
     'Not sure what I will be doing here yet.']],
    [['Bedroom',
     ['phone', 'book'],
     'PUZZLES'],
     ['Upstairs',  #Above Bedroom
      ['Random Objects'],
      'PUZZLES']
     ]],
    [[['Garden',
     ['shovel', 'flowers'],
     'PUZZLES']],
    [['Living Room',
     ['keys', 'computer', 'sofa'],
     'PUZZLES']]]
]

Feel free to correct me if I am wrong.

Using def I created varname(variable), type('str'), take(thing), drop(thing), move(dir), print_location() and many more functions.