Оптимизирован FizzBuzz на языке Brainfuck


Пока ищу на Brainfuck связанные вещи, я наткнулся на Саймона Форсберг по FizzBuzz на языке Brainfuck и нахально прокомментировал ссылку на мой собственный на Brainfuck FizzBuzz ответ на PPCG. Он предложил мне разместить свой вопрос комментарий код с подробным объяснением.

Во-первых, код (350 байт):

+[-[>+<<]>-]>--[>+>++>++>++++++>+>>>++++++<<<[<]>- 
]<+++++[>+>+>->>->++>+>>--[<<]>-]>[>]<--<->>>[<<-[
<]<[>+++>+<<.<.<..[<]<]>>-[<<]>[<+++++>.>.>..[>>>]
<<+[<]]>[>>>]<<[[-]>>]>[>++++++++++[->++++++++++>+
<<]<[->+>-<<]>>++[>[>>>]<[>++++++++++>+>]<<-<-]+++
++++++>[-<->]<[->+<]>>[>]++++++++[-<++++++<++++++>
>]<<<[>[-]]>[>]<[.[-]<]<[-<+>]>]++++++++++.[-]<<-]

Попробуйте его онлайн!

Это может быть разделена на три секции:

  • Лента поколения: устанавливает ленту в правильном формате
  • В то время как цикл более 100 чисел:
    • Проверив количество: проверяет, является ли число делится на 3 или 5, и печати Fizz и/или жужжание, если так.
    • Печать количество: только если это не FizzBuzz количество

Установка Ленты:

FizzBuzz tape setup

  • Ячейка 3: счетчик для раздела "Базз"
  • Ячейки 4 по 8. Эти значения ASCII для "BuziF", компактный способ представления как "шипение" и "кайф".
  • Ячейки 9: счетчик для раздела "Физз"
  • Ячейка 11: общий счетчик для отслеживания 100 номеров

Код на Brainfuck:

Generates the number 61:
+[-[>+<<]>-]>--
This is taken from the Esolangs brainfuck constants page at https://esolangs.org/wiki/Brainfuck_constants

Sets all the cells to values very close to the needed ones
Basically multiplies 61 by various values (going over 255 wraps around to 0)
[>+>++>++>++++++>+>>>++++++<<<[<]>-]
Tape looks like:
    0 0' 61 122 122 110 61 0 0 110
It needs to be:
    0 5  66 117 122 105 70 3 0 100
Notice that (almost) all of these values are off by multiples of 5 so we increment a cell to 5
<+++++
And add/subtract 5s from each value
[>+>+>->>->++>+>>--[<<]>-]
Leaving the tape as:
    0' 5 66 117 122 105 71 5 0 100
We make some final changes to get the desired cells
>[>]<--<->>>
    Before leaving the memory pointer on the counter

Внутри цикла:

Проверка шипение/жужжание

Как Физз Базз и счетчики изначально настроены на 5 и 3 соответственно. На каждой итерации цикла, то оба счетчика будут уменьшаться. Если дойдет до 0, их соответствующую строку печатается и сбрасывает счетчик. Он также устанавливает проверьте позже, чтобы не печатать номер. Вот это представление Python из этого раздела кодекса.

fizz = 3
buzz = 5
for i in range(1,101):
    check = False
    fizz -= 1
    buzz -= 1
    if fizz == 0:
        print("Fizz",end='')
        fizz = 3
        check = True
    if buzz == 0:
        print("Buzz",end='')
        buzz = 5
        check = True
    if not check:
        print(i,end='')
    print()

В соответствующем разделе на Brainfuck является:

Tape Format:
    0 BCounter "BuziF" FCounter Check 0 Counter

<<- Decrement Fizz counter
[<]<[ If Fizz counter == 0
    >+++   Reset counter
    >+<<   Increment check cell
    .<.<.. Print "Fizz"
[<]<]
>>- Decrement Buzz counter
[<<]>[ If Buzz counter == 0
    <+++++   Reset counter
    >.>.>..  Print "Buzz"
    [>>>]<<+ Increment check cell
[<]]

Печать количество

Если проверка FizzBuzz пуста, нам нужно напечатать число в качестве фактической строки. Поскольку на Brainfuck не есть способ, чтобы преобразовать значение ячейки в печатных номер (сюрприз), мы должны преобразовать счетчика для двух значений ASCII (не три, поскольку 100-это "кайф"), представляющего число.

Однако, счетчик подсчета вниз от 100, мы сначала должны вычесть его из 100. Тогда мы получим число по модулю 10, который оставляет нас десятки и синглов в разных клетках. Прежде чем хоть печатать, мы должны проверить, является ли десятков цифра 0, в этом случае убираем его. Затем мы добавляем 48 номерам, чтобы преобразовать его в ASCII-код числа и распечатать их. Вот еще код на Python:

def printNumber(n):
    #Only works for numbers between 0 and 100
    tens = n//10
    singles = n%10
    if tens != 0:
        print(chr(tens+48), end='')
    print(chr(singles+48), end='')

Соответствующий код на Brainfuck:

