Edward Atkin - Coding Heaven

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.

built with btw btw logo