Viết cho vui đầu năm: FizzBuzz với Python

Viết cho vui đầu năm: FizzBuzz với Python
Photo by jakob5200 from Pixabay

Bài toán FizzBuzz thì quá kinh điển rồi, có lẽ ai học lập trình cũng đã từng làm quen với bài toán này ít nhất một lần. Trong bài viết này, tôi sẽ tổng hợp một số các khác nhau để giải bài toán này với ngôn ngữ Python. Mục đích vui vẻ là chính, cải thiện suy nghĩ đã đình trệ nhiều ngày là phụ.

Simple

print('1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzbuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzbuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzbuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzbuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzbuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzbuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz')

Normal

for i in range(1, 101):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 5 == 0:
        print("Buzz")
    elif i % 3 == 0:
        print("Fizz")
    else:
        print(i)

Recursive function

def count(num):
    if num >= 1:
        count(num - 1)
        fizz_buzz(num)


def fizz_buzz(num):
    if num % 15 == 0:
        print("FizzBuzz")
    elif num % 3 == 0:
        print("Fizz")
    elif num % 5 == 0:
        print("Buzz")
    else:
        print(num)


count(100)

No repetition

for i in range(1, 101):
    msg = ""
    if i % 3 == 0:
        msg += "Fizz"
    if i % 5 == 0:
        msg += "Buzz"
    print(msg or num)

OOP

class FizzBuzz:
    def __init__(self, num):
        self.num = num

    def count(self):
        for i in range(1, self.num + 1):
            self.fizz_buzz(i)

    def fizz_buzz(self, num):
        if num % 15 == 0:
            print("FizzBuzz")
        elif num % 3 == 0:
            print("Fizz")
        elif num % 5 == 0:
            print("Buzz")
        else:
            print(num)


FizzBuzz(100).count()

Lazy

import itertools


class FizzBuzzRule(object):
    @classmethod
    def say(cls, word):
        return cls(word)

    def __init__(self, word):
        self.word = word

    def for_multiples_of(self, number):
        return itertools.cycle((*itertools.repeat('', number - 1), self.word))


numbers = itertools.count(1)
fizzes = FizzBuzzRule.say('Fizz').for_multiples_of(3)
buzzes = FizzBuzzRule.say('Buzz').for_multiples_of(5)
fizzbuzz_generator = (f'{fizz}{buzz}' or n
                      for n, fizz, buzz
                      in zip(numbers, fizzes, buzzes))
for word in itertools.islice(fizzbuzz_generator, 100):
    print(word)

Lazy short code

from itertools import cycle, count, islice

fizzes = cycle([""] * 2 + ["Fizz"])
buzzes = cycle([""] * 4 + ["Buzz"])
both = (f + b for f, b in zip(fizzes, buzzes))
fizzbuzz = (word or n for word, n in zip(both, count(1)))

for i in islice(fizzbuzz, 100):
    print(i)

Generator

for n in range(1, 101):
    fb = ''.join(denom[1] if n % denom[0] == 0 else ''
                 for denom in [(3, 'Fizz'), (5, 'Buzz')])
    print(fb or n)

Short code

for i in range(1, 101):
    print(
        "FizzBuzz" if i % 15 == 0 else
        "Buzz" if i % 5 == 0 else
        "Fizz" if i % 3 == 0 else
        str(i)
    )

Shorter code

