Home Creators Posts Import Register Favorites Logout

Content

I did it! I made Fifty Fizzbuzzes! Yes, fifty different implementations of the classic Fizzbuzz programming exercise. Some of them output the solution. Some of them are flagrantly wrong. Some write you poetry, some play you songs.

Twitter user @quasiben was kind enough to figure out how to host an interactive version with all the dependencies, go here and click Fifty Fizzbuzzes.ipynb (it might take a minute to load).

It's on my github here, where it's read-only, unless you download the file and run it, for which you'll need jupyter python stuff. I use Anaconda.

Fifty is a lot of programs, even if many are just 1 to 5 lines. It was an intense exercise.

favourites:

#22, which uses a linear regression and proves AI is smarter than humans.

#25, which reveals the state of mind of someone who's halfway through writing 50 fizzbuzzes.

#32, which plays a quite musical auralization of the algorithm ♬

#40, a chatbot that will listen to you and write you a poem ✍️

#48, a complete text adventure with sound effects and monsters to fight 👻🗡

#49, for the comments.

discussion:

Tell me if it works and what your favorite fizzbuzz is, and other favourite implementations. For example here's one about using a neural network that I find quite inspiring and hope to have the skills to do soon.

Also if you're a python person who can critique any parts where I could have done something more easily if I only knew about some method or another, let me know that too! I am still getting to know the basics of how python does things, which was the point of this exercise.

Here's a public post about the project on my website, which is a good place to share it from. But I wanted a private post here on Patreon where we can have comments and discussion.

intro text on "Make 50 of Something" and "Fizzbuzz":

One of the many things I learned from Evelyn Eastmond in my time working with her is this technique for deeply exploring, releasing yourself from preconceptions, thinking in new ways.

You make 50 of something. In one big marathon. (Maybe spaced over a few days, but it's important to exhaust your possibilities to break and illuminate habits, rather than making habits as with making a thing a week.)

50 is a LOT, and it takes you on this weird journey of ups and downs and complexifying and simplifying and combining and taking apart. It can be oddly emotional and intense.

This technique was meant for artists, but my research group has used it for VR stuff and programming language design too. So now to learn python, over the weekend I made 50 implementations of fizzbuzz.

Fizzbuzz is a classic simple programming exercise and common interview question based on a classic kids game, where you take turns counting, but if the number is divisible by 3 you say "fizz", and if it's divisible for 5 you say "buzz", and if it's divisible by both you say "fizzbuzz".

Enjoy!

Vi

P.S. If you talk to the poem-friend bot and it writes you a poem, share it here if you like! I'm curious to see.

Files

vihart/fiftyfizzbuzzes

Fifty different implementations of Fizzbuzz in Python. - vihart/fiftyfizzbuzzes

Comments

Kenny Tilton

Oh, man, I did not see the homework (report my favorite)... can I just do a Lisp version?

vihart

Sure! As you know, homework is mandatory always.

Matt Cengia

Oh wow. Vi, this is amazing :) I particularly liked #32, the second audio attempt; I was actually disappointed that it finished so soon and had to bump the upper limit to 301 to satisfy my ears!

Kenny Tilton

Oh, OK. My favorite was 36 or 37, the Venn diagram one. I do better with pictures. Now let's see how well Patreon formats code:

Kenny Tilton

