• Create Account

## Zork like text based game python

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

19 replies to this topic

### #1JonathanCCC  Members

160
Like
0Likes
Like

Posted 21 February 2014 - 09:13 PM

hello,

i've an absolute beginner and i'm trying to create a zork like text based game to learn. I have 2 questions, the first is that when I add 2 items to the list "inventory" it displays them like this:

so it displays them twice and i'm not sure why, also, i'd like it to just display them each on a different line such as

knife

secondly, i'm sure what I have done so far is a really bad an inefficient way of doing it, are there any tips or ideas I could use to write it better and re-use certain code for the commands etc before I go further? thanks a lot

import os, random, time

global name
name = "unknown"
inventory = []

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)

def introduction():
global name
print("banner")
print("do intro text")
name = str(input("Your name:"))

def easternfields():
here = 1
knifetaken = 0
print("\nEastern Fields")
print("\nDescription")
while here == 1:
command = str(input("> "))
command.lower()
lowcommand = command.lower()
if lowcommand == "inv":
displayinventory()
elif lowcommand == "look":
print("\nYou look around the eastern fields")
elif lowcommand == "take knife" and knifetaken != 1:
print("\nknife taken.")
knifetaken = 1
inventory.append('knife')
lowcommand = ""
elif lowcommand == "take knife" and knifetaken == 1:
elif lowcommand == "drop":
whichitem = str(input("item: "))
if whichitem in inventory:
inventory.remove(whichitem)
else:
print("\nCommand not recognised")

def southernfields():
here = 1
print("\nSouthern Fields")
print("\nDescription")
while here == 1:
command = str(input("> "))
command.lower()
lowcommand = command.lower()
if lowcommand == "inv":
displayinventory()
elif lowcommand == "look":
print("\nYou look around the southern fields")
elif lowcommand == "take flask" and flasktaken != 1:
lowcommand = ""
elif lowcommand == "take flask" and flasktaken == 1:
elif lowcommand == "drop":
whichitem = str(input("item: "))
if whichitem in inventory:
inventory.remove(whichitem)
elif lowcommand == "go east":
here = 0
easternfields()
else:
print("\nCommand not recognised")

southernfields()


### #2BeerNutts  Members

4290
Like
4Likes
Like

Posted 21 February 2014 - 09:29 PM

There are a few things going on that you should think about:

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)


You're printing "inventory" for each item "i".  You should have: "print i" not "print inventory"  (no need for () around the parameter)

Also, you really should have a function defined for when you wait for input from your user, and, you should have set descriptions ready for generic responses.  Otherwise, you'll have the exact same lines of code for waiting on input in all your rooms.

When you're more comfortable, you really should have an external file that lays out all the rooms, items in a room, actions possible in a room, and exits (and what rooms they connect to).

You'll get there, but take baby steps.  If you find your self doing the same thing over and over, think about how you could make it a function, and do it just once.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

### #3dejaime  Members

4157
Like
0Likes
Like

Posted 21 February 2014 - 09:29 PM

I am not sure about what language you are using (I should pay more attention to titles), but it looks to me like this code:

for i in inventory:
print(inventory)


actually means: "For all items in the inventory, print the entire inventory." 'd
So, maybe this will work?

for i in inventory:
print( inventory[i] )
// Or maybe
for i in inventory:
print( i )


About the efficiency, don't worry, ignoring this is probably the best thing you can do for now.
Concentrate on learning the basics first, then you can start to think about efficiency.

Edited by dejaime, 21 February 2014 - 09:36 PM.

### #4Buckeye  GDNet+

10739
Like
3Likes
Like

Posted 21 February 2014 - 10:55 PM

You might also think about having an inventory for each area. If the user drops the knife in an area and wanders elsewhere, he should be able to return to the area and pick the knife back up. You could also use an area inventory to fill out the "look" command. If the user picks something up, put it in the player inventory and remove it from the area inventory. Rather than setting up separate variables for each "taken" item, if the player "takes" something: look in his inventory to see if he already has it. Then check the area inventory to see if the item's there.

>look

You look around the fields.

You see a knife.

You see a flask.

>take bottle

You already have the bottle.

>take balloon

There is no balloon around here.

>take tree

The trees around here are firmly rooted.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

### #5jjd  Members

