Access a function variable from outside the function in python - python

I have a python function and would like to retrieve a value from outside the function. How can achieve that without to use global variable. I had an idea, if functions in python are objects then this could be a right solution?
def check_difficulty():
if (difficulty == 1):
check_difficulty.tries = 10
elif (difficulty == 2):
check_difficulty.tries = 5
elif (difficulty == 3):
check_difficulty.tries = 3
try:
difficulty = int(input("Choose your difficulty: "))
check_difficulty()
except ValueError:
difficulty = int(input("Type a valid number: "))
check_difficulty()
while check_difficulty.tries > 0:
I am new to python so excuse me...

def check_difficulty(difficulty):
if (difficulty == 1):
return 10
elif (difficulty == 2):
return 5
elif (difficulty == 3):
return 3
tries = 0
while tries > 0:
difficulty = int(input("Choose your difficulty: "))
tries = check_difficulty(difficulty)
tries = tries - 1

if you use a while loop and put everything inside in a structured way, a function will not be needed.

You can change this to a class to get your tries:
class MyClass:
def __init__(self):
self.tries = 0
def check_difficulty(self, difficulty):
if (difficulty == 1):
self.tries = 10
elif (difficulty == 2):
self.tries = 5
elif (difficulty == 3):
self.tries = 3
ch = MyClass()
try:
difficulty = int(input("Choose your difficulty: "))
ch.check_difficulty(difficulty)
except ValueError:
difficulty = int(input("Type a valid number: "))
ch.check_difficulty(difficulty)
ch.tries
# 5

If you want the question answered within the construct of your current code simply put your try, except before the function. You can call a function anywhere in the code it doesn't ave to be after the function is created . So something like this:
try:
difficulty = int(input("Choose your difficulty: "))
check_difficulty()
except ValueError:
difficulty = int(input("Type a valid number: "))
check_difficulty()
def check_difficulty():
if (difficulty == 1):
check_difficulty.tries = 10
elif (difficulty == 2):
check_difficulty.tries = 5
elif (difficulty == 3):
check_difficulty.tries = 3
while check_difficulty.tries > 0:
however, I would have to agree with the other answers and just kind of put everything together within the same loop and you won't have to worry about this. I created a guessing game recently that actually had something similar to this. Here is the difficulty portion of that code:
def guessing_game():
again = ''
# Define guesses/lives
while True:
try:
guesses_left = int(input('How many guess would you like(up to 4)?: '))
if 1 > guesses_left or guesses_left > 4:
print('You must choose between 1 and 4 for your guess amount. Try again.')
continue
break
except:
print('You must enter a valid number between 1 and 4. Try again.')
# Define difficulty based on guesses_left
difficulty = ''
if guesses_left == 1:
difficulty = 'Hard Mode'
elif guesses_left == 2:
difficulty = 'Medium Mode'
elif guesses_left == 3:
difficulty = 'Easy Mode'
elif guesses_left == 4:
difficulty = 'Super Easy Mode'
print('You are playing on ' + difficulty + ' with ' + str(guesses_left) + ' guesses.')
#code continues under this line to finish#

Related

Giving one hint for each of the tries (guessing number game)

