Want a beginner Python Project that’s going to test you? A program longer than 40 lines of code?
Look no further, here’s Bagels!
This is from The Big Book of Small Python Projects – Chapter 1 Bagels.
Watch the Study Session #2 for the full programming behind the scenes.
Disclaimer, some areas of this blog post are still under construction, look for Work In Progress (WIP).
Global Variables, Main Function
Let’s break Bagels down.
First, import the random module and set two global variables.
numDigits
sets the number of digits for the player to guess. Then maxGuesses
sets the maximum amount of guesses the player can take before the game is over. Both of these can be adjusted.
import random
numDigits = 3
maxGuesses = 10
Let’s add the main function and print the instructions for the player.
def main():
print('''
I am thinking of a {}-digit number. Try to guess what it is.
Here are some clues:
When I say: That means:
Pico One digit is correct but in the wrong position.
Fermi One digit is correct and in the right position.
Bagels No digit is correct.
I have thought up a number.
You have 10 guesses to get it.
'''.format(numDigits))
Main Game Loop
while True:
secretNum = getSecretNum()
print('I have thought up a number.')
print(' You have {} guesses to get it.'.format(maxGuesses))
Let’s set the number of guesses to 1 and create a while
loop, as long as the number of guesses is less than or equal to the max number of guesses the player can continue.
The guess
variable is declared as a blank string so this makes it usable later in the program. If guess was declared inside the while
block, then it would be local to that block only.
numGuesses = 1
while numGuesses <= maxGuesses:
guess = ''
while len(guess) != numDigits or not guess.isdecimal():
print('Guess #{}: '.format(numGuesses))
guess = input('> ')
Next, creating a clues
variable set to the function getClues
which passes guess
and secretNum
through it. Then, assign and increase numGuesses
by 1.
clues = getClues(guess, secretNum)
print(clues)
numGuesses += 1
Now, let’s add an if
statement to check the player’s guess, compare guess
to secretNum
and if it matches or is equal too, break
.
Then let the player know they’re out of guesses by an if
statement comparing numGuesses
to be greater than maxGuesses
.
if guess == secretNum: break
if numGuesses > maxGuesses:
print('You ran out of guesses.')
print('The answer was {}.'.format(secretNum))
print('Do you want to play again? (yes or no)')
Lastly, give the option to the player to play again now they’ve run out of guesses. If the player doesn’t input the letter ‘y’ or a word that starts with ‘y’, then a break
statement is used and the program displays a final message.
if not (input('> ').lower().startswith('y')): break
print('Thanks for playing!')
Functions (WIP)
Let’s take a closer look at our two custom functions, getSecretNum
and getClues
.
So, first set a new variable numbers
and assign the numbers from 0 to 9 as a string through the list()
to convert them. Then using the random module, pass numbers
through and shuffle the order.
def getSecretNum():
numbers = list('0123456789')
random.shuffle(numbers)
Alright, now let’s define another new variable secretNum
to a blank string. Then, in order to set the secretNum
let’s use a for
loop. In this case, i
is a local variable which only works inside this for
loop. The range()
is set to the original variable numDigits
which by default was set to 3, but you can edit this to whatever you want. secretNum
will assign and add one number as a string, this is why this program uses strings and not integers. If this was adding integers, it would increase in value, example, as integers 4 + 3 + 1 would equal 8, but as strings, it makes 431.
secretNum = ''
for i in range(numDigits):
secretNum += str(numbers[i])
return secretNum
Next up, the getClues
function.
def getClues(guess, secretNum):
if guess == secretNum:
return 'You got it!'
clues = []
for i in range(len(guess)):
if guess[i] == secretNum[i]:
clues.append('Fermi')
elif guess[i] in secretNum:
clues.append('Pico')
if len(clues) == 0:
return 'Bagels'
else:
clues.sort()
return ''.join(clues)
if __name__ == '__main__':
main()
Reflection (WIP)
How defining functions work, still getting my head around flow control, this helped to see a function on later lines can be called on eariler on in the program.
I don’t always need to use elif
, I’m still getting the hang of if
statements, so it’s nice to see how you don’t always need to use elif
.
The question about why numDigits errors when the number is over 10, that’s because there’s only 0 through to 9, there’s only 10 digits to choose from.