Brainfuck 프로그램 확인


17

그러나 또 다른 Brainfuck 파싱 문제이지만 이번에는 ... 다릅니다.

당신은 Brainfuck 프로그램을 만드는 회사 인 Infinite Monkeys Incorporated에서 다양한 흥미로운 문제를 해결하기 위해 노력하고 있습니다 (사고로, 회사는 무작위로 프로그램을 만듭니다). 그러나 Brainfuck 만 실행하는 빠른 Turing 컴퓨터는 구문 오류와 관련하여 작고 값 비싼 문제가 있습니다-컴퓨터를 만들고 컴퓨터가 폭발합니다. 아마도 디자인 결함 일지 모르지만 아무도 왜 그런지 고민하지 않았습니다.

튜링 머신 (특히 빠른 머신)은 비싸기 때문에 (결국 무한 RAM이 필요) 코드를 실행하기 전에 프로그램에 구문 오류가 없는지 확인하는 것이 좋습니다. 회사에서 많은 코드를 실행하므로 수동 확인이 작동하지 않습니다. Brainfuck 코드 용 STDIN을 읽고 프로그램에 구문 오류가있는 경우 종료 상태가 0 (오류) 이외의 값으로 설정된 상태로 종료하는 프로그램을 작성하십시오 (예 :] 일치하지 않기 때문에 구문 오류 [임). 프로그램이 완전히 정상이면 종료 상태가 0으로 설정된 상태에서 종료하십시오.

프로그램이 관련된 실수를 올바르게 인식하는지 확인하십시오 []. 다른 컴퓨터가 폭발하기를 원하지 않습니까? 아, 그리고 가능한 한 짧은 지 확인하십시오-상사는 짧은 프로그램에 대해 비용을 지불합니다 (그가 빠르거나 다른 것으로 생각하기 때문에). 아, 그리고 당신은 Brainfuck에서 코딩 할 필요가 없습니다 (실제로 Brainfuck은 종료 코드를 지원하지 않기 때문에 할 수 없습니다)-코드는 일반 컴퓨터에서 실행됩니다.

보시다시피, Brainfuck 프로그램이 "유효한"(페어링 된 []기호 가 있는지) 여부를 확인해야합니다 . Brainfuck 프로그램은 이외의 다른 문자를 가질 수 []있으므로 다른 명령이 있기 때문에 프로그램을 거부하지 마십시오. 가장 작은 코드가 승리하지만 어쨌든 상향 투표에 더 관심이있을 것입니다.


1
프로세스 종료 코드 설정을 허용하지 않는 언어는 어떻습니까?
Kendall Frey

1
@ KendallFrey : 간단하고 다른 것을 사용하십시오. 또는 GolfScript에서 Ruby 코드를 포함하십시오. 아마도 이것은 난해한 프로그래밍 언어를 차단할 것입니다.
Konrad Borowski

1
실패시 오류 코드를 1 이외의 다른 것으로 설정해도됩니까 (물론 0이 아닌 한)?
marinus

@ marinus : 왜 당신이 그것을 원할 지 모르겠지만 괜찮습니다.
Konrad Borowski

@GlitchMr :이므로 GCD(a,b)대신 사용할 수 있습니다 0 != a || b.
marinus

답변:


6

GolfScript, 18 자

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

입력의 대괄호가 균형을 이루면이 코드는 종료 코드 0으로 성공적으로 실행되고 일부 쓰레기는 표준 출력으로 인쇄합니다. 그렇지 않은 경우 0이 아닌 종료 코드로 실패하고 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) 의 첫 번째 항목을 찾으려고 시도합니다. 변수는 배열이었습니다. 그렇다면 0으로 나누면 원하는 충돌이 발생합니다.

추신. 다른 두 가지 18 문자 솔루션은 다음과 같습니다.

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

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

아아, 아직 "빈 배열 문제"를 해결하는 더 짧은 방법을 찾지 못했습니다.