I am making a game which requires the user to enter a number. They get four tries, and if they get the number wrong, they get a hint.
How can I try to give only one hint for each of the four tries the user has to get the number right? For example, after the user gets the first try wrong, I would like the program to display the even_or_odd hint.
from random import randrange
new_number = randrange(1, 101)
class Hints:
def __init__(self, new_number):
self.new_number = new_number
def even_or_odd(self):
if self.new_number % 2 == 0:
print('Hint. The number is even.')
else:
print('Hint. The number is odd.')
def multiple3to5(self):
for x in range(3, 6):
n = self.new_number % x
if n == 0:
print(f'Hint. The number is a multiple of {x}', end = ' ' )
def multiple6to10(self):
for x in range(6, 11):
n = self.new_number % x
if n == 0:
print(f'Hint. The number is a multiple of x {x}', end = ' ')
print('Guess a number beteen 1 and 100.')
hint = Hints(new_number)
for x in range(1, 5):
is_answer_given = False
while not is_answer_given:
try:
user_input = int(input(f'Attempt {x}: '))
is_answer_given = True
except ValueError:
print('Please enter a numerical value.')
if user_input == new_number and x == 1: #hint after first attempt
print('You win!')
break
else:
print('Incorrect!')
hint.even_or_odd()
if user_input == new_number and x == 2: #hint after second attempt
print('You win!')
break
else:
print('Incorrect!')
hint.multiple3to5()
if user_input == new_number and x == 3: #hint after third attempt
print('You win!')
break
else:
print('Incorrect!')
hint.multiple6to10()
if x == 4:
print('You are out of attempts!')
print(f'The number was {new_number}')
break
You should make one if statement that checks for the correct answer. In the else statement you can use if - elif statements to check for the attempt number.
if user_input == new_number:
print('You win!')
break
else:
print('Incorrect!')
if x == 1:
hint.even_or_odd()
elif x == 2:
hint.multiple3to5()
elif x == 3:
hint.multiple6to10()
else:
print('You are out of attempts!')
print(f'The number was {new_number}')
The reason you see multiple hints on attempt is that for multiple if statements their condition is not true, so their 'else' block is run
Here is a neat trick:
from random import randrange
new_number = randrange(1, 101)
class Hints:
def __init__(self, new_number):
self.new_number = new_number
self.choices = {
1: self.even_or_odd,
2: self.multiple3to5,
3: self.multiple6to10
}
def run(self,key):
action = self.choices.get(key)
action()
def even_or_odd(self):
if self.new_number % 2 == 0:
print('Hint. The number is even.')
else:
print('Hint. The number is odd.')
def multiple3to5(self):
for x in range(3, 6):
n = self.new_number % x
if n == 0:
print(f'Hint. The number is a multiple of {x}', end = ' ' )
else:
print("Well, Not a multple of 3 or 5")
def multiple6to10(self):
for x in range(6, 11):
n = self.new_number % x
if n == 0:
print(f'Hint. The number is a multiple of x {x}', end = ' ')
else:
print("Well, Not a multple of 6 or 10")
print('Guess a number beteen 1 and 100.')
hint = Hints(new_number)
print(new_number)
i = 3
win = False
while i >= 1 :
is_answer_given = False
while not is_answer_given:
try:
user_input = int(input(f'Attempt {i}: '))
is_answer_given = True
except ValueError:
print('Please enter a numerical value.')
if user_input == new_number:
print('You win!, Number is: {new_number}')
win = True
break
hint.run(i)
i -= 1
if not win:
print("You lost!")
print(f"Number is {new_number}")

Why does python show 'list index out of range' error?

I am very new to python, and started learning just 1 week ago. This program works very well except when I enter a number into guess1 variable that starts with 0.
import random
import sys
def script():
while True:
number1 = random.randint(1000, 9999)
number1 = int(number1)
while True:
print ("Enter Your Guess")
guess1 = input()
guess1 = int(guess1)
while True:
if guess1 != number1:
break
elif guess1 == number1:
print ("Your Guess Was Right!")
print ("Do you want to play again? Type YES or NO")
ask = input()
ask = str(ask)
if ask == "YES" or ask == "yes":
script()
elif ask == "NO" or ask == "no":
sys.exit()
else:
print ("Invalid input, try again.")
continue
number = list(str(number1))
guess = list(str(guess1))
if len(guess) > 4:
print ("Please type a 4-digit number")
continue
bulls = 0
wr = 0
cows = 0
a = 3
while a >= 0:
if number[a] == guess[a]:
number[a] = 'a'
guess[a] = 'b'
bulls += 1
a -= 1
b = 0
c = 0
while b < 4:
c = 0
while c < 4:
if number[b] == guess[c]:
number[b] = 'a'
guess[c] = 'b'
wr += 1
c += 1
b += 1
z = bulls + wr
cows = 4 - z
bulls = str(bulls)
cows = str(cows)
wr = str(wr)
print ("Cows: "+cows)
print ("Bulls: "+bulls)
print ("Wrongly Placed: "+wr)
break
script()
This was a program written for a game, in which a 4-digit number is to be guessed. We do it by starting with a random number, and we get clues in the form of cows, bulls and wrongly placed. Cows mean the number is wrong, Bulls mean the number is right, and wrongly placed means the number is right but wrongly placed.
The whole thing works properly, but when I enter a number starting with 0, it shows something like this :-
Traceback (most recent call last):
File "GuessingGame.py", line 61, in <module>
script()
File "GuessingGame.py", line 36, in script
if number[a] == guess[a]:
IndexError: list index out of range
Please help, thanks!
UPDATE:
Thanks to user #blue_note 's answer, The program works now! This is how it has been modified -
import random
import sys
def script():
while True:
number1 = random.randint(1000, 9999)
number1 = int(number1)
while True:
print ("Enter Your Guess")
guess1 = input()
number = list(str(number1))
guess = list(str(guess1))
if guess[0] == 0:
guess1 = str(guess1)
else:
guess1 = int(guess1)
while True:
if guess1 != number1:
break
elif guess1 == number1:
print ("Your Guess Was Right!")
print ("Do you want to play again? Type YES or NO")
ask = input()
ask = str(ask)
if ask == "YES" or ask == "yes":
script()
elif ask == "NO" or ask == "no":
sys.exit()
else:
print ("Invalid input, try again.")
continue
bulls = 0
wr = 0
cows = 0
a = 3
while a >= 0:
if number[a] == guess[a]:
number[a] = 'a'
guess[a] = 'b'
bulls += 1
a -= 1
b = 0
c = 0
while b < 4:
c = 0
while c < 4:
if number[b] == guess[c]:
number[b] = 'a'
guess[c] = 'b'
wr += 1
c += 1
b += 1
z = bulls + wr
cows = 4 - z
bulls = str(bulls)
cows = str(cows)
wr = str(wr)
print ("Cows: "+cows)
print ("Bulls: "+bulls)
print ("Wrongly Placed: "+wr)
break
script()
Since my guess will always be wrong if the first digit is 0, I don't have the need to convert it into int.
Again, thanks for the help guys! This was my first question on the website. It is really a cool website.
When you pass, say, an integer starting with 0, say, 0123, and you convert it to int in the next line, you are left with 123 (3 digits). Later, you do number = list(str(number1)), so your number is ['1', '2', '3'] (length 3). Then, you try to get number[a] with a=3, and that's were you get the error.
You could do something like
number = list(str(number1) if number1 > 999 else '0' + str(number1))