2140
Like
3Likes
Like

Posted 22 February 2014 - 04:42 AM

There are a few things going on that you should think about:

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)


You're printing "inventory" for each item "i".  You should have: "print i" not "print inventory"  (no need for () around the parameter)

That is only valid if you are not using python 3.0+ so it is generally consider a better practice to use the parentheses because it works across more version of python.

-Josh

--www.physicaluncertainty.com
--irc.freenode.net#gdnet

### #6JonathanCCC  Members

160
Like
2Likes
Like

Posted 22 February 2014 - 10:46 AM

thanks alot for your help and suggestions guys,

I did indeed fix the inventory listing problem by printing i instead of inventory

for i in inventory:
print(i)


I also took up the suggestion of adding an item list for each area, allowing the user to drop items and return to them with this code for example:

southernfieldsitems = ['flask', 'shoe']

elif lowcommand == "look":
print("\nYou look around the southern fields")
print("\navailable items: ")
for i in southernfieldsitems:
print(i)

elif lowcommand == "take":
takewhat = str(input("item: "))
takewhatlow = takewhat.lower()
if takewhatlow in southernfieldsitems:
inventory.append(takewhatlow)
southernfieldsitems.remove(takewhatlow)
else:
print("There is no item of that sort here")
elif lowcommand == "drop":
whichitem = str(input("item: "))
if whichitem in inventory:
inventory.remove(whichitem)
southernfieldsitems.append(whichitem)
elif lowcommand == "go east":
here = 0
easternfields()



I thought about creating a function that waits for the commands but i'm not quite sure how i'd do it because some commands will depend on whats in the area, plus I intend to add things like NPCs etc later on and combat. I suppose I wouldn't know how to pass all the relevant information back and forth between a command function and the area function so it knows what's going on.

also you'll notice i've been using 2 variables for the "take" and "drop" command, after you type either it asks you to type which item, that is because I don't know how to check the second word in a string variable so that instead the user could simply type "take flask" all in one line, then I check the second word against the areas item list. Is there an easy way to do that?

thanks again

### #7Oralordos  Members

892
Like
2Likes
Like

Posted 22 February 2014 - 11:30 AM

Something like this should help.

splitCommand = lowcommand.split()
if splitCommand[0] == 'take':
takewhat = splitCommand[1]


The split method of strings returns a list of what was in the string separated by whitespace like spaces. So 'take flask' would return ['take', 'flask'].

### #8gasto  Members

303
Like
0Likes
Like

Posted 22 February 2014 - 11:47 AM

There are a few things going on that you should think about:

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)


You're printing "inventory" for each item "i".  You should have: "print i" not "print inventory"  (no need for () around the parameter)

That is only valid if you are not using python 3.0+ so it is generally consider a better practice to use the parentheses because it works across more version of python.

-Josh

You would be printing i as a tuple in versions of Python preceding 3.0 .

Intel Core 2 Quad CPU Q6600, 2.4 GHz. 3GB RAM. ATI Radeon HD 3400.

### #9JonathanCCC  Members

160
Like
0Likes
Like

Posted 22 February 2014 - 01:18 PM

Something like this should help.

splitCommand = lowcommand.split()
if splitCommand[0] == 'take':
takewhat = splitCommand[1]


The split method of strings returns a list of what was in the string separated by whitespace like spaces. So 'take flask' would return ['take', 'flask'].

yep, works perfect thank you

### #10jjd  Members

2140
Like
1Likes
Like

Posted 22 February 2014 - 07:05 PM

There are a few things going on that you should think about:

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)


You're printing "inventory" for each item "i".  You should have: "print i" not "print inventory"  (no need for () around the parameter)

That is only valid if you are not using python 3.0+ so it is generally consider a better practice to use the parentheses because it works across more version of python.

-Josh

You would be printing i as a tuple in versions of Python preceding 3.0 .

Not sure what you mean, but calling print(i) simply prints out the value of i in either python2 or python3 and has nothing to do with tuples.

-Josh

--www.physicaluncertainty.com
--irc.freenode.net#gdnet

### #11JonathanCCC  Members

160
Like
0Likes
Like

Posted 23 February 2014 - 03:54 PM

also can someone help me with using multiple source files in python?

the game is getting large now so I want to put new functions on a separate file but i'm having trouble getting it to work.

