I'm writing a small game in python in which certain events happen and effect variables which need to stay in certain parameters. I have the main file and then another file which has all of the events in them. Some of the values are changed in the function then supposed to change the overall values in main (Sorry if that doesnt make sense)
Here's the part in main:
while (army > -100 and army < 100 and people > -100 and people < 100 and church > -100 and church < 100 and affairs > -100 and money < 100 and money > -100):
os.system('clear')
#Top Bar. Should Stay throughout game.
print("[-]==[King: " + king + "]==[Years in power:" + str(years) +"]==[Army: " + str(army) + "]==[People: " + str(people) + "]==[Church: " + str(church) + "]==[Foreign Affairs: " + str(affairs) + "]==[Economy: " + str(money) +"]==[-]")
print(people)
event1(army, people, church, affairs, money, years)
That loops until one of the parameters falls below 0 then there's losing conditions
Right now there is only one event, and it's not quite finished, but I only need one thing to at least see a change in the values.
Here that:
def event1(army, people, church, affairs, money, years):
#Feilds are Flooding
print("")
print("Sire! The Feilds in the eastern baronies are flooding! What should we do?")
print("")
print("Choices:")
print("1: The rain will pass, do nothing. (~Money, People)")
print("2: Have the Royal Builders build flood protection! (~Money, People)")
print("")
c=input("Your choice sire: ")
while True:
if c > 2:
print("")
print("Please chose a valid option")
print("Your choice sire: ")
continue
if c == 1:
time.sleep(2)
print("")
print("You do nothing, your people starve from flooded feilds (-People, +Money)")
money = money+20
people = people-20
years = years+1
raw_input("Press Enter to go to the next year")
return money
return years
return people
break
After it runs the event the values people, money and years are all supposed to change, but when it loops, nothing changes.
Any help is appreciated! Thank you!
Those are local variables. As soon as you leave the method scope, the value is lost, unless you return and actually use the returned values.
In your caller, assign your variables with the new returned values:
money, years, people = event1(army, people, church, affairs, money, years)
and in event1, perform only one return (others are unreachable) of the tuple containing the 3 values you want to return (which is unpacked to the 3 upper level eponymous variables):
return money, years, people
YOU DO NOT NEED THE RETURN!!!!!!!!!!!!!!!!!!!! COMPLETELY REMOVE IT! READ THIS! (should help)
The return in fact ruins your command, and there is a really easily explainable way to understand how it works.
First I need to explain something, because I am kind of confused about your code. Return is used to make the value of your command whatever you have returned. Return is used like this:
def AddThreethousandTwohundredSeventyNineToNum(num):
num = num + 3279
return num
and then
print AddThreethousandTwohundredSeventyNineToNum(4)
It should print "3283". (3279 + 4)
print printThreethousandTwohundredSeventyNineToNum(2)
It will print "3281".
You can also do cool things like:
if AddThreethousandTwohundredSeventyNineToNum(x) == y:
DoSomething
All return does is make the value OF THE FUNCTION whatever you want it to be. In the last code, the function looks for what I made num, and sees that it is 4 or 2, so it does num = num + 3279, so num gets increased by 3279 (3273 or 3271). When you do return num, it makes THE FUNCTION equal num.
That means what you have done is changed all those beatiful values in lines 21-23 (money, people, etc.) and technically that is all you had to do. However, when you returned the numbers, you made your command not only change those values, but also become a number, and obviously you cant just have a number lying around in your command. Or else the interpreter will not understand.
I hope I was clear enough, and if not, please please PLEASE tell me (please).
Related
I've written a program for a Number guessing game in Python which i have almost completed. However, there is one small problem i can't figure out. After the game finishes I want the statistics to be printed out for each player to a .txt with the following information:
Username | Win or Loss | Number of Guesses.
I can't figure out how to generate the Win/Loss statistic in the following line for each player:
f.write(str(playerName)+ '|' +str(numberOfGuesses)+'\n').
If anyone could please provide some advice it would be greatly appreciated. I have displayed part of the code as follows:
won = False
while numberOfGuesses < maxGuesses:
guess = int(input('What is your guess?: '))
numberOfGuesses += 1
if guess < number:
print('Too low')
if guess > number:
print('Too high')
if guess == number:
won = True
break
print('You have', str(maxGuesses - numberOfGuesses) + ' guesses remaining\n')
if won:
print('Congratulations!!! You guessed the number in ' + str(numberOfGuesses) + ' tries!')
else:
print('Game Over!!! You did not guess the correct number, the number was ' + str(number))
f = open('Statistics.txt', 'a')
f.write(str(playerName)+ '|' +str(numberOfGuesses)+'\n')
f.close()
f = open('Statistics.txt', 'r')
print(f.read())
It's pretty, simple.
To clarify, if won == True, you want to write "Won" to the line and if won == False, you want to write "Loss" to the line right?
win_or_loss = 'Loss'
if won:
win_or_loss = 'Win'
Then you just use this variable when you write to the file
f.write(str(playerName)+ '|' + win_or_loss + '|' +str(numberOfGuesses)+'\n')
Also, you don't need to wrap playerName in str() since it is already a string.
Since you have playerName in the mix, I assume you're trying to keep score stats per player. In that case, I suggest you create a dictionary keyed on player names. The values can be lists of [numCorrect, totalGuesses] per player. You would update numCorrect and totalGuesses during each player's turn as appropriate. In the end, you would walk through that dictionary and process the results.
Here's the logic to implement so you can get the Win/Loss stats.
For each game, you will have the following
Player Name, Win or Loss flag, Total Guesses.
Read statistics file to see if player exists. If player exists, then retrieve the following information:
Player Name, Win Count, Loss Count, Win-Loss Stats, Lowest Number of Guesses
* Win Count will be # of times player has won in the past
* Loss Count will be # of times player has lost in the past
* Win-Loss stat will be Win / (Win + Loss). If you want % then x by 100
* Lowest Number of Guesses for the first entry will be numberOfGuesses
For all subsequent entries, you need to update the record in the file based on new calculations as shown below.
If current game is win, win_count += 1
If current game is loss, loss_count += 1
win_loss stat will remain win_count / (win_count + loss_count)
if numberOfGuesses < lowest_number_of_guesses: lowest_number_of_guesses = numberOfGuesses.
#you can modify this with walrus option if you use 3.8+
Write back this stats to the file. This will keep track of the status for the player and you can use this to keep the stats updated every time the player plays
Since you are going to have a lot of I/O with the above logic, you may want to read the file into memory and calculate this in memory, then write to file as part of normal program exit. One challenge is that the data will be lost if the program abruptly crashes.
Hope this helps you implement a good logic.
I wanted to write this in comments but the max chars exceeded. So put this in the answer comments. I would prefer you write the code as it will help you with the implementation of the logic.
So I'm working a quiz on Python as a project for an Intro to Programming course.
My quiz works as intended except in the case that the quiz variable is not being affected by the new values of the blank array. On the run_quiz function I want to make the quiz variable update itself by changing the blanks to the correct answer after the user has provided it.
Here's my code:
#Declaration of variables
blank = ["___1___", "___2___", "___3___", "___4___"]
answers = []
tries = 5
difficulty = ""
quiz = ""
#Level 1: Easy
quiz1 = "Python is intended to be a highly " + blank[0] + " language. It is designed to have an uncluttered " + blank[1] + " layout, often using English " + blank[2] + " where other languages use " + blank[3] + ".\n"
#Level 2: Medium
quiz2 = "Python interpreters are available for many " + blank[0] + " allowing Python code to run on a wide variety of systems. " + blank[1] + " the reference implementation of Python, is " + blank[2] + " software and has a community-based development model, as do nearly all of its variant implementations. " + blank[1] + " is managed by the non-profit " + blank[3] + ".\n"
#Level 3: Hard
quiz3 = "Python features a " + blank[0] + " system and automatic " + blank[1] + " and supports multiple " + blank[2] + " including object-oriented, imperative, functional programming, and " + blank[3] + " styles. It has a large and comprehensive standard library.\n"
#Answer and quiz assignment
def assign():
global difficulty
global quiz
x = 0
while x == 0:
user_input = raw_input("Select a difficulty, Press 1 for Easy, 2 for Medium or 3 for Hard.\n")
if user_input == "1":
answers.extend(["readable", "visual", "keywords", "punctuation"])
difficulty = "Easy"
quiz = quiz1
x = 1
elif user_input == "2":
answers.extend(["operating systems", "cpython", "open source", "python software foundation"])
difficulty = "Medium"
quiz = quiz2
x = 1
elif user_input == "3":
answers.extend(["dynamic type", "memory management", "programming paradigms", "procedural"])
difficulty = "Hard"
quiz = quiz3
x = 1
else:
print "Error: You must select 1, 2 or 3.\n"
x = 0
def run_quiz():
n = 0
global tries
global blank
print "Welcome to the Python Quiz! This quiz follows a fill in the blank structure. You will have 5 tries to replace the 4 blanks on the difficulty you select. Let's begin!\n"
assign()
print "You have slected " + difficulty + ".\n"
print "Read the paragraph carefully and prepare to provide your answers.\n"
while n < 4 and tries > 0:
print quiz
user_input = raw_input("What is your answer for " + blank[n] + "? Remember, you have " + str(tries) + " tries left.\n")
if user_input.lower() == answers[n]:
print "That is correct!\n"
blank[n] = answers[n]
n += 1
else:
print "That is the wrong answer. Try again!\n"
tries -= 1
if n == 4 or tries == 0:
if n == 4:
print "Congratulations! You are an expert on Python!"
else:
print "You have no more tries left! You can always come back and play again!"
run_quiz()
I know my code has many areas of improvement but this is my first Python project so I guess that's expected.
The problem is that your variable, quiz, is just a fixed string, and although it looks like it has something to do with blanks, it actually doesn't. What you want is 'string interpolation'. Python allows this with the .format method of str objects. This is really the crux of your question, and using string interpolation it's easy to do. I'd advise you to take some time to learn .format, it's an incredibly helpful function in almost any script.
I've also updated your code a bit not to use global variables, as this is generally bad practice and can lead to confusing, difficult to track bugs. It may also impair the uncluttered visual layout :). Here is your modified code, which should be working now:
quizzes = [
("""\
Python is intended to be a highly {} language.\
It is designed to have an uncluttered {} layout,\
often using English {} where other languages use {}
""", ["readable", "visual", "keywords", "punctuation"], "Easy"),
("""\
Python interpreters are available for many {}\
allowing Python code to run on a wide variety of systems.\
{} the reference implementation of Python, is {}\
software and has a community-based development model, as\
do nearly all of its variant implementations. {} is managed by the non-profit {}
""", ["operating systems", "cpython", "open source", "python software foundation"], "Medium"),
("""\
Python features a {} system and automatic {} and\
supports multiple {} including object-oriented,\
imperative, functional programming, and\
{} styles. It has a large and comprehensive standard library.
""", ["dynamic type", "memory management", "programming paradigms", "procedural"], "Hard")
]
#Answer and quiz assignment
def assign():
while True:
user_input = raw_input("Select a difficulty, Press 1 for Easy, 2 for Medium or 3 for Hard.\n")
if user_input == "1":
return quizzes[0]
elif user_input == "2":
return quizzes[1]
elif user_input == "3":
return quizzes[2]
else:
print "Error: You must select 1, 2 or 3.\n"
continue
break
def run_quiz():
n = 0
#Declaration of variables
blank = ["___1___", "___2___", "___3___", "___4___"]
tries = 5
print "Welcome to the Python Quiz! This quiz follows a fill in the blank structure. You will have 5 tries to replace the 4 blanks on the difficulty you select. Let's begin!\n"
quiz, answers, difficulty = assign()
print "You have selected {}.\n".format(difficulty)
print "Read the paragraph carefully and prepare to provide your answers.\n"
while n < 4 and tries > 0:
print quiz.format(*blank)
user_input = raw_input("What is your answer for {}? Remember, you have {} tries left.\n".format(blank[n], tries))
if user_input.lower() == answers[n]:
print "That is correct!\n"
blank[n] = answers[n]
n += 1
else:
print "That is the wrong answer. Try again!\n"
tries -= 1
if n == 4 or tries == 0:
if n == 4:
print "Congratulations! You are an expert on Python!"
else:
print "You have no more tries left! You can always come back and play again!"
run_quiz()
A little more on string interpolation:
You're doing a lot of "start of string " + str(var) + " end of string". This can be achieved quite simply with "start of string {} end of string".format(var)" - it even automatically does the str conversion. I've changed your quiz variables to have "{}" where either "__1__" etc should be displayed or the user's answer. You can then do quiz.format(*blank*) to print the 'most recent' version of the quiz. * here 'unpacks' the elements of blank into separate arguments for format.
If you find it more easy to learn with example usage, here are two usages of format in a simpler context:
>>> "the value of 2 + 3 is {}".format(2 + 3)
'the value of 2 + 3 is 5'
>>> a = 10
>>> "a is {}".format(a)
'a is 10'
I've also stored the information about each quiz in a list of tuples, and assign now has a return value, rather than causing side effects. Apart from that, your code is still pretty much intact. Your original logic hasn't changed at all.
Regarding your comment about objects:
Technically, yes, quizzes is an object. However, as Python is a 'pure object oriented language', everything in Python is an object. 2 is an object. "abc" is an object. [1, 2, 3] is an object. Even functions are objects. You may be thinking in terms of JavaScript - with all of the brackets and parentheses, it kind of resembles a JS Object. However, quizzes is nothing more than a list (of tuples). You might also be thinking of instances of custom classes, but it's not one of those either. Instances require you to define a class first, using class ....
A bit more on what quizzes actually is - it's a list of tuples of strings, lists of strings and strings. This is a kind of complicated type signature, but it's just a lot of nested container types really. It firstly means that each element of quizzes is a 'tuple'. A tuples is pretty similar to a list, except that it can't be changed in place. Really, you could almost always use a list instead of a tuple, but my rule of thumb is that a heterogenous collection (meaning stuff of different types) should generally be a tuple. Each tuple has the quiz text, the answers, and the difficulty. I've put it in an object like this as it means it can be accessed by indexing (using quiz[n]), rather than by a bunch of if statements which then refer to quiz1, quiz2, etc. Generally, if you find yourself naming more than about two variables which are semantically similar like this, it would be a good idea to put them in a list, so you can index, and iterate etc.
Only now have I read your question properly.
You first make your strings quiz1, quiz2 an quiz3.
You only do that once.
After that you change your blanks array.
But you don't reconstruct your strings.
So they still have the old values.
Note that a copy of elements of the blanks array is made into e.g. quiz1.
That copy doesn't change automagically after the fact.
If you want to program it like this, you'll have to rebuild your quiz1, quiz2 and quiz3 strings explicitly each time you change your blanks array.
General advice: Don't use so many globals. Use function parameters instead. But for a first attempt I guess it's OK.
[edit]
A simple modification would be:
Replace your quiz, quiz1, quiz2 and quiz3 by functions get_quiz (), get_quiz1 () etc. that get the most recent version, including the altered elements of blanks.
This modification doesn't make this an elegant program. But you'll come to that with a bit more experience.
A long shot in case you wonder (but don't try to bridge that gap in one step):
In the end Quiz will probably be a class with methods and attributes, of which you have instances.
To be sure: I think that experimenting like this will make you a good programmer, more than copying some ready to go code!
I am new to programming and trying to get a head start on my class next semester. I am trying to show the total cost and then print it. Where am I going wrong?
print('Would you like a rental car?')
rental = (input('Yes or No? '))
if rental.lower() == yes:
car = float(input('Dollar Amount?'))
else:
print('Thank You!')
print('Would you need a flight?')
flight = (input('Yes or No '))
if flight.lower() == yes:
plane = float(input('Dollar Amount? '))
else:
print('Thank You!')
print('Would need a hotel?')
hotel = (input('Yes or No? '))
if hotel.lower() == yes:
room = float(input('Dollar Amount? '))
sum = travel (room + plane + car)
print('This is the total amount that it may cost you, ' + travel '!')
Problem 1
Fix your indentation. Python uses indentation to define what block code is executed in (i.e. in an if statement, or after it). Here's what you should do:
Select all (cmd / ctrl + a), and then keep pressing (cmd / ctrl + [) to de-indent. Do this until nothing is indented.
On any line you want in an if / else statement, press the TAB key at the start of that line.
Problem 2
The input function (which gets user input) returns a string. You then try to compare this to an undefined variable yes. Replace the yes in your if statements with "yes" or 'yes' to ensure you are comparing two strings.
Problem 3
Remember to end all of your strings, with a closing quotation mark. You forgot one printing "Thank You" after the "Would you need a flight?" question.
Replace: print('Thank you.) with print('Thank you.')
Problem 4
Second-to-last line, you define sum, which is never used. Then, you try to use the undefined travel function to add up your three variables. This line of code, in general, makes no sense. I am assuming that you meant this:
travel = (room + plane + car)
Problem 5
You can't concat floats / ints to strings.
This should be the final line:
print('This is the total amout that it is may cost you, '+str(travel)+'!')
Also, you forgot the concat operator (+) when appending the exclamation mark.
Final Code:
Here is the working version of your code:
print('Would you like a rental car?')
rental = (input('Yes or No? '))
if rental.lower() == 'yes':
car = float(input('Dollar Amount?'))
else:
print('Thank You!')
print('Would you need a flight?')
flight = (input('Yes or No '))
if flight.lower() == 'yes':
plane = float(input('Dollar Amount? '))
else:
print('Thank You!')
print('Would need a hotel?')
hotel = (input('Yes or No? '))
if hotel.lower() == 'yes':
room = float(input('Dollar Amount? '))
travel = (room + plane + car)
print('This is the total amout that it is may cost you, ' + str(travel)+ '!')
Recommendations:
This works, but it could be better. Here are a few recommendations, which will help you not only with this project, but also with further ones:
You can combine your print and input functions together, since input basically prints and then waits for input. To format it like you have now, simply include a newline character, \n. For example, instead of
print('Would you like a rental car?')
rental = (input('Yes or No? '))
you could do
rental = input("Would you like a rental car?\nYes or No?")
These lines could actually be simplified further. You don't need to define the variable rental, but instead you can just use its' output directly in the if statement, i.e.
if input("Would you like a rental care?\nYes or No?").lower() == "yes" :
...
Learn to use try / catch statements to catch errors. When entering the amount for a travel expense, the user has to type a number. But what if they type a string instead? Your program would crash. Learn how to use try / catch statements to prevent this from happening (https://docs.python.org/3/tutorial/errors.html)
There's not really much apart from that. These were all just beginners mistakes, and soon you'll be writing good code that works well :D
I was also impressed to see how you handled the "yes" / "no" user input by converting the answers to lower case and then checking them, which is something that a lot of people of your skill level neglect to do.
I'm fairly new to the programming game; I'm 3/4 of the way through Learn Python the Hard Way and I had a question about a little text-based game I made... So in this game my guy is stranded on a desert island and you have the option(raw input) of going left right or into the jungle. After choosing a direction, you're given the option to choose how many miles to walk. Each direction is supposed to have a different end result (and mile distance).
If you enter a number that is less than the number of miles to the destination, you're prompted with a choice to either "turn around or "keep going". If you enter turn around, you're taken back to the beginning, where you're again asked to choose a direction. If you enter keep going, the program returns to miles(), where you can choose a new amount of miles to walk.
def miles():
print "How many miles do you walk?"
miles_choice = raw_input("> ")
how_much = int(miles_choice)
if how_much >= 10:
right_dest()
elif how_much < 10:
turn()
else:
print "You can't just stand here..."
miles()
Ok so here's two questions:
How would I make it so that if the user originally enters a number of miles less than the destination distance, and the second mile input + the first mile input == the amount of miles to the destination, it will add the inputs and run my destination function, not just repeat miles().
Since all three final destinations will have different distances, should I write three separate mile functions? Is there a way to make it so that depending on the original direction chosen, miles() will run the different endpoints?
I'm sorry if this doesn't make a lick of sense... I'm still learning and I'm not sure how to fully explain what I'm trying to get across.
You could store the amount of miles to walk in each direction in a dict, and then check the dict to see if the user has walked far enough:
distances = {
'right': 7,
'left': 17,
'forward': 4
}
direction_choice = raw_input("> ")
miles_choice = raw_input("> ")
if how_much >= distances['direction_choice']:
right_dest()
elif how_much < distances['direction_choice']:
turn()
else:
print "You can't just stand here..."
miles()
Be sure to properly validate and cast the user input, which I have not addressed. Good luck!
I don't fully understand the requirements (the intended behavior and constraints). However, you might consider passing a parameter to your function (through and argument) to convey the maximum number of miles which the play could go in that direction).
For example:
#!/usr/bin/env python
# ...
def miles(max_miles=10):
print "How many miles do you walk?"
while True:
miles_choice = raw_input("> ")
try:
how_much = int(miles_choice)
except ValueError, e:
print >> sys.stderr, "That wasn't a valid entry: %s" % e
continue
if max_miles > how_much > 0:
break
else:
print "That's either too far or makes no sense"
return how_much
... in this case you pass maximum valid number of miles into the function through the "max_miles" argument and you return a valid integer (between 1 and max_miles) back.
It would be the responsibility of this function's caller to then call right_dest() or turn() as appropriate.
Note that I've removed your recursive call to miles() and replace it with a while True: loop, around a try: ... except ValueError: ... validation loop. That's more appropriate than recursion in this case. The code does a break out of the loop when the value of how_much is valid.
(By the way, if you call miles() with no parameter then the argument will be set to 10 as per the "defaulted argument" feature. That's unusual to Python (and Ruby) ... but basically makes the argument optional for cases where there's a sensible default value).
#Question #1: I used Class intern variables. You will maybe need them for further programming parts and should take it to zero when you are done on one direction, to start with zero for next step/lvl.
#Question #2: Dictionaries are the best way to do so,self.dest. Parameter pos used as key to get the value from the dictionary.
class MyGame:
def __init__(self):
self.current_miles = 0
self.dest = {'Left' : 10, 'Into the jungle' : 7, 'Right' : 22}
def miles(self,pos):
print "How many miles do you walk?"
miles_choice = raw_input("> ")
self.current_miles += int(miles_choice)
if self.current_miles >= self.dest.get(pos):
self.miles("Right")
elif self.current_miles < self.dest.get(pos):
print "you went "+ str(self.current_miles) + " miles"
else:
print "You can't just stand here..."
self.miles(pos)
mg = MyGame()
mg.miles('Into the jungle')
So I am having trouble getting this system to work, and I can't be sure that I'm asking the right question, but here is what is happening and what I want to happen.
money = 1
def Stats():
print
print "money " + str(money)
def gainM():
money + 2
Stats()
if money == 1:
gainM()
Now what happens when it goes to print money, the value is still 1 even though I add 2 to the value. (code is not a copy of my actual program, but an example to show what is happening.)
money + 2 is a no-op. You actually have to assign money to a new value
money = money + 2
# or
money += 2
But then you'll find you get an error - you can't assign to variables outside a function scope. You can use the global keyword:
global money
money += 2
This will allow you to change the value of money within the function.
However, the recommended way is passing money as a parameter:
def gainM(money):
money += 2
Stats()
return money
if money == 1:
money = gainM(money)
If you're using the second option (which you should be), you also need to change your Stats function, to have a money parameter as well.
def Stats(money):
print
print "money " + str(money)
Otherwise the function will print 1 instead of 3.
Another recommendation - use string formatting.
'money %d' % money # the old way
'money {}'.format(money) # the new and recommended way
Now you pass money into the Stats function.
def gainM(money):
money += 2
Stats(money)
return money
You need to assign the new value to money. Like so:
money = money + 2
Or the shorthand form:
money += 2
Also, if the variable is outside your function, you need to declare it global(so it doesn't instead create a local variable)
So you end up with:
def gainM():
global money
money += 2
Stats()
Edit: just to clarify, I'm not saying you should use global variables. In general they are a bad idea(though they may be useful in some situations). However, that's what this particular example needs to work. Chances are, however, that what you want is probably a class with instance variables that the methods of that class modify. However, given that you don't seem to have grasped the basics of the language yet, take things one step at a time and don't worry about any words in my previous sentences you didn't understand for now :)