Поради щодо гольфу в мозковій роботі


23

Які загальні поради щодо гольфу в мозковій дурці? Я шукаю ідеї, які взагалі можуть бути застосовані для кодування проблем із гольфом, які, принаймні, дещо характерні для головного мовлення (наприклад, "видалити коментарі" - це не відповідь). Будь ласка, опублікуйте одну пораду за кожну відповідь.

Відповіді:


25

Подання однієї поради на відповідь було б занадто багато відповідей.

  • Навчіться думати в Brainfuck. Це дуже відрізняється від усього іншого. Читайте та пишіть, переписуйте та переписуйте безліч програм, що ведуть мозку. Мова не дає вам багато чого працювати, тому важливо використовувати те, що вона дає вам гнучко та ефективно. Не дозволяйте будь-яким абстракціям між вами і мовою - заходьте туди і хапайтеся за це.

  • Будьте дуже комфортні з неруйнівним регулюванням потоку. Щоб вийти з циклу рішення, а не нулювати початкову клітинку, скопіювавши її в іншому місці, а потім скопіювавши її назад після виходу з циклу, часто краще перемістити вказівник на попередній нуль поблизу. Так, це означає, що вказівник буде знаходитися в різних місцях, залежно від того, ви пройшли цикл, але це також означає, що ці місця, ймовірно, мають різні розташування довколишніх нулів і ненулів, які ви можете використовувати для повторної синхронізації місця вказівника за допомогою іншого циклу. Ця методика є основою для хорошого програмування Brainfuck, і різні її форми постійно виявляться корисними.

  • Це і той факт, що кожен >або <витрати означають, що деталі компонування пам'яті важливі. Спробуйте стільки варіацій вашого макета, скільки у вас є терпіння. І пам’ятайте, макет пам'яті не повинен бути жорстким відображенням даних на місця. Він може перетворюватися на хід виконання.

  • У більш широкому масштабі розгляньте та навіть спробуйте впровадити безліч різних алгоритмів. Спочатку не буде очевидно, який саме алгоритм буде найкращим; може навіть не бути очевидним, який базовий підхід буде найкращим, і, мабуть, це буде щось інше, ніж те, що було б найкращим у звичайній мові.

  • Якщо ви маєте справу з великими або змінними розмірами даних, подивіться, чи існує якийсь спосіб, щоб ви могли обробляти їх локально, не відслідковуючи, наскільки вони великі чи числове розташування в них.

  • Однакові дані можуть бути двома різними речами. (Найчастіше - число чи символ, а також ненульовий позиційний маркер. Але дивіться random.b , де біт лічильник подвоюється як значення однієї комірки стільникового автомата.)

  • Один і той же код може робити дві різні речі, і це набагато простіше зробити це мовою, де код такий же загальний <+<. Будьте уважні до таких можливостей. Насправді, ви можете час від часу помічати навіть у тому, що здається добре написаною програмою, що є невеликі частини, які можна видалити повністю, нічого не додавати, і річ, за випадковістю, все-таки працюватиме бездоганно.

  • Для більшості мов ви часто використовуєте компілятор або інтерпретатор, щоб перевірити поведінку програми. Мова Brainfuck вимагає більшого концептуального контролю; якщо вам потрібен компілятор, щоб розповісти, що робить ваша програма, у вас недостатньо чіткого розуміння вашої програми, і вам, ймовірно, потрібно ще раз поглянути на це - принаймні, якщо ви хочете мати достатньо чітке зображення концептуальний ореол подібних програм, щоб бути хорошим у гольфі. З практикою ви будете виробляти десяток версій програми, перш ніж спробувати запустити її, і до цього моменту ви будете на 95% впевнені, що ваша найкоротша версія буде працювати правильно.

  • Удачі! Дуже мало людей намагаються писати Brainfuck стисло, але я думаю, що це єдиний спосіб, коли мова може виправдати постійну увагу - як приголомшливо незрозуміла форма мистецтва.


3
Читаючи це, мені зараз хочеться спробувати програмування в Brainfuck ..
Клавдіу,

