KeyError when searching for items in dict inventory - python

Over the past few months I've been attempting to create a text-based Zork-style game as a project to teach myself Python.
Thanks to the wonderful people here at stackoverflow and plenty of youtube video's, I've made decent progress. The issue I'm currently dealing with is towards the bottom of the code, in the Bag class.
As you will see below in my bag class, I have a method called Take. This method originally was not within the bag class, it was in the section at the bottom that reads user commands.
class Bag:
def __init__(self, inventory):
self.inventory = inventory
def addToInventory(self, item):
for key in list(Location.room.roominv.keys()):
self.inventory.append(Location.room.roominv[key])
del Location.room.roominv[key]
def SearchRoom(self):
if Location.room.roominv:
for item in list(Location.room.roominv.keys()):
print("you find a", item)
else:
print("You don't find anything")
def NoneHere(self, command):
print("You can't find a", command)
def Take(self, command):
for key in list(Location.room.roominv.keys()):
if Location.room.roominv[key].name == command.split()[1]:
bag.addToInventory(key)
print('you take the', key)
def CheckTake(self):
if Location.room.roominv and command.split()[1] in Location.room.roominv:
self.Take(command)
else:
self.NoneHere(command.split()[1])
def CheckInv(self):
for item in list(bag.inventory):
print("Your bag contains:", item.name)
player = Player("Jeff", 100)
bag = Bag([])
Location = Location('introd')
command = ' '
while command != "":
command = input('>>> ')
if command in Location.room.exits:
Location.travel(command)
elif command == 'look':
Location.RoomDesc()
elif command == '':
print('You have to say what it is you want to do!')
command = '#'
elif command == 'search':
bag.SearchRoom()
elif command.split()[0] == 'Take':
bag.CheckTake()
elif command == 'Inventory':
bag.CheckInv()
else:
print('Invalid command')
I was advised to separate the logic of user commands from the rest of the game so I moved it to a specified class.
Before I did this however, the game would have no problem picking up only specific items from a rooms inventory. Now it picks up all.
(Code defining each room will be posted at bottom, I've been importing it from a separate .py file)
Currently, only one of my rooms contains more than one Item. The "inside cottage" room, which contains "Ornate_Key" and "Knife".
Here's the strange thing. If I try to take the Ornate_Key, it picks it up fine (Also picks up the Knife though).
However if I try to take the Knife, I receive an error with this traceback
Traceback (most recent call last):
File "C:/Users/Daniel/Python 3.6/Scripts/PythonPR/Flubbo'sModuleTest.py", line 156, in <module>
bag.CheckTake()
File "C:/Users/Daniel/Python 3.6/Scripts/PythonPR/Flubbo'sModuleTest.py", line 130, in CheckTake
self.Take(command)
File "C:/Users/Daniel/Python 3.6/Scripts/PythonPR/Flubbo'sModuleTest.py", line 122, in Take
if Location.room.roominv[key].name == command.split()[1]:
KeyError: 'Ornate_Key'
I've spent about 6 hours tinkering with this code, going back to older versions and comparing this current one to ones where I wasn't hitting this issue, and I can't figure out why this suddenly started happening.
I am very new to coding in general, so I'm very fuzzy on architecture/the fundamentals of things. Does anyone have any idea what is causing this issue?
At the very bottom of this page I will post a section of code from an older version that is not experiencing this problem.
Considering this post is already very long, I might as well post an example game to demonstrate exactly what is happening.
>>> look
You are in a forest, you can hear wildlife all around you. There seems to be a clearing in the distance.
{'Search the ground', 'Go North'}
>>> search
you find a Sword
>>> Take Sword
you take the Sword
>>> n
moving to clearing
You are in a clearing surrounded by forest. Sunlight is streaming in, illuminating a bright white flower in the center of the clearing. To the South is the way you entered the forest. A well worn path goes to the East. In the distance a harp can be heard.
{'Go East', 'Take flower', 'Go south'}
>>> e
moving to forest path
You begin walking down a well beaten path. The sounds of the forest surround you. Ahead you can see a fork in the road branching to the South and East.You can smell smoke coming from the South, and can hear a stream to the East
{'Go East', 'Go West', 'Go South'}
>>> e
moving to stream
You come upon a relaxing stream at the edge of the woods. It looks like there is something shiny in the water. To your South is a rickety looking shack, to your West is the forest path you came down
{'Go West', 'Go South'}
>>> Take Rusty_Key
you take the Rusty_Key
>>> s
moving to shack
In front of you is a shack, possibly used as an outpost for hunting. It looks dilapidated.
{'Go North', 'Go South'}
>>> s
moving to inside shack
The inside of the shack is dirty. Bits of ragged fur are scattered about the floor and on a table against the back wall.A sharp looking knife is on the table. There is an ornate key hanging on the wall by a string.
{'Take Key', 'Take Knife', 'Go North'}
>>> search
you find a Knife
you find a Ornate_Key
>>> Take Ornate_Key
you take the Ornate_Key
>>> Inventory
Your bag contains: Sword
Your bag contains: Rusty_Key
Your bag contains: Knife
Your bag contains: Ornate_Key
>>>

Any particular reason why you have a Take method in Bag? It seems totally redundant, considering all you want to do is add that item if it exists in a dictionary. Try this:
def CheckTake(self):
key = command.split()[1]
if Location.room.roominv and key in Location.room.roominv:
bag.addToInventory(key)
print('you take the', key)
else:
self.NoneHere(key)
Also, your code is inconsistent. In some places, you access globals directly, while in other places, you redundantly pass it to a function. I would strongly advice you to take this to Code Review and get your act together once you get this working.

Related

Why Python shell shows 'NameError: name 'inputwhichpower' is not defined. Did you mean: 'inputwhichpet'?'

I am making a text adventure game while i get stuck in 'NameError: name 'inputwhichpower' is not defined. Did you mean: 'inputwhichpet'?' inputwhichpower and inputwhichpet is a input. I have no idea what is causing the problem and how to fix it. my code is so big, so i am just uploading the code where the problem is facing on.
if inputcattype=="fire":
inputwhichpower = input("Choose a power. [Fire Balls]")
if inputwhichpower=="fire balls":
print("Fire balls come out of nowhere and hit Slenderbot.")
print("It took 3 Damage. It died.")
Your variable inputwhichpower is out of the second if statement's scope.
Here's the solution, you jsut have to specifiy that there IS a variable like that:
inputwhichpower = "";
if inputcattype=="fire":
inputwhichpower = input("Choose a power. [Fire Balls]")
if inputwhichpower=="fire balls":
print("Fire balls come out of nowhere and hit Slenderbot.")
print("It took 3 Damage. It died.")

Confused about the use of def() in Python

So, a while ago I started a project for educational and entertainment purposes on creating a Python based interaction story.
I wrote the code snippet below but I'm confused about something. (Bear in mind I'm new to Python so if it's something simple don't be rude please) In the snippet below I can call the function before I write it. For example, the first one I call upon is "path_1_1()" which then prints the path_1_1() function below. I'm confused as to why I can't do this in other Python programs and scripts? Because it gives me a NameError and says the variable is not defined.
def meadow():
print("You are in a tall grassy meadow\n\
there is lots of grass all around you\n\
however there are 2 paths\n\
the Train Rail Path\n\
or the Forest Path..")
meadow_choice = input("Which path will you choose? : ")
if meadow_choice =="Train Rail" or meadow_choice == "Train Rail Path" or meadow_choice == "train rail" or meadow_choice == "train rail path":
print("You've chosen the Train Rail Path")
path_1_1()
elif meadow_choice =="Forest Path" or meadow_choice == "forest path" or meadow_choice == "Forest" or meadow_choice == "forest":
print("You've chosen the Forest Path")
path_1_2()
else:
print("Woops, that's not a choice, try again.")
meadow()
# Train Rail Path 1.1
def path_1_1():
print("You walk up the train rail, cautious of\n\
oncoming trains. As you look around you spot a\n\
Small Note, and a Large hole..")
path_1_1_choices =input("Which would you like to investigate, the Small Note, or the Large Hole? : ")
if path_1_1_choices == "Small Note" or path_1_1_choices == "small note":
print("You've chosen to investigate the Small Note")
path_2_2_1()
elif path_1_1_choices == "Large Hole" or path_1_1_choices == "large hole":
print("You've chosen to investigate the Large Hole")
path_2_1_1()
else:
print("Woops, that's not a choice, try again.")
path_1_1()
Simply put, when you just define a function, you can call another function that comes later in the code.
However, when you call and execute the function, the called function should be pre defined.
def function_a():
function_b()
return 0
def function_b():
pass
This is valid.
function_a()
def function_a():
pass
This raises NameError, since function_a() was called before it was defined.
Python reads line one by one so when you call a fonction before writing it raises a NameError. However defining a fonction using def don't run any code, it only indicates to Python that the function exists and can be call further. So you can define all your functions first and, after that, call them without worrying about the order in which they are called.

