So I'm doing a project for an online class and when i got it scored it came back as not passed because my "play game" function was more than 18 lines long and I'm supposed to optimize it. The problem is they didn't make any suggestions as to what i should do and I keep looking at it and feel as if I need everything in it to make the fill in the blank quiz I'm building work. Any suggestions would be great as I am still very new to coding, and maybe what they are asking me to do is easy and I'm over complicating it in my head. This is the part of the code they want optimized...
def play():
'''
This is the main function which allows to play the game/quiz.
It calls the previous functions we have written.
'''
quiz = difficulty_level(user_level) #gives the difficulty
paragraph that the user asks for.
print quiz
print "\nYou will get maximum 3 guesses for each blank. Good luck.\n"
answers_list = relate_answer(user_level) #makes sure that the right
list is called up
blanks_index = 0
answers_index = 0
number_of_guesses = 3
while blanks_index < len(blanks): #This loop keeps going if all the
blanks are not replaced.
user_answer = raw_input("type in your answer for " + blanks[blanks_index] + ": ")
if check_answer(user_answer,answers_list,answers_index) == "Correct":
print "Awesome job! You gave the right answer!\n"
quiz = quiz. replace(blanks[blanks_index],user_answer)
blanks_index += 1
answers_index += 1
number_of_guesses = 3
print quiz
else:
number_of_guesses -= 1
if number_of_guesses == 0:
print "Game over! But try again!"
break
elif number_of_guesses < 0:
print "invalid"
break
else:
print "please try again."
print "You have " + str(number_of_guesses) + " guesses left."
print "Congratulations! You really know your stuff!."
play()
A quick summation of changes:
It looks like answers_index and blanks_index share the same state, no matter what, so we can generalize that to one variable idx. That cuts down on the number of variables you have to keep track of.
As others have suggested, initializing variables as a tuple like var1, var2 = 1, 2 decreases length and makes code more readable (to a point). If you have lots of variables to initialize, you can break the initialization into groups of related variables.
Setting a default value to user_level increases readability, and also gives an easy place to start debugging your function. This occurs in the def statement, so if you don't pass the argument, user_level will be 1, otherwise it will be whatever you give it in the function call. Example play(user_level=40) will overwrite that default value.
Putting the game loss condition at the start of the while loop increases visibility of the checks the code goes through before executing anything unnecessary. This should help you avoid the case where guess would be less than 0, because that code won't execute when guess==0 is True.
Setting a lose boolean with the check after exiting the while loop will also prevent the wrong print statement at the end from executing. That way, if the player loses, you will print the proper message.
Breaking the update of quiz into another function adds a more compact breakpoint into the code. In general, smaller functions that do less are preferable to large functions that do a lot. The smallest number of changes necessary is a good standard for what should be wrapped into a function, though this could be considered a stylistic convention more than a hard and fast rule.
The correct_answer method allows you to update quiz and guess in one line, and if something is wrong with the update itself, you don't have to run the entire script over and over. Instead you can take the quiz that might be causing the problem and plug it into that function until you find what's causing the problem.
I've made some minimal updates to the function you've provided which keep most of your conventions so far. Hopefully this is helpful, and happy coding!
def correct_answer(quiz, blank, answer):
"""
Function to update the quiz and return
both the quiz and reset guess to 3
"""
print("Awesome job! You gave the right answer!\n")
quiz = quiz.replace(blank, answer)
return quiz, 3
def play(user_level=1):
'''
This is the main function which allows to play the game/quiz.
It calls the previous functions we have written.
'''
idx, guess, lose = 0, 3, False
quiz = difficulty_level(user_level) #gives the difficulty paragraph that the user asks for.
print(quiz)
print("\nYou will get maximum 3 guesses for each blank. Good luck.\n")
answers_list = relate_answer(user_level) #makes sure that the right list is called up
while idx < len(blanks): #This loop keeps going if all the blanks are not replaced.
if guess <= 0:
lose = True
break
user_answer = raw_input("type in your answer for %s:" %str(blanks[idx]))
if check_answer(user_answer,answers_list,idx) == "Correct":
quiz, guess = correct_answer(quiz, blanks[idx], user_answer)
print(quiz)
else:
guess -= 1
print("please try again.\nYou have %s guesses left.\n"%str(guess))
idx += 1
if lose:
print("Game over, try again")
else:
print("Congratulations! You really know your stuff!.")
play(user_level = 3)
Related
Hello fellow programmers! I am a beginner to python and a couple months ago, I decided to start my own little project to help my understanding of the whole development process in Python. I briefly know all the basic syntax but I was wondering how I could make something inside a function call the end of the while loop.
I am creating a simple terminal number guessing game, and it works by the player having several tries of guessing a number between 1 and 10 (I currently made it to be just 1 to test some things in the code).
If a player gets the number correct, the level should end and the player will then progress to the next level of the game. I tried to make a variable and make a true false statement but I can't manipulate variables in function inside of a while loop.
I am wondering how I can make it so that the game just ends when the player gets the correct number, I will include my code down here so you guys will have more context:
import random
import numpy
import time
def get_name(time):
name = input("Before we start, what is your name? ")
time.sleep(2)
print("You said your name was: " + name)
# The Variable 'tries' is the indication of how many tries you have left
tries = 1
while tries < 6:
def try_again(get_number, random, time):
# This is to ask the player to try again
answer = (input(" Do you want to try again?"))
time.sleep(2)
if answer == "yes":
print("Alright!, well I am going to guess that you want to play again")
time.sleep(1)
print("You have used up: " + str(tries) + " Of your tries. Remember, when you use 5 tries without getting the correct number, the game ends")
else:
print("Thank you for playing the game, I hope you have better luck next time")
def find_rand_num(get_number, random, time):
num_list = [1,1]
number = random.choice(num_list)
# Asks the player for the number
ques = (input("guess your number, since this is the first level you need to choose a number between 1 and 10 "))
print(ques)
if ques == str(number):
time.sleep(2)
print("Congratulations! You got the number correct!")
try_again(get_number, random, time)
elif input != number:
time.sleep(2)
print("Oops, you got the number wrong")
try_again(get_number, random, time)
def get_number(random, try_again, find_rand_num, time):
# This chooses the number that the player will have to guess
time.sleep(3)
print("The computer is choosing a random number between 1 and 10... beep beep boop")
time.sleep(2)
find_rand_num(get_number, random, time)
if tries < 2:
get_name(time)
tries += 1
get_number(random, try_again, find_rand_num, time)
else:
tries += 1
get_number(random, try_again, find_rand_num, time)
if tries > 5:
break
I apologize for some of the formatting in the code, I tried my best to look as accurate as it is in my IDE. My dad would usually help me with those types of questions but it appears I know more python than my dad at this point since he works with front end web development. So, back to my original question, how do I make so that if this statement:
if ques == str(number):
time.sleep(2)
print("Congratulations! You got the number correct!")
try_again(get_number, random, time)
is true, the while loop ends? Also, how does my code look? I put some time into making it look neat and I am interested from an expert's point of view. I once read that in programming, less is more, so I am trying to accomplish more with less with my code.
Thank you for taking the time to read this, and I would be very grateful if some of you have any solutions to my problem. Have a great day!
There were too many bugs in your code. First of all, you never used the parameters you passed in your functions, so I don't see a reason for them to stay there. Then you need to return something out of your functions to use them for breaking conditions (for example True/False). Lastly, I guess calling functions separately is much more convenient in your case since you need to do some checking before proceeding (Not inside each other). So, this is the code I ended up with:
import random
import time
def get_name():
name = input("Before we start, what is your name? ")
time.sleep(2)
print("You said your name was: " + name)
def try_again():
answer = (input("Do you want to try again? "))
time.sleep(2)
# Added return True/False to check whether user wants to play again or not
if answer == "yes":
print("Alright!, well I am going to guess that you want to play again")
time.sleep(1)
print("You have used up: " + str(tries) + " Of your tries. Remember, when you use 5 tries without getting the correct number, the game ends")
return True
else:
print("Thank you for playing the game, I hope you have better luck next time")
return False
# Joined get_number and find_random_number since get_number was doing nothing than calling find_rand_num
def find_rand_num():
time.sleep(3)
print("The computer is choosing a random number between 1 and 10... beep beep boop")
time.sleep(2)
num_list = [1,1]
number = random.choice(num_list)
ques = (input("guess your number, since this is the first level you need to choose a number between 1 and 10 "))
print(ques)
if ques == str(number):
time.sleep(2)
print("Congratulations! You got the number correct!")
# Added return to check if correct answer is found or not
return "Found"
elif input != number:
time.sleep(2)
print("Oops, you got the number wrong")
tries = 1
while tries < 6:
if tries < 2:
get_name()
res = find_rand_num()
if res == "Found":
break
checker = try_again()
if checker is False:
break
# Removed redundant if/break since while will do it itself
tries += 1
The code creates a random addition problem and spits out "Congratulations" if correct and "sorry...." if the inputted value is wrong. The while loop repeats this process until the user inserts "N" for the question "continue (Y/N):, at the same time it keeps track of how many questions have been answered, and which ones are correct. The code works fine, my problem is it has repetitive code. I was wondering if there is a way to shrink it.
**I appreciate everyone one's help and advice. I"m a noob that's just learning python **
import random
correct=0
count=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
else:
print('Your final score is',correct,'/',count)
A first start, would be eliminating the code before the while, by initializing the count variable (which keeps track of the turns), in zero, and allowing the while loop to run the first turn, we just need to have a variable like want_to_play and by default it's True, so the first time we'll be playing, and at the end of the game If I don't input Y or y it will asume I don't want to play any more and set the variable to false, that way I can have all the turns ran by the while loop.
and you'll be getting something like this.:
from random import sample
correct = 0
count = 0 # STartint in turn zero
want_to_play = True # Control Variable
while want_to_play:
count += 1
# First turn this is zero, and adds one.
[num1, num2] = sample(range(0, 101), 2)
# Just another way of getting two random numbers from 1 up to (including) 100.
# Printing could be done in one line.
print(format(num1, '5d') + '\n+' + format(num2, '4d'))
answer = int(input('= '))
# The comparison really doesn't really hurt if you do it this way.
if answer == num1 + num2:
print('Congraulations!')
correct += 1
else:
print('Sorry the correct answer is', sum)
# HERE you ask if you want to play again or not, using a one line if
# you decide.
want_to_play = (True if 'y' == input('Continue (Y/N).lower():')
else False)
else:
print('Your final score is',correct,'/',count)
By initializing the variable c as "Y", the condition is met and the loop can be executed:
import random
correct=0
count=1
c = "Y"
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
c = c.upper()
else:
print('Your final score is',correct,'/',count)
I also added the method upper() to the Y/N input so the user can also type it in lowercase
Try to move as much of the processing as possible into the loop. The first "paragraph" of your code was basically a duplicate of the main-loop. By creating the continuation variable c so that it drops straight into the loop, most of that first block could be removed.
import random
correct=0
count=0
c = 'Y'
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congratulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
else:
print('Your final score is',correct,'/',count)
The two formula printing statements can also be reduced to a single one:
print(format(num1,'4d'))
print('+',num2)
could be
print( format(num1,'4d') + '+', num2 )
The variable sum could be removed, but it does make the code self-documenting, which is a good thing.
I am a beginner student in a python coding class. I have the majority of the done and the program itself works, however I need to figure out a way to make the program ask if wants a subtraction or an adding problem, and if the user would like another question. I asked my teacher for assistance and he hasn't gotten back to me, so I'm simply trying to figure out and understand what exactly I need to do.
import random
x = int(input("Please enter an integer: "))
if x < 0:
x = 0
print('Negative changed to zero')
elif x == 0:
print('Zero')
elif x == 1:
print('Single')
else:
print('More')
maximum = 10 ** x;
maximum += 1
firstnum = random.randrange(1,maximum) # return an int from 1 to 100
secondnum = random.randrange(1, maximum)
compsum = firstnum + secondnum # adds the 2 random numbers together
# print (compsum) # print for troubleshooting
print("What is the sum of", firstnum, " +", secondnum, "?") # presents problem to user
added = int(input("Your answer is: ")) # gets user input
if added == compsum: # compares user input to real answer
print("You are correct!!!")
else:
print ("Sorry, you are incorrect")
You'll want to do something like this:
def foo():
print("Doing good work...")
while True:
foo()
if input("Want to do more good work? [y/n] ").strip().lower() == 'n':
break
I've seen this construct (i.e., using a break) used more often than using a sentinel in Python, but either will work. The sentinel version looks like this:
do_good_work = True
while do_good_work:
foo()
do_good_work = input("Want to do more good work? [y/n] ").strip().lower() != 'n'
You'll want to do more error checking than me in your code, too.
Asking users for input is straightforward, you just need to use the python built-in input() function. You then compare the stored answer to some possible outcomes. In your case this would work fine:
print('Would you like to test your adding or subtracting skills?')
user_choice = input('Answer A for adding or S for subtracting: ')
if user_choice.upper() == 'A':
# ask adding question
elif user_choice.upper() == 'S':
# ask substracting question
else:
print('Sorry I did not understand your choice')
For repeating the code While loops are your choice, they will repeatedly execute a statement in them while the starting condition is true.
while True: # Condition is always satisfied code will run forever
# put your program logic here
if input('Would you like another test? [Y/N]').upper() == 'N':
break # Break statement exits the loop
The result of using input() function is always a string. We use a .upper() method on it which converts it to UPPERCASE. If you write it like this, it doesn't matter whether someone will answer N or n the loop will still terminate.
If you want the possibility to have another question asked use a while loop and ask the user for an input. If you want the user to input whether (s)he want an addition or substraction you already used the tools to ask for such an input. Just ask the user for a string.
I have previously studied Visual Basic for Applications and am slowly getting up to speed with python this week. As I am a new programmer, please bear with me. I understand most of the concepts so far that I've encountered but currently am at a brick wall.
I've written a few functions to help me code a number guessing game. The user enters a 4 digit number. If it matches the programs generated one (I've coded this already) a Y is appended to the output list. If not, an N.
EG. I enter 4567, number is 4568. Output printed from the list is YYYN.
import random
def A():
digit = random.randint(0, 9)
return digit
def B():
numList = list()
for counter in range(0,4):
numList.append(A())
return numList
def X():
output = []
number = input("Please enter the first 4 digit number: ")
number2= B()
for i in range(0, len(number)):
if number[i] == number2[i]:
results.append("Y")
else:
results.append("N")
print(output)
X()
I've coded all this however theres a few things it lacks:
A loop. I don't know how I can loop it so I can get it to ask again. I only want the person to be able to guess 5 times. I'm imagining some sort of for loop with a counter like "From counter 1-5, when I reach 5 I end" but uncertain how to program this.
I've coded a standalone validation code snippet but don't know how I could integrate this in the loop, so for instance if someone entered 444a it should say that this is not a valid entry and let them try again. I made an attempt at this below.
while myNumber.isnumeric() == True and len(myNumber) == 4:
for i in range(0, 4)):
if myNumber[i] == progsNumber[i]:
outputList.append("Y")
else:
outputList.append("N")
Made some good attempts at trying to work this out but struggling to patch it all together. Is anyone able to show me some direction into getting this all together to form a working program? I hope these core elements that I've coded might help you help me!
To answer both your questions:
Loops, luckily, are easy. To loop over some code five times you can set tries = 5, then do while tries > 0: and somewhere inside the loop do a tries -= 1.
If you want to get out of the loop ahead of time (when the user answered correctly), you can simply use the break keyword to "break" out of the loop. You could also, if you'd prefer, set tries = 0 so loop doesn't continue iterating.
You'd probably want to put your validation inside the loop in an if (with the same statements as the while loop you tried). Only check if the input is valid and otherwise continue to stop with the current iteration of your loop and continue on to the next one (restart the while).
So in code:
answer = [random.randint(0, 9) for i in range(4)]
tries = 5
while tries > 0:
number = input("Please enter the first 4 digit number: ")
if not number.isnumeric() or not len(number) == len(answer):
print('Invalid input!')
continue
out = ''
for i in range(len(answer)):
out += 'Y' if int(number[i]) == answer[i] else 'N'
if out == 'Y' * len(answer):
print('Good job!')
break
tries -= 1
print(out)
else:
print('Aww, you failed')
I also added an else after the while for when tries reaches zero to catch a failure (see the Python docs or maybe this SO answer)
I'm making a number guessing game and can someone tell me why it wont work properly?
import random
import time
time.time()
count=0
a = random.randint(0,100)
b = int(input("What number will you guess?"))
while b != a:
if b > a:
print("TOO BIG")
count = count + 1
elif b < a:
print("TOO SMALL")
count = count + 1
else b == a:
print("YOU WIN")
count = count + 1
time=time.time()
print("You took",count,"tries")
print("It took you",time,"second")
The reason this isn't working properly is because you're calling b = input outside of your while loop. As it stands, the user will be asked a single time what their guess is, then the loop will just move infinitely, because b is never being modified.
This loop will accomplish more what you want:
a = random.randint(0,100)
b = -1
while b != a:
b = int(input("What number will you guess?"))
A few notes, though:
Firstly, as Lee Daniel Crocker points out, the user will actually never see "YOU WIN", because you've structured your if-elif-else statement incorrectly. else by definition cannot have a condition - it exists purely in exclusion to all other conditionals in the same block. Additionally, your else statement is the opposite of your while condition. When that else becomes true, the loop exits. You'll need to handle printing "YOU WIN" somewhere else.
Second, you're not validating the user's input in any way - if they enter 'a', the program will crash, because you can't cast 'a' to an int. Either add an exception handler (for ValueError) or using isdigit() on the string, then casting it.
Third, you're not using time.time() correctly - you need to subtract the time at which the user wins from the time at which they started, then represent that value, which is in seconds, in some meaningful way. As it stands you're telling each player that they took the number of seconds since the beginning of the UNIX epoch to complete the game.
Also, for usability reasons, you should probably provide the user some way to break out - a string like "QUIT" - because as it stands, the only way to restart/quit is to either close the application or KeyboardInterrupt.
You need to accept input in the loop. Move the line b = int(input("What number will you guess?")) within the loop.