If the number check is 0 (reset the cell if not)
>[>>>]<<[[-]>>]>
[
    Tape looks like:
        BuziF c 0 100-N' 0  where 100-N is the counter and N is the number
    We won't use anything left of the 100-N

    Generate the number 100 and the number 10
    >(10++++++++++)[->(10++++++++++)>+<<]
    Tape: 0 100-N 0' 100 10
    Subtract 100-N from 100 while keeping a copy of the 100-N
    <[->+>-<<]
    And increment N by 2 to counter some modulo stuff
    >>++
    Tape: 0 0 100-N N+2' 10 0
    [ While N
        Tape: 0 0 100-N N' Modulo Quotient 0;
        >[>>>]< If the modulo is 0:
            [>++++++++++>+>] Reset the modulo to 10 and increment the Quotient
        <<-<- Decrement both N and the modulo
    ]
    Tape: 0 0 100-N 0' 9-single tens
    Subtract the singles cell from 10
    +++++++++>[-<->]<[->+<]>>[>]
    Tape:  0 0 100-N 0 single tens 0'
    If the tens cell is 0: 
     Tape: 0 0 100-N 0 single 0'

    Add 48 to both cells
    (8++++++++)[-<(6++++++)<(6++++++)>>]
    Tape: 0 0 100-N 0 single tens 0'
    OR
    Tape: 0 0 100-N 48 single 0'

    If the tens cell was 0 reset the 48 cell
    <<<[>[-]]
    Tape: 0 0 100-N 0 single tens 0'
    OR
    Tape: 0 0 100-N 0 single 0'

    Print the tens (if needed) and singles while resetting the cells
    >[>]<[.[-]<]<
    Move the 100-N cell back to the correct position
    [-<+>]>
    Tape: 0 100-N 0' 0 0
]

И Наконец-То!

Печать новой строки

++++++++++.[-]

И декрементирования счетчика

<<-]

Основные Вопросы:

  • Я могу сделать это любой более оптимизирован? Моими основными заботами являются:
    • Количество печатной секции, которая является крайне неэффективным по модулю раздел
    • Настройка ленты, которая, вероятно, может быть короче.
    • Я должен настроить строку ячейки (10) в разделе поколения ленте, а не создать его один раз за цикл?

Только переживает он так подробно в этот вопрос я уже продумала несколько способов, чтобы сократить код, так что, по крайней мере.

TAPE FORMAT:
0
5   : Buzz Counter (BC)
66  : ASCII "B"
117 : ASCII "u"
122 : ASCII "z"
105 : ASCII "i"
70  : ASCII "F"
3   : Fizz Counter (FC)
0   : FizzBuzz Check (Ch)
100 : Loop counter (C)
0

Some definitions:
' : Memory pointer is on this cell
_ : Substitute for dash
p : Substitute for plus
N : The current number

Generates the number 61:
+[-[>+<<]>-]>--
This is taken from the Esolangs brainfuck constants page at https://esolangs dot org/wiki/Brainfuck_constants

Sets all the cells to values very close to the needed ones
Basically multiplies 61 by various values (going over 255 wraps around to 0)
[>+>++>++>++++++>+>>>++++++<<<[<]>-]
Tape looks like:
    0 0' 61 122 122 110 61 0 0 110
It needs to be:
    0 5  66 117 122 105 70 3 0 100
Notice that (almost) all of these values are off by multiples of 5 so we increment a cell to 5
<+++++
And add/subtract 5s from each value
[>+>+>->>->++>+>>--[<<]>-]
Leaving the tape as:
    0' 5 66 117 122 105 71 5 0 100
We make some final changes to get the desired cells
>[>]<--<->>>
Finally leaving the memory pointer on the counter

TAPE: 0 5 66 117 122 105 71 5 0 100'

[
    CHECKING FOR FIZZBUZZ
    <<- Decrement Fizz counter
    [<]<[ If Fizz counter == 0
        >+++   Reset counter
        >+<<   Increment check cell
        .<.<.. Print "Fizz"
    [<]<]
    >>- Decrement Buzz counter
    [<<]>[ If Buzz counter == 0
        <+++++   Reset counter
        >.>.>..  Print "Buzz"
        [>>>]<<+ Increment check cell
    [<]]

    PRINTING NUMBER
    If the number check is 0 (reset the cell if not)
    >[>>>]<<[[-]>>]>
    [
        TAPE: BC BuziF FC 0 100_N' 0 
        We won't be using anything left of the 100_N so we can ignore it

        Generate the number 100 and the number 10
        >(10++++++++++)[->(10++++++++++)>+<<]
        Tape: 0 100_N 0' 100 10
        Subtract 100_N from 100 while keeping a copy of it
        <[->+>-<<]
        And increment N by 2 to counter some modulo stuff
        >>++
        Tape: 0 0 100_N Np2' 10 0
        [ While N
            Tape: 0 0 100_N N' Modulo Quotient 0;
            >[>>>]< If the modulo is 0:
                [>++++++++++>+>] Reset the modulo to 10 and increment the Quotient
            <<-<- Decrement both N and the modulo
        ]
        Tape: 0 0 100_N 0' 9_single tens
        Subtract the singles cell from 10
        +++++++++>[-<->]<[->+<]>>[>]
        Tape:  0 0 100_N 0 single tens 0'
        If the tens cell is 0: 
         Tape: 0 0 100_N 0 single 0'

        Add 48 to both cells
        (8++++++++)[-<(6++++++)<(6++++++)>>]
        Tape: 0 0 100_N 0 single tens 0'
        OR
        Tape: 0 0 100_N 48 single 0'

        If the tens cell was 0 reset the 48 cell
        <<<[>[-]]
        Tape: 0 0 100_N 0 single tens 0'
        OR
        Tape: 0 0 100_N 0 single 0'

        Print the tens (if needed) and singles while resetting the cells
        >[>]<[.[-]<]<
        Move the 100_N cell back to the correct position
        [-<+>]>
        Tape: 0 100_N 0 0' 0
    ]
    Print a newline
    ++++++++++.[-]
    And decrement counter
    <<-
]


208
5
задан 1 февраля 2018 в 02:02 Источник Поделиться
Комментарии