Python 3 craps simulation - python

I'm not sure how I could incorporate my roll() function into the playRound(). The playRound is supposed to simulate the actual round of craps. I have to have the roll() function as is along with all of the other code. The only segment I can edit is the playRound() function.
from random import (random, randint)
def roll():
return randint( 1, 6 ), randint( 1, 6 )
def playRound():
def main():
print("Craps simulation")
while True:
response = input("Enter an integer value > 0 ")
if response == "":
print("Thank you for your business!")
break
try:
num_trials = int(response)
if num_trials < 1:
raise ValueError("Input must be >= 1 ")
roundsPlayed = 0
wins = 0
while roundsPlayed < num_trials:
roundsPlayed += 1
if playRound():
wins += 1
print( "Probability of winning is {0:>0.2%}".format( wins/num_trials ) )
except ValueError as err:
print( err )
except TypeError as err:
print( err )
main()

You are allowed to call any function as long as it is in scope. In Python, every function defined on the outermost scope layer is callable from anywhere within the script (or module namespace, if you're using it as such). This is referred to as the global scope.
When you have a function that returns multiple values, Python lets you catch them very easily with different variables by using commas to separate them.
Here's a small example of calling roll within playRound and storing the return values in two variables:
def playRound():
roll1, roll2 = roll()

Related

How can I unit test a function that is called by another function

I am trying to unit test my program and have decided to unit test the withdraw_cash function. However, it is called by the bank_atm function. I have never called a function that is dependent on another function and am confused about how to do this. Would i use mock and patch to do this?
The tests would be:
check whether entering valid amount
check whether amount is less than balance
user = {
'pin': 1234,
'balance': 100
}
def withdraw_cash():
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
if amount > user['balance']:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
user['balance'] = user['balance'] - amount
print(f"£{user['balance']}")
return
finally:
print("Program executed")
def bank_atm():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
withdraw_cash()
to_exit = True
if count == 3:
print('3 UNSUCCESFUL PIN ATTEMPTS, EXITING')
print('!!!!!YOUR CARD HAS BEEN LOCKED!!!!!')
try:
bank_atm()
except ValueError as v:
print(f"ERROR: {v}")
To expand on the comments. Put UI interactions in separate functions, such as getpin and getpounds. They can then be tested separately from the business functions. One can either mix manual input with the unittests or automate them by patching sys.stdin/out. My proof-of-concept experiment, which passes on 3.11.0b3 run from IDLE editor.
import sys
import unittest
from unittest.mock import patch
def getpin(realpin):
return input('Your pin? ') == realpin
class ManualTest(unittest.TestCase):
def test_pin(self):
print('\n(Enter 1234)')
self.assertEqual(getpin('1234'), True)
print('\n(Enter 1)')
self.assertEqual(getpin('1234'), False)
class MockOut:
def write(self, string): pass
# Or 'write = Mock()' to save and check prompts, using mockout.
class MockIn:
def readline(self): # input() uses readline, not read.
return self.line
#patch('sys.stdin', new_callable=MockIn)
#patch('sys.stdout', new_callable=MockOut)
class AutoTest(unittest.TestCase):
def test_pin(self, mockout, mockin):
mockin.line='1234\n' # input removes '\n' if present.
self.assertEqual(getpin('1234'), True)
mockin.line='1233'
self.assertEqual(getpin('1234'), False)
if __name__ == '__main__':
unittest.main(verbosity=2)
I have now refactored my program, by breaking it down into separate functions as you said but when I try and run a test specifically for one function, it runs the whole thing and asks for input from each function. I feel like testing each function individually will have to require specific parameters not dependent on the other function.
user = {
'pin': 1234
}
def withdraw_cash(amount):
balance_account = 100
if amount > balance_account:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
new_balance = balance_account - amount
return new_balance
def get_pin():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
return get_amount(pin)
#return pin
if count == 3:
a = '3 UNSUCCESFUL PIN ATTEMPTS, EXITING \n !!!!!YOUR CARD HAS BEEN LOCKED!!!!!'
return a
def get_amount(pin):
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
#print(amount)
return withdraw_cash(amount)
#return amount
try:
get_pin()
except ValueError as v:
print(f"ERROR: {v}")

How write User Input Data to External Text File?

I would like to be able to take the test scores the user inputs and write to an external text file. Then have the application read off the values from the and calculate the average. However, I am unsure as to how to implement the python syntax within the loop and the functions. I've attempted to utilize my resources to get a better idea of how to do this, but I've been having some trouble understanding how python handles external files. In addition, would using append be better than write in this scenario?
Current Syntax:
def testAvgCalculation():
#Variables
total = 0
total_quiz = 0
while True:
#User Input and Variable to stop loop
inpt = input("Enter score: ")
if inpt.lower()== 'stop':
break
#Data Validation
try:
if int(inpt) in range(1,101):
total += int(inpt)
total_quiz += 1
else:
print("Score too small or Big")
except ValueError:
print("Not a Number")
return total, total_quiz
def displayAverage(total, total_quiz):
average = total / total_quiz
print('The Average score is: ', format(average, '.2f'))
print('You have entered', total_quiz, 'scores')
#Main Function
def main():
total, total_quiz = testAvgCalculation()
displayAverage(total, total_quiz)
#Run Main Function
main()
This is hacky as heck, but I tried to work with what was already there. I split the data validation section of the original function off into a separate function. In main() it returns its value counter, which keeps track of how many values were entered, to calculate_average(), which then reads the file line by line until counter becomes 0, which means it's about to read the word "stop" (which allows EOF recognition via the 'and' in the if statement), performs the calculation and returns its values.
def write_file():
#Variables
counter = 0
file = open("Scores.txt", "w")
while True:
#User Input and Variable to stop loop
inpt = input("Enter score: ")
file.write(inpt + "\n")
if inpt.lower()== 'stop':
file.close()
break
counter += 1
return counter
def calculate_average(counter):
total = 0
total_quiz = counter
scores = open("Scores.txt", "r")
s = ""
try:
while counter > 0 and s != 'stop':
s = int(scores.readline())
if int(s) in range(1,101):
total += int(s)
counter -= 1
else:
print("Invalid data in file.")
except ValueError:
print("Invalid data found")
return total, total_quiz
def displayAverage(total, total_quiz):
average = total / total_quiz
print('The Average score is: ', format(average, '.2f'))
print('You have entered', total_quiz, 'scores')
#Main Function
def main():
total, total_quiz = calculate_average(write_file())
displayAverage(total, total_quiz)
#Run Main Function
main()
NOTE: the file is created initially in write mode which overwrites the file each time so you never need a new one. if you want to keep a record you might like to change it to append, though you'll need to manage extracting the proper lines from among old input.
Not pretty at all, but should give you an idea of how to accomplish what you were going for.

How can I create a like-a-template function which takes a bunch of code as an argument?

I want to create a function which takes a bunch of code as so-called "argument", so that I can implement any block-of-code I want later on.
Here is a sample:
def loop(c):
while c != (1 or 0):
try:
c = int(input("Choice? (1/2) - "))
except ValueError:
print("Enter a valid value.")
else:
if c == 1:
# i want to have different implementations of loop(c) by writing any (bunch of) statements i want here.
elif c == 0:
print("Goodbye...")
else:
print("Please enter either 1 or 0.")
What I basically want to do is to create a template so that I can use this code snippet with if block (where the comment-line is) is filled (replaced) with anything I want. How can I do it?
You can easily accept functions as arguments:
def loop(c, func):
while c != (1 or 0):
try:
c = int(input("Choice? (1/2) - "))
except ValueError:
print("Enter a valid value.")
else:
if c == 1:
func()
elif c == 0:
print("Goodbye...")
else:
print("Please enter either 1 or 0.")
An example of calling it would be one of these:
def a():
# whatever code you want here
print('in the function')
loop(c, a)
Or even simpler (for simple functions):
loop(c, lambda: print('in a lambda'))
You can pass a callable (function or lambda) to your function as an argument.
def perform_function(func):
if input() == "foo":
func()
perform_function(lambda: print("Hello World"))

"TypeError: 'function' object is not subscriptable" on a string?

I'm scripting a small game to guess a number and I don't understand why I'm getting this error as both num and userNum in my numCheck() function should be strings and not functions.
import random
def num():
"""Returns a number between 1000 and 9999."""
num = str(random.randint(1000, 9999))
print("Random number is: " + num) #for testing purposes
return num
def userNum():
"""Asks user for a number between 1000 and 9999."""
while True:
try:
userNum = int(input("Choose a number between 1000 and 9999: "))
except ValueError:
print("This isn't a number, try again.")
continue
if userNum < 1000 or userNum > 9990:
print("Your number isn't between 1000 and 9999, try again.")
continue
else:
break
userNum = str(userNum)
return userNum
def numCheck(num, userNum):
"""Checks the number of cows and bulls."""
cow = 0
bull = 0
for i in range(0, 3):
if userNum[i] == num[i]:
cow += 1
else:
bull += 1
print("You have " + str(cow) + " cow(s) and you have " + str(bull) + " bull(s).")
return cow
def gameLoop():
"""Loops the game until the user find the right number."""
num()
cow = 0
if cow < 4:
userNum()
numCheck(num, userNum)
else:
print("Congratulation, You found the right number!")
gameLoop()
The error I get when I run the script is the following:
==================== RESTART: /home/pi/Desktop/cowbull.py ====================
Random number is: 8104
Choose a number between 1000 and 9999: 5555
Traceback (most recent call last):
File "/home/pi/Desktop/cowbull.py", line 47, in <module>
gameLoop()
File "/home/pi/Desktop/cowbull.py", line 43, in gameLoop
numCheck(num, userNum)
File "/home/pi/Desktop/cowbull.py", line 30, in numCheck
if userNum[i] == num[i]:
TypeError: 'function' object is not subscriptable
>>>
Note that other things may not be working or perfect at the moment, but I'm only trying to figure out the logic of this error so I can continue on.
Thanks for the help!
Here is your function gameLoop:
def gameLoop():
"""Loops the game until the user find the right number."""
num()
cow = 0
if cow < 4:
userNum()
numCheck(num, userNum)
else:
print("Congratulation, You found the right number!")
You call a function named userNum() but you don't assign its returned value to a variable. In the next line you pass userNum as an argument to the function numCheck. Since userNum was a function in the previous line, it must still be a function now (it's perfectly legitimate in Python to pass a function as an argument to another function).
In the previous line, you need to assign the returned value from userNum to a new variable. Then pass that variable to numCheck:
x = userNum()
numCheck(num, x)
You have made exactly the same mistake with the function num. Even though you want num and userNum to be strings, in fact both of them are functions. Both functions return a string, but you need to assign the returned values to new variables in order to use them later.
Abdou's comment is correct that it's confusing to use the same variable name to mean different things.

