Here is my first program I'm working on. I have built a framework here showing the sort of output and user interaction I would like during runtime, but it feels grossly oversized and unintuitive. Here is the code:
# This is an advanced guess the number game.
import random # The very basis of this game.
import math # Used for math.ceil
import time # Used to split up long portions of text.
def introDisplay(): # Displays the intro and defines the playerName Var. at the local scope, then returns it to the global scope.
print('The Guessing Game! Now with more frustration!')
playerName = input('\nHello, what is your name? ')
print('\nWelcome ' + playerName + '.')
print('\nThis is a guessing game with three different modes. It also has two different')
print('settings for each mode. The range in which you will be guessing numbers, and')
print('the amount of attempts you will have. You will be playing through the modes in')
print('order, but you can always return to a game mode you\'ve unlocked.')
#time.sleep(5)
if playerName == 'Debug':
gameModesUnlocked = input('\nEnter number of modes unlocked. <1/2/3> ')
gameModesUnlocked = int(gameModesUnlocked)
else:
gameModesUnlocked = 1
return playerName, gameModesUnlocked
def getSettings():
while True: # Main loop 1: Game mode.
gameMode = chooseGameMode(playerName, gameModesUnlocked)
confirmedGameMode = confirmGameMode(gameMode, gameModesUnlocked)
if confirmedGameMode == True:
break
while True: # Main loop 2: Range settings.
rangeLower, rangeHigher, rangeLowerString, rangeHigherString, chooseToDefineRange = chooseRange()
if chooseToDefineRange == True:
rangeLower, rangeHigher, rangeLowerString, rangeHigherString = defineRange()
confirmedRange = confirmRange(rangeLowerString, rangeHigherString)
if confirmedRange == True:
break
while True: # Main loop 3: Attempt settings.
attemptsNumber, attemptsNumberString, chooseToDefineAttempts = chooseAttempts(rangeLower, rangeHigher)
if chooseToDefineAttempts == True:
attemptsNumber, attemptsNumberString = defineAttempts(rangeLower, rangeHigher)
confirmedAttempts = confirmAttempts(attemptsNumberString)
if confirmedAttempts == True:
break
def chooseGameMode(playerName, gameModesUnlocked): # Here the player chooses the game mode and the result is returned to the playGame function.
if gameModesUnlocked == 1: # Ends this function if there is no possible choice to be made.
print('\nOk, ' + playerName + ' Let\'s play the first mode: Simple guessing game!')
gameMode = 1
return gameMode
print('\nOk, ' + playerName + ' choose which mode you would like to play.')
if gameModesUnlocked == 2:
tempInput = input('The simple guessing game, or the one with addition and subtraction? <1/2> ')
while True:
if len(tempInput) == 1 and tempInput in '12':
gameMode = int(tempInput)
break
else:
tempInput = input('Please choose 1 or 2. ')
elif gameModesUnlocked == 3:
tempInput = input('The simple guessing game, the one with addition and subtraction, or the one with\nmore advanced maths? <1/2/3> ')
while True:
if len(tempInput) == 1 and tempInput in '123':
gameMode = int(tempInput)
break
else:
tempInput = input('Please choose 1, 2 or 3. ')
else:
print('Error!') # Work on error handling.
return gameMode
def confirmGameMode(gameMode, gameModesUnlocked):# Used to confirm that the player is happy with their game mode setting. Result controls interaction with main loop 1.
confirmedGameMode = True # Defined here to avoid repetition. Only returned in Escape #1/2.
if gameModesUnlocked == 1: # Ends this function if there is no possible choice to be made. Escape #1
return confirmedGameMode
if gameMode == 1: # Reiterates to the chosen mode to the player.
print('\nYou have chosen mode the first: Simple guessing game.', end=' ')
elif gameMode == 2:
print('\nYou have chosen mode the second: Guessing game with addition and subtraction.')
elif gameMode == 3:
print('\nYou have chosen mode the third: Guessing game with more advanced maths.')
tempAnswer = input('Continue? <y/n> ').lower()
while True: # Input loop.
if tempAnswer == 'y': # Returns and does break while loop in main. Escape #2
print('\nOk!')
return confirmedGameMode
elif tempAnswer == 'n': # Returns and does not break while loop in main. Escape #3
print('\nThen, let\'s try again.')
confirmedGameMode = False # Will not allow main loop to be broken.
return confirmedGameMode
elif len(tempAnswer) != 1 or tempAnswer not in 'yn': # Bad input in 'tempAnswer', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <y/n> ').lower()
def chooseRange(): # Here the player chooses between 3 pre-set ranges to play in, or chooses to define their own, either choice ends the function.
rangeLower = 1 # Sets some defaults to avoid empty variables being returned, using the defaults for the 's' range setting.
rangeLowerString = '1'
rangeHigher = 20
rangeHigherString = '20'
chooseToDefineRange = False
chosenRangeType = input('\nWould you like a small, medium or large range? Or perhaps you\'d like to\nchoose the range yourself? <s/m/l/*> ').lower()
while True: # Input loop.
if chosenRangeType == 's': # This section accepts input for the pre-sets and breaks out of the input loop, allowing the function to return.
break
elif chosenRangeType == 'm':
rangeHigher = 40
rangeHigherString = '40'
break
elif chosenRangeType == 'l':
rangeHigher = 60
rangeHigherString = '60'
break
elif chosenRangeType == '*': # This section handles the case that users would like to define their own range. New input loop.
tempAnswer = input('Really choose your own range? <y/n> ').lower()
while True: # Input loop.
if tempAnswer == 'y':
chooseToDefineRange = True
return rangeLower, rangeHigher, rangeLowerString, rangeHigherString, chooseToDefineRange
elif tempAnswer == 'n':
chosenRangeType = input('Then, let\'s try again. <s/m/l/*> ').lower()
break
elif len(tempAnswer) != 1 or tempAnswer not in 'yn': # Bad input in 'tempAnswer', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <y/n> ').lower()
elif len(chosenRangeType) != 1 or chosenRangeType not in 'sml*': # Bad input in 'chosenRangeType', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <s/m/l/*> ').lower()
return rangeLower, rangeHigher, rangeLowerString, rangeHigherString, chooseToDefineRange
def defineRange(): # Called when the player decides to define their own range to play in.
tempInput = input('Please choose the lower number in your range. (1-9990) ')
while True: # Input loop.
try: # Tries to assign tempInput to an integer, impossible if input is not a number.
rangeLower = int(tempInput)
if rangeLower in range(1,9991):
rangeLowerString = tempInput
break # Breaks this input loop if input is as expected, allowing the next one to run.
else:
tempInput = input('Please enter a number between 1 and 9990. ') # Bad input in 'tempInput', make new call and re-run input loop.
except ValueError: # This line is called in the case that a non-number is input.
tempInput = input('Please enter a number between 1 and 9990. ') # Bad input in 'tempInput', make new call and re-run input loop.
tempInteger = rangeLower + 10
tempString = str(tempInteger)
tempInput = input('Please choose the higher number in your range. (' + tempString + '-10000) ')
while True: # Input loop.
try: # Tries to assign tempInput to an integer, impossible if input is not a number.
rangeHigher = int(tempInput)
if rangeHigher in range(tempInteger,10001):
rangeHigherString = tempInput
break # Breaks this input loop if input is as expected, allowing the function to return.
else:
tempInput = input('Please enter a number between ' + tempString +' and 10000. ') # Bad input in 'tempInput', make new call and re-run input loop.
except ValueError: # This line is called in the case that a non-number is input.
tempInput = input('Please enter a number between ' + tempString +' and 10000. ') # Bad input in 'tempInput', make new call and re-run input loop.
return rangeLower, rangeHigher, rangeLowerString, rangeHigherString
def confirmRange(rangeLowerString, rangeHigherString): # Used to confirm that the player is happy with their range setting.
tempAnswer = input('\nYour range will be between ' + rangeLowerString + ' and ' + rangeHigherString + '. Are you happy with this? <y/n> .').lower()
while True: # Input loop.
if tempAnswer == 'y':
print('Ok!')
confirmedRange = True #
break # Breaks, allowing the function to return, and the program to leave main loop 2.
elif tempAnswer == 'n':
print('Then, let\'s try again.')
confirmedRange = False #
break # Breaks, allowing the function to return, but does not let the program leave main loop 2.
elif len(tempAnswer) != 1 or tempAnswer not in 'yn': # Bad input in 'tempAnswer', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <y/n> ').lower()
return confirmedRange
def chooseAttempts(rangeLower, rangeHigher):
rangeTrue = rangeHigher - rangeLower + 1 # Sets some defaults to avoid empty variables being returned, using the defaults for the 'e' attempt setting.
attemptsNumber = int(math.ceil(rangeTrue / 2))
chooseToDefineAttempts = False
chosenDifficulty = input('Now, let\'s choose your difficulty! Would you like it to be easy, normal or hard?\nOr choose your own amount of attempts? <e/n/h/*> ').lower()
while True: # Input loop.
if chosenDifficulty == 'e': # This section accepts input for the pre-sets and breaks out of the input loop, allowing the function to return.
break
elif chosenDifficulty == 'n':
attemptNumber = int(math.ceil(rangeTrue / 3))
break
elif chosenDifficulty == 'h':
attemptNumber = int(math.ceil(rangeTrue / 4))
break
elif chosenDifficulty == '*': # This section handles the case that users would like to define their own number of attempts. New input loop.
tempAnswer = input('Really choose your own number of attempts? <y/n> ').lower()
while True: # Input loop
if tempAnswer == 'y':
chooseToDefineAttempts = True
return attemptsNumber, attemptsNumberString, chooseToDefineAttempts
elif tempAnswer == 'n':
chosenDifficulty = input('Then, let\'s try again. <e/n/h/*> ').lower()
break
elif len(tempAnswer) != 1 or tempAnswer not in 'yn': # Bad input in 'tempAnswer', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <y/n> ').lower()
elif len(chosenDifficulty) != 1 or chosenDifficulty not in 'enh*': # Bad input in 'chosenDifficulty', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <e/n/h/*> ').lower()
attemptsNumberString = str(attemptsNumber)
return attemptsNumber, attemptsNumberString, chooseToDefineAttempts
def defineAttempts(rangeLower, rangeHigher): # Called when the player decides to define their own number of attempts to play with.
rangeTrue = rangeHigher - rangeLower + 1 # Some maths and assignment used in this function.
attemptsFloor = int(math.ceil(rangeTrue * .10))
attemptsCeiling = int(math.ceil(rangeTrue * .90))
attemptsFloorString = str(attemptsFloor)
attemptsCeilingString = str(attemptsCeiling)
tempInput = input('Please enter the number of attempts you would like to use (' + attemptsFloorString + '-' + attemptsCeilingString + '). ')
while True: # Input loop.
try: # Tries to assign tempInput to an integer, impossible if input is not a number.
attemptsNumber = int(tempInput)
if attemptsNumber in range(attemptsFloor,attemptsCeiling):
attemptsNumberString = tempInput
break # Breaks this input loop if input is as expected, allowing the function to return.
else:
tempInput = input('Please enter a number between ' + attemptsFloorString + ' and ' + attemptsCeilingString + '. ') # Bad input in 'tempInput', make new call and re-run input loop.
except ValueError: # This line is called in the case that a non-number is input.
tempInput = input('Please enter a number between ' + attemptsFloorString + ' and ' + attemptsCeilingString + '. ') # Bad input in 'tempInput', make new call and re-run input loop.
return attemptsNumber, attemptsNumberString
def confirmAttempts(attemptsNumberString):
tempAnswer = input('\nYou will have ' + attemptsNumberString + ' attempts. Are you happy with this? <y/n> .').lower()
while True: # Input loop.
if tempAnswer == 'y':
print('Ok!')
confirmedAttempts = True #
break # Breaks, allowing the function to return, and the program to leave main loop 3.
elif tempAnswer == 'n':
print('Then, let\'s try again.')
confirmedAttempts = False #
break # Breaks, allowing the function to return, but does not let the program leave main loop 3.
elif len(tempAnswer) != 1 or tempAnswer not in 'yn': # Bad input in 'tempAnswer', make new call and re-run input loop.
tempAnswer = input('Please make a valid choice. <y/n> ').lower()
return confirmedAttempts
# PROGRAM START #############################################################################
playerName, gameModesUnlocked = introDisplay()
gameMode, rangeLower, rangeHigher, rangeLowerString, rangeHigherString, attemptsNumber, attemptsNumberString = getSettings()
I know I'm making very poor use of functions here, and getting to the point where I understand how to use arguments correctly will make my program a lot smaller and neater. For example I have a few function that are almost identical except for their expected input and output, can I merge them with better use of arguments? And how would I go about that?
At the moment I am only working on the first part of the program, where you choose your settings. There are three different types of functions, 'choose'. 'define' and 'confirm'. If anyone could show me an example of how they might go about writing this part of my program in a more intuitive way I would be very grateful.