FizzBuzz

cs v kategorii code • 11 min. čtení

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. :-)



Sdílejte:   Facebook   Twitter   Reddit   Tumblr   Pinterest




Může se vám také líbit

en What Makes Good Program?, November 20, 2018
en Old Code, October 31, 2018
en Fast JSON Schema for Python, October 1, 2018
en Open Source Responsibilities, September 6, 2018
en Deployment of Python Apps, August 15, 2018


Populární v kategorii code

en Makefile with Python, November 6, 2017
en Deployment of Python Apps, August 15, 2018
cs Jasně, umím Git…, August 6, 2014
cs Checklist na zabezpečení webových aplikací, March 1, 2016
cs Pokročilé regulární výrazy, August 17, 2014