Перевірте програму Brainfuck


17

Ще одна проблема розбору Brainfuck, але цього разу ... інша.

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

Оскільки машини Тьюрінга (особливо швидкі) дорогі (адже вони мають нескінченну оперативну пам'ять, яка коштує), було б краще переконатися, що програма не має синтаксичних помилок перед виконанням коду. У вашій компанії буде запущено багато коду, тому ручна перевірка не працюватиме. Напишіть програму, яка зчитує код STDIN для Brainfuck і виходить зі статусом виходу, встановленим на що-небудь, крім 0 (помилка), якщо програма має якусь синтаксичну помилку (наприклад, ]це синтаксична помилка, оскільки немає відповідності [). Вийдіть зі статусом виходу 0, якщо програма повністю нормальна.

Переконайтеся, що ваша програма правильно помічає помилки, пов’язані з цим []. Ви б не хотіли, щоб інший комп'ютер вибухнув, чи не так? О, і переконайтеся, що це якомога коротше - ваш начальник платить за короткі програми (бо він вважає, що вони швидкі, чи щось). О, і вам не доведеться кодувати в Brainfuck (насправді, ви не можете, оскільки Brainfuck не підтримує вихідні коди) - ваш код буде працювати на звичайному комп'ютері.

Отже, як ви бачите, ваша робота - перевірити, чи є програма Brainfuck "дійсною" (має парні []символи). Зауважте, що програми Brainfuck можуть мати інші символи [], тому не відмовляйте програмі лише тому, що в ній є інші команди. Найменший код виграє, але, напевно, ви б більше піклувалися про оновлення коштів.


1
Що з мовами, які не дозволяють встановити код виходу з процесу?
Кендалл Фрей

1
@KendallFrey: Просто, використовуй щось інше. Або в GolfScript вставте код Ruby. Можливо, це блокує деякі езотеричні мови програмування, але добре ...
Конрад Боровський

1
Чи добре встановити код помилки на щось інше, ніж на 1 (якщо це, звичайно, не 0) при відмові?
marinus

@marinus: Я не знаю, чому ви цього хочете, але я думаю, що це добре.
Конрад Боровський

@GlitchMr: тому що тоді я можу використовувати GCD(a,b)замість 0 != a || b.
marinus

Відповіді:


6

GolfScript, 18 символів

.{[]`?)},~](`91?./

Цей код успішно працює з вихідним кодом 0 (і виводить сміття в stdout), якщо квадратні дужки у введенні врівноважені. Якщо їх немає, він виходить з ладу з ненульовим кодом виходу і друкує повідомлення про помилку на stderr, наприклад:

(eval):2:in `/': divided by 0 (ZeroDivisionError)

або

(eval):1:in `initialize': undefined method `ginspect' for nil:NilClass (NoMethodError)

Оскільки виклик нічого не сказав про вихід на stdout / stderr, я вважаю, що це відповідає. У будь-якому випадку ви завжди можете переспрямувати їх на /dev/null.

Пояснення:

Код {[]`?)},знімає з вводу все, крім квадратних дужок, і ~оцінює результат як код GolfScript. Найскладніша частина полягає в тому, що незбалансовані дужки цілком легальні в GolfScript (і, справді, мій код включає в себе один!), Тому нам потрібен інший спосіб, щоб зробити код аварією.

Трюк, який я використовую, полягає в тому, щоб залишити копію введення в нижній частині стека, зібрати весь стек в масив (використовуючи незбалансований ]) і перенести перший елемент на вимкнений. На даний момент можуть статися три речі:

  • Якщо вхід закінчився незакритим [, спроба змістити елемент з порожнього масиву призведе до збою інтерпретатора (що в цьому випадку саме те, що ми хочемо!)
  • Якщо дужки на вході були врівноваженими, зміщеним елементом буде вихідний рядок введення.
  • В іншому випадку (якщо вхід був ]незакритим або незакритим [), це буде масив.

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

Натомість, моє поточне подання використовує дуже брутальний метод, щоб повідомити масиви з рядків: він скасовує їх і намагається знайти перше виникнення [(код ASCII 91), який буде нульовим, якщо і лише якщо не буде евальовано змінною був масив. Якщо так, поділ нуля з собою викликає бажаний збій.

Пс. Два інших 18-ти карткових рішення:

.{[]`?)},{.}%~](n<

і

.{[]`?)},~]([n]+n<

На жаль, я ще не знайшов коротшого способу вирішити "проблему порожнього масиву".


це врівноважено ?: ][(тобто невдача у вашій програмі?)
Джастін

@Quincunx: Збивається, як слід.
Ільмарі Каронен

Однак це, як виявилося, прийняло [[]; Я це виправив зараз, ціною 4 символи, і він зараз проходить всі мої тести.
Ільмарі Каронен

Якщо я вас правильно зрозумів, у вас було рішення з 14 знаків, яке не в змозі розрізнити рядок і масив лише у випадку, якщо масив порожній. 1+перетворить порожній масив у не порожній масив, не порожній масив - у не порожній масив, а рядок - у рядок.
Пітер Тейлор

@PeterTaylor: Так, так і було .{[]`?)},~](n<. Я спробувати свій 1+, але мені здається , що потреби масиву містить що - то інше , ніж число (імовірно , так що інтерпретатор буде збій , коли він намагається рекурсивно порівнює символ з масивом / рядком). Використання n+також не працює, оскільки примушує масив до рядка; [n]+ робить роботу, але по- , як і раніше ставить мене в 18 символів.
Ільмарі Каронен

17

Brainfuck 76 байт

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

Це виходить з його зв'язків, якщо квадратні дужки не врівноважуються, перетворюючи інтерпретатор / компілятор BF на невдалий час виконання, а деякі з них мають вихідні коди для цього.

вимагає eof = 0, значення загортання та кінцеве число комірок

В Ubuntu ви можете використовувати інтерпретатор bf( sudo apt-get install bf)

% echo '[[[]' | bf -n bf_matching.bf
Error: Out of range! Youwanted to '<' below the first cell.
To solve, add some '>'s at the beginning, for example.
an error occured
% echo $? 
5
% bf -n bf_matching.bf < bf_matching.bf
% echo $?
0

5
Мені подобається, як ти використовував Brainfuck, хоча в питанні сказано, що це неможливо.
Riking

Ух ти. Я чесно здивований. Я припускав, що це неможливо, але це не так.
Конрад Боровський

1
@xfix: Brainfuck є завершеним, тому він може робити все, що завгодно (зважаючи на обмеження вводу / виводу.)
marinus

2
@marinus Тюрінг повноти означає лише, що він може робити всі обчислення. Brainfuckє Turing завершеним без вводу-виводу, оскільки ви можете запустити програму, яка обчислює будь-який обчислення і бачити результат, перевіряючи його пам'ять після запуску. BF без вводу-виводу зробить людей менш зацікавленими, оскільки це буде важко зробити комунальні послуги. наприклад, я ніколи не міг зробити свого перекладача .
Сільвестер

14

Befunge 98 - 26 31 20 19 символів

~:']-!\'[-!-+:0`j#q

Позбувся деяких масових умов. Тепер програма працює наступним чином:

~:   read an input char and duplicate it

']-! push a 1 if the char is the ] char, 0 otherwise

\    swap the comparison value for the duplicated input char

'[-! push a 1 if the char is the [ char, 0 otherwise

-    subtract the two comparison values. If the second one is 1, the first is 0, 
     so the result is -1. Else if the second one is 0, the first is 1 and the result is
     1. Else, the first and the second are both 0 and the result is 0

+    Add the number to the counter (which is 0 if there is none already)

:0`  test if the counter is positive (that'd mean an invalid program). Pushes a 1 if 
     positive, 0 otherwise.

j#q  if the counter is positive, then this jumps to the q. Otherwise, it skips the q 
     and continues to the ~ at the beginning of the line. If there are no more chars in
     the input, then the IP will be sent back to the q. 

qвиходить із програми та виводить верхнє значення у вигляді значення помилки. Значення помилки буде -1 1, якщо їх занадто багато ], 0, якщо вони врівноважені, і позитивне негативне, якщо їх занадто багато [. Якщо число додатне від’ємне, то стільки абсолютного значення цього числа] для збалансування програми потрібно .

Редагувати: переключення приросту та зменшення. [використовується для збільшення лічильника і ]використовується для його зменшення. Перемикаючи його, я економляв 1 char, тому що для умови виходу я повинен лише перевірити, чи лічильник позитивний, а не негативний.


Стара версія

~:'[-!j;\1+\#;']-!j;1-#;:0\`j#q

Цей код працює наступним чином:

~    read one char of input
:    duplicate it
'[-! push 1 if the character is [, 0 otherwise
j    jump that number of characters
;    skip until next ;
\1+\ increment counter

similarily for ].

#q when end of input is reached, ~ reflects the IP back. q ends the program with the error value on the stack.

Редагувати: зрозумів, що це прийняте введення, як ][, тепер, воно закінчується, коли підрахунок стає негативним, використовуючи

:0\`j


@JoKing, це дуже приємно, використовуючи відстань між собою [і ]робити порівняння з обома.
Джастін

6

J ( 38 35)

exit({:+.<./)+/\+/1 _1*'[]'=/1!:1[3

Пояснення:

  • 1!:1[3: читати stdin
  • '[]'=/: створити матрицю, де перший рядок є бітною маскою [s на вході, а другий рядок - ]s.
  • 1 _1*: помножте перший ряд на 1, а другий ряд на -1.
  • +/: підсумовуйте стовпці матриці разом, даючи дельта-відступ на символ
  • +/\: створити загальну кількість цих даних, надаючи рівень відступу для кожного символу
  • ({:+.<./): повертають GCD остаточного елемента ( {:) та найменшого елемента ( <./). Якщо всі дужки збігаються, обидва мають бути 0таким чином, це повернеться 0. Якщо дужки не збігаються, вона поверне ненульове значення.
  • exit: встановіть для цього значення виходу та вийдіть.

Приємна розбивка ...
Кріс Кешвелл

6

рубін (64)

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.empty?

раніше (68) було:

exit ARGF.read.tr('^[]','').tap{|x| 0 while x.gsub!('[]','')}.empty?

Інше еквівалентне рішення використовує

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.size>0

не можна використовувати sizeпоодинці, оскільки це дасть помилкові негативи (!!!), коли загальна кількість незбалансованих дужок кратна 256


Це кодегольф. Я впевнений, що тут можна видалити пробіл. Рубі дещо чутливий до білого простору, але в багатьох випадках ігнорує це. Для початку вам не потрібен пробіл біля =оператора.
Конрад Боровський

краща версія (дещо натхненна рішенням sed + tr). Я не впевнений, що зможу набагато краще, ніж це. Принаймні, вона має лише 4 пробіли!
переписано

1
І все-таки я можу зняти два з них.
Конрад Боровський

2
Я думаю, що простори навколо банки 0можуть пройти.
marinus

приголомшливий космічний трюк, дякую!
переписано

5

Perl, 30 символів

Ваш основний рекурсивний регекс Perl на допомогу:

perl -0ne 'exit!/^(([^][]|\[(?1)\])*)$/'

Для тих, хто не знайомий з аргументами командного рядка, що використовуються тут: -0дозволяє встановити символ закінчення рядка для цілей введення файлів; Використання -0без аргументу встановлює символ рядкового закінчення на EOF. -nавтоматично $_заздалегідь зчитує вхід (у цьому випадку весь файл) .

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


Здогадуюсь, мені доведеться краще пограти в мою відповідь, щоб перемогти це рішення на 30 чар
Джастін

Там. Моє рішення зараз набагато коротше, ніж було раніше. Приємне рішення. +1
Джастін

4

баш (тр + sed) - 42

[ -z `tr -Cd []|sed ":a;s/\[\]//g;t a"` ]

Якщо ви не заперечуєте проти повідомлень про помилки, ви можете видалити останній пробіл між `і ]отримати довжину 41.