Completing a Startup Menu in Function - Python

I'm trying to finish writing this function that contains five different options and uses a While loop to allow the user to enter in their choice with the entry '5' exiting the loop. Below is the code I have so far, I'm having trouble completing the menu part within the def_main function. I keep getting an error after else:
break
Any input would be appreciated. Thank you for reading.
def main():
menuOption = 0
while 1 == 1:
print("1. Expanded Sum\n2. Reverse Expanded Sum\n3. Reverse Integer\n4. Product Table\n5. Exit\n")
menuOption = int(input("Enter correct menu option: "))
while menuOption<1 or menuOption>5:
print("Incorrect menu option!!")
menuOption = int(input("Enter correct menu option: "))
if menuOption == 5:
return
while 1 == 1:
num = int(input("Enter positive Integer: "))
if num <= 0:
print("You have entered negative integer or zero.")
continue
else:
break
if menuOption == 1:
printSum(num, int(False))
elif menuOption == 2:
printSum(num, int(True))
elif menuOption == 3:
print(str(reverseInt(num)))
elif menuOption == 4:
printProductTable(num)
if __name__ == "__main__": main()
def printSum(n, reverse):
s = sum(range(n+1))
if reverse:
print('+'.join(str(i) for i in range(1, n+1)) + ' = ' + str(s))
else:
print('+'.join(str(i) for i in range(n, 0, -1)) + ' = ' + str(s))
def reverse_int(n):
Reverse = 0
while(n > 0):
Reminder = n %10
Reverse = (Reverse *10) + Reminder
n = n //10
print(Reverse)
def printProductTable(n):
for row in range(1,n+1):
print(*("{:3}".format(row*col) for col in range(1, n+1)))
What is the error you are getting at the break?
It looks like your spacing might be off in the continue, I assume your else goes to the if at the top of the statement, but your continue does not match with it.
Rather than doing while 1==1 you can write while True. And also you have already checked while menuOption<1 or menuOption>5. So if your menuOption is a negative number it already falls into this condition as, say, -2 < 1.
And also seems like your code is not formatted. Means, continue is just above the else. It will generate the error. Re-formate your code. Give proper indentation.

TypeError: unsupported operand type(s) for divmod(): 'NoneType' and 'Int'