I know in C you could just do "#include whatever.c" or something

right now I have main.py

I want to create a blank file called functionstwo.py to add into main

EDIT: SOLUTION FOUND

Edited by JonathanCCC, 23 February 2014 - 04:24 PM.

### #12JonathanCCC  Members

160
Like
0Likes
Like

Posted 23 February 2014 - 06:25 PM

also can somebody tell me how to error handle no input

for example below is a typical function in my game to handle an "area" or "room" - if the command isn't part of any of the IF tests, it simply prints "unknown command"

but if the player types no input and just presses enter, the game crashes. How should I check for no input in the "command" variable to then print "please enter a command" instead of the game just crashing? Thanks in advance!

def southernfields():
here = 1
print("Southern Fields")
while here == 1:
command = str(input("\n> "))
lowcommand = command.lower()
splitCommand = lowcommand.split()
if splitCommand[0] == "inv" or splitCommand[0] == "inventory":
globalz.displayinventory()
elif splitCommand[0] == "talk":
print("nobody here to talk to")
elif splitCommand[0] == "attack":
print("nothing here to attack")
elif splitCommand[0] == "look":
print("You are in vegetation filled fields to the south of the castle. To the north, archers can be seen practicing"
" near the castles southern wall. To the east, more plains are seen on the horizon. To the west, mountainous terrain"
" with what looks like a tower barely visible in the distance.")
print("\nitems: ")
itemsize = len(globalz.southernfieldsitems)
if itemsize > 0:
for i in globalz.southernfieldsitems:
print(i)
else:
print("nothing here")
elif splitCommand[0] == "take":
size = len(splitCommand)
if size > 1:
if splitCommand[1] in globalz.southernfieldsitems:
if globalz.playeritems < 5:
globalz.inventory.append(splitCommand[1])
globalz.southernfieldsitems.remove(splitCommand[1])
globalz.playeritems += 1
print(splitCommand[1] + " taken.")
else:
print("you cannot carry more than 5 items.")
else:
print("there is no item of that sort here")
else:
print("take which item?")
elif splitCommand[0] == "drop":
size = len(splitCommand)
if size > 1:
if splitCommand[1] in globalz.inventory:
globalz.inventory.remove(splitCommand[1])
globalz.southernfieldsitems.append(splitCommand[1])
globalz.playeritems -= 1
print(splitCommand[1] + " dropped.")
else:
print("you have no such item")
else:
print("drop which item?")
elif splitCommand[0] == "examine":
size = len(splitCommand)
if size > 1:
if splitCommand[1] in globalz.southernfieldsitems or splitCommand[1] in globalz.inventory:
globalz.whatisit(splitCommand[1])
else:
print("no such item")
else:
print("examine which item?")
elif lowcommand == "go east":
here = 0
easternfields()
elif lowcommand == "go west":
here = 0
westernfields()
elif lowcommand == "go north":
here = 0
northern1()
elif lowcommand == "go south":
print("South leads back to the villages where you came from, the people aren't expecting you to return"
elif lowcommand == "go":
print("go where?")
elif lowcommand == "location":
print("southern fields")
elif lowcommand == "status":
globalz.displaystatus()
elif splitCommand[0] == "use":
size = len(splitCommand)
if size > 1:
if splitCommand[1] in globalz.inventory:
globalz.usewhat(splitCommand[1])
else:
print("you have no such item")
else:
print("use which item?")
else:
print("unknown command")


### #13LennyLen  Members

5416
Like
2Likes
Like

Posted 23 February 2014 - 08:36 PM

also can someone help me with using multiple source files in python?

also can somebody tell me how to error handle no input

If you have a new problem it's best to start a new topic.  This makes it easier for other people who have the same problem in the future find a thread that might have the answers they're looking for.

### #14gasto  Members

303
Like
1Likes
Like

Posted 24 February 2014 - 08:51 AM

There are a few things going on that you should think about:

def displayinventory():
print("\nInventory:")
for i in inventory:
print(inventory)


You're printing "inventory" for each item "i".  You should have: "print i" not "print inventory"  (no need for () around the parameter)

That is only valid if you are not using python 3.0+ so it is generally consider a better practice to use the parentheses because it works across more version of python.

-Josh

You would be printing i as a tuple in versions of Python preceding 3.0 .

Not sure what you mean, but calling print(i) simply prints out the value of i in either python2 or python3 and has nothing to do with tuples.

-Josh

(it is not sufficient to enclose a single value in parentheses).

Intel Core 2 Quad CPU Q6600, 2.4 GHz. 3GB RAM. ATI Radeon HD 3400.

### #15BeerNutts  Members

4290
Like
1Likes
Like

Posted 24 February 2014 - 02:19 PM

Jonathan,

The way you're going about writing that single room is going to lead to A LOT of coding.  Let me show you a little snippet of pseudo-code that might give you an idea of a generic way to handle this stuff

# setup the 'field' room
Rooms['field'].description = "You are in a large wheat field.  It looks to have been recently harvested."
Rooms['field'].exits = {'n': 'outside_house', 'e': 'well'}
Rooms['field'].items = ('sycthe')

# setup the 'well' room
Rooms['well'].description = "You are standing, looking down a well."
Rooms['well'].actions = ('cut rope')
Rooms['well'].exits = {'w': 'field'}

# setup 'outside_house' room
Rooms['outside_house'].description = "You're standing outside an old farm house."
Rooms['outside_house'].exits = {'s': 'field'}

currentRoom = 'field'

while isRunning:
# print the description of the current room
print Rooms[currentRoom].description
# list the items in the room
if Rooms[currentRoom].items:
while item in Rooms[currentRoom].items:
print ' You see a ' + item
print 'The available exits are: '
while exitDirs in Rooms[currentRoom].exits:
print exitDirs
print 'command> '

# get the command

# check for all the generic commands: look, invenrtory, help, quit, etc.

# loop through all the possible exits for this room
while exitDirs in Rooms[currentRoom].exits:
if command[0] == exitDirs:
# change our room to this one
currentRoom = Rooms[currentRoom].exits[exitDirs]
break
# if the user issues  aget, check the item is in the room...
if command[0] == 'get':
while item in Rooms[currentRoom].Items:
# if so, add the item to the inventory, and remove the item form the room
if command[1] == item:
Inventory.append(item)
Rooms.currentRoom].Items.remove(item)
# check if the user performed some available action
while action in Rooms[currentRoom].actions:
if command == action:
PerformAction(currentRoom, action)
break