Святе лайно, думав, що я визнав твоє ім'я. Великий шанувальник ваших мозкових програм, особливо вашого суперкороткого самоперекладача!
Джо Кінг

"Ви можете час від часу помічати ... що є невеликі частини, які можна видалити цілком, нічого не додано, і річ, за випадковістю, все одно працюватиме бездоганно". Це так правда, особливо для початківця. Наскільки я пам'ятаю лише одну відповідь на BF, наскільки я пам'ятаю, але історія її перегляду містить щонайменше 3 випадки, коли я грав із програмою і випадково пішов: "Ей, програма все одно працює, якщо я видалю цей біт! "
ETHproductions

"Спробуйте стільки варіацій вашого макета, скільки у вас є терпіння", або можете змусити : P
Esolanging Fruit

9

Кілька порад тут:

Константи:

На сторінці констант Esolangs є надзвичайно корисний список найкоротших способів створення конкретних значень. Я вважаю, що я консультую цю сторінку хоча б двічі за програму.

Початок всього:

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

При цьому встановлюється стрічка у форматі 3 * n ^ 2, який виглядає так

3 6 12 24 48 96 192 128 0 0 '

Чому це так важливо?

Спустимось до списку:

  • 3 і 6 нудні
  • 12: близько 10 (нова лінія) або 13 (повернення вагона). Також можна використовувати для лічильника на 0-9
  • 24: Близько до 26, кількість літер в алфавіті
  • 48: ASCII для 0
  • 96: Близько до 97, ASCII для a
  • 196 і 128: 196-128 = 64, близько 65, ASCII для A.

З цього одного алгоритму ми починаємо практично кожну послідовність у діапазоні ASCII, а також лічильник для кожного та новий рядок у простому досяжності.

Практичний приклад:

Друк усіх великих і малих літер і цифр.

За допомогою алгоритму:

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

Без:

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

Ми витрачаємо більшість байтів, просто ініціалізуючи стрічку у другому прикладі. Частина цього компенсується додатковими рухами в першому прикладі, але цей спосіб явно має перевагу.

Кілька інших цікавих алгоритмів у тому ж ключі:

3 * 2 ^ n + 1:

+++[[<+>>++<-]+>]
Tape: 4 7 13 25 49 65 197 129 1 0'

Це компенсує значення на 1, що забезпечує кілька речей. Це робить 12 повернення вагона, 64 - фактичним початком великого алфавіту, а 24 - ближче до 26.

2 ^ n:

+[[<+>>++<-]>]
Tape: 1 2 4 8 16 32 64 128

Оскільки 64 хороший для великих літер, 32 - це ASCII для простору, а 128 може бути використаний як лічильник для 26 (130/5 = 26). Це може зберегти байти в певних ситуаціях, коли цифри та малі літери не потрібні.

