This tool is a simple FizzBuzz algorithm tester, by Karim Sultan (May 2020). Wait, what is FizzBuzz you ask? It's simple:
Output, from 1 to 100 (configurable via command line):
if x divisible by 15: Fizzbuzz
else if x divisible by 5: Buzz
else if x divisible by 3: Fizz
else: output X
The purpose is to spur critical thought and to try to resolve a problem with simple rules in the most efficient manner. I came across this interesting challenge thanks to Tom Scott's Youtube video:
https://www.youtube.com/watch?v=QPZ0pIK_wsc (Well worth watching).
You can execute the script (Python 3.7+) from any command line with:
Python FizzBuzz.py
This will run it in verbose mode for a range of 1-100, for each algorithm and then compare and rank their times.
The value of 100 is in line with Tom's video, but this can be changed (see below).
Note if running under Linux, you can issue:
chmod 644 FizzBuzz.py
and then execute it directly as:
./FizzBuzz.py
To get a list of the possible command line arguments, use --help
To run an exhaustive test with range 1..100,000, without results cluttering
the output, use:
Python FizzBuzz.py -m 100000 -v false
OR
Python FizzBuzz.py --max=100000 --verbose=false
You can test just a single algorithm with --algo or -a
Python FizzBuzz.py -m 150000 -a Racers -v false
Please note that the Recursive algorithm has a maximum recursion limit after which it will not run and will return a bogus high-time to go to the bottom of the rankings.
Ok, so I'm watching Tom's video, and it invites so many different approaches. To construct it well, we need elegance, not just a bunch of repeated code in a massive file. Fortunately, Python now has some great object oriented features, and they are leveraged here.
There is a base class FizzBuzz
which implements the standard, basic algorithm. It provides core code
(register algorithm name, start the timer, report the output, return the elapsed time).
Now the fun begins; subsequent algorithms just inherit from this base class, and only
re-implement the algorithm execution. The timing and reporting comes for free. Next, to make
testing easier, a list of class names (matching the algorithms) is maintained in main()
.
Using a nifty feature of Python, each string in this list is used to invoke the class it
represents, and the algorithm is executed. This makes adding new algorithms a plug'n'play
approach (and also allows for specifying a specific algorithm from the command line.
There are 10 that were implemented, by no means exhaustive:
- FizzBuzz (default / base class, using modulus)
- Sieve (modeled after the famous Sieve of Eratosthenes for primes)
- Minefield (A character search and replace)
- Dictionary
- Lambda (Uses nested Lambda expressions / similar to inline macros)
- Recursion (Limited by Python's recursion limit)
- Nested (An anti-recursion approach)
- Unrolled (An old-school approach to loop optimization)
- Pattern (FizzBuzz has a repeating pattern every 15 numbers)
- Racers (my favourite; two "cars" racing on a number line)
No threaded approaches were implemented, as Python does not offer a true multi-core threading model that is easily accessed.
Which is fastest? It depends on the iterations.
Try running with 1,000,000:
Pyton FizzBuzz.py -m 1000000 -v false
(be sure to set -v false
) and you'll get a fair distribution of results.
There is a png of a test of 1,000,000,000 (billion) in the source directory.
The sky is the limit! Why not try your own approach and see how it stacks up against the stock ones? Extending FizzBuzz.py
is simple:
- Create a new class with the algorithm as the name, inheriting from FizzBuzz. This example, we will use "NewAlgo" as the name:
class NewAlgo(FizzBuzz):
- Next, override
__init__
and register the name, as follows (arrow indicates indent):
def __init__(self):
-->super().__init__("Approach #10: New Algorithm")
- Override
doFizzBuzz(self)
with your implementation - Finally, in
main()
, find thealgos
array and add"NewAlgo"
as a member to it.
For the love of the game. For which Tom's video re-sparked. I'm a middle-aged programmer who wrote code as a kid on Commodore 64s - and it was fun. Then you make it your career and it becomes anything but. So, thank you Tom Scott for re-igniting the spark.