nested function in python (taking the output from another function)

I have problem with getting output from another function to use in a function.
I don't know the syntax of function in python. How do i take a output of another function to use in a function when i define it.
def hero_attribute(hero_selection()): #This syntax isn't accepted
#This program will calculate the damge of hero with stats
global hero_str_result
global hero_agi_result
global hero_int_result
def hero_selection():
print """1. Life Stealer (strength hero)\n
2. Phantom lancer (agility hero)\n
3. Phantom Assassin (agility hero)\n
4. Wrait King (strength hero) \n
"""
print "Please enter hero selection: "
hero_num = int(raw_input("> "))
return hero_num
def hero_attribute(hero_selection()): #This syntax isn't accepted
if hero_num == 1: # Life stealer
hero_str = 25
hero_agi = 18
hero_int = 15
#Hero growth stats
str_growth = 2.4
agi_growth = 1.9
int_growth = 1.75
elif hero_num == 2: # Phantom lancer
hero_str =
hero_agi = ?
hero_int = ?
#Hero growth stats
str_growth = 2.4
agi_growth = 1.9
int_growth = 1.75
elif hero_num == 3: # Phantom Assassin
hero_str = ?
hero_agi = ?
hero_int = ?
#Hero growth stats
else: #Wraith King
hero_str = ?
hero_agi = ?
hero_int = ?
#hero growth stats
str_growth = ?
agi_growth = ?
int_growth = ?
return (hero_str,hero_agi,hero_int,str_growth,agi_growth,int_growth)
def hero_type(hero_num):
if hero_num == 1:
hero_type = "str"
elif hero_num == 2
hero_type = "agi"
elif hero_num == 3
hero_type = "agi"
else:
hero_type = "str"
#the function will ask user what to do with the hero
def hero_build():
print "What do you want to do with the hero?"
print """1. Build hero with stat
2. Build hero with item (not yet)
3. Build hero with level
"""
user_choice = int(raw_input("> "))
if user_choice == 1:
print "You want to build hero with stats!"
print "Please enter number of stats that you want to add: "
hero_stats = int(raw_input=("> "))
hero_str, hero_agi, hero_int,str_growth,agi_growth,int_growth = hero_attribute() #This function will take the result of hero_str, hero_agi,hero_int
hero_str_result = hero_str + str_growth * hero_stats
hero_agi_result = hero_agi + agi_growth * hero_stats
hero_int_result = hero_int + int_growth * hero_stats
return hero_str_result, hero_agi_result, hero_int_result
print "This is the result of your build: ", hero_build()
A function is a piece of code that receive arguments, and to those arguments you assign a name. For example:
def square(x):
return x * x
this function computes the square of a number; this unknown number in the body of the function will be called x.
Once you have a function you can call it, passing the values you want as arguments... for example
print( square(12) )
will print 144 because it will call the function square passing x=12 and 12*12 is 144.
You can of course pass a function the result of calling another function, e.g.
def three_times(x):
return 3 * x
print( square( three_times(5) ) )
will display 225 because the function three_times will be passed 5 and it will return 3*5, the function square will be passed 15 and will return 15*15.
In the function definition (the def part) you will always just have names for the parameters. What you want to pass to the function will be written at the call site.
What you want is to be able to pass a function as argument. This, however, is already incorporated into python from design: you simply pass it as you pass any other argument.
Example:
def apply(f,x):
return f(x)
def sq(x):
return x*x
def cb(x):
return x*x*x
apply(sq,2)
4
apply(cb,2)
8
Apply is defined with its first argument being a function. You know that only when you actually read the definition of apply. There you see that f is treated as a function, as opposed to x which is treated "as a number".

Categories