Виберіть реалізацію, яка відповідає питанню:

  • Негативні клітини майже завжди корисні, і немає причин уникати їх (якщо це не змінить ваш обліковий запис)
  • Майже те саме, що з обгортаючими клітинками, тим більше, що багато констант використовують обгортку.
  • Довільні розміри комірок корисні для нескінченних математичних послідовностей, таких як обчислення послідовності Фібоначчі нескінченно ( +[[-<+>>+>+<<]>]) або обробка більших / від'ємних чисел. Мінус полягає в тому, що деякі поширені методи, такі як [-]і на них [->+<]не можна покластися, лише на випадок, коли число заперечне.
  • EOF як 0, -1 або без змін. 0, як правило, бажано, оскільки ви можете перебирати весь вхід без додаткових перевірок. -1 корисно при переході на масиви. Я ще не знайшов використання для жодних змін :(.

Слідкуйте за тим, що відбувається фрік:

У будь-який час ви повинні мати коментарі щодо того, де має бути вказівник стосовно даних навколо нього, і переконайтеся, що ви знаєте діапазон можливих значень кожної комірки. Це особливо важливо, коли ви розділили вказівник перед циклом, тому що ви хочете потім об'єднати дві можливості разом.

У будь-який момент мій код завалений коментарями до кожного іншого рядка, який виглядає приблизно так:

*0 *dat a_1 ?  0' !0 0*
 or
*0 *dat 0' ap1 0  !0 0*

Деякі додаткові поради - присвоїти символам особливі значення. У наведеному вище прикладі, 'де знаходиться вказівник, *означає повторення в цьому напрямку, ?означає клітинку з невідомим значенням, !0означає ненульову клітинку, _є замінником -і pє замінником +. orМається на увазі, що стрічка може бути схожою на представлення, і її потрібно обробляти як таку.

Ваша схема символів не обов'язково повинна бути такою ж, як у мене (яка має кілька недоліків), вона просто повинна бути узгодженою. Це також надзвичайно корисно при налагодженні, оскільки ви можете запустити його до цього моменту і порівняти фактичну стрічку з тією, що у вас повинна бути, що може вказувати на потенційні недоліки у вашому коді.


5

Моя головна порада не буде .

Гаразд, добре, ви хочете щось корисніше за це. BF - це вже дуже лайлива мова, але те, що вас справді вбиває, - це арифметика, що ефективно потрібно робити уніарно. Варто прочитати сторінку констант в Esolang, щоб вибрати, як саме ефективно писати великі цифри, а також використовувати обгортку, де це можливо.

Доступ до пам'яті також дуже дорогий. Оскільки ви читаєте зі стрічки, вам потрібно пам’ятати, куди в будь-який момент рухається ваша голова. В відміну від інших мов , де ви можете просто написати a, b, cв БФ ви повинні явно перемістити голову кілька байт вліво або вправо, так що ви повинні пам'ятати про те, де ви зберігаєте що. Я майже впевнений, що організувати свою пам’ять оптимальним способом - це нелегко, тому удачі з цим.


5

У цій відповіді я багато разів звертаюсь до конкретної комірки на стрічці. Не має значення, яка це клітина, але це одна і та сама клітина протягом усього відповіді. Для цілей цієї публікації я буду називати цю клітинку "Тодд".

При спробі встановити комірку на постійне значення, іноді виплачується не закінчити її відразу. Наприклад, скажіть, що ви хотіли, щоб Todd містив 30. Пізніше у вашому коді (який може змінювати значення Todd, але ніколи його не читає) ви повертаєтесь до Todd. Якщо значення Тодда дорівнює 0, програма закінчується. В іншому випадку значення Тодда друкується назавжди.

Згідно зі сторінкою esolangs.org про константи, що трапляються у головному мозку (які, можливо, можуть бути предметом підказки самостійно!), Найкоротший спосіб отримати 30 - це >+[--[<]>>+<-]>+. Це ведуче >лише для того, щоб нічого ліворуч від вказівника не було змінено, але в цьому випадку ми припустимо, що ми не переймаємось цим і відкинемо його. Використовуючи цей код, ваш код виглядатиме приблизно так:

+[--[<]>>+<-]>+(MISC. CODE)(GO TO TODD)[.]

Ви можете придумати перший фрагмент коду, як це:

(SET TODD TO 30)(MISC. CODE)(GO TO TODD)[.]

Але пам'ятайте , останні два символи в цьому фрагменті: >+. Так само справедливо думати про це так:

(SET TODD TO 29)(GO TO TODD)(ADD 1 TO TODD)(MISC. CODE)(GO TO TODD)[.]

Зауважте, що ви (GO TO TODD)двічі! Ви можете замість цього написати свій код таким чином:

(SET TODD TO 29)(MISC. CODE)(GO TO TODD)(ADD 1 TO TODD)[.]
+[--[<]>>+<-](MISC. CODE)(GO TO TODD)+[.]

Якщо припустити, що кількість байтів, на які вона займає, (GO TO TODD)раніше однакова, один менший хід == один менше байт! Іноді той факт, що ваша початкова позиція змінилася, позбавляє цієї вигоди, але не завжди.


0

Крихітна підказка для викликів без вкладень. Ви можете використовувати ,замість цього [-], якщо вам потрібно швидко очистити клітинку, оскільки більшість інтерпретаторів (включаючи TIO.run) встановить вміст комірок, щоб представлення EOF дорівнювало нулю. Це робить програми мініатюрними, але кому це все одно в коді гольфу?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.