Pickle module that breaks the code from the book "Conceptual Programming with Python"

I'm taking the example from the book "Conceptual Programming with Python".
Some introduction to the problem that the code is aimed at solving:
Example: Creating a Knowledge Base
As a second example for OOP, we are going to implement a simple guessing game! But this game will be able to learn from experience, that is, you will be able to teach the program as you play. For this example, we will create a knowledge base of animals. The user will think of an animal, and the computer will have to figure out which animal it is by asking you (sensible) questions about that animal; the answer will be either yes or no. If it fails to guess correctly the animal, the program will ask you what would be a sensible question to be able to find the right solution next time!
Example 1: The computer only knows how to distinguish between a bird or a cat depending on whether it has 4 legs or not. That is, the initial knowledge base only contains these two animals and one single question.
You: Think of a cat.
Computer: Does it have 4 legs?
You: Yes
Computer: Were you thinking of a cat?
You: Yes
Computer: I knew it !! Let's keep playing! I am good at this!
Once again, this follows a tree structure! Depending on whether the user answers yes or no, the computer will ask a different question, or will provide an answer!
Example 2: You teach the computer a new question.
You: Think of a dog.
Computer: Does it have 4 legs?
You: Yes
Computer: Were you thinking of a cat?
You: No
Computer: What animal were you thinking of?
You: Dog
Computer: What is a question to distinguish between dog and cat?
You: Does it bark?
Computer: For a dog, what should be the answer?
You: Yes
Now for the pickle fragment:
Files need to be always opened first; then manipulate them (for example loading their content into a data structure), and finally close them when they are no longer in use. So, we are going to try to open a file called animal.kb in which we will save the tree. The first time we open the file, it will be empty, so we will create our previous knowledge base. To do so, we will use a try-except structure. Why? Whenever we try to open a file that doesn’t exist, this will create an exception FileNotFoundError. We can simply catch it and create the knowledge base ‘manually’. Then we let the user play, and we keep updating the knowledge base kb. At the end of the program, when the user doesn’t want to play anymore, we ‘dump’ the information contained in kb on the file “animal.kb”.
After the 2nd try with opening the "animal.kb" knowledge base the error appears:
```
Do you want to play? y
Traceback (most recent call last):
File "...\ConceptualPython02\knowledgeBase.py", line 71, in <module>
kb = kb.play()
AttributeError: 'NoneType' object has no attribute 'play'
Process finished with exit code 1
```
That's the problematic code:
import pickle
class Knowledge:
pass
class Question(Knowledge):
def __init__(self, text, if_yes, if_no):
self.text, self.if_yes, self.if_no = text, if_yes, if_no
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
class Answer(Knowledge):
def __init__(self, text):
self.text = text
def play(self):
if ask("Were you thinking of a {} ? ".format(self.text)):
print("I knew it!")
return self
# here we got it right, # so we simply return the
# Answer node as it is.
else:
newanimal = input("What animal were\ "
"you thinking of? ")
newquestion = input("What is a question "
"to distinguish between {} and {} ?"
.format(self.text, newanimal))
# but in case we didn't know the animal
# we need to modify the node adding # the appropriate question and# what to do
# ifyes and if no
if ask("For {} , what should be the answer? ".format(newanimal)):
return Question(newquestion,
Answer(newanimal), self)
else:
return Question(newquestion,
self, Answer(newanimal))
def ask(q):
while True:
ans = input(q + " ")
if ans == "y":
return True
elif ans == "n":
return False
else:
print("Please answer y or n!")
try:
file = open("animal.kb", "rb")
kb = pickle.load(file)
file.close()
except FileNotFoundError:
kb = Question("Does it have 4 legs?", Question("Does it bark?",
Answer("dog"), Answer("cat")), Answer("bird"))
while True:
if not ask("Do you want to play?"):
break
kb = kb.play()
file = open("animal.kb", "wb")
pickle.dump(kb, file)
file.close()
Of course, also, it doesn't cache the new questions about the animals as it should have.
play should always return a Knowledge instance (or inherited from it). But when in Question.play the call to ask returns True, you don't return anything:
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
So change the indentation of return self so it is always executed.