I am doing past coursework for practice, but I'm not sure what to do.
The task: create a game where the user has to guess a random 4 digit number(no repeated digits).
The problem: my code kind of works - like when you input a number with no repeating digits, it's fine, but when you enter, for example, 1223 I get the error:
TypeError: unsupported operand type(s) for divmod(): 'NoneType' and 'Int'
I have looked online and cannot find an answer. Any help would be greatly appreciated.
Thank you
Code below
import random
from collections import Counter
def rng():
num = []
i = 0
while i <=3:
rng = random.randrange(1,9)
if num.count(rng) == 0:
num.append(rng)
i+=1
return num
def menu():
userGuesses = 1
num = rng()#sort out a new num every time
print(num)
x = True
while x == True:
userExit = input("Would you like to exit(yes or no)")
if userExit == "yes":
print("Exiting...")
exit()
elif userExit == "no":
x = False
over = game(num)
while over !=True:
over = game(num)
userGuesses+=1
print("Congratulations you got it right, and it only took you ", userGuesses, " guesses!")
menu()
else:
print("Invalid entry")
def userInput():
userNum = int(input("Please enter a four digit number(no repeated digits)"))
if(userNum > 1000 or userNum < 9999):
print("...")
c = Counter(str(userNum))
if any(value > 1 for value in c.values()):
print ("Your number has repeating digits, please change it.")
else:
x = False
return userNum
else:
print("Invalid entry")
def convertToArray(userNum):
userArray = []
while userNum != 0:
userNum, x = divmod(userNum, 10)
userArray.append(int(x))
userArray.reverse()
print(userArray)
return userArray
def check(userArray, num):
i = 0
bulls = 0
cows = 0
while i<=3:
if num[i] == userArray[i]:
bulls +=1
elif int(userArray[i] in num):
cows +=1
i+=1
print("Bulls:")
print(bulls)
print("Cows:")
print(cows)
if bulls == 4:
return True
else:
return False
def game(num):
userNum = userInput()
userArray = convertToArray(userNum)
if check(userArray, num) == True:
return True
else:
return False
#Main-----------------------------------------------------------------
print("""Hello and welcome to the game \"Cows and Bulls\":
*In this game you enter a 4 digit number
*We compare it to a random number
*If you get the right number in the right 'place' then you get one bull
*If you get the right number in the wrong 'place then you get one cow'
*The game is over when you get 4 bulls, or all the numbers in the right place""")
menu()
Yes - your function doesn't actually return anything because of the print statements, hence an implicit None is returned - but there's another solution you can use.
Take advantage of the fact that userInput will return None if the input isn't valid. Have a condition just before userArray = convertToArray(userNum) to check if userNum is None:
def game(num):
userNum = userInput()
if userNum is None:
# Bad input was given
return False
userArray = convertToArray(userNum)
if check(userArray, num) == True:
return True
else:
return False
def userInput():
userNum = int(input("Please enter a four digit number(no repeated digits)"))
if(userNum > 1000 or userNum < 9999):
print("...")
c = Counter(str(userNum))
if any(value > 1 for value in c.values()):
print ("Your number has repeating digits, please change it.")
else:
x = False
return userNum
else:
print("Invalid entry")
when userNum is repeated, you return nothing. you should return something and pass it to convertToArray

Python 2.7 Slot Machine if statement issue