균형이 맞습니까? : ][(즉 프로그램에서 실패합니까?)
Justin

@Quincunx : 예상대로 실패합니다.
Ilmari Karonen

그러나 그것은 받아들이는 것으로 판명되었습니다 [[]. 지금은 4 자의 비용으로 문제를 해결했으며 지금은 모든 테스트를 통과합니다.
Ilmari Karonen

내가 올바르게 이해하면 배열이 비어있는 경우에만 문자열과 배열을 구별하지 못하는 14 문자 솔루션이 있습니다. 1+빈 배열을 비어 있지 않은 배열로, 비어 있지 않은 배열을 비어 있지 않은 배열로, 문자열을 문자열로 변환합니다.
피터 테일러

@PeterTaylor : 그렇습니다 .{[]`?)},~](n<. 나는 당신을 시도 않았다 1+,하지만 배열 요구가 뭔가 포함 할 것으로 보인다 다른 (가 반복적으로 배열 / 문자열로 문자를 비교하려고 할 때 인터프리터가 충돌 것이다 아마 그래서) 숫자보다 더합니다. n+배열을 문자열로 강제 변환하기 때문에 using도 작동하지 않습니다. [n]+ 수행 작업을하지만, 여전히 18 개 문자에서 저를 둔다.
Ilmari Karonen

17

Brainfuck 76 바이트

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

대괄호가 불균형하면 bf 인터프리터 / 컴파일러가 런타임에 실패하고 일부는 종료 코드가 있음을 나타 내기 위해 본드가 사라집니다.

eof = 0, 랩핑 값 및 finit 수의 셀 필요

우분투에서는 통역사를 사용할 수 있습니다 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

오 와우. 솔직히 놀랐습니다. 나는 불가능하다고 가정했지만 그렇지 않습니다.
Konrad Borowski

1
@xfix : Brainfuck은 완전히 완료되었으므로 무엇이든 할 수 있습니다 (I / O 제약 조건 제공)
marinus

2
@marinus Turing completness는 모든 계산을 수행 할 수 있음을 의미합니다. Brainfuck계산을 계산하고 실행 후 메모리를 검사하여 결과를 볼 수있는 프로그램을 실행할 수 있으므로 I / O없이 튜링 완료입니다. I / O가없는 BF는 유틸리티를 만들기가 어렵 기 때문에 사람들의 관심을 떨어 뜨릴 수 있습니다. 예를 들어 리스프 통역사 로 만들 수 없었습니다 .
Sylwester

14

비 펀지 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 문자를 저장합니다.


구 버전

~:'[-!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. 중괄호가 일치하지 않으면 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의 배수 일 때 거짓 부정 (!!!)을 나타 내기 때문에 단독으로 사용할 수 없습니다


이것은 codegolf입니다. 여기에서 공백을 제거 할 수 있다고 확신합니다. 루비는 공백에 다소 민감하지만, 많은 경우이를 무시합니다. 우선 =연산자 근처에 공백이 필요하지 않습니다 .
Konrad Borowski

더 나은 버전 (sed + tr 솔루션에서 영감을 얻음). 나는 이것보다 훨씬 나아질 수 있는지 확신하지 못한다. 최소한 4 개의 공백이 있습니다!
다시 작성

1
그러나 두 가지를 제거 할 수 있습니다.
Konrad Borowski

2
나는 주위의 공간 0이 갈 수 있다고 생각합니다 .
marinus

멋진 우주 트릭, 감사합니다!
다시 작성

5

펄, 30 자

구조에 대한 기본 Perl 재귀 정규식 :

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

여기에 사용 된 명령 줄 인수에 익숙하지 않은 사용자 -0는 파일 입력을 위해 줄 끝 문자를 설정할 수 있습니다. -0인수없이 사용 하면 줄 끝 문자를 EOF로 설정합니다. -n입력 (이 경우 전체 파일)을 자동으로 읽습니다.$_사전에 .

정규식이 일치하면 종료 코드에 대해 0으로 무시되는 true 값을 리턴합니다. 그렇지 않으면 false 리턴 값은 종료 코드 1을 생성합니다.


이 30 문자 솔루션을이기려면 내 대답을 더 잘 골프화해야한다고 생각합니다.
Justin

그곳에. 내 솔루션은 이제 이전보다 훨씬 짧습니다. 좋은 해결책. +1
Justin

4

배쉬 (tr + sed)-42

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

당신이 오류 메시지를 꺼리지 않는 경우에 당신은 사이 마지막 공간을 제거 할 수 `]길이 (41)를 얻을 수 있습니다.


내가 아무것도 그리워하지 않는 한, 당신은 쓸데없는 사용을 cat하고 있습니다 $()(또한 "[]"로 쓸 수 있습니다 []). 나는이 대답을 받아 들였지만 길이가 향상 될 때까지 짧게 bash의 경우 더 짧을 수 있으므로 이것을 높이 지 않을 것입니다.
Konrad Borowski

글쎄, 실제로 나는 쉘 스크립팅을 잘 모른다. 나는 그 일을 대부분 할 수 없습니다. 나는 바꿨다$() 백틱으로 하고 제안한 "[]"-> []를 수행했습니다.
shiona


1
나는 시도하고 실패했지만 칼을 썼다. 그러나 나는 틀렸다.
shiona

3

펄 (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 명의 가드를 사용하는 것이 if-then-else보다 밀도가 높은 것 같습니다. 또한 괄호가 올바른 순서인지 확인하지는 않습니다 ( "] ["패스).


와우, 오늘 지적되었을 때만이 의견을 보았습니다. 내 코드를 수정했지만 예, 가드가 밀도가 높은 것으로 보입니다 (+1).
jgon

3

씨, 73 64 자

breadbox의 제안 덕분에 (아마도 엔디안이 작동해야하지만) :

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의 하위 바이트로 단일 문자를 읽고 EOF에서 0을 반환합니다. i+1 != 0대괄호 따옴표가 -1이 아니면; 그것들을 곱하면 (안전한) 부울로 작동하며보다 적은 문자를 사용합니다.&&
  • c==91에 대해 1로 평가 '['되고c==93 1로 평가에 대한']' . (더 작지만 약간 생각할 수없는 약간의 트러블 한 비트 트릭 트릭이있을 수 있습니다.)
  • return i균형이 맞으면 상태 코드 0으로 종료하고 그렇지 않으면 0이 아닙니다. -1을 반환하면 기술적으로 POSIX를 위반하지만 실제로는 아무도 신경 쓰지 않습니다.

이전 버전:

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

getchar()read 대신 사용 하면 코드가 단축되고 변수 int대신 (암시 적) 사용할 수 있습니다 char. 또한 전역은 자동으로 0으로 초기화됩니다.
breadbox

감사합니다. getchar ()에 대해 잊었습니다. 그래도 전역 초기화가 어떻게 도움이되는지 확실하지 않습니다. 전역 int를 정의하면 암시 적 argc를 사용하는 것보다 더 많은 문자가 필요합니다.
푹신한

1
글로벌도 암시적일 수 있습니다. 함수 외부 c;에서는 전역 int를 정의합니다.
breadbox

한편 getchar (c)는 어떤 식 으로든> = 0으로 테스트해야하고 read ()로 전달 된 c에 대한 암시 적 int가 엔디안 때문에 일하십시오.
솜털

는 어때 ][ ? 균형이 맞지 않다고 확신합니다. 적어도 한 번 이상 부정적인지 추적하지 않아도됩니까?
vsz

2

루아, 56

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

"^%b[]$"이게 뭐야? 설명 할 수 있습니까? 확실히, 이것은 정규식이 아닙니까?
Cruncher

@Cruncher : 아닙니다. 그것은 정규 표현식이 아닌 루아 패턴입니다 (루아 패턴은 정규 표현식과 유사하지만 그렇지 않습니다). 이 경우 문자열의 시작 ( ^), 균형 잡힌 세트 와 그 사이 ( ) 및 문자열 끝 ( ) [과 일치합니다 . ]%b[]$
Konrad Borowski

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

MATHEMATICA, 88 자

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

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

s name like RegularExpression 기능을 사용하면 StringLengthMathematica로 텍스트 코드 골프 컨텍스트를 이길 수 없습니다! :)
Murta

나는 당신이 무엇을 의미하는지 안다 :) ToCharacterCode것보다 훨씬 길다 ord... PS : 종료 코드를 설정하는 것은 어떻습니까?
Ajasja

Length[StringCases[s,"["|"]"]//.{x___,"[","]",y___}:>{x,y}]
alephalpha

1

루비, 59 58

브라켓 열기 및 닫기를 스캔 [하고 1로 계산 ]하고 -1로 계산 하고 카운트가 0 아래로 떨어지면 종료합니다.

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

1
공감하고 한 문자 씩 줄였습니다 ( exit 1요청한 경우 공백을 제거했습니다 ).
Konrad Borowski

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-errhalt*예를 들어 짧아 질 수 있습니다 .
Outgolfer Erik


1

하스켈 ( 167) )

누군가가 그것을 더 짧게 만드는 방법에 대한 제안이 있다면, 나는 그것들을 듣게되어 기쁩니다 :)

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 : user13350에서 영감을 얻은 가드를 사용하여 술어를 테스트하고 8 바이트를 제거하는 보조 기능을 만들었습니다.



@ user202729 훌륭한 지적입니다. 매우 부주의했습니다. 이제 수정되었습니다.
jgon

1

Stax , 14 11

╬Äτ↔EªÉs «Ü

실행 및 디버깅

-3 바이트에 대한 @recursive의 크레딧입니다.

ASCII 상응 :

.[]Y|&{yz|egp!

을 제외한 모든 문자 []를 제거한 다음 []문자열이 더 이상 변경되지 않을 때까지 제거하십시오 . 1마지막 문자열이 비어 있으면 반환 합니다.


1
좋은. .[]|&문자를 필터링 한 다음 리터럴을 다시 사용할 수 있습니다. 11
재귀
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.