def PerformAction(currentRoom, action):
# check the room versus the action and see if it's still viable


I know the above will not compile in python (I've done very little in it), but you should be able to get the gist of it.

Edited by BeerNutts, 24 February 2014 - 02:23 PM.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

### #16JonathanCCC  Members

160
Like
0Likes
Like

Posted 25 February 2014 - 02:13 PM

thanks BeerNutts, I see what you mean. I can see my code is really "dirty", does the pseudo code you use things like classes and objects?

### #17BeerNutts  Members

4290
Like
3Likes
Like

Posted 25 February 2014 - 02:52 PM

thanks BeerNutts, I see what you mean. I can see my code is really "dirty", does the pseudo code you use things like classes and objects?

It can use a class, but it doesn't have to.  You can use dict's to hold the Rooms variables as well.

If using dicts...

Rooms['field'] = {'description': 'You are in a large wheat field.  It looks to have been recently harvested.', \
'exits': {'n': 'outside_house', 'e': 'well'}, 'actions': [], 'items': ['scythe']}
...
# and access them via
print Rooms['field']['description']


Or If you use classes, it might be like this:

class Room:
def __init__(self, description, exits, actions, items)
self.Description = description
self.Exits = exits
self.Actions = actions
self.Items = items

Rooms['field'] = Room("You are in a large wheat field.  It looks to have been recently harvested.", \
{'n': 'outside_house', 'e': 'well'}, [], ['scythe'])
...
# And access them like this
print Rooms['field'].Description



I think that's how it works (again, my python is shaky), but you should get the idea.  Keep working at it and you'll get it.  Use the internet to find the answers.

Edited by BeerNutts, 25 February 2014 - 02:55 PM.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

### #18JonathanCCC  Members

160
Like
0Likes
Like

Posted 25 February 2014 - 04:58 PM

thanks very much

### #19JonathanCCC  Members

160
Like
0Likes
Like

Posted 03 March 2014 - 06:17 PM

ok i've started doing a new one to test classes and OOP for the first time, so i'm very new to this part of programming, before as you've seen I would just have global variables and functions all over the place for every room etc. So i'm seeing how much I can condense it and if it's possible to just have a class, a main game loop, and a few check command side functions.

Below is what i've come up with so far, what i'm struggling with already is performing the actions of "go north" or whatever and then performaction function knowing where "go north" is from the current room so I can change the room in the main loop. Any suggestions on the lay-out and basic design so far? Is it possible to have just one main loop for a reasonably interactive text game or am I destined to add a few room functions again?

thanks for any help

import sys, os, time

inventory = []
Running = True

class Room:
def __init__(self, name):
self.name = ""
self.desc = ""
self.items = []
self.actions = []
self.items.append(item)
self.actions.append(action)

entrance = Room("Entrance")
entrance.name = "Entrance"
entrance.desc = "You are in at the entrance of the town"

def main():
currentRoom = entrance
while Running == True:
os.system('clear')
print("\n\nTest Game\n----------\n\n")
print(currentRoom.name)
print("\n" + currentRoom.desc)
if currentRoom.items:
print("\nAvailable items:")
for i in currentRoom.items:
print(i)
command = str(input("\n> "))
checkaction(currentRoom, command)

def checkaction(room, action):
if action in room.actions:
print("Valid action")
performaction(room, action)
if action == "inv" or "inventory":
size = len(inventory)
if size > 0:
for i in inventory:
print(i)
input("")

def performaction(room, action):
if action == "take pistol":
inventory.append("Pistol")
room.items.remove("Pistol")

main()



### #20BeerNutts  Members

4290
Like
1Likes
Like

Posted 07 March 2014 - 11:50 PM

You really need to link exits.  In all text adventure games, moving in a direction is done via a single letter: n, e, s, w, u, d (up and down are the last 2).  You really should assign exits to rooms, and be able to easily link rooms to exits, as I showed in my example above.

Also, I would not include the name of the room in the class defintion, I'd use the name as the key in a dictionary.  The dictionary is a mapping of room names to Room objects

Also, you need to use the class constructor.  Why pass in the name if you don't assign it in the constructor?  In my rooms, all Room variables require at least 2 things: description and exits (as a list of dictionaries).  Create your constructor to take those in and use them:

class Room:
def __init__(self, description, exits):
self.desc = description
self.exits = exits
self.items = []
self.actions = []

# This creates a room with the key being the room name Entrance, and the single exit n (north) leads to the room Town_Gate
Rooms['Entrance'] = Room("You are at the entrance to a town", {'n' : 'Town_Gate'})

# This creates a room with the key being the room name Town_Gate, and 2 exits, s, back to entrance and e leads to the room Town_Square
Rooms['Town_Gate'] = Room("You are at the gates of the town.", {'s' : 'Entrance', 'e' : 'Town_Square'})

# This is copied almost EXACTLY from my post a few posts ago, it just shows how you use the variable CurrentRoom, which is the key  into the dictionary Rooms

# start at entrance
currentRoom = 'entrance'

while isRunning:
# print the description of the current room
print Rooms[currentRoom].description
# list the items in the room
if Rooms[currentRoom].items:
while item in Rooms[currentRoom].items:
print ' You see a ' + item
print 'The available exits are: '
while exitDirs in Rooms[currentRoom].exits:
print exitDirs
print 'command> '

# get the command

# check for all the generic commands: look, invenrtory, help, quit, etc.

# loop through all the possible exits for this room
while exitDirs in Rooms[currentRoom].exits:
if command[0] == exitDirs:
# change our room to this one
currentRoom = Rooms[currentRoom].exits[exitDirs]
break
# if the user issues a get for the 1st word, check the item is in the room...
if command[0] == 'get':
while item in Rooms[currentRoom].Items:
# if so, add the item to the inventory, and remove the item form the room
if command[1] == item:
Inventory.append(item)
Rooms.currentRoom].Items.remove(item)

# check if the user performed some available action
while action in Rooms[currentRoom].actions:
if command == action:
PerformAction(currentRoom, action)
break

def PerformAction(currentRoom, action):
# check the room versus the action and see if it's still viable


Edited by BeerNutts, 08 March 2014 - 05:15 PM.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.