I recently posted a guide to writing FizzBuzz in Ruby without using any conditionals. I focused on functional/declarative programming themes because I felt they were a good model of how I approached the problem, and also because they made certain things easy, like iteration, which would otherwise pose a problem without conditionals.
I had a lot of fun doing this challenge initially. For some reason, taking a new approach to a simple task really set me going — I guess it's true what they say about constraints bringing out creativity. I thought it would be nifty to write a somewhat obfuscated, one-liner version of this, and mystifying it by eschewing map
and hiding the iteration mechanism.
I've moved it onto 5 lines for "readability" (one-line gist here):
def fizzbuzz(start, limit)
loop do
puts "#{'fizz' * (((start % 3 / (start % 3 + 1.0)).ceil - 1) * (-1))}#{'buzz' * (((start % 5 / (start % 5 + 1.0)).ceil - 1) * (-1))}#{start.to_s * ((start % 3 / (start % 3 + 1.0)).ceil * ((start % 5) / ((((start += ((limit + 1) - start)/((limit + 1) - start)) - 1) % 5) + 1.0)).ceil)}"
end
end
Most of this code is just the functions f
, g
, and h
from the previous post, pasted together on one line. But, since we aren't allowed to use conditionals, the loop is infinite. Not only that, but it's only one print statement, so it looks like it should just print the same thing over and over, forever!
In order to increment the input number, I used a trick that functional programmers would shudder at, the sum-and-assign +=
operator. To get the program to terminate, I just force it to crash. I melded both of these into a single expression: in the final use of start
in the loop, I increment it by 1. But instead of using the literal value 1
, I calculate it in such a way that will crash if start
is larger than limit
.
This bit:
((limit + 1) - start)/((limit + 1) - start)
will return 1 in most cases, but will try to divide by 0 (and thus crash) if start
is 1 greater than limit
. So in every iteration of the loop, I replace the final usage of start
with
((start += ((limit + 1) - start)/((limit + 1) - start)) - 1)
which will either crash if start == limit + 1
, or otherwise reduce to (start += 1) - 1
, which increments start
and returns the previous value of start
, by subtracting one from the result. I need it to return the previous value of start
because if it doesn't crash, it needs to use the same value of start
that it did in the rest of the print statement.
Pretty much everything in this post is taboo in production code, but if you enjoy coding as a kind of mind-bending sport, it's fun to create a double-take-inducing solution to such a simple problem.