My code freezes and stops, what's wrong with it? - python

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 !! ;)"

Related

Why does my code keep on looping like this when I'm using functions?

So I'm trying to make a Hangman console game and im trying to check how many tries I have left and then later add a game over function if tries left. One part of it is working the stringcount function is working properly until I have to call the goAgain function, I'll explain the issue lower in the document
import time
hangmanSolved = "What 'eva hh"
chosingletter = input("Input a letter you would like to try! ")
def goAgain(defaultTries):
defaultTries -= 1
print("Head drawn!", defaultTries, "tries left ")
stringcount()
# if a letter is in, and how many letters are in
def stringcount():
count = 0
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
goAgain(defaultTries=5)
elif count == 1:
print("There is only one ", chosingletter, " in this sentence! ")
else:
print("There is ", lettersIn, chosingletter, "'s in this sentence! ")
stringcount()
When I run the code and guess a wrong letter, or rather when I have to call goAgain function it keeps on looping me this output:
Input a letter you would like to try! j
There are no j 's in this sentence!
Head drawn! 4 tries left
There are no j 's in this sentence!
Head drawn! 4 tries left
How can I fix this looping, and the tries counter?!?
So first of all the counter is wrong because you are using a local variable. When the method is called with defaultTries = 5 it will always start at 5 even though you have done defaultTries -= 1.
To fix this you need to read up and assign a global variable outside of the scope so that whenever the user is wrong that global variable gets subtracted.
Furthermore, I am unsure as to why you would use the time module here. What is your goal by doing this?
What you are trying to do is loop through the sentence and check if the letter the user inputs exists inside the sentence. There are easier ways to go about this.
You can use string.indexOf('a'). where 'a' you can change it to the letter you are searching for (the user's input). It returns the index of the first occurrence of the character in the character sequence represented by this object, or -1 if the character does not occur.
I would start with changing those things first!
Every time you call goAgain you call it with defaultTries set to 5. Then, in that function, it subtracts one, leaving you with 4. Then it calls stringount which again calls goAgain which will call stringcount and so on. There's nothing that breaks out of the loop.
So you need to change three things:
Don't pass in the same value of defaultTries every time you call goAgain. You want to allow that variable to decrease.
Git rid of the goAgain function. Instead put that logic in stringcount itself.
Check the value of the number of tries remaining and if it's zero, print out some kind of message, but don't call stringcount in that branch.
def stringcount(tries = 5):
count = 0
tries =- 1
if tries == 0:
print("No tries remaining")
else:
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
stringcount(tries)
elif count == 1:
print("There is only one ", chosingletter, " in this sentence! ")
else:
print("There is ", lettersIn, chosingletter, "'s in this sentence! ")
stringcount()
A few other things you can consider changing:
The standard formatting in Python is PEP8 and you should review those. For example, Python convention is to use snake_case instead of camelCase. So you would use something like default_tries instead of defaultTries for example.
It's probably more explicit to check if count == 0 than it is to check if not count.
I think you don't need the loop that updates the variable count. Just use lettersIn (which you should rename as letters_in or, better, just call this count). Now you also don't need to set count==0 at the top of the function.
You're having problems because you are basically using a recursive strategy but you haven't defined a base case, and also because you reinitialize your defaultTries variable to 5 every time you call the goAgain() function. A base case is a condition where you tell a recursive function to stop. In this case tries needs to be 0. Here's an example of what your code might look like:
def goAgain(tries):
tries -= 1
if tries==0:
print("You lose")
return None
print("Head drawn!", tries, "tries left ")
stringcount(tries)
def stringcount(defaultTries=5): #This is how you set default args
chosingletter = input("Input a letter you would like to try! ")
count = 0
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
goAgain(defaultTries)
It's up to you whether you want to keep goAgain() and stringcount() separate. I think it makes sense to keep them separate because I can imagine you want to check how many tries are in goAgain and then print new statements accordingly, like "left arm drawn!" etc.

It wont print out the code at the bottom on the program

For some reason the print command at the bottom is not printing out it is just looping no matter how I put indentation as well.
result_list = []
print("Welcome to Speed Cameras")
while 1:
result_list.append(input("New Reading: "))
if result_list == "END":
break
try:
max_speed = max(result_list)
min_speed = min(result_list)
avg_speed = len(result_list) / len(result_list)
print("Max is:", max, " MPH:")
print("Min is:", min, " MPH")
print("Avg is", avg_speed, "MPH")
finally:
print("Thanks For Submitting")
You have 2 issues and both are here
if result_list == "END":
break
result_list is a list so it will never be equal to a string, instead you could check if the last item is END like this result_list[-1] == "END"
the second problem you have is indentation, your break is not in the if statement but in the while loop, but this doesn't seem to be the case with your error, so i think you copied your code into the question with an error
Here is the code would work:
result_list = []
print("Welcome to Speed Cameras")
while 1:
# you need test the input first before append it to the list and not test the list
inp = input("New Reading: ")
if inp == "END":
break
else:
result_list.append(float(inp)) # turn your input into a number before appending
try:
max_speed = max(result_list)
min_speed = min(result_list)
# len(result_list) / len(result_list) make no sense, use sum()
avg_speed = sum(result_list) / len(result_list)
print("Max is:", max_speed, " MPH:") # your variable name was wrong here
print("Min is:", min_speed, " MPH") # your variable name was wrong here
print("Avg is", avg_speed, "MPH")
# since you try, you should do something when you don't pass the try
# 1 there is no input at all
# 2 the input need to be numbers
except:
print('at least one speed input is needed, or please make sure your input to be a number')
finally:
print("Thanks For Submitting")
A few mistakes:
Test the input instead of the list, and then append it to the list
Need to turn input into number
Average speed formula need to be fixed
Don't forget except in try-except-finally
Wrong variable names inside print()
Please reading your own code a few time before post it for help. Some mistakes like variable names and avg-speed formula, are easy to identify.
Anyway hope this would help.

Inconsistent Python outcomes

So I'm having this problem in which my code is inconsistently failing at random times, this has been answered before:(Python 3.7.3 Inconsistent code for song guessing code, stops working at random times now I have had to add a leaderboard to this song guessing game I am doing. I randomly choose a number of which is used to find the artist and song. If right, it will remove the song and artist to prevent dupes and carry on. Here is the code:
loop = 10
attempts = 0
ArtCount = len(artist)
for x in range (ArtCount):
print(ArtCount)
randNum = int(random.randint(0, ArtCount - 1))
randArt = artist[randNum]
ArtInd = artist.index(randArt)# catches element position
songSel = songs[randNum]
print (randNum)
print ("The artist is " + randArt)
time.sleep(0.5)
songie = songSel
print( "The songs first letter be " + songSel[0])
time.sleep(0.5)
print("")
question = input("What song do you believe it to be? ")
if question == (songSel):
songs.remove(songSel)
artist.remove(randArt)
print ("Correct")
print ("Next Question")
if attempts ==0:
points = points + 5
print("+5 Points")
print("")
if question != (songSel):
loop = loop + 1
attempts = attempts + 1
print("")
print("Wrong,", attempts, "questions wrong, careful!")
print("")
time.sleep(0.5)
if attempts == 5:
break
print("GAME OVER")
Pardon my mess, I'm just starting off in making large code, will clean up when finished. I've had the additional problem of having the count controlled loop as 10 (the amount of questions) then having to go pas the loop when you get a question wrong, I've tried having it loop by the amount of songs in the list and I've also tried making a variable that +1 when you get it wrong so you have space to answer but that doesn't work either. After implementing the leaderboard it now doesn't remove any songs (I was messing with the indentation to make the leaderboard print every time.) The error I randomly get is;
randArt = artist[randNum]
IndexError: list index out of range
I'm never sure why this is the code that is the problem, I'm not even sure if it's necessary.
Please, don't use
randNum = int(random.randint(0, ArtCount - 1))
You may easily get a random artist by using:
randArt = random.choice(artist)
The problem is your code had modify the artist array length when you remove item on true answer. You need to get the right artist count after you change.
for x in range (ArtCount):
print(ArtCount)
count = len(artist) # get the new length here
randNum = int(random.randint(0, count - 1)) # use the new length here instead of your old ArtCount

How to not print duplicate lines from an external text file?

I am trying to create a multiple choice quiz using python. I have an external .txt file that has 20 questions in and I want it to select 10 random questions from that file, which it currently does. The file has the layout:
1,Who was the first man to walk on the moon?,A.Michael Jackson,B.Buzz Lightyear,C.Neil Armstrong,D.Nobody,C
The problem i'm having is that I don't want it to print the same question twice.
The only way I can think to solve this is to add detail[0], which is the question number, to a list defined in python and then check within that list to make sure that the question number isn't duplicated.
import random
qno = []
def quiz():
i = 0
global score #makes the score variable global so it can be used outside of the function
score=0 #defines the score variable as '0'
for i in range (1,11): #creates a loop that makes the program print 10 questions
quiz=open('space_quiz_test.txt').read().splitlines() #opens the file containing the questions, reads it and then splits the lines to make them seperate entities
question=random.choice(quiz)
detail = question.split(",")
print(detail[0],detail[1],detail[2],detail[3],detail[4],detail[5])
print(" ")
qno.append(detail[0])
print(qno)
if detail[0] in qno is False:
continue
qno.append(detail[0])
print(qno)
elif detail[0] in qno is True:
if detail[0] not in qno == True:
print(detail[0],detail[1],detail[2],detail[3],detail[4],detail[5])
print(" ")
qno.append(detail[0])
print(qno)
while True:
answer=input("Answer: ")
if answer.upper() not in ('A','B','C','D'):
print("Answer not valid, try again")
else:
break
if answer.upper() == detail[6]:
print("Well done, that's correct!")
score=score + 1
print(score)
continue
elif answer.upper() != detail[6]:
print("Incorrect, the correct answer is ",detail[6])
print(score)
continue
quiz()
When I run this code I expect that no question is repeated twice but it always seems to do that, i'm struggling to think of a way to do this. Any help would be grateful, Thank you!
Use this:
questions = random.sample(quiz, 10)
It will select a random sublist of length 10, from the quiz list.
Also:
You should read the file, and make the question list outside the loop, then just loop over the questions:
with open('space_quiz_test.txt') as f:
quiz = f.readlines()
questions = random.sample(quiz, 10)
for question in questions:
...
Read all the questions:
with open('space_quiz_test.txt') as f:
quiz = f.readlines()
Shuffle the list of questions in place:
random.shuffle(quiz)
Loop on the shuffled list:
for question in quiz:
print(question)
This is because random.choice can give the same output more than once. Instead of using random.choice try
random.shuffle(list) and then choosing the first 10 records from the shuffled list.
quiz=open('space_quiz_test.txt').read().splitlines()
random.shuffle(quiz)
for question in quiz[1:11]:
detail = question.split(",")
print(detail[0],detail[1],detail[2],detail[3],detail[4],detail[5])
You can accomplish this by drawing the questions all at once with choice without replacement, then iterating over those.
import numpy as np
quiz=open('space_quiz_test.txt').read().splitlines() #opens the file containing the questions, reads it and then splits the lines to make them seperate entities
questions=np.random.choice(quiz, size=10, replace=False)
for question in quesions: #creates a loop that makes the program print 10 questions
#rest of your code
Instead of opening the file 10 times, get 10 questions from it and loop asking them:
def get_questions(fn, number):
with open(fn) as f:
# remove empty lines and string the \n from it - else you get
# A\n as last split-value - and your comparisons wont work
# because A\n != A
q = [x.strip() for x in f.readlines() if x.strip()]
random.shuffle(q)
return q[:number]
def quiz():
i = 0
global score # makes the score variable global so it can be used outside of the function
score=0 # defines the score variable as '0'
q = get_questions('space_quiz_test.txt', 10) # gets 10 random questions
for question in q:
detail = question.split(",")
print(detail[0],detail[1],detail[2],detail[3],detail[4],detail[5])
print(" ")
# etc ....
Doku:
inplace list shuffling: random.shuffle
There are several other things to fix:
# global score # not needed, simply return the score from quiz():
my_score = quiz() # now my_score holds the score that you returned in quiz()
...
# logic errors - but that part can be deleted anyway:
elif detail[0] in qno is True: # why `is True`? `elif detail[0] in qno:` is enough
if detail[0] not in qno == True: # you just made sure that `detail[0]` is in it
...
while True:
answer=input("Answer: ").upper() # make it upper once here
if answer not in ('A','B','C','D'): # and remove the .upper() downstream
print("Answer not valid, try again")
else:
break

For loop only executes 1 time, though given a range of 5

This question already has answers here:
How can I use `return` to get back multiple values from a loop? Can I put them in a list?
(2 answers)
Closed 2 days ago.
I have the following code:
def input_scores():
scores = []
y = 1
for num in range(5):
score = int(input(print('Please enter your score for test %d: ' %y)))
while score < 0 or score > 100:
print ('Error --- all test scores must be between 0 and 100 points')
score = int(input('Please try again: '))
scores.append(score)
y += 1
return scores
When I run it, the output is as follows:
Please enter your score for test 1:
None
Then I'll enter the test score next to None, as, say 95
It then runs through the rest of the program without prompting me for the next test score to add to the scores list. I'm really curious why that is
Thanks in advance for taking the time to help
Sincerely,
~Dustin
You return from inside the loop. Move return scores one indent left.
your return statement is indented too much, causing the function to return on the first iteration. It needs to be outside of the for block. This code works:
def input_scores():
scores = []
y = 1
for num in range(5):
score = int(input('Please enter your score for test %d: ' %y))
while score < 0 or score > 100:
print ('Error --- all test scores must be between 0 and 100 points')
score = int(input('Please try again: '))
scores.append(score)
y += 1
return scores
You indentation of the code seems whacky. It looks like the return statement is inside the scope of the for loop. So after the first iteration the return statement takes you out of the function completely.
You're returning scores at the end of each loop iteration (so in other words, after the first loop iteration finishes, you return all the scores thereby exiting the function, and the loop).
Change your code to be:
for num in range(5):
# ...
return scores # Note the indentation is one tab less than the loop's contents
Others have correctly pointed out that the indentation of your return statement was causing the problem. Also, you might want to try it like this, using len(scores) to control the loop, as #max suggested:
def input_scores(num_tests=5, max=100, min=0):
scores = []
while len(scores) < num_tests:
score = int(input('Please enter your score for test {0}: '.format(len(scores)+1)))
if score < min or score > max:
print ('Error --- all test scores must be between 0 and 100 points.')
else:
scores.append(score)
return scores

Categories

Resources