Some thoughts on FizzBuzz ------------------------- markus schnalke 2015-05-03 The task is easy: Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz". !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! ! ! If you've never implemented FizzBuzz, ! ! then stop reading here and implement it first! ! ! ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! . . . . Michi told me about FizzBuzz and said that the guys at university wanted to do this as a test at the beginning of the semester with an undergraduate students class. They just wanted to see how they would manage the task. I found this idea wonderful. Before I studied the FizzBuzz problem, however, I needed to implement it myself. This first implementation is the critical one. You can never restore the same situation again. Hence, I ensured to avoid any further information about FizzBuzz. I also haven't thought much about the problem before I started to implement it. (Michi and I have only discussed the general topic of doing such tests with students.) Well, then one morning, I had some spare time and went for the challenge. I chose to implement it in awk (because awk is a favorite programming language for me). This was the result: BEGIN { for (i=1; i<=100; i++) { if (i%3==0) {printf("Fizz"); x++} if (i%5==0) {printf("Buzz"); x++} if (!x) {printf("%d", i)} printf("\n") x=0; } } Actually, this is the result after my third try. First, I accidently inverted the modulo calculation (if (i%3) ...) -- pretty stupid, yes. Even more stupid was the try to solve the error quickly: if (!i%3) ... (wrong precedence!). Well, trial'n'error is just too tempting when having the computer at hand! Nonetheless, I like my solution, even now, that I thought more about the problem. My code is not perfect but pretty good, I think. In the days since then, I made some more thoughts on the problem. This is the essence: 1) The problem sounds easier than it is. 2) The problem is more staightforward than it sounds. 3) There is a stong temptation to implement it as compact as possible, because the description seems to imply a compact solution. 4) The key point is to realize that we need to handle four cases: - by 3 and by 5 - by 3 - by 5 - neither by 3 nor by 5 If one discovers this and implements these four explicit cases, then the solution is pretty straightforward. (Just care for the order of the cases!) 5) One should resist the strong temptation to implement the program with only three cases. It's the most dangerous source of error (for all those who get the for-loop right). It's much more difficult to write an elegant solution with three cases, and those solutions are likely more difficult to understand. 6) You succeed if you use an idiomatic for-loop and handle the four cases separately. 7) Don't try to be clever! The most straight-forward and thus foolproof solution is IMO: BEGIN { for (i=1; i<=100; i++) { if (i%15==0) { print "FizzBuzz" } else if (i%3==0) { print "Fizz" } else if (i%5==0) { print "Buzz" } else { print i } } } It contains only one tricky part: the modulo 15. Although it is difficult to see this possibility in the first place (at least for non-mathematicians), it is easy to understand it when reading the code. (One might even argue, that the problem description ``multiples of both three and five'' is unnecessarily complicated compared to ``multiples of fifteen''. For mathematicians, however, there exists no semantic difference between the two description.) An improved version of my three-case-solution from above (inspired by the Wikipedia example) is: BEGIN { for (i=1; i<=100; i++) { s="" if (i%3==0) {s="Fizz"} if (i%5==0) {s=s "Buzz"} if (!s) {s=i} print s } } Conclusion: FizzBuzz (hopefully) teaches that it is crucial to abstract the real problem from the problem description. It shows the temptation to give it a quick shot, which is assumed to succeed, thus skipping the development of a structured problem model. All those who take the time to develop this structured problem model have the best basis to get the code right ... not only in this academic example but especially in their real work. (The undergraduate's widespread problem of getting the counting loop right is a different problem that comes from their lack of knowing language idioms. Using an idiomatic for-loop ensures that it iterates exactly 100 times.)