Якщо я нічого не пропускаю, ви марно користуєтесь catі $()(також "[]"можна записати як []). Я прийняв цю відповідь, але, поки не побачу покращення в довжині, я не збираюсь підтримувати це, оскільки, якщо коротко, це може бути набагато коротшим за баш.
Конрад Боровський

Ну, насправді я так добре не знаю сценаріїв оболонок. Я не в змозі змусити більшість із них працювати. Я замінив $()backtikks і зробив "[]"-> []ви запропонували.
shiona


1
Я міг би мечем, я намагався і не зміг цього, але помилявся.
shiona

3

Perl (56 символів)

$/=0;$r=qr/[^][]*(\[(??{$r})\])*[^][]*/;<>=~m/^$r$/||die

Очевидне рішення Perl: рекурсивна регулярна виразка. На жаль, це досить багатослівна конструкція.


3

Хаскелл (143)

import System.Exit
f=exitFailure
v c []|c==0=exitSuccess|True=f
v c (s:t)|c<0=f|s=='['=v(c+1)t|s==']'=v(c-1)t|True=v c t
main=getContents>>=v 0

до jgon: використання 2 охоронців здається більш щільним, ніж тоді. Крім того, я не думаю, що ваші перевіряють, чи дужки в правильному порядку ("] [" проходить)


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