(defparameter *buzz* '((3 :fizz)(5 :buzz)(15 :fizzbuzz))) (let* ((hits (sort (copy-list *buzz*) '> :key 'car)) ;; higher divisor takes precedence (source (loop for n upfrom 1 below (1+ (caar hits)) for w = (loop for (d w) in hits when (zerop (mod n d)) return w) collect w))) ;; source is now (nil nil fizz nil buzz etc.... (rplacd (last source) source) ;; source now ends with its start, so is endless (loop for n upfrom 1 upto 101 for s in source do (print (or s n))))

Dan Carmon

Thanks for posting these buzz fizzbuzzez, Vi! When you described this project in the previous post, I was skeptical that it was really possible to do so many different variations on it, but I'm very impressed with the results, particularly with the more artsy versions, such as #32, #35, #39, #43, #46, #48... My very favourite is #32 - the 15-period rhythm and the ascending note are just so *nice*. Its inclusion in #48 is also great. I was even more excited for the opportunity to give some programming advice! I hope it would be helpful. I had quite a lot to say, so I will split it into a few comments. A couple of disclaimers: I am mostly experienced with python 2.7, and only a little bit with 3.*, so it's quite possible that some of my suggestions might not actually work, or might be considered outdated. But I hope not! The second disclaimer is that while I am a python enthusiast, I am not a professional programmer, and my recommendations reflect only my own preference, and not necessarily any commonly accepted best-practices. Let's start off with the smallest of things! In fizzbuzz 3 (and probably in many others): Instead of having similar, simple assignments in many lines, do them all together: > div3, div5 = bool(i%3),bool(i%5) (Just a personal preference, really. Two lines is OK too.) ---- In fizzbuzz 19: I would write "if 0 not in bizlet" rather than "if not(0 in bizlet)". It's equivalent, probably, but reads nicer - closer to human language, and fewer parentheses. ---- 30,32: Don't give into numpy's oppression! Don't use 2 * np.pi ! Instead, try > from math import tau # !!!! (This is actually one of python 3's most important advantages over python 2, in my opinion.) ---- 12 and 13 make me sad about python 3's futuristic division :( Assuming regular (c-like) int division, one could have tested these as e.g. > if 3*(n/3) == n: In python 3, a viable alternative to > if n/3 == int(n/3): is > if n/3 == n//3: It is probably better practice as well, since it is more efficient to ask the computer to perform integral division than to perform floating point division and then round down. However, unlike n%3 == 0, comparing the integral division with floating point division will probably break down for very large values of n. ---- A couple of minor bugs: 47 has a logic bug: "not div3 or div5" should be "not (div3 or div5)" or "not div3 and not div5" 17-19 contain a probabilistic bug: There's a 1 in 101 probability of getting an input that would crash the game after getting the player's input (discovered empirically while playing with #19). This rises from random.randint and range having different conventions for ranges. Really, the convention for random.randint is pretty whack. Also the print command > print("How about",a,"?") Has the unfortunate consequence of printing a space between a and the "?", which I assume is unwanted. One way to avoid this would be > print("How about %d?"%(a)) (I'm sure some people prefer to use the snazzy {} things for string formatting, but I like %d just fine. But look it up! It's really cool.)

Dan Carmon

Hmm, I posted a couple of subcomments, but it looks like they got eaten by something. Trying again... Lists! And other containers! Generating lists in one-liners is one of python's defining characteristic. 9, 10: Don't generate lists using for loops and append (if avoidable). Use maps or list comprehensions instead. In example 9, replace first three lines by: > listbuzz = list(range(1,101)) (fun note: before python 3, using list here would have been redundant, as range would already be a list; the abstract iterator used to be xrange) In example 10, replace first three lines by: > listbuzz = ["fizzbuzz"]*100 Relevant also to 17, 18, and others... More complicated examples can be generated using list comprehension. For example, instead of list = [] for i in range(100): if i%17 < 3: list.append(i**2 - (i%5) + i/7) One can write list = [i**2 - (i%5) + i/7 for i in range(100) if i%17 < 3] ---- 45: Another great opportunity for list comprehension! Consider the one-liners: numberSet = set(range(1,101)) fizzSet = set(range(1,101,3)) buzzSet = set(range(1,101,5)) or all together: > numberSet, fizzSet, buzzSet = map(set,[range(1,101),range(1,101,3),range(1,101,5)]) Also, setDict is a list, not a dict. What a shame! Especially since the conditional in the loop could have been avoided if it were a dict. Dictionaries have the dict.get(k,default) method, which returns dict[k] if k is a key in dict, and otherwise returns default. Consider: setDict = {1:'fizz',2:'buzz',3:'fizzbuzz'} # note that 0 is not a key! for i in range(1,101): for j in range(4): if i in setSet[j]: print(setDict.get(j,i)) ---- 46: To get things out of sets, you can convert them to a list: > fizzbuzzList = list(fizzbuzzSet) But, this is problematic, since there is no guarantee that they'll be returned in any specific order. If it's a set of numbers, most often you would want to sort them as you output them: > fizzbuzzList = sorted(fizzbuzzSet) Fun!

Dan Carmon

