FizzBuzz is variously a drinking game, a math game, a way of learning numbers in a foreign language
and more importantly (for this blog) a programming kata. The principle of FizzBuzz is a counting
and substitution game you count to a limit and replace some numbers with words. In the classic example you replace any number which is divisible by 3 with Fizz and any number
divisible by 5 with Buzz, and any number which is divisible by both with FizzBuzz.
So a classic game to 20 looks like this:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
It is fairly trivial to make a program to print lists like this out and can be done with some basic programming skill. This is a
Python function which, given a limit, will print numbers under the limit with the required replacements.
def fizz_buzz(limit)
for i in range(1, limit + 1):
if (i % 15 == 0):
print("FizzBuzz")
elif (i % 5 == 0):
print("Buzz")
elif (i % 3 == 0):
print("Fizz")
else:
print(i)
This is a nice and simple function that can be followed fairly easily. It loops over the values 1 – limit inclusively, if the number is divisible by 3 and 5 it prints FizzBuzz, if the number is divisible by 5 it prints Buzz, if it is divisible by 3 it prints Fizz, and if none of the above it prints the number.
This is all well and good, but it’s when you are asked to expand the rules that this approach falls down. For instance this only has one special case but if you want to say Pop rather than a multiple of 7 then the function becomes this.
def fizz_buzz_pop(limit)
for i in range(1, limit + 1):
if (i % 105 == 0):
print("FizzBuzzPop")
elif (i % 35 == 0):
print("BuzzPop")
elif (i % 21 == 0):
print("FizzPop")
elif (i % 15 == 0):
print("FizzBuzz")
elif (i % 7 == 0):
print("Pop")
elif (i % 5 == 0):
print("Buzz")
elif (i % 3 == 0):
print("Fizz")
else:
print(i)
And of course if you say that multiples of 11 become Bizz you get into real trouble.
I feel a more generic approach is needed here. Here is a fairly simple class called
AdvancedFizzBuzz
which will give us a fully extensible FizzBuzz machine.
class AdvancedFizzBuzz(object):
def __init__(self, mapping)
self.map = mapping
def __getitem__(self, index):
ret_val = ""
modified = False
for key in self.map:
if (index % key == 0):
modified = True
ret_val += self.map[key]
if (not modified):
ret_val = index
return ret_val
def run(self, limit):
for i in range(1, limit + 1):
print(self[i])
The constructor takes a dictionary which maps numbers to what to print instead of their multiples. This is fairly straight forward and as it says in the doc string if you give it a dictionary with mapping[3] = Fizz, mapping[5] = Buzz it will be FizzBuzz.
The function __getitem__()
is more mysterious if you are not familiar with pythons magic methods. If you aren’t then I hugely recommend this guide, it has helped me enormously. What this function does is make your class indexable, just like a list or dictionary.
What the function actually does is the work of this class. It looks through all it’s rules (they keys in it’s map) and finds if the number it has been given is divisible by them. If it is divisible then it will append it’s key word onto the string to be returned and also mark the the value as modified. If the value has been modified it returns the string otherwise it returns the number itself.
The run() function is self-explanatory it goes through 1 – limit inclusively and prints the return value from the previous function.
This means that this class does not need editing to extend it’s functionality. I simply provide a different dictionary of rules. The results of running the function fizz_buzz_pop(110) and using the class with the dictionary {3: ‘Fizz’, 5: ‘Buzz’, 7: ‘Pop’} are given as text files in this repository. I used 110 so that it got to at least the first FizzBuzzPop which is at 105.
And of course this means that rather than writing a new function for multiples of 11 being Bizz you use the dictionary {3: ‘Fizz’, 5: ‘Buzz’, 7: ‘Pop’, 11: ‘Bizz’}.
The source code used in this article can be found in this repository.