1. Основи
Щоб зрозуміти Brainfuck, ви повинні уявити нескінченний масив комірок, ініціалізованих 0
кожним.
...[0][0][0][0][0]...
Коли запускається програма brainfuck, вона вказує на будь-яку клітинку.
...[0][0][*0*][0][0]...
Якщо перемістити вказівник праворуч, >
ви переміщуєте вказівник з комірки X на комірку X + 1
...[0][0][0][*0*][0]...
Якщо ви збільшуєте значення комірки, +
ви отримуєте:
...[0][0][0][*1*][0]...
Якщо ви знову збільшите значення комірки, +
ви отримаєте:
...[0][0][0][*2*][0]...
Якщо ви зменшите значення комірки, -
ви отримаєте:
...[0][0][0][*1*][0]...
Якщо ви перемістите вказівник ліворуч, <
ви переміщуєте вказівник від клітини X до комірки X-1
...[0][0][*0*][1][0]...
2. Введення
Для читання символів використовується кома ,
. Що це робить: Прочитайте символ зі стандартного вводу та запишіть його десятковий код ASCII у фактичну комірку.
Погляньте на таблицю ASCII . Наприклад, десятковий код !
є 33
, поки a
є 97
.
Що ж, давайте уявимо, що пам'ять програми BF виглядає так:
...[0][0][*0*][0][0]...
Якщо припустити, що стандартний вхід означає a
, якщо ви використовуєте ,
оператор комами , BF - це зчитування a
десятичного коду ASCII 97
в пам'ять:
...[0][0][*97*][0][0]...
Як правило, ви хочете думати саме так, проте правда трохи складніша. Правда в тому, що BF читає не символ, а байт (що б там не було). Дозвольте показати вам приклад:
У Linux
$ printf ł
відбитки:
ł
що є специфічним польським характером. Цей символ не кодується кодуванням ASCII. У цьому випадку це кодування UTF-8, тому він використовував більше одного байта в пам'яті комп'ютера. Ми можемо довести це, зробивши шістнадцятковий дамп:
$ printf ł | hd
який показує:
00000000 c5 82 |..|
Нулі компенсуються. 82
є першим і c5
представляє другий байт ł
(для того, щоб ми їх прочитали). |..|
- це графічне зображення, яке неможливо в цьому випадку.
Добре, якщо ви передасте ł
як вхід до програми BF, яка читає один байт, пам'ять програми буде мати такий вигляд:
...[0][0][*197*][0][0]...
Чому 197
? Добре 197
десятковий - c5
шістнадцятковий. Здається, знайоме? Звичайно. Це перший байт ł
!
3. Вихід
Для друку символів ви використовуєте крапку. .
Це робиться так: Припустимо, що ми обробляємо фактичне значення комірки, як десятковий код ASCII, друкуємо відповідний символ до стандартного виводу.
Що ж, давайте уявимо, що пам'ять програми BF виглядає так:
...[0][0][*97*][0][0]...
Якщо ви зараз використовуєте оператор dot (.), BF - це друк:
а
Тому що a
десятковий код в ASCII є 97
.
Так, наприклад, така програма BF (97 плюсів по 2 крапки):
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++ ..
Збільшить значення клітинки, яку вона вказує, до 97 і роздрукує її в 2 рази.
аа
4. Петлі
У BF петля складається з циклу початку [
і циклу циклу ]
. Ви можете подумати, що це як у C / C ++, де умова є фактичним значенням комірки.
Подивіться програму BF нижче:
++[]
++
приріст фактичного значення комірки вдвічі:
...[0][0][*2*][0][0]...
І []
це як while(2) {}
, значить, це нескінченна петля.
Скажімо, ми не хочемо, щоб ця петля була нескінченною. Ми можемо зробити, наприклад:
++[-]
Отже, кожен раз, коли цикл циклу, він зменшує фактичне значення комірки. Як тільки фактичне значення комірки 0
закінчиться циклом:
...[0][0][*2*][0][0]... loop starts
...[0][0][*1*][0][0]... after first iteration
...[0][0][*0*][0][0]... after second iteration (loop ends)
Розглянемо ще один приклад скінченного циклу:
++[>]
Цей приклад показує, що ми не повинні закінчувати цикл у комірці, з якої починається цикл:
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
Однак це є гарною практикою закінчитись з того, з чого ми почали. Чому? Тому що, якщо цикл закінчується іншою коміркою, яку він розпочав, ми не можемо припустити, де буде вказати комірку. Якщо чесно сказати, така практика робить мозковий епізод менш мозковим.