import random
numbers = []
wheel1 = 0
wheel2 = 0
wheel3 = 0
winnings = int(0)
balance = int(50)
def generator(balance):
number1 = random.random()
number2 = random.random()
number3 = random.random()
if number1 < 0.05:
wheel1 = "Cherry"
elif number1 < 0.15:
wheel1 = "Diamond"
elif number1 < 0.30:
wheel1 = "Hearts"
elif number1 < 0.65:
wheel1 = "Spade"
elif number1 < 1:
wheel1 = "Monkey"
if number2 < 0.05:
wheel2 = "Cherry"
elif number2 < 0.15:
wheel2 = "Diamond"
elif number2 < 0.30:
wheel2 = "Hearts"
elif number2 < 0.65:
wheel2 = "Spade"
elif number2 < 1:
wheel2 = "Monkey"
if number3 < 0.05:
wheel3 = "Cherry"
elif number3 < 0.15:
wheel3 = "Diamond"
elif number3 < 0.30:
wheel3 = "Hearts"
elif number3 < 0.65:
wheel3 = "Spade"
elif number3 < 1:
wheel3 = "Monkey"
return wheel1
return wheel2
return wheel3
def win(generator,balance):
generator(balance)
if wheel1 =="Monkey"and wheel2 == "Monkey"and wheel3 == "Monkey":
print "JACKPOT!"
winnings = int(50)
balance + winnings
print 'JACKPOT!'
else:
print 'noice'
winnings = int(10)
balance + winnings
print 'noice'
return balance
print "Welcome to the International Slot Machine"
print ""
print "Balance: $",balance
print ''
spinyn = (raw_input("Would you like to spin? $5 per spin. Enter y or n:\n"))
while True:
if spinyn == "y":
break
elif spinyn == "n":
print "Final Balance: $",balance
print "Thank you for using the International Slot Machine"
raise SystemExit
else:
spinyn = raw_input('\033[31mPlease enter only y or n.\033[0m\n')
spin = (raw_input("Press enter to spin for $5:\n"))
while True:
if spin == '':
balance = balance - 5
if balance <= 0:
print ""
print "Final Balance: $",balance
print "You have run out of money, the game has now ended."
raise SystemExit
print ""
print "\033[34mResult:\033[0m"
print "\033[34m-------\033[0m"
balance = generator(balance)
print ""
print win(generator,balance)
print "New balance:$",balance
print ""
spinagain = (raw_input("Would you like to spin again? Press enter to spin again, type anything to exit.\n"))
while True:
if spinagain == "":
break
else:
print "Final Balance: $",balance
print "Thank you for using the International Slot Machine"
raise SystemExit
else:
spin = (raw_input("Please press enter to spin.\n"))
I appreciate any suggestions about the method of selecting a random symbol, but please withhold as there is only one question I have. My question is: In the win function, how do I make it recognise the 3 wheel outputs. I've done what I thought would work however it does not, even when I land on 3 monkeys.
Any other suggestions are welcome. But please keep in mind that is the most important.
Thank you very much in advance.
The problem that you have here is that your concept of scope needs a little help.
This answer is a really good start.
To make a short example of your code, let's just do this:
def generator(balance):
wheel_1 = 'Monkey'
wheel_2 = 'Diamond'
wheel_3 = 'Heart'
return wheel_1, wheel_2, wheel_3
def win(generator):
print wheel_1, wheel_2, wheel_3
win(generator)
What you'll get here is a NameError, because wheel_1 (and 2 & 3) don't actually exist within the win function. They only exist within the generator function. So what you need to do is get the values from the generator function, and put them somewhere that 'win' can see. You can actually do this pretty easily, since we're already returning the values from the generator function:
# Note: generator was removed as a parameter.
# We don't need it here, because if Python
# can't find the name `generator` it will look
# in the enclosing scope and find the function
# `generator` there.
def win():
# What we want to do is *call* `generator` and
# assign the results to some variables that *are*
# in `win`'s scope
wheel_1, wheel_2, wheel_3 = generator()
print wheel_1, wheel_2, wheel_3
As you mentioned, you can definitely improve some things in your current code. You've noticed inside your generator function there's code that looks almost exactly the same. When you look at code and you get that feeling, that's what's called a "code smell". That's what happens when your (sub)conscious mind sees some code that it knows could be improved. In this particular case there's a principle called DRY - Don't Repeat Yourself.
You can replace your existing code with the following:
def spin_one():
number = random.random()
if number < 0.05:
result = 'Cherry'
elif number < 0.15:
result = 'Diamond'
elif number < 0.30:
result = 'Hearts'
elif number < 0.65:
result = 'Spade'
else:
result = 'Monkey'
return result
def generator():
return spin_one(), spin_one(), spin_one()
And what I might even do is remove the generator call altogether and simply do this:
if all((spin_one() == 'Monkey' for _ in xrange(3))):
You can read the docs on all.
Though, if you want to have more than just win a lot and win a little, then you'd need to keep the values:
wheels = [spin_one() for _ in xrange(3)]
Then you can do:
if all(wheel == 'Monkey' for wheel in wheels):
# Alternatively, wheels.count('Monkey') == 3
print 'Jackpot'
elif wheels.count('Hearts') == 2:
print 'Win'
elif all(wheel == 'Lemon' for wheel in wheels):
print 'You lose'
And any other kind of winning you might want to add.
Prompt
I don't think this is either better or worse than your current prompt approach, but I used to use it all the time in my C++ course.
def prompt():
choice = raw_input('(Y)es or (N)o: ').lower()
if choice == 'y':
return True
elif choice == 'n':
return False
else:
print '**ERROR** Please input "y" or "n"'
return prompt()
It's a nice, simple way to get a handle on recursion :)

Categories