My python code doesn't work

Struggling to work out why python complaining at line 4:
import sys
import re
problem = input("What is wrong with your mobile device?").lower
water = re.search(r'water', problem)
screen = re.search(r'screen', problem)+ re.search(r'smashed',problem)or re.search(r'cracked',problem)+ re.search(r'display',problem)
software=re.search(r'software',problem)+ re.search(r'program',problem)
keypad=re.search(r'keypad',problem)+ re.search(r'keyboard',problem)+ re.search(r'text',problem)
speakers=re.search(r'sound',problem)+ re.search(r"can't here",problem)+ re.search(r'cant hear',problem)
microphone=re.search(r'microphone',problem)+ re.search(r'cant hear me',problem)+ re.search(r"can't hear me",problem)
battery=re.search(r'battery',problem)+ re.search(r'swollen',problem)
charger=re.search(r'Charger',problem)+ re.search(r'charge',problem)+ re.search(r'charging',problem)
if water:
print("If your phone has suffered water dammage there is not much you can do, it is recomended that you buy a new phone")
sys.exit
elif screen:
print("If your screen is cracked then it is recomended that you get it repaired this is not too expensive.")
sys.exit
elif software:
print("If you have a software issue then contact the product manurfacture, they are the only ones qualified to fix this.")
sys.exit
elif keypad:
print("Clean your keypad with a wetwipe, do not get the charger port or jack port wet.")
sys.exit
elif microphone:
print("Your microphone hole may be blocked, please clean this with a soft dry tooth brush, if this does not work then please retern the hand held device to its manufactures.")
sys.exit
elif battery:
print("If your battery is enlarged/swollen you have probbaly over charged it it is recomended that you buy a ned battery.")
sys.exit
elif speakers:
print("The speaker on most phone is located on the side or back or the device if this is blocked then please attemt to clean this with a dry, soft toothbrush, if this does not work please contact the product manurfacture.")
sys.exit
elif charger:
print("If you have not tryed buying a new charger then try that. If a new charger does not work, please send your mobile device to the product manurfacture.")
sys.exit
else:
print("please write your problem again, attempt to use keywords that relate to your problem.")
sys.exit
If someone could tell me how to correct this or correct this themselves it would be much appreciated.
you are not calling the function lower in line 3. In order to call it, you have to write 2 parenthesis after it. Thus, correct that line as follows:
problem = input("What is wrong with your mobile device?").lower()
The problem is actually on line 3. According to this article, Python 2 uses raw_input to get input, while Python 3 uses input. It looks like your code is expecting a Python 3 environment, but your environment is actually Python 2.
You can replace your call to input with a call to raw_input if you are, indeed, running in a Python 2 environment.
In addition, you must use parentheses after the call to lower so that the method actually gets called.
Python 2
problem = raw_input("What is wrong with your mobile device?").lower()
Python 3
problem = input("What is wrong with your mobile device?").lower()

