Bulls And Cows
Designing The Game
Here’s the basic strategy for writing any computer program:
- Understand the problem you are trying to solve.
- Break the problem into smaller pieces.
- Combine the pieces into a finished program.
Understanding the game
Start by reading the Wikipedia article that explains the
Bulls and Cows game. Try to imagine how you would play this game against the computer.
Break up the problem
Next, try to think of all the different actions your program will have to perform. Here’s the list I came up with:
- create the secret number
- get the player’s guess
- count the number of bulls and cows
- determine if a digit is a bull or a cow
- display the number of bulls and cows in the player’s guess
A structure chart will help you visualize how the pieces of the program fit together. Sketch out a structure chart using paper and pencil. Don’t waste time trying to make it pretty. Try to organize the activities into top-level, mid-level, and low-level functions.
Implementing The Game
You should design top-down, but you should implement bottom-up. There are several reasons for this:
- The lowest level functions are the easiest to write and test because they don’t depend on anything else.
- Just like an Egyptian pyramid, each higher level is built on the level below it.
Determining if a digit is a bull or a cow
The is_bull
and is_cow
functions are the foundation of the game and everything else depends on them.
A digit is a bull if it appears at the same position in both the secret number and the guess.
I could write the function like this
def is_bull(digit, secret, guess):
''' Return True if the digit appears at the same position in both numbers '''
if (digit in secret) and (digit in guess):
return secret.index(digit) == guess.index(digit)
else:
return False
But I’m not going to. Instead, I’ll write it like this:
def is_bull(digit, secret, guess):
''' Return True if the digit appears at the same position in both numbers '''
try:
return secret.index(digit) == guess.index(digit)
except ValueError:
return False
I’m not testing for digit in secret
or digit in guess
because index will raise an exception if the value isn’t found. Don’t repeat functionality that Python gives you for free. Your code will be simpler and easier to understand.
The is_cow
function is similar to is_bull
. A digit is a cow if it appears in both numbers, but at different positions.
def is_cow(digit, secret, guess):
''' Return True if the digit appears at different positions in both numbers '''
try:
return secret.index(digit) != guess.index(digit)
except ValueError:
return False
Counting bulls and cows
Now it’s time to count the number of bulls and cows in the player’s guess.
def count_bulls(secret, guess):
count = 0
for digit in guess:
if is_bull(digit, secret, guess):
count += 1
return count
def count_cows(secret, guess):
count = 0
for digit in guess:
if is_cow(digit, secret, guess):
count += 1
return count
Do you see how I was able to build these new functions from the is_bull
and is_cow
functions I’ve already written? Let’s keep going.
def print_bulls_and_cows(secret, guess):
''' Print a hint to the player. '''
bulls = count_bulls(secret, guess)
cows = count_cows(secret, guess)
message = 'There are {0} bulls and {1} cows.'.format(bulls, cows)
print message
The game is over when you find 4 bulls. Don’t be afraid to write short functions if they help you express the logic of your program.
def game_over(secret, guess):
''' Return True if the game is over.
The game is over when the player guesses all 4 bulls.
'''
return count_bulls(secret, guess) == 4
Generating the secret number and getting the player’s guess
Spend some time getting familiar with Python’s standard modules.
Generating the secret number requires you to know a little bit about Python’s random number module. You can’t just pick a random number between 1000 and 9999 because some of the digits might repeat. For example, you might get
and so forth. Fortunately, the random.sample
function does exactly what we want.
import random
def generate_secret_number():
''' Return a string of 4 unique digits. '''
digits = random.sample('0123456789', 4)
return ''.join(digits)
You’ll also need to get the player’s guess. You should clean up the input by stripping off any leading or trailing spaces.
def new_guess():
''' Return the player's guess as a string. '''
return raw_input('Enter your guess: ').strip()
At this point you’ve written everything except the top level function.
def bulls_and_cows():
secret_number = generate_secret_number()
players_guess = ''
while not game_over(secret_number, players_guess):
print_bulls_and_cows(secret_number, players_guess)
players_guess = new_guess()
That’s it!