FizzBuzz zná zřejmě každý programátor. Není to nic těžkého, implementace může vypadat třeba takto:
for index in range(1, 20):
if index % 15 == 0:
print 'FizzBuzz'
elif index % 3 == 0:
print 'Fizz'
elif index % 5 == 0:
print 'Buzz'
else:
print index
Ale to není sranda. Sice je to úloha na rychlé vyřazení špatných programátorů, ale paradoxně selhávají i schopní, protože se snaží na první dobrou napsat řešení nějak chytře (rozuměj one-linově). A nepovede se. Třeba:
for index in range(1, 20):
print 'Fizz' * int(index % 3 == 0) + 'Buzz' * int(index % 5 == 0) or index
Ale to stále není sranda. Třeba takový Javista by mohl namítnout, že v tom je málo tříd…
class FizzBuzzNumber(int):
def __str__(self):
return (self.fizz + self.buzz) or super(FizzBuzzNumber, self).__str__()
@property
def fizz(self):
return 'Fizz' if self.is_fizz else ''
@property
def buzz(self):
return 'Buzz' if self.is_buzz else ''
@property
def is_fizz(self):
return self % 3 == 0
@property
def is_buzz(self):
return self % 5 == 0
for index in range(1, 20):
print FizzBuzzNumber(index)
Mně to přišlo ale stále málo crazy. Když už mám třídu, proč si nevytvořit dynamicky třídu pro každé číslo. Když to jde, že?
class FizzBuzzNumberType(type):
_class_cache = {}
def __new__(mcs, name, bases, attributes):
return mcs.create_instance
@classmethod
def create_instance(cls, number):
return cls.create_or_get_class(number)(number)
@classmethod
def create_or_get_class(cls, number):
if number not in cls._class_cache:
cls._class_cache[number] = cls.create_class(number)
return cls._class_cache[number]
@classmethod
def create_class(cls, number):
printable_number = cls.get_printable_number(number)
attributes = {
'__str__': lambda self: printable_number,
}
new_cls = type.__new__(FizzBuzzNumberType, 'FizzBuzzNumber({})'.format(number), (int,), attributes)
return new_cls
@staticmethod
def get_printable_number(number):
return 'Fizz' * int(number % 3 == 0) + 'Buzz' * int(number % 5 == 0) or str(number)
class FizzBuzzNumber(int):
__metaclass__ = FizzBuzzNumberType
for index in range(1, 20):
print FizzBuzzNumber(index)
Tím sranda nemusí končit. Můžeme klidně pokračovat generováním kódu z XML. Aneb můžeme programovat aniž bychom museli měnit kód!
Ale to už je fakt za hranicí šílenosti. Pojďme zkusit něco jiného. Co třeba CSS?
.fizzbuzz {
counter-increment: index;
}
.fizzbuzz:nth-of-type(n)::before{
content: counter(index);
}
.fizzbuzz:nth-of-type(5n)::before{
content: "";
}
.fizzbuzz:nth-of-type(3n)::before{
content: "fizz";
}
.fizzbuzz:nth-of-type(5n)::after{
content: "buzz";
}
Kam se hrabe JavaScript. :-)
Přemýšlel jsem, v čem ještě by šlo implementovat FizzBuzz. Vzpomněl jsem si na hlášku: Když se někteří lidé setkají s problémem, pomyslí si: „Já vím! Použiji regulární výrazy.“ V tom okamžiku mají problémy dva.
seq 1 19 | sed -r '3~3 s/[0-9]*/Fizz/; 5~5 s/[0-9]*$/Buzz/'
A taky že ano. První řešení je velice jednoduché. Tak ještě jednou bez počítání řádků!
seq 1 19 | sed -r 's/^([0369]|[258][0369]*[147]|[147]([0369]|[147][0369]*[258])*[258]|[258][0369]*[258]([0369]|[147][0369]*[258])*[258]|[147]([0369]|[147][0369]*[258])*[147][0369]*[147]|[258][0369]*[258]([0369]|[147][0369]*[258])*[147][0369]*[147])*$/Fizz\1/;s/^Fizz[0-9]*[05]$/FizzBuzz/; s/^Fizz[0-9]*$/Fizz/; s/^[0-9]*[05]$/Buzz/'
Ufff. Šlo by to napsat s menším počtem kroků, ale jeden konečný automat mi pro dnešek stačil.
Co vy, máte taky nějaký crazy FizzBuzz?
P.S.: Pro silnější nátury jsem narazil na oblíbený Brainfuck. A pro ověření si můžete udělat vlastní interpreter. :-)