Fizz Buzz but it’s Excessively Overengineered
Ever since FizzBuzz first emerged in the famous piece 'Why Can't Programmers.. Program?', it's become a rite of passage. It's a simple program requiring but simple logic, a simple loop and a simple if/else if/else statement.
So FizzBuzz was never supposed to be challenging, or difficult, it was just there to illustrate a point. It’s child’s play to any programmer worth their weight in salt. So naturally, it’s time to completely ignore that and make something incredibly complicated and mess around.
For the uninitiated, the FizzBuzz program is nothing more than printing output to a console with some conditions. We count up from one, if a number is divisible by 3 we print a "Fizz". If it's divisible by 5 we print a "Buzz". Should it be divisible by both a 3 and a 5, we output "FizzBuzz".
Here’s the very simplest of implementations in Python, printing our FizzBuzz sequence from 1 to 100:
for i in range(1, 101):
if i % 3 == 0 and i % 5 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
Sure, it works, but it’s kind of blunt. Adding a Python dictionary allows some modularity. By iterating over the keys of the dictionary we can check whether there is a Fizz, Buzz or FizzBuzz and extend the dictionary for as many fizzes, buzzes, bazzes, fozzes and whatever else our hearts may desire with no need to alter the main FizzBuzz logic:
fizz_buzz_dict = {
3: 'Fizz',
5: 'Buzz',
}
for i in range(1, 101):
output = ""
for key, s in fizz_buzz_dict.items():
if i % key == 0:
output += s
if output == "":
output = i
print(output)
I’m not very creative with coming up with these made up words though, so let’s create a procedurally generated FizzBuzz program instead. All we need is a starting letter, an ending letter and a vowel inbetween. From running this, I was presented with a fine ZakkQiggRabb program:
import random
CACHE = set()
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
def create_word():
return random.choice(CONSONANTS).upper() + random.choice(VOWELS) + random.choice(CONSONANTS) * 2
def generate_fizzbuzz_dict(words=2, max_num=10):
fb_dict = {}
# Ensure enough unique numbers are available
if words > max_num:
max_num = words
# Generate the words
for i in range(words):
# Generate our word without repeats
while True:
word = create_word()
if word not in CACHE:
CACHE.add(word)
break
# Find an available dictionary key
while True:
rand_n = random.randint(1, max_num)
if rand_n not in fb_dict:
fb_dict[rand_n] = word
break
# Return the dictionary
return fb_dict
def print_fizzbuzz(dictionary, count=100):
for i in range(1, count+1):
output = ""
for key, s in dictionary.items():
if i % key == 0:
output += s
if output == "":
output = i
print(output)
dict = generate_fizzbuzz_dict(5, 100)
print_fizzbuzz(dict)
But I’m a Python programmer, so it is absolutely essential that everything is a class object. If I can’t instantiate a FizzBuzz object, I lose all credibility. So I present to you, the FizzBuzz class for Python. This extends FizzBuzzes functionality for everything you could possibly need. Should you ever find yourself in a life or death situation, where someone is demanding you program a FizzBuzz program, then you simply need instantiate a FizzBuzz object with classic=True.
class FizzBuzz:
def __init__(self, dictionary=None, classic=False):
"""Initialise the fizzbuzz object
If classic is true, we use the classic fizzbuzz dictionary
Note: This will overwrite any dictionary passed in
If no dictionary is passed in, we use an empty dictionary
Otherwise we use the passed in dictionary"""
self.classic = classic
if self.classic:
dictionary = {
3: 'Fizz',
5: 'Buzz',
}
if dictionary is None:
self.dictionary = {}
else:
self.dictionary = dictionary
def update(self, dictionary):
"""Update the fizzbuzz dictionary with the passed in dictionary"""
self.dictionary.update(dictionary)
def overwrite(self, dictionary):
"""Overwrite the fizzbuzz dictionary with the passed in dictionary"""
self.dictionary = dictionary
def add(self, key, value):
"""Add a key and value to the fizzbuzz dictionary"""
self.dictionary[key] = value
def remove(self, key):
"""Remove a key and value from the fizzbuzz dictionary"""
del self.dictionary[key]
def print(self, count=100):
"""Print the fizzbuzz"""
for i in range(1, count+1):
output = ""
for key, s in self.dictionary.items():
if i % key == 0:
output += s
if output == "":
output = i
print(output)
def get_sequence(self, count=100):
"""Returns the fizzbuzz sequence as a list"""
l = []
for i in range(1, count+1):
output = ""
for key, s in self.dictionary.items():
if i % key == 0:
output += s
if output == "":
output = i
l.append(output)
return l
def print_dict(self):
"""Print the fizzbuzz dictionary"""
print(self.dictionary)
def print_classic(self, count=100):
"""Print the classic fizzbuzz"""
# Create a FizzBuzz object and use the methods to print the classic fizzbuzz
fb = FizzBuzz(classic=True)
fb.print(count)
del fb
def print_classic_dict(self):
"""Print the classic fizzbuzz dictionary"""
# Create a FizzBuzz object and use the methods to print the classic fizzbuzz dictionary
fb = FizzBuzz(classic=True)
fb.print_dict()
del fb
def randomise(self, words=2, max_num=10):
"""Generate a random fizzbuzz dictionary
Note: This will overwrite any dictionary passed in"""
CACHE = set()
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
def create_word():
return random.choice(CONSONANTS).upper() + random.choice(VOWELS) + random.choice(CONSONANTS) * 2
def generate_fizzbuzz_dict(words, max_num):
fb_dict = {}
# Ensure enough unique numbers are available
if words > max_num:
max_num = words
# Generate the words
for i in range(words):
# Generate our word without repeats
while True:
word = create_word()
if word not in CACHE:
CACHE.add(word)
break
# Find an available dictionary key
while True:
rand_n = random.randint(1, max_num)
if rand_n not in fb_dict:
fb_dict[rand_n] = word
break
# Return the dictionary
return fb_dict
self.dictionary = generate_fizzbuzz_dict(words=words, max_num=max_num)
# Test the FizzBuzz class
fb = FizzBuzz()
fb.print()
fb.print_classic()
fb.randomise()
fb.print()
fb.add(7, 'Seven')
fb.update({11: 'Eleven', 13: 'Thirteen'})
fb.print()
fb.remove(7)
fb.print_dict()
But we’re not done yet, are we? Surely there must be something really, really stupid we can do to tie this post up?
Well I haven’t been studying data science for nothing, for I now know how to generate sounds with Numpy. And so, we can convert our FizzBuzz sequence into something almost, but not quite, entirely unlike music. An education well spent.
import numpy as np
import simpleaudio as sa
def generate_song(fizz_buzz_list):
song = []
for item in fizz_buzz_list:
if isinstance(item, int):
freq = 220 + item * 10 # Adjust frequency based on number
duration = 300 # milliseconds
song.extend(np.linspace(0, np.pi * 2 * freq * duration / 1000, int(44100 * duration / 1000)))
else:
# Base the frequency on the characters in the word
freq = 220 + sum([ord(c) for c in item]) * 10
duration = 500 # milliseconds
song.extend(np.linspace(0, np.pi * 2 * freq * duration / 1000, int(44100 * duration / 1000)))
return song
fb = FizzBuzz()
fb.randomise(20, 50)
# Get the list
fizz_buzz_sequence = fb.get_sequence(1000)
# Generate FizzBuzz and turn it into a song
song_sequence = generate_song(fizz_buzz_sequence)
# Play the song
audio = np.array(song_sequence)
play_obj = sa.play_buffer(audio, 1, 2, 44100)
play_obj.wait_done()
My god it’s beautiful.