I'm working on a simple text-based trivia game as my first python project, and my program won't terminate once the score limit is reached.
def game(quest_list):
points = 0
score_limit = 20
x, y = info()
time.sleep(2)
if y >= 18 and y < 100:
time.sleep(1)
while points < score_limit:
random.choice(quest_list)(points)
time.sleep(2)
print("Current score:", points, "points")
print("You beat the game!")
quit()
...
It looks like the points variable is not increased. Something like this might work in your inner loop:
while points < score_limit:
points = random.choice(quest_list)(points)
time.sleep(2)
print("Current score:", points, "points")
I'm assuming that quest_list is a list of functions, and you're passing the points value as an argument? To make this example work, you'll also want to return the points from the function returned by the quest_list that's called. A perhaps cleaner way to build this would be to return only the points generated by the quest. Then you could do something like:
quest = random.choice(quest_list)
points += quest()
Unless points is a mutable data structure, it won't change the value. You can read more about that in this StackOverflow question.
Related
I've been stuck with something which has really halted my learning process as someone who has just started learning cs
Suppose I get an output score every turn in an iteration and the score for every turn is a random number ranging from 1 to 15
Now for every turn I want to print whether the score jump in that respective term is the biggest score jump in ALL of the turns played yet. It won't print anything if it isn't the biggest jump in score yet
I just can't seem to wrap my head around executing something like this and it has put everything I have to learn after it to a halt
#This is the function where I try to define the highest point for the score in this function-
def highest_gain(previous_value, highest_point) :
def say(score0) :
if previous_value == 0:
print ('Biggest gain by player0 yet with',score0,'points!')
return highest_gain(score0, score0)
gain = score0 - previous_value
if gain > highest_point:
print('Biggest gain by player0 yet with',score0,'points!')
return highest_gain(score0, gain)
return say
#This is the function for updating the score every turn and then call it with below-
while n > 0:
score += random.randint(1, 15)
f = say(score)
n -= 1
return score
score0(6,0,highest_gain(0,0))
Any help on this would be really appreciated🙏 . This has been bugging me for a few days now. I just can't seem to understand why the values inside of highest_gain can't remain updated after every turn they are executed.
This does what you ask, but I suspect what you need is not what you asked for.
import random
highest = 0
def score0(n):
global highest
score = 0
for i in range(n):
bump = random.randint(1, 15)
if bump > highest:
highest = bump
print('Biggest gain by player0 yet with',bump,'points!')
score += bump
return score
score0(6)
I'm new to python so don't be surprised it if is something really basic, but i've been trying to write this code that asks math questions and then saves the scores in order to show them again at the start of the loop, but it doesn't save the scores. what should i change?
this is the code
scores = []
names = []
while True:
f = open("highscore.txt", "r")
for line in f:
line = line.strip("\n")
line = line.split(" ")
names.append(line[0])
scores.append(int(line[1]))
print(f.read())
for pos in range(len(names)) :
print(pos + 1, names[pos], scores[pos])
f.close()
score = 0
print("hello, welcome to maths game")
print("\nQuestion 1: what is 2 x 2 x 2?")
answer = int(input("your answer >"))
if answer == 8:
print("correct")
score = score + 1
print("your score is ", score)
else:
print("incorrect")
print("the score is ", score)
print("\nQuestion 2: what is 34 x 2?")
answer = int(input("your answer >"))
if answer == 68:
print("correct")
score = score + 1
print("your score is", score)
else:
print("incorrect")
print("the score is", score)
name = input("what is your name?")
position = 0
for compare_score in scores :
if score < compare_score:
position = position + 1
scores.insert(position, score)
names.insert(position, name)
scores = scores[:5]
names = names[:5]
f = open("highscore.txt", "w")
for pos in range (len(names)):
f.write(names[pos] + " " + scores[pos])
it doesn't give any kind of error message, just loops back and doesn't save the names, neither the scores
You have a for-loop on scores that adds a new item to the scores list at each iteration. The for-loop will never reach the end of the list because there is always 'one more'.
Alain T.'s answer has already stated the root cause that you experienced. The loop never stops which appears to you as "freezing" since there are no outputs or indicators that you (as a user/developer) see that the loop still runs. So actually nothing freezes here .. it just runs forever.
For that reason I wanted to add a short note how to drill down the problem your own the next times..
Keyword here is clearly: debugging.
Debugging means: "finding out what your code does while being executed"
A very simple but (at least for small programs) quite effective approach is using one or more print() statements. These can be used to display the value of variables, the property of an object or just some statement like print("I am before the loop") to know where execution runs/stops..
A possible would be: (look at the print statements)
while True:
print("in while") #<-- this one
...
print("before loop") #<-- this one
for compare_score in scores :
print("in loop") #<-- this one repeats....
if score < compare_score:
position = position + 1
scores.insert(position, score)
names.insert(position, name)
scores = scores[:5]
names = names[:5]
print("After loop") #<-- never see this one
f = open("highscore.txt", "w")
for pos in range (len(names)):
f.write(names[pos] + " " + scores[pos])
Running your program again should print out:
in while
before loop
in loop
in loop
in loop
in loop
in loop
in loop
in loop
...
and so on... So what you know now is:
Everything before the loop at least executed
The loop runs forever .
So now it would be time to dig a little deeper inside the loop.
Most interesting would be to examine the variable on which the loop exit
depends.
In your case that is the length of the scores list:
for compare_score in scores:
So the loop runs until there are no more scores to compare left in the scores list.
So it might be a good idea to print() the length of the list to check if and how it decreases until there are no more scores to compare.
So add something like this:
Check the two print() statements containing len(scores)
for compare_score in scores:
print("in loop")
if score < compare_score:
position = position + 1
scores.insert(position, score)
names.insert(position, name)
scores = scores[:5]
names = names[:5]
print(len(scores)) #<--- this one
# or a bit nicer as f-string:
print(f"len score: {len(scores)}") #<--- this one
print("After loop")
Both are displaying the length of the scores list.
The former one just does it a little nicer.
There is a lot more to debugging. Many tools like VSCode, Pycharm, etc. support a lot more sophisticated methodologies to step through code, set breakpoints, inspect objects and variables ..
But for small ans simple projects and when the focus is on learning, instant feedback and repeating. At least to my mind. Print() debugging gives you a lot of insight in a very easy and simple manner.
Oh, and if you read until here:
"Welcome to the community" Just jokin', welcome !! ;)"
initial_p = input("Enter the initial point")
def game():
x = 1
guess = input("Guess value")
if guess == 1:
initial_p += 2
else:
initial_p -= 2
game()
replay = raw_input("Do you want to try it again? Y/N")
if replay == 'Y':
game()
each game needs 2 points
I made it really simple just to explain this stuff easily
So to play each game, it requires you to have at least 2 points otherwise it becomes game over
if you guess right, you earn 2 points
if not, you lose 2 points.
with the outcome(points), you can either play again or quit
if you play again, you pay two points
HOWEVER, when you play for the second time or more, that line
initial_p += 2 and initial_p -= 2 still have points that you typed in the very beginning
The quick and dirty response is to change to the following.
def game(initial_p):
#Your Code
return initial_p
initial_p = game(initial_p)
Basically, you're placing the global variable as a local variable and reassigning the global.
This should also happen at the very bottom as well.
Also, you can just ask for the input inside of the function, and have a default argument of initial_p.
For example,
def game(first_time=True)
#Ask for input with if first_time:
return initial_p
And modify some global point value or something from the return.
Sorry if this is sloppy, was written on my mobile.
So I have the following code:
def monsterturn():
global monster
global playerhp
turn = True
print "Rolling for", monster, "...(14 or better to hit)"
time.sleep(1)
if r > 14:
print r, "- The", monster, "hit you!"
playerhp-=1
time.sleep(0.5)
print "Your HP:", playerhp
if playerhp == 0:
turn = False
time.sleep(0.5)
print "YOU HAVE BEEN SLAIN."
else:
turn = False
time.sleep(1.5)
playerturn()
elif r < 14:
print r, "- The", monster, "missed you."
turn = False
playerturn()
r = randrange(1, 21)
The function playerturn() is structured exactly like monsterturn(), except with the global variable monsterhp instead of playerhp, r2 instead of r, and dialogue for the player instead of the monster. The problem is, it calculates a random integer once, and then keeps it, which often winds up with nobody hitting anyone, forever. How can I get it to calculate a different random integer every time?
Also, the function playerturn() is called, and at the end triggers monsterturn(), which triggers playerturn(), and so on, until somebody dies.
I think you should just rethink your overall design, as this would cause you to run into issues. This is largely theoretical, but the longer your fight is, the deeper your call stack would become, in the end possibly resulting in a stack overflow (and also increased memory consumption; even if it continues to run fine).
Instead, I'd suggest you rework the functions to return a boolean value, whether the game should continue. You're then able to just loop as long as both functions return true, essentially meaning the game continues:
while playerturn() and monsterturn():
To make each hit/attack random, you'd reassign r a random value right before using it:
...
time.sleep(1)
r = randrange(1, 21)
if r > 14
...
Calculate r within the loop, instead of outside it.
You can also improve this greatly by factoring out the common material, so that monster and player have the same turn function. You'd do this by avoiding the reference to global variables and passing in the details that change (opponent's hitpoints, the message to print, and so forth)
I'm new to python, and I'm building a game to teach myself python. This game will have a number of lessons, with questions and answers; the user will gain and lose points depending on the validity of their answers.
I'm using dictionaries to store the questions and answers that will be asked in each lesson.
I want to display and check the keys and values of the dictionary only at specific points (e.g. after the user enters a command). To do this, I imagined that I could create functions containing the dictionaries and then pass them to a main function when needed.
But when I run the code below, I get the following error: AttributeError: 'function' object has no attribute 'iteritems'
So I have two questions:
I tried removing the dictionary from within a function, and it works
just fine then. Is there any way (or reason) to make it work within
a function?
Is it possible to use just one dictionary and check the keys and values of a section of it at certain points?
Here's my code so far. Any advice whatsoever would be much appreciated!
points = 10 # user begins game with 10 pts
def point_system():
global points
#help user track points
if 5 >= points:
print "Careful. You have %d points left." % points
elif points == 0:
dead("You've lost all your points. Please start over.")
else:
print "Good job. Spend your points wisely."
def lesson1():
#create a dictionary
mydict = {
"q1":"a1",
"q2":"a2"
}
return mydict
def main(lesson):
global points
#get key:value pair from dictionary
for k, v in lesson.iteritems():
lesson.get(k,v) # Is the .get step necessary? It works perfectly well without it.
print k
user_answer = raw_input("What's your answer?: ")
#test if user_answer == value in dictionary, and award points accordingly
if user_answer == v:
user_answer = True
points += 1 #increase points by 1
print "Congrats, you gained a point! You now have %d points" % points
point_system()
elif user_answer != v:
points -= 1 #decrease points by 1
print "Oops, you lost a point. You now have %d points" % points
point_system()
else:
print "Something went wrong."
point_system()
main(lesson1)
and the code that works:
points = 10 # user begins game with 10 pts
#create a dictionary
lesson1 = {
"q1":"a1",
"q2":"a2"
}
def point_system():
global points
#help user track points
if 5 >= points:
print "Careful. You have %d points left." % points
elif points == 0:
dead("You've lost all your points. Please start over.")
else:
print "Good job. Spend your points wisely."
def main(lesson):
global points
#get key:value pair from dictionary
for k, v in lesson.iteritems():
lesson.get(k,v) # Is the .get step necessary? It works perfectly well without it.
print k
user_answer = raw_input("What's your answer?: ")
#test if user_answer == value in dictionary, and award points accordingly
if user_answer == v:
user_answer = True
points += 1 #increase points by 1
print "Congrats, you gained a point! You now have %d points" % points
point_system()
elif user_answer != v:
points -= 1 #decrease points by 1
print "Oops, you lost a point. You now have %d points" % points
point_system()
else:
print "Something went wrong."
point_system()
main(lesson1)
You're calling main() with the lesson1 function and not the result of the lesson1 function (which is a directory).
You should write:
main(lesson1())
By the way, lesson1 must also return the created directory for this to work:
def lesson1():
#create a dictionary
mydict = {
"q1":"a1",
"q2":"a2"
}
return mydict
You passed a function that returns a dictionary so you should call the function first to get the dictionary. So you may modify your code so that main accepts dictionary (the code actually expects a dictionary):
main(lesson1())
If you really would like to pass a function then you should modify you main to execute function first to get the dictionary:
def main(lessonFunc):
global points
lesson = lessonFunc()
#get key:value pair from dictionary
for k, v in lesson.iteritems():
but the first option is probably better. You could also pack a lesson into an object.