DEV Community

Discussion on: Unconditional Challenge: FizzBuzz without `if`

Collapse
 
kallmanation profile image
Nathan Kallman

Happy Juneteenth! I love everyone's approaches here, it's fun to see the way each person thinks through the problem.

I'll be posting my answers on Monday (along with the next installment of With Only CSS) so encourage your friends to give this a shot over the weekend (or take another go yourself)!

Follow me and react with a 🔖 so you remember to come back and see what I post here.

Drop a 🦄 or ❤️ if you'd be interested in some follow up posts going more in depth into each (OO/FP) solution: how they work; how they are similar; and how they are different.

Thanks everyone who took the time to post a solution to my little challenge; I'll see you all on Monday!

Collapse
 
kallmanation profile image
Nathan Kallman • Edited

As promised, here is my functional approach to solving this (deeper article on it to come soon)

const functionalTrue = (onTrue, onFalse) => onTrue;
const functionalFalse = (onTrue, onFalse) => onFalse;
const isDivisible = (dividend, divisor) => [functionalTrue, ...Array(divisor).fill(functionalFalse)][dividend % divisor];

const functionalFizzBuzz = (n) => {
  const divisible_by_three = isDivisible(n, 3);
  const divisible_by_five = isDivisible(n, 5);
  return divisible_by_three(divisible_by_five("FizzBuzz", "Fizz"), divisible_by_five("Buzz", n));
};

Similar to Heiker's solution above; the main part of this solution is defining "true" and "false" as functions taking the same two parameters but returning one or the other.

Collapse
 
kallmanation profile image
Nathan Kallman • Edited

You can see both solutions in action on this codepen (planning one final post doing a compare/contrast between the two approaches)

Collapse
 
kallmanation profile image
Nathan Kallman

And here is my object-oriented approach (deeper article on it to come soon)

const baseBoolean = {
  setThen: function(then) { return { ...this, then }; },
  setOtherwise: function(otherwise) { return { ...this, otherwise }; },
};

const objectOrientedTrue = {
  ...baseBoolean,
  evaluate: function() { return this.then; },
};

const objectOrientedFalse = {
  ...baseBoolean,
  evaluate: function() { return this.otherwise; },
};

const objectOrientedNumber = {
  value: 0,
  isaMultipleCache: [objectOrientedFalse],
  setValue: function(n) { return { ...this, value: n, isaMultipleCache: [objectOrientedTrue, ...Array(n).fill(objectOrientedFalse)] }; },
  isaMultipleOf: function(dividend) { return this.isaMultipleCache[dividend.value % this.value]; }
};

const objectOrientedFizzBuzz = {
  for: function(n) {
    const number = objectOrientedNumber.setValue(n);
    return this.three
               .isaMultipleOf(number)
               .setThen(
                 this.five
                     .isaMultipleOf(number)
                     .setThen("FizzBuzz")
                     .setOtherwise("Fizz")
                     .evaluate()
               )
               .setOtherwise(
                 this.five
                     .isaMultipleOf(number)
                     .setThen("Buzz")
                     .setOtherwise(number.value)
                     .evaluate()
               )
               .evaluate();
  },
  three: objectOrientedNumber.setValue(3),
  five: objectOrientedNumber.setValue(5),
};

Similarly to the functional approach; the main part of this solution is defining "true" and "false" as objects. But now instead of parameters, the objects have the same interface and return one or the other of the attributes set on the object.