FizzBuzz is originally a game to help kids to learn the mathematical division by playing with numbers. If a number has a given factor, it is replaced with the matching word: “Fizz” when divisible by 3, “Buzz” when divisible by 5. Later Fizz-Buzz becomes a well-known short programming problem to select developer candidates. Fizz-Buzz is also used as an icebreaker for adult groups, in the training, facilitation or Agile background . As I was reading further information about Fizz-Buzz, I realized the problem could be more difficult thanks to many variations, for learning kids as much as for programmers. Thus this game is here an opportunity to play with the Java programming language features as well as some programming paradigms such as the object-oriented and functional ones, while building a fluent API. The whole has been made in the Test-Driven Development way and Git-Flow is choosen as the version control workflow.

You shall not pass

Usage

Fizz-Buzz basics

Fizz-Buzz of one number

To get the result of Fizz-Buzz for a given number n: fizzBuzz.of(n) where fizzBuzz is an instance of the FizzBuzz class.
For example: fizzBuzz.of(3) returns “Fizz” and fizzBuzz.of(5) returns “Buzz”.

Fizz-Buzz of several arbitrary numbers

To get the result of Fizz-Buzz for several given numbers n1, n2, …, nx: fizzBuzz.of(n1, n2, ..., nx).
For example: fizzBuzz.of(3, 5, 15) returns “Fizz Buzz FizzBuzz”.

Fizz-Buzz of a range of numbers

To get the result of Fizz-Buzz for a given range of numbers: fizzBuzz.from(start).to(end).
For example: fizzBuzz.from(1).to(15) returns “1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz”.

Notice that the start and end numbers are inclusive.

More rules

Fizz-Buzz variations

You can choose the game rules to be applied. The followings ones are popular variations.

Fizz-Buzz in various manners

You can invoke the Fizz-Buzz variations with a more concise syntax, thanks to static methods provided by the PlatAt and I classes. The PlayAt class proposes all the known Fizz-Buzz variations by naming them, while the I class do the same thing by variation-based verbs.
For example with the PlatAt class: fizzBuzz() is to play at Fizz-Buzz, sevenBoom() at 7Boom, fizzBuzzWoof() at Fizz-Buzz-Woof, fizzBuzzPopWhack() at Fizz-Buzz-Pop-Whack and fizzBuzzPopWhackZingChop() at Fizz-Buzz-Pop-Whack-Zing-Chop.
For example with the I class: fizzbuzzify(values) transforms values according to the Fizz-Buzz rules, while fizzbuzzify(start).until(end) transforms the numbers between the start and endvalues. The same principle is applied to all variations: sevenboomify, fizzbuzzwoofify, fizzbuzzpopwhackify, fizzbuzzpopwhackzingchopify.

Combining some Fizz-Buzz variations

You can combine some variation rules to be applied by chaining the corresponding methods.
For example: fizzBuzz.whenNumberHasFactors().whenNumberContainsDigits().of(3, 5, 15, 30, 315) returns “FizzFizz BuzzBuzz FizzBuzzBuzz FizzFizzBuzz FizzFizzBuzzBuzz”.

Notice that the variation rules are applied according to the Fizz-Buzz order: Fizz at first, Buzz after. Also notice that each time a condition is satisfied the matching word is repeated. If you will not, as playing at 7Boom, you can specify it: fizzBuzz.wordsOnlyOnce().whenNumberHasFactors().whenNumberContainsDigits().of(55) returns “Buzz” only, instead of “BuzzBuzz”. On the contrary, if you wish a word was repeated as many times as a condition is true, you can also specify it: fizzBuzz.wordsNTimes().whenNumberHasFactors().whenNumberContainsDigits().of(55) returns “BuzzBuzzBuzz”.

Playing with custom words

You can specify your own custom words, each associated to one property.
For example: fizzBuzz.word("Foo", 3).word("Bar", 5).of(3, 5, 15) returns “Foo Bar FooBar”.

