Large amount of if, elif, else statements causing issues - python

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

Related

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.

Repeating a function with another function

for an assignment we needed to make a function that flipped a coin and another to flip it 100 times. I was able to make a function that flipped a coin, but got stuck when trying to call it a 100 times with another function. This is what I have right now:
import random
def TC():
face = random.randint(0,1)
if face == 1:
return "head"
else:
return "tail"
print TC()
def ply(flips):
for i in range(flips):
return TC()
print ply(100)
When I run it it just says 'none.' Please tell me where I am going wrong. Thank You!
Just to start, your method naming is very bad. I doubt this is how your professor is teaching you to name methods and variables. It's ugly, against Python standards and hard to read I suggest you take some time and read PEP 8 it's how python was intended to be written.
So instead of TC you should use something like flip_coin and instead of ply use something like play_coin_flip or even simply play.
Next I don't know if I'm stepping outside of what you have learned but instead of using randon.randint you can use randon.choice.
And finally, as others have said, when you return you quit any other execution in a function and return whatever variable you retrun in that statement thus nullifying any other iterations of the loop you're performing. I suggest something like the below as a better program with corrections applied to make it function as intended.
from random import choice
faces = ['head', 'tail']
def flip_coin():
face = choice(faces)
return face
def play_coin_flip(flips = 1):
for i in range(flips):
print(flip_coin)
if __name__ == "__main__":
play_coin_flip(100)

What is the right balance for logging, commenting and test cases when coding?

One thing I have noticed about when I code is that commenting, logging and writing test cases takes me out of any flow I am in and slows down my coding speed. So I am wondering if I do it too much/more than necessary. If I am using a debug logger, is there such thing as logging TOO much stuff? Also, is there a way to make the output log file color coordinated so that I can easily find issues/places where the value is not what I expect? Also, should I comment everything or just certain places explaining why I do something? Finally, what should I be making test cases for? Is it every single if statement or just every function?
Take this code for example:
def parse_data(raw_):
# Assume raw is a dict
parsed_output = dict()
for i in raw_.keys():
if i["type"] == "child":
parsed_output[i] = {"type": "Student"}
else:
parsed_output[i] = {"type": "Teacher"}
if 14 <= i["age"] <= 19:
parsed_output[i]["division"] = "High School"
elif 11 <= i["age"] < 14:
parsed_output[i]["division"] = "Middle School"
elif i["age"] < 11:
parsed_output[i]["division"] = "Elementary"
else:
parsed_output[i]["division"] = "Staff"
parsed_output[i]["name"] = i["name"]
return parsed_output
Should I add in a logging line after every if saying that it found a Student in High School? Or should I just put a debug line saying the # of People found in raw, and one after that says the number of people found in High School, Middle School, Elementary, and staff? For test cases, should I write one for each if statement in this function, or for the function as a whole? Also, for a function like this, do you have separate files you use as "test data" and expected output? Finally, in this function, should I comment before each of the if blocks what each is looking for, or only comment before the first parsed_output to explain that the reason I created a dict at parsed_output[i] was to avoid an index error?

python randomly shuffled multiple choice questionaire

I'm making a subclass for multiple choice questions under a superclass of trivia questions for my Python university course. The multiple choice aspect works, but I want to shuffle the order of the answers for extra credit.
Some of my code:
class ChoiceQuestion(Question) :
def __init__(self) :
super().__init__()
self._choices = []
def addChoice(self, choice, correct) :
self._choices.append(choice)
if correct :
# Convert len(choices) to string.
choiceString = str(len(self._choices))
self.setAnswer(choiceString)
# Override Question.display().
def display(self) :
# Display the question text.
super().display()
# Display the answer choices.
for i in range(len(self._choices)) :
choiceNumber = i + 1
print("%d: %s" % (choiceNumber, self._choices[i]))
The question choices are added in a seperate file I have no control over as a test-file. This is run by the professor after turning in whatever variation of the first code. Here is what he runs it on. Side note: there are of course import statements in the second file, but I have the other stuff solved and it's very long. Didn't want to include stuff that has been worked out.
print('\n')
mcq = ChoiceQuestion()
mcq.setText("In which country was the inventor of Python born?")
mcq.addChoice("Australia", False)
mcq.addChoice("Canada", False)
mcq.addChoice("Netherlands", True)
mcq.addChoice("United States", False)
for i in range(3) :
presentQuestion(mcq)
## Presents a question to the user and checks the response.
# #param q the question
#
def presentQuestion(q) :
q.display() # Uses dynamic method lookup.
response = input("Your answer: ")
if q.checkAnswer(response):
print("Correct")
else:
print("Incorrect") # checkAnswer uses dynamic method lookup.
# Start the program.
With that said, I need to display the options in a random order, while updating the number value tied to that choice slot. I.e. if Netherlands is randomized into slot 1, typing "1" will print "Correct". I also have to make sure I don't allow the same option to appear more than once.
How should I go about it? What are some suggestions? Note: I can only modify the first program
Here are a couple of things to think about:
As kiran.koduru mentioned, look at using the random module for easily shuffling lists.
Currently your code stores the correct answer as it is received. This makes it difficult because when the answers are shuffled the stored answer is no longer correct. An alternative is to store choice and correct together and calculate the correct answer after your choices are shuffled.
Your code does not know in addChoice whether or not there will be more choices added, so shuffling there will result in wasted computation.

Categories

Resources