Large amount of if, elif, else statements causing issues

I am working on some code for my game and I am having an issue. I apologize in advance if this is hard to understand. The first section works fine. There is a large amount of code so I pasted it into codepad.org for easier sharing. Here's the link; http://codepad.org/kT8szBb2
Lines 108 and 142 are supposed to work together. I've tried different things like adding in this:
if True:
to try and reposition the indent level but for whatever reason it doesn't seem to work. Any suggestions work; I'm willing to try anything even if it means re-writing the entire segment. Thanks in advance.
Okay, I think I've found the issue. You don't quite understand how indentation works. You have code that looks like this:
if a:
if b:
if c:
A()
else:
B()
else:
C()
This isn't how Python works. Python works with the following structure:
if a:
A()
elif b:
B()
elif c:
C()
I'd really like to know where that mistake in understanding came from, because this is some extremely messy code.
I took the liberty of refactoring your code to be sane.
def weaponsel():
swep = None
#again, I'm not really sure where this is coming from or what you're doing with it
#so it's hard to say if you should be saving the contents of swep before you run
#the function, possibly to return if you select /return/ at the first prompt?
while swep is None:
print "What weapon would you like to use?"
if weapondict["s1"] == None:
print "Error #1: No weapons in the backpack. Contact me (Karatepig) at /hashed out for security/ and make me aware of this error."
print "I can return you to the beginning of this checkpoint or I can end the game. Type /return/ to return or /end/ to end."
er1=raw_input()
if er1.lower() == "end":
import sys
sys.exit()
elif er1.lower() == "return":
return None
else:
print "Sorry, I don't understand."
er1d()
for weapon in ['s1','s2','s3','s4','s5','s6','s7','s8']:
if weapondict[weapon]:
print("The weapon {} is available".format(weapondict[weapon]))
# as a side note, this can probably also be:
## for weapon in weapondict.values():
## print("The weapon {} is available".format(weapon))
# but that depends on what weapondict looks like!
# It should be easy to expand to "types" of weapons, as well
# using something e.g.
## weapondict = {"Rusty Sword":Sword(dmg=3), "Sharpened Spear":Spear(dmg=7)}
# and testing for type(Sword) or type(Spear) based on player class or etc.
# but you'd need to build classes for this to work, e.g.
## class Weapon(object):
## def __init__(self,dmg=1):
## self.dmg = dmg
##
## class Sword(Weapon):
## self.type = "Sword"
## self.dmgType = "Slashing"
##
## class Spear(Weapon):
## self.type = "Spear"
## self.dmgType = "Thrusting"
# then you can have slashing do more damage to lightly armored targets and
# thrusting do more damage to heavily armored targets and etc. Even writing
# methods to attack characters based on their equipped weapons. This is a
# PRIME example of where OOP will get you big results fast!
weapon=raw_input()
if weapon.lower() not in weapondict.values():
print "Sorry, I don't understand that.\n\n"
continue
print("You have selected the {}".format(weapon))
swepd1 = raw_input("Is that what you want? ")
if swepd1.lower() in ("y","yes"): swep = weapon
If you have any questions, don't hesitate to ask. I haven't actually tested this, so syntax errors may abound. I'm fairly certain it works as intended, however. As a side note -- where does weapondict come from? It's not in your code anywhere and it's likely that this function can't see it (unless you defined it earlier as global weapondict.)
There is really no need for all those if's. You should absolutely be using a for loop.
weapons = { 1:'sword', 2:'mace', 3:'bow'}
for wep in weapons:
print('the {} is available'.format(weapons[wep]))
outputs:
the sword is available
the mace is available
the bow is available

Categories

Resources