for i in range(1, 101):
    print("Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or i)

Shorter another version

for i in range(100):
    print(i % 3 // 2 * 'Fizz' + i % 5 // 4 * 'Buzz' or i + 1)

One line

print('\n'.join("Fizzbuzz" if i % 15==0 else "Fizz" if i % 3==0 else "Buzz" if i % 5==0 else str(i) for i in range(1, 101)))

Brain hacking

print('\n'.join((x % 3 < 1) * 'Fizz' + (x % 5 < 1) * 'Buzz' or str(x) for x in range(1, 101)))

Brains hacking

for thing in map(
    lambda x: '{}{}'.format(
        next(map(lambda y: 'Fizz' if x % 3 == 0 else '', [x])),
        next(map(lambda y: 'Buzz' if x % 5 == 0 else '', [x]))
    ) if (True in [bool(x % n == 0) for n in [3, 5]]) else x,
    range(1, 101)
):
    print(thing)

Perl style

t, f, b, p = 3, "zFzi", "zuzB", 5
y, z = 2, 0
list(map(
    print,
    [next(filter(lambda i: isinstance(i, str), ((i % t, i % p).count(z) != y or ''.join(
        sorted(f)) + ''.join(sorted(b)), i % t or ''.join(sorted(f)), i % p or ''.join(sorted(b)), str(i)))) for i in range(1, (y * p) ** y + 1)]
))

Dict miracle

FIZZ_BUZZ = {
    3: "Fizz",
    5: "Buzz",
    15: "FizzBuzz"
}


def fizz_buzz():
    for i in range(1, 101):
        print(FIZZ_BUZZ.get(
            15 * (not i % 15) or 5 * (not i % 5) or 3 * (not i % 3),
            i
        ))


fizz_buzz()

Interview version

for n in range(1, 101):
    print('FizzBuzz'[n % -3 & 4: 12 & 8 - (n % -5 & 4)] or n)

Just for fun

def get_index(i):
    return bool(i % 3)+2*bool(i % 5) if i != 0 else 3


def afb(x):
    return ('fizzbuzz', 'buzz', 'fizz', str(x))[get_index(x)]


def fizzbuzz(inpt):
    return print('\n'.join([afb(i) for i in inpt]))


fizzbuzz(range(1, 101))

Enterprise version

from abc import ABCMeta, abstractmethod
import enum


class SomethingerBase(metaclass=ABCMeta):
    @abstractmethod
    def set_at(self, value):
        pass

    @abstractmethod
    def step(self):
        pass

    @abstractmethod
    def is_something(self):
        pass


class ActorBase(metaclass=ABCMeta):
    @abstractmethod
    def canact(self):
        pass

    @abstractmethod
    def act(self, value):
        pass

    @abstractmethod
    def execute(self, func):
        pass

    @abstractmethod
    def get_actor_cannot_act_exception(self):
        pass


class FizzerBuzzerInterface(SomethingerBase):
    @abstractmethod
    def is_fizzy(self):
        pass

    @abstractmethod
    def is_buzzy(self):
        pass

    @abstractmethod
    def get_at(self):
        pass


class Fizzer:
    def __init__(self):
        self._at = None

    def set_at(self, value):
        self._at = value

    def step(self):
        self._at += 1
        self._at %= 3

    def is_fizzy(self):
        return not self._at


class FizzerSomethingerAdaptor(SomethingerBase):
    def __init__(self, fizzer):
        self.fizzer = fizzer

    def set_at(self, value):
        self.fizzer.set_at(self, value)

    def step(self):
        self.fizzer.step()

    def is_something(self):
        return self.fizzer.is_fizzy()


class Buzzer:
    def __init__(self):
        self._at = None

    def set_at(self, value):
        self._at = value

    def step(self):
        self._at += 1
        self._at %= 5

    def is_buzzy(self):
        return not self._at


class BuzzerSomethingerAdaptor(SomethingerBase):
    def __init__(self, fizzer):
        self.buzzer = fizzer

    def set_at(self, value):
        self.buzzer.set_at(self, value)

    def step(self):
        self.buzzer.step()

    def is_something(self):
        return self.buzzer.is_buzzy()


class FizzerBuzzer:
    def __init__(self, fizzer_somethinger, buzzer_somethinger):
        self._at = None
        if not isinstance(fizzer_somethinger, SomethingerBase):
            raise ValueError("Got {!r} expected {!r}".format(
                type(fizzer_somethinger), SomethingerBase))
        if not isinstance(buzzer_somethinger, SomethingerBase):
            raise ValueError("Got {!r} expected {!r}".format(
                type(buzzer_somethinger), SomethingerBase))
        self.fizzer_somethinger = fizzer_somethinger
        self.buzzer_somethinger = buzzer_somethinger

    def set_at(self, value):
        self._at = value

    def step(self):
        self._at += 1
        self.fizzer_somethinger.step()
        self.buzzer_somethinger.step()

    def is_fizzy(self):
        return self.fizzer_somethinger.is_something()

    def is_buzzy(self):
        return self.buzzer_somethinger.is_something()

    def is_something(self):
        return self.is_fizzy() or self.is_buzzy()

    def get_at(self):
        return self._at


class FizzBuzzRunner:
    class StateEnum(enum.IntEnum):
        state_number = 0
        state_fizz = 1
        state_buzz = 2
        state_fizzbuzz = 3

    def __init__(self, fizzerbuzzer, actor):
        if not isinstance(fizzerbuzzer, FizzerBuzzer):
            raise ValueError("Got {!r} expected {!r}".format(
                type(fizzerbuzzer), FizzerBuzzer))
        if not isinstance(actor, ActorBase):
            raise ValueError("Got {!r} expected {!r}".format(
                type(actor), ActorBase))
        self.fizzerbuzzer = fizzerbuzzer
        self.actor = actor

    def gen_state(self):
        result_state = self.StateEnum.state_number
        if self.fizzerbuzzer.is_something():
            if self.fizzerbuzzer.is_fizzy():
                result_state |= self.StateEnum.state_fizz
            if self.fizzerbuzzer.is_buzzy():
                result_state |= self.StateEnum.state_buzz
        return result_state

    def get_state_function(self, result_state):
        if result_state == self.StateEnum.state_number:
            return self.state_number
        if result_state == self.StateEnum.state_fizz:
            return self.state_fizz
        if result_state == self.StateEnum.state_buzz:
            return self.state_buzz
        if result_state == self.StateEnum.state_fizzbuzz:
            return self.state_fizzbuzz

    def step(self):
        self.fizzerbuzzer.step()
        result_state = self.gen_state()
        state_executor = self.get_state_function(result_state)
        if not self.actor.canact():
            raise actor.get_actor_cannot_act_exception()
        self.actor.execute(state_executor)

    def state_fizzbuzz(self, act):
        act("FizzBuzz")

    def state_fizz(self, act):
        act("Fizz")

    def state_buzz(self, act):
        act("Buzz")

    def state_number(self, act):
        act(self.fizzerbuzzer.get_at())

    def step_n(self, n):
        for i in range(n):
            self.step()


def main():
    fizzer = Fizzer()
    fizzer.set_at(0)
    fizzer_somethinger = FizzerSomethingerAdaptor(fizzer)
    buzzer = Buzzer()
    buzzer.set_at(0)
    buzzer_somethinger = BuzzerSomethingerAdaptor(buzzer)
    fizzerbuzzer = FizzerBuzzer(fizzer_somethinger, buzzer_somethinger)
    fizzerbuzzer.set_at(0)

    class PrintActor(ActorBase):
        class _ActorCannotActException(ValueError):
            pass

        def canact(self):
            return True

        def act(self, value):
            print(value)

        def execute(self, func):
            func(self.act)

        def get_actor_cannot_act_exception(self):
            return self._ActorCannotActException
    fizzbuzzrunner = FizzBuzzRunner(fizzerbuzzer, PrintActor())
    fizzbuzzrunner.step_n(100)


main()

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.