Playing with custom predicates

You can specify your own custom predicates, to be applied to any numbers: a given number is replaced with a word if the provided predicate is satisfied. Such a predicate checks if a property is applicable to a value. You have to define your predicate by using a Java 8 lambda that returns a boolean: (value, property) -> { /* TODO: return a boolean */ }.
For example: fizzBuzz.word("Even", 2).whenNumberSatisfies((value, property) -> value % property == 0).from(1).to(4) returns “1 Even 3 Even”. More sophisticated predicate implementations are allowed, like digital sequences, thresholds based on arithmetical calculations, etc.

More customizations

FizzBuzz result as a list

You can get a list of words as a Fizz-Buzz result instead of a string of words based on the concatenation. Splitting the string result is no longer needed.
For example: fizzBuzz.asList().of(3, 5) returns { "Fizz", "Buzz" }.

Separating words while printing

You can print the words being separated by predefined or custom separators. The predefined separators are : comma, semi-colon, slash, backslash, dash, line feed.
For example: fizzBuzz.separatedByComma().of(3, 5) returns “Fizz, Buzz” and fizzBuzz.separatedBy("-*-").of(3, 5) returns “Fizz-*-Buzz”.

The word separator can be a predefined or custom punctuation mark. In this case, the all sentence is completed with it. The predefined punctuation marks are : exclamation mark, full stop (period).
For example: fizzBuzz.punctuatedByExclamationMark().of(3, 5) returns “Fizz! Buzz!” and fizzBuzz.punctuatedBy("?").of(3, 5) returns “Fizz? Buzz?”.

Some French alternatives exist because of one space before some punctuation marks.
For example: fizzBuzz.separatedByFrenchSemiColon().of(3, 5) returns “Fizz ; Buzz” and fizzBuzz.separatedByFrenchExclamationMark().of(3, 5) returns “Fizz ! Buzz !”.

You can even print the fizzbuzzified numbers between brackets just after the FizzBuzz words.
For example: fizzBuzz.separatedByComma().withNumbers().from(1).to(5) returns “1, 2, Fizz (3), 4, Buzz (5)”.

More features

Finding the most Fizzy-Buzzy

You can find the most Fizzy-Buzzy number in some given arbitrary numbers or in a given range of numbers, that is to say the number whose the corresponding expression after being fizzbuzzified contains the greater number of Fizz-Buzz words, such as “Fizz” or “Buzz”.
For example: fizzBuzz.findTheMostFizzyBuzzy().of(1, 3).asNumber() returns 3 and fizzBuzz.findTheMostFizzyBuzzy().from(1).to(15).asNumber() returns 15.

You can find the most Fizzy-Buzzy expression in some given arbitrary numbers or in a given range of numbers, that is to say the expression that contains the greater number of FizzBuzz words, such as “Fizz” or “Buzz”.
For example: fizzBuzz.findTheMostFizzyBuzzy().of(1, 3).asWord() returns “Fizz” and fizzBuzz.findTheMostFizzyBuzzy().from(1).to(15).asWord() returns “FizzBuzz”.

Alternating substitution words

You can specify several custom words each associated to the same single property. These words will be alternately substituted for any number satisfying a property-based predicate.
For example: fizzBuzz.alternateWords({ "Foo", "Bar" }, 2).from(1).to(6) returns “1 Foo 3 Bar 5 Foo” and fizzBuzz.alternateWords({ "Foo", "Bar" }, 3).word("Baz", 5).from(1).to(10) returns “1 2 Foo 4 Baz Bar 7 8 Foo Baz”.

Of course, you can accumulate single words and alternate words into the same way of play.

Release Notes

Version 1.6: alternate words

Version 1.5: expandable predicates

Version 1.4: expandable words

Version 1.3: word repetition by occurrence

Version 1.2: word repetition by predicate

Version 1.1: first variation

Version 1.0: basics