A variation of FizzBuzz, this challenge tests your ability to output or style things in different ways based on a recurring indexing pattern using Twig.
In FizzBuzz, counting from 1 to 100, you replace the number each time you encounter a multiple of 3 with “Fizz”, a multiple of 5 with “Buzz” and a multiple of both 3 and 5 with “FizzBuzz”. So the result is:
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, ...
The challenge is to write a twig macro called “fizzBuzz” that will accept 3 parameters: entries
(an array of entries), fizz
(an array of integers) and buzz
(also an array of integers). The macro should output the titles of each of the provided entries as header tags with a class of “fizz” each time a multiple of one or more of the integers in the fizz
array is encountered, “buzz” each time a multiple of or more one of the integers in the buzz
array is encountered, and “fizzbuzz” each time a multiple of one or more of the integers in both the fizz
and buzz
arrays is encountered. So for example, calling:
{% set entries = craft.entries.limit(22).all() %}
{{ fizzBuzz(entries, [3, 7], [5, 17]) }}
Should output:
<h4 class="">Entry Title 1</h4>
<h4 class="">Entry Title 2</h4>
<h4 class="fizz">Entry Title 3</h4>
<h4 class="">Entry Title 4</h4>
<h4 class="buzz">Entry Title 5</h4>
<h4 class="fizz">Entry Title 6</h4>
<h4 class="fizz">Entry Title 7</h4>
<h4 class="">Entry Title 8</h4>
<h4 class="fizz">Entry Title 9</h4>
<h4 class="buzz">Entry Title 10</h4>
<h4 class="">Entry Title 11</h4>
<h4 class="fizz">Entry Title 12</h4>
<h4 class="">Entry Title 13</h4>
<h4 class="fizz">Entry Title 14</h4>
<h4 class="fizzbuzz">Entry Title 15</h4>
<h4 class="">Entry Title 16</h4>
<h4 class="buzz">Entry Title 17</h4>
<h4 class="fizz">Entry Title 18</h4>
<h4 class="">Entry Title 19</h4>
<h4 class="buzz">Entry Title 20</h4>
<h4 class="fizz">Entry Title 21</h4>
<h4 class="">Entry Title 22</h4>
The macro must output the tags with the appropriate classes given the 3 parameters as described above. It should not rely on any plugins and the code will be evaluated based on the following criteria in order of priority:
Therefore the code should be readable and easy to understand. It should be concise and non-repetative, but not at the expense of readability. It should be performant, but not at the expense of readability or brevity.
fizz
and buzz
parameters as integers. {% set entries = [] %}
{% set entry = craft.entries.one() %}
{% for i in 1..100 %}
{% set entries = entries|merge([entry]) %}
{% endfor %}
Solution submitted by Jason Sawyer on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set count = loop.index %}
{% set className = '' %}
{% for fiz in fizz if count is divisible by(fiz) %}
{% set className = 'fizz' %}
{% endfor %}
{% for buz in buzz if count is divisible by(buz) and className|length < 5 %}
{% set className = className ~ 'buzz' %}
{% endfor %}
<h4 class="{{ className }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Otto Radics on 11 November 2018.
{% macro fizzBuzz(entries, fizzArray, buzzArray) %}
{% for entry in entries %}
{% set fizzClass = null %}
{% set buzzClass = null %}
{% set mainIndex = loop.index %}
{# fizzArray #}
{% for fizzItem in fizzArray %}
{% if mainIndex is divisible by(fizzItem) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
{# buzzArray #}
{% for buzzItem in buzzArray %}
{% if mainIndex is divisible by(buzzItem) %}
{% set buzzClass = 'buzz' %}
{% endif %}
{% endfor %}
<h4 class="{{ fizzClass ?? null ~ buzzClass ?? null }}">
{{ entry.title }}
</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Josh Magness on 11 November 2018.
<style>
body{background:#282828;color:#fff}h1,h2,h3,h4,h5,h6{margin:1em}.fizz{color:#facb3e}.buzz{color:#75e5fa}.fizzbuzz{color:#fa67ee}
</style>
{% import _self as macro %}
{% set entries = range(1, 21) %}
{% macro fizzBuzz(entries) %}
{% for entry in entries %}
{% set variable = '' %}
{% if entry is divisible by(3) %}
{% set variable = 'fizz' %}
{% endif %}
{% if entry is divisible by(5) %}
{% set variable = 'buzz' %}
{% endif %}
{% if entry is divisible by(5) and entry is divisible by(3) %}
{% set variable = 'fizzbuzz' %}
{% endif %}
<h4 class="{{ variable }}">Entry Title {{ entry }}</h4>
{% endfor %}
{% endmacro %}
{{ macro.fizzBuzz(entries) }}
Solution submitted by Quentin Delcourt on 11 November 2018.
{% macro fizzBuzz(entries, fizzNumbers, buzzNumbers) %}
{%- for entry in entries -%}
{%- set entryIndex = loop.index -%}
{# Is it a "fizz" number? #}
{%- set isFizz = false -%}
{%- for fizzNumber in fizzNumbers -%}
{% set isFizz = isFizz or (entryIndex is divisible by(fizzNumber)) %}
{%- endfor -%}
{# Is it a "buzz" number? #}
{%- set isBuzz = false -%}
{%- for buzzNumber in buzzNumbers -%}
{% set isBuzz = isBuzz or (entryIndex is divisible by(buzzNumber)) %}
{%- endfor -%}
{# Determine the class to use #}
{%- set entryClass = (isFizz and isBuzz)
? 'fizzbuzz'
: (isFizz) ? 'fizz'
: (isBuzz) ? 'buzz'
: '' -%}
<h4 class="{{ entryClass }}">
{{- entry.title -}}
</h4>
{% endfor -%}
{% endmacro %}
Solution submitted by Henry Bley-Vroman on 11 November 2018.
{% macro fizzBuzz(items, fizzes, buzzes) %}
{% for item in items %}
{% set class = '' %}
{% set i = loop.index %}
{%- for fizz in fizzes if class != 'fizz' and i is divisible by(fizz) -%}
{% set class = 'fizz' -%}
{% endfor -%}
{% for buzz in buzzes if 'buzz' not in class and i is divisible by(buzz) -%}
{% set class = class ~ 'buzz' -%}
{% endfor -%}
<h4 class="{{ class }}">
{{- item.title -}}
</h4>
{% endfor %}
{% endmacro %}
{#
Note: I would prefer `<h4 {%- if class %} class="{{ class }}"{% endif %}>`,
but that doesn't meet challenge's requirements.
#}
Solution submitted by Alex Roper on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{%- for entry in entries %}
{%- set index, fizz, buzz = loop.index, null, null -%}
{%- for number in fizzes %}
{%- set fizz = index is divisible by(number) ? 'fizz' : fizz -%}
{% endfor -%}
{%- for number in buzzes %}
{%- set buzz = index is divisible by(number) ? 'buzz' : buzz -%}
{% endfor -%}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro fizzBuzz %}
Solution submitted by Craft CMS Berlin Meetup on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{% for entry in entries %}
{# We have to access loop.index here, otherwise loop.parent in child loops will have the wrong context. #}
{% set parentIndex = loop.index %}
{% set fizz = '' %}
{% set buzz = '' %}
{% for f in fizzes %}
{# This would work fine in pure Twig, but not in Craft: #}
{# set fizz = (loop.parent.loop.index % f == 0)? 'fizz': fizz #}
{# Instead, we'll use our parentIndex variable from above: #}
{% set fizz = (parentIndex % f == 0)? 'fizz': fizz %}
{% endfor %}
{% for b in buzzes %}
{# Same deal as above... #}
{% set buzz = (parentIndex % b == 0)? 'buzz': buzz %}
{% endfor %}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Pierre Stoffe on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set entryIndex = loop.index %}
{# Find out if entryIndex is a multiple of any integer from the fizz array #}
{% set fizzMultiples = [] %}
{% for int in fizz %}
{% if entryIndex is divisible by(int) %}
{% set fizzMultiples = fizzMultiples|merge([entryIndex]) %}
{% endif %}
{% endfor %}
{# Find out if entryIndex is a multiple of any integer from the buzz array #}
{% set buzzMultiples = [] %}
{% for int in buzz %}
{% if entryIndex is divisible by(int) %}
{% set buzzMultiples = buzzMultiples|merge([entryIndex]) %}
{% endif %}
{% endfor %}
{# Assign the relevant classes based on the arrays created above #}
{% set classes = [] %}
{% if entryIndex in fizzMultiples and entryIndex in buzzMultiples %}
{% set classes = classes|merge(['fizzbuzz']) %}
{% else %}
{% if entryIndex in fizzMultiples %}
{% set classes = classes|merge(['fizz']) %}
{% elseif entryIndex in buzzMultiples %}
{% set classes = classes|merge(['buzz']) %}
{% endif %}
{% endif %}
<h4 class="{{ classes|join(' ') }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Lindsey DiLoreto on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% from _self import addClass %}
{% for entry in entries %}
{% set f = addClass('fizz', fizz, loop.index)|trim %}
{% set b = addClass('buzz', buzz, loop.index)|trim %}
<h4 class="{{ f ~ b }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
{% macro addClass(class, numbers, index) %}
{% set output = '' %}
{% for num in numbers if index is divisible by(num) %}
{% set output = class %}
{% endfor %}
{{ output }}
{% endmacro %}
Solution submitted by Andrew Welch on 11 November 2018.
{#
# Challenge #1 – Putting the Fizz back in your Buzz
# https://craftcodingchallenge.com/challenge-1-putting-the-fizz-back-in-your-buzz
# @author Andrew Welch, nystudio107
#}
{#
# Return the value of `className` if `number` is a multiple of any of the values in the `values` array
# Otherwise, return an empty string
# @param int number
# @param int[] values
# @param string className
#}
{%- macro getClassIfMultiple(number, values, className) -%}
{% spaceless %}
{% set result = "" %}
{# Micro-optimization to not execute the loop if we already have set `result` #}
{% for value in values if not result %}
{% if number is divisible by(value) %}
{% set result = className %}
{% endif %}
{% endfor %}
{{ result }}
{% endspaceless %}
{%- endmacro -%}
{#
# Output each of the entry.title's with appropriate classes set depending on
# whether the index is a multiple of the numbers in fizz[] and buzz[]
# @param Entry[] entries
# @param int[] fizz
# @param int[] buzz
#}
{% macro fizzBuzz(entries, fizz, buzz) %}
{# Do the gruntwork via a reusable macro #}
{% from _self import getClassIfMultiple %}
{# Calculate the classes for each potential entry #}
{% for entry in entries %}
{% set fizzClass = getClassIfMultiple(loop.index, fizz, "fizz") %}
{% set buzzClass = getClassIfMultiple(loop.index, buzz, "buzz") %}
<h4 class="{{ fizzClass ~ buzzClass }}">{{ "#{entry.title} #{loop.index}" }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Patrick Harrington on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) -%}
{#- We'll be pulling in another macro so as not to be repeating ourselves too much. #}
{% import _self as macros %}
{%- for entry in entries %}
<h4 class="
{#- A couple of ternaries with whitespace control - and mocking having our other macro "return" a value -#}
{{- (macros.hasDivisibleNumber(entry.id, fizzes) == "true") ? 'fizz' }}
{{- (macros.hasDivisibleNumber(entry.id, buzzes) == "true") ? 'buzz' -}}
">
{{- entry.title ~ " " ~ entry.id -}}
</h4>
{% endfor %}
{% endmacro %}
{#- Checks to see if the given ID matches the rules of divisibility #}
{% macro hasDivisibleNumber(id, ints) -%}
{#- Mark as true if the ID actually exists in the array -#}
{%- set return = (id in ints) ? 'true' : '' -%}
{%- if return is empty -%}
{#- Only check keys that are less or half of the ID (otherwise they can't be divisors) -#}
{%- for int in ints if (int <= (id / 2)) -%}
{#- If cleanly divisible, mark as true -#}
{%- if id % int == 0 -%}
{%- set return = 'true' -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{#- Pseudo-return in Twig ;) -#}
{{- return -}}
{%- endmacro %}
Solution submitted by John F Morton on 11 November 2018.
{% macro divisibeByArray(mynumber, myarray) %}{% spaceless %}
{% set myreturn = 0 %}
{% for mydivider in myarray %}
{% if myreturn == 0 and mynumber is divisible by(mydivider) %}
{% set myreturn = myreturn + 1 %}
{% endif %}
{% endfor %}
{% if myreturn == 1%}
{{ myreturn }}
{% endif %}
{% endspaceless %}{% endmacro %}
{% macro fizzBuzz(allIntegers, fizzArray, buzzArray) %}
{% import _self as helpers %}
{% for myentry in allIntegers %}
{% set myclassname1 = helpers.divisibeByArray(myentry, fizzArray) ? 'fizz' : '' %}
{% set myclassname2 = helpers.divisibeByArray(myentry, buzzArray) ? 'buzz' : '' %}
{% set myclassname = myclassname1 ~ myclassname2 %}
{#<h4 class='{{ myclassname }}'>{{ myentry }} is {{ myclassname ? myclassname : 'nothing'}}</h4>#}
<h4 class='{{ myclassname }}'>Entry Title {{ myentry }}</h4>
{% endfor %}
{% endmacro %}
{% import _self as macros %}
Solution submitted by Spenser Hannon on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{%- for entry in entries -%}
{%- set fizz = '' -%}
{%- set buzz = '' -%}
{%- set n = loop.index -%}
{%- for f in fizzes -%}
{%- if fizz is empty -%}
{%- set fizz = (n % f == 0) ? 'fizz' : '' -%}
{%- endif -%}
{%- endfor -%}
{%- for b in buzzes -%}
{%- if buzz is empty -%}
{%- set buzz = (n % b == 0) ? 'buzz' : '' -%}
{%- endif -%}
{%- endfor -%}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry }}</h4>
{%- endfor -%}
{% endmacro %}
Solution submitted by Doug St. John on 11 November 2018.
<html>
<head>
<title>craftcodingchallenge #1 | dstjohn</title>
<link type="text/css" rel="stylesheet" href="https://craftcodingchallenge.com/interface/css/fizzbuzz.css" />
</head>
<body>
{# Get entries list #}
{% set entries = [] %}
{% set entry = craft.entries.one() %}
{% for i in 1..100 %}
{% set entries = entries|merge([entry]) %}
{% endfor %}
{% import _self as self %}
{{ self.fizzBuzz(craft.entries.limit(22).all(), [3, 7], [5, 17]) }}
</body>
</html>
{# Generate output #}
{% macro fizzBuzz(entries, fizzIds, buzzIds) %}
{% import _self as self %}
{% for entry in entries %}
{% set class = [
self.checkDivisible(loop.index, fizzIds, 'fizz'),
self.checkDivisible(loop.index, buzzIds, 'buzz'),
]|join %}
<h4 class="{{ class }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
{# Return classString if loopIndex is divisible by one of the divisibleIds passed #}
{% macro checkDivisible(loopIndex, divisibleIds, classString) %}{% spaceless %}
{% set break = false %}
{% for id in divisibleIds if not break %}
{% if loopIndex is divisible by(id) %}
{{ classString }}
{% set break = true %}
{% endif %}
{% endfor %}
{% endspaceless %}{% endmacro %}
Solution submitted by Trevor Plassman on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{# Save outer loop index to variable for inner loop modulus calc #}
{% set i = loop.index %}
{# Start w/ empty class variable to add to #}
{% set class = '' %}
{# Check if current index is fizzy, but only once #}
{% set fizzy = false %}
{% for f in fizz if not fizzy %}
{% if i % f == 0 %}
{% set class = class ~ 'fizz' %}
{% set fizzy = true %}
{% endif %}
{% endfor %}
{# Check if current index is buzzy, but only once #}
{% set buzzy = false %}
{% for b in buzz if not buzzy %}
{% if i % b == 0 %}
{% set class = class ~ 'buzz' %}
{% set buzzy = true %}
{% endif %}
{% endfor %}
<h4 class="{{ class is not empty ? class }}">
{{ entry.title }}
</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Oliver Stark on 11 November 2018.
{% macro fizzBuzz(not, so, important) %}
<h4 class="">Entry Title 1</h4>
<h4 class="">Entry Title 2</h4>
<h4 class="fizz">Entry Title 3</h4>
<h4 class="">Entry Title 4</h4>
<h4 class="buzz">Entry Title 5</h4>
<h4 class="fizz">Entry Title 6</h4>
<h4 class="fizz">Entry Title 7</h4>
<h4 class="">Entry Title 8</h4>
<h4 class="fizz">Entry Title 9</h4>
<h4 class="buzz">Entry Title 10</h4>
<h4 class="">Entry Title 11>/h4>
<h4 class="fizz">Entry Title 12</h4>
<h4 class="">Entry Title 13</h4>
<h4 class="fizz">Entry Title 14</h4>
<h4 class="fizzbuzz">Entry Title 15</h4>
<h4 class="">Entry Title 16</h4>
<h4 class="buzz">Entry Title 17</h4>
<h4 class="fizz">Entry Title 18</h4>
<h4 class="">Entry Title 19</h4>
<h4 class="buzz">Entry Title 20</h4>
<h4 class="fizz">Entry Title 21</h4>
<h4 class="">Entry Title 22</h4>
{% endmacro %}
Solution submitted by Steve Rowling on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set classes = [] %}
{% set tests = {
'fizz': fizz,
'buzz': buzz
} %}
{% set number = loop.index %}
{% for key,test in tests %}
{% for int in test %}
{% if number is divisible by(int) and (classes|indexOf(key) == -1) %}
{% set classes = classes|merge([key]) %}
{% endif %}
{% endfor %}
{% endfor %}
<h4 class="{{ classes|join('') }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Christian Seelbach on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{%- for entry in entries %}
{%- set index = loop.index %}
{%- set isFizz = false %}
{%- set isBuzz = false %}
{%- for int in fizz %}
{%- set isFizz = isFizz or index is divisible by(int) %}
{%- endfor %}
{%- for int in buzz %}
{%- set isBuzz = isBuzz or index is divisible by(int) %}
{%- endfor %}
{%- set classes = [
isFizz and not isBuzz ? 'fizz',
not isFizz and isBuzz ? 'buzz',
isFizz and isBuzz ? 'fizzbuzz',
]|filter|join(' ') -%}
<h4 class="{{ classes }}">{{ entry.title }}</h4>
{%- endfor -%}
{% endmacro %}
Solution submitted by Paul Verheul on 11 November 2018.
{% macro fizzBuzz(entries, fizz = [], buzz = []) %}
{% for entry in entries %}
{# safe the loop variable into a new one, to prevent interference with the next for-loop #}
{% set entryLoop = loop %}
{# set a base 'class' variable, to not have to worry about a default value later on #}
{% set class = '' %}
{#
# Loop through all fizzes and buzzes to check if we should add them.
# If we find a fizz or a buzz, break from our loop by setting the typeFound variable to true.
# We do it this way, to have the possibility of adding, for example, 'fuzz' by adding two lines of code.
#}
{% for type in ['fizz', 'buzz'] %}
{% set typeFound = false %}
{% for int in _context[type] if not typeFound %}
{% if entryLoop.index is divisible by(int) %}
{% set class = class ~ type %}
{% set typeFound = true %}
{% endif %}
{% endfor %}
{% endfor %}
<h4 class="{{ class }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by John Wells on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{# The "loop" variable cannot be used in a looping condition #}
{% set index = loop.index %}
{# False by default #}
{% set isFizz = false %}
{% set isBuzz = false %}
{% for n in fizz if index is divisible by(n) %}
{% set isFizz = true %}
{% endfor %}
{% for n in buzz if index is divisible by(n) %}
{% set isBuzz = true %}
{% endfor %}
<h4 data-loop="{{ index }}" class="{{ isFizz ? 'fizz' }}{{ isBuzz ? 'buzz' }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}