3

C, 73 64 символів

Завдяки пропозиціям із хлібопекарської роботи (хоча для цього, мабуть, потрібна робота з невеликим рівнем дії):

i;main(c){while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

Як це працює:

  • неявна int глобальна i стає ініціалізованою до 0
  • c стає неявним int, який отримує argc (ініціалізується на 1, але нам все одно, до тих пір, поки вищі біти не встановлені)
  • read(0,&c,1)зчитує один символ у низькому байті c (на архітектурах мало-ендіанських країн) і повертає 0 у EOF; i+1 != 0за винятком випадків, коли врівноважена дужка не дорівнює -1; множення їх разом працює як (безпечний) булевий І, що займає один менше знака, ніж&&
  • c==91оцінює до 1 для '[', а c==93до 1 для']' . (Можливо, є якийсь хитро хитрий трюк, який буде меншим, але я нічого не можу придумати.)
  • return iвиходить із кодом статусу 0, якщо він збалансований, не нульовим, якщо він не є. Повернення -1 технічно порушує POSIX, але насправді ніхто про це не цікавить.

Попередня версія:

main(i){char c;i=0;while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

Використання getchar()замість читання скоротить код і дозволить використовувати (неявно) intзамість charвашої змінної. Також пам’ятайте, що глобальні символи автоматично ініціалізуються до нуля.
хлібопічка

Дякую, я забув про getchar (). Не впевнений, як допомагає глобальний init, але для визначення глобального int я бере більше символів, ніж використання неявного argc.
пухнастий

1
Глобали також можуть бути неявними. Поза функцією c;визначає глобальний int.
хлібопічка

Тим часом, getchar (c) в кінцевому підсумку не робить його більш коротким, принаймні, використовуючи цей підхід, тому що його потрібно якось перевірити на> = 0, і неявний int для c переданий у read () не гарантується робота через витривалість.
пухнастий

Про що ][? Я впевнений, що це не збалансовано. Чи не потрібно вам відслідковувати, чи хоч раз це стає негативним?
vsz

2

Луа, 56

os.exit(("["..io.read"*a".."]"):match"^%b[]$"and 0 or 1)

"^%b[]$"що це? Ти можеш пояснити? Звичайно, це не регулярний вираз?
Cruncher

@Cruncher: Це не так. Це шаблон Lua, а не регулярний вираз (шаблони Lua схожі на регулярні вирази, але їх немає). У цьому випадку він відповідає початку string ( ^), збалансованому набору [і ]з чим-небудь між ( %b[]) та кінцем string ( $).
Конрад Боровський

1

GTB , 55

0→O:0→X[`I@I="[":X+1→X@I="]":X-1→X@X<0:1→O@!!Ig;e]l;e~O

Пропускає []

Використовуйте 0для зупинки.


1

МАТЕМАТИКА, 88 чол

s = "[ [ my crazy code ] [ don't explode please! [] [ :)Ahh) ]  [] []]]";

r=StringReplace;
StringLength@FixedPoint[r[#,"[]"-> ""]&,r[s,Except@Characters["[]"]-> ""]]

З функцією s name like RegularExpression` і StringLengthя ніколи не можу перемогти текстовий код гольфу в контексті з Mathematica! :)
Мурта

Я знаю, що ви маєте на увазі :) ToCharacterCodeнабагато довше, ніж ordтак ... PS: А як же встановити вихідний код?
Аяджа

Length[StringCases[s,"["|"]"]//.{x___,"[","]",y___}:>{x,y}]
алефальфа

1

Рубі, 59 58

Сканує відкриття та закриття дужки, рахуючи [як 1 і ]як -1, і виходить, якщо кількість опускається нижче 0.

b=0
$<.read.scan(/\]|\[/){exit 1if(b+=92-$&.ord)<0}
exit b

1
Оновлений і скорочений на один символ (я видалив пробіли після, exit 1якщо ви запитаєте).
Конрад Боровський

1

Hassium , 104 байт

func main(){l=0;r=0;b=input();foreach (c in b){if(c=="[")l++;if(c=="]")r++;}if(!(r==l))exit(1);exit(0);}

Повна розширена (примітка не працює в онлайн - перекладача , як вхід () відключений) тут


1

Код машини Тьюрінга, 286 276 байт

Знову я використовую визначений синтаксис таблиці правил тут .

0 * * l 1
1 _ ! r Q
5 _ _ r 5
5 * * * W
W [ ! l E
W ] ! l T
W _ _ l I
W * ! r *
E ! ! l *
E * * * R
R _ [ r O
R * * l *
T ! ! l *
T * * * Y
Y _ _ r U
Y * * l *
U [ _ r O
U ! ! * halt-err
I ! ! l *
I _ _ r halt
I * * l halt-err
O ! ! r Q
O _ _ l I
O * * r *
Q ! ! r *
Q * * * W

Припиняє стан, haltщоб прийняти вхід та halt-errвідхилити його.


halt-errможуть бути коротшими, як, halt*наприклад,
Ерік Аутгольфер


1

Хаскелл ( 167) , 159)

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

import System.Exit
p x y b|b=x|True=y
main=getContents>>=(return.all (>=0).scanl (\v->p (v-1) (v+1).(==']')) 0.filter (`elem`"[]"))>>=p exitSuccess exitFailure

Редагувати: виправлена ​​проблема, вказана на мене в коментарях (додано 11 байтів).

Редагування 2: Створена допоміжна функція для тестування предикатів за допомогою охоронців, натхнених користувачем13350, видалення 8 байт.



@ user202729 Це прекрасний момент, це було супер недбало. Досить впевнений, це зараз виправлено.
jgon

1

Стакс , 14 11 символів

╬Äτ↔EªÉs «Ü

Запустіть і налагоджуйте його

Зарахуйте до @recursive за -3 байти.

ASCII еквівалент:

.[]Y|&{yz|egp!

Видаліть усі символи, крім цього [], а потім видаліть, []поки рядок більше не зміниться. Повернутись, 1якщо остаточний рядок порожній.


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