Learn with Me: FizzBuzz
Come along a journey with me as a stumble through a beginner-level coding challenge.
Fizz buzz is a group word game for children to teach them about division. Players take turns to count incrementally, replacing any number divisible by three with the word "fizz", and any number divisible by five with the word "buzz". (thanks Wikipedia)
The coding challenge 'FizzBuzz' is essentially the same. Print out every number 1-100 except for every number that is divisible by 3 print 'fizz', for every number that is divisible by 5 print 'buzz', and for numbers that are divisible by both print 'fizzbuzz'.
This challenge is sometimes presented in coding interviews for greener devs with less code experience to determine whether or not they can think logically about code rather than just button smashing until a program runs (no offense if this is you...because this is also usually me). There are a TON of resources that go through this exercise and give you hints but I really wanted to try this for myself to see what challenges I encountered. If you haven't done this exercise yourself and you want to, READ NO FURTHER because there are spoilers...
Anytime I'm starting a new project or challenge process I have three main parts to writing my code: Planning, Execution, and Beautification.
(This exercise was completed in a Ruby environment, I believe the 'math' gem would be required if you do not have one in your framework.)
First things first I like to plan mentally and get a general structure before I start writing things out. Having the logic and the desired end-result set in my brain prior to the start of a project stops me from getting overwhelmed when I actually start writing down the code.
I decided what my base structure would look like:
A repeating block
with an number variable that increases with each pass through the block
An 'if/else' block within the repeating block
An 'if' for 'fizz'
An 'else' for 'buzz'
Another 'else' for 'fizzbuzz'
And a print/puts for the number
In this step of the process I start to write my code. It's messy and ugly but it gets results! I'm going to take you through the first few iterations of my code (and yes it's not pretty).
Iteration 1: No Loop
describe 'FizzBuzz' do i = 0 if (i / 3 % 1).zero? puts 'fizz' if (i / 5 % 1).zero? puts 'buzz' end elsif (i / 5 % 1).zero? puts 'buzz' else puts i end end
Okay so I knew I needed an 'if' statement to loop the number through so that the system would print the right option, so that's where I started to get my thoughts on 'paper'. But when I went to try it out I ran into my first problem...there was no loop, I only had one number to loop through the chain.
Iteration 2: Added Loop
describe 'FizzBuzz' do i = 0 while i < 101 do if (i / 3 % 1).zero? puts 'fizz' if (i / 5 % 1).zero? puts 'buzz' end elsif (i / 5 % 1).zero? puts 'buzz' else puts i end i = i + 1 end end
Can we all agree that stack overflow is God's gift to developers? Or I suppose it's developers' gift to developers...but since some developers think they are gods I guess it works either way? ANYWAYS, after a quick google search I decided on a 'while' loop. This is not the best way...but it's my way and I'm okay with it. Now my numbers were looping and I was printing 100 items but my list looked like this:
fizz fizz fizz fizz buzz fizz ...
wth is going on...
Iteration 3: Debug
describe 'FizzBuzz' do i = 0 while i < 16 do fizz = i / 3 puts fizz i = i + 1 end end
I needed to see what was happening with my calculations, so I removed all the printing of 'fizzbuzz' an shortened my loop.
0 0 0 1 1 1 ...
Why are these all whole numbers?? OH DUH. My code thinks 'i' is an integer, therefore every response is being rounded and I'm not getting accurate results. What I needed to do was convert 'i' into a float to preserve the decimals.
Iteration 4: Float Conversion
describe 'FizzBuzz' do i = 1.to_f while i < 16 do fizz = (i / 3) buzz = (i / 5) if (fizz % 1).zero? puts 'fizz' if (buzz % 1).zero? puts 'buzz' end elsif (fizz % 1).zero? puts 'fizz' elsif (buzz % 1).zero? puts 'buzz' else puts i end i = i + 1 end end
Alright, so now my integer starts off as a float. No more rounding, and the right things are getting printed! Almost...but look what happened once I got to '15':
... 11.0 fizz 13.0 14.0 fizz buzz
I need 'fizzbuzz' to be on one line! That, and my double 'if' is ugly. Let's see if Stack Overflow has any ideas again.
Iteration 5: Working Code
describe 'FizzBuzz' do i = 1.to_f while i < 16 do fizz = (i / 3) buzz = (i / 5) if (fizz % 1).zero? && (buzz % 1).zero? puts 'fizzbuzz' elsif (fizz % 1).zero? puts 'fizz' elsif (buzz % 1).zero? puts 'buzz' else puts i end i = i + 1 end end
It's ALIVE. 'fizzbuzz' is on one line now and I've successfully completed an entry-level code question *pats intermediate-leveled self on back*.
... 11.0 fizz 13.0 14.0 fizzbuzz
Now I'm checking the most complex outcome first then going down the 'if' list in decreasing complexity before finally printing the number itself.
Although this step is not important for learning it is crucially important for writing actual readable code. In software, someone else will have to look at your code, understand it, and be able to make adjustments to it. Therefore you really need to know how to clean it up.
For this step I did a few things:
Converted the printed float back into an integer
Removed the unnecessary variables
Updated the number incrementing to i += 1 for clarity
If this were actual code for a group project I may also add some comments or descriptions so that future devs would understand my thought process and be able to contribute easily.
I'm sure this could be better but I wanted to show how my first-time run through of this challenge looked in a 45 minute time-box.
describe 'FizzBuzz' do i = 1.to_f while i < 101 if (i / 5 % 1).zero? && (i / 3 % 1).zero? puts 'fizzbuzz' elsif (i / 3 % 1).zero? puts 'fizz' elsif (i / 5 % 1).zero? puts 'buzz' else puts i.to_i end i += 1 end end
Here is what my coworker came up with in the same time-frame:
number = 100 for i in 1..number if i % 3 == 0 && i % 5 == 0 puts "fizzbuzz" elsif i % 3 == 0 puts "fizz" elsif i % 5 == 0 puts "buzz" else puts i end end
I like this one more because the 'for i in 1..number' increments the number for you as it loops.
Have you completed this challenge? What language did you use? What challenges did you face?
If you're an interviewer, have you ever asked this question of an interviewee? What are the responses like?