Last comment! This one got eaten twice. I guess Patreon doesn't like it when comments are being posted in close proximity? Also, this seems to take up quite a lot of space in the comments section, sorry about that. I somehow expected these to be collapsed until viewed... Anyhow. Fizzbuzz 19: I would have implemented the switch-case (of streak) in function right(...) differently. You always have the same functionality - update streakMult and print a message, the values of which depend on the value of streak. I would use a dictionary defined globally like so: streakDict = {3 : (2,"THREE IN A ROW!\nPOINTS MULTIPLIER x2"), 5 : (3,"!!!FIVE IN A ROW!!!!\n!!!POINTS MULTIPLIER x3!!!"), 10: (5,"!!!!!!!!!!!!!!!\n!!!TEN IN A ROW!!!!\n!!!POINTS MULTIPLIER x5!!!\n!!!!!!!!!!!!!!!"), 15: (15,"FIZZBUZZ STREAK BONUS"*15) And then the code inside right(...) would be simply: if streak in streakDict: streakMult, message = streakDict[streak] print(message) Less code replication, and much easier to update in case you want to add more levels of multipliers. There's also a lot of code repetition in the main body. The logic there would probably have been cleaner if the computer would calculate the expected answer ahead of time, and then just compare it to the input. e.g.: answer = ["d","","","a","","s","a","","","a","s","","a","",""][a%15] # or by any other means if ask == answer: points, streak, streakMult = right(points,streak,streakMult) else: points, streak, streakMult = wrong(points,streak,streakMult) This could have been slightly nicer if the "" was also a single character, say, " ". Then we could have used a string instead of a list: > answer = "d a sa as a "[a%15] But we can also patch it to use an empty string like so: > answer = "d a sa as a "[a%15].replace(" ","") or > answer = "d a sa as a "[a%15].strip() ---- 39: I would recommend using enumerate or zip. Instead of for j in range(len(self.numbers)): if i%self.numbers[j] == 0: fuzzstring += self.text[j] write for j,num in enumerate(self.numbers): if i%num == 0: fuzzstring += self.text[j] or for num,txt in zip(self.numbers,self.text): if i%num == 0: fuzzstring += txt In this example it doesn't make much difference, but it can be more dramatic when these values are referred to more than once - for example, it would make the (for j) loop in #41 much nicer, in my opinion. Also, regarding that loop, you can write "k /= self.numbers[j]" just as well as *= and += !

Rajat Tibrewal

Also, the poem you asked for: I Am I doing Very I am well! What I doing about Am you? I very well, You I am doing well! see Its I what a Am very sunny I doing about day Today... I am well! you? are You? I doing very well, what Am what secrets I you do You I am doing well! about see keep? Very I its

Gregor Shapiro

If you format the numbers with the same number of digits and line break after one repeat of the pattern: 0102fizz04buzzfizz0708fizzbuzz11fizz1314fizzbuzz 1617fizz19buzzfizz2223fizzbuzz26fizz2829fizzbuzz 3132fizz34buzzfizz3738fizzbuzz41fizz4344fizzbuzz 4647fizz49buzzfizz5253fizzbuzz56fizz5859fizzbuzz 6162fizz64buzzfizz6768fizzbuzz71fizz7374fizzbuzz 7677fizz79buzzfizz8283fizzbuzz86fizz8889fizzbuzz 9192fizz94buzzfizz9798fizzbuzz Looks best of course in monospaced font...

WW

You need a version with no modulus, no division, and no multiplication. In case it has to run really fast on an PIC microcontroller or something :-)

WW

also, in general, you shouldn't need a special case for "fizzbuzz", since it would print fizz an buzz anyway.

vihart

Ooh I hadn't tried that! Listening to it now. Yep, it's pretty great!

vihart

Use 385 to finish out the octave.

vihart

Ooh thank you for taking the time to write all this out, it's very helpful! I didn't know python did some of these things.

vihart

I didn't think to do 01 instead of 1! That would let me take advantage of of a different way to do one like #5.

vihart

There's a few that fit that constraint! #5 is probably the most robust.

Gregor Shapiro

Compare lists of the numbers in base 3 and base 5!

WW

I don't know if I could come up with 50 ways to write this, but it's fascinating that even given the 50 examples, people are able to come up with MORE methods.

I dare you to pronounce this correctly

#50 was very touching (especially after going through all previous 49) Also, my poem: I Am I in The I am depths Of I in despair Am my I the piano Is I am in depths out Of I of tune Am the no, I in despair please Spread I am depths my the Word! I in the piano Am of

vihart

This poem really captures the disorganized sorrow of being alone in the universe without an in-tune piano to talk to. Glad you liked 50!

Daniel Barkalow

Here's a trick I often find helpful: 'print((i%3==0)*"fizz"+(i%5==0)*"buzz" or i)'. The 'or' operator produces the first true value, if any, otherwise the last value. So you can implement it as "Say all of the words that apply. If you haven't said anything, say the number." Another option you didn't explore was per-rule state that carries over from one iteration to the next, to replace division or even looking at the counter unless you're saying it.

Jack Mudge

It's a little old, but a really interesting implementation in Fractran via Common Lisp can be found here: <a href="https://malisper.me/building-fizzbuzz-fractran-bottom/" rel="nofollow noopener" target="_blank">https://malisper.me/building-fizzbuzz-fractran-bottom/</a> It's an interesting insight into symbolic computation; very basic components are gradually built up until it's possible to describe loops and conditionals in fractran - the only real "trickery" used (as it were) is to provide a mechanism for a fractran program to output data.

vihart

I love how fizzbuzz gives so many opportunities to look at how different datatypes interact and the intricacies of operators. Python seems to have a lot of things that make sense.