Modilar SNISP의 정지 문제 해결


10

의 정신 Befinge에 대한 중단 문제를 해결 ,의라는 또 다른 차원의 언어로 정의 할 수 Modilar SNISP을 . Modilar SNISP에는 다음 6 가지 지침이 있습니다.

  • \ 다음과 같이 명령 포인터를 지시합니다.
    • 맨 위에서 접근하면 오른쪽으로 이동하십시오.
    • 오른쪽에서 접근하면 위로 올라가십시오.
    • 바닥에서 접근하면 왼쪽으로 이동하십시오.
    • 왼쪽에서 접근하면 내려갑니다.
  • / 다음과 같이 명령 포인터를 지시합니다.
    • 맨 위에서 접근하면 왼쪽으로 이동하십시오.
    • 왼쪽에서 접근하면 위로 올라갑니다.
    • 바닥에서 접근하면 오른쪽으로 이동하십시오.
    • 오른쪽에서 접근하면 내려갑니다.
  • ! 다음 명령을 건너 뜁니다.
  • @ IP 위치 및 방향을 호출 스택으로 푸시합니다.
  • #호출 스택에서 IP 위치와 방향을 표시하고 복원 한 후 다음 명령을 건너 뜁니다. 호출 스택이 비어 있으면 실행이 중지됩니다.
  • . 아무것도하지 않습니다.

명령 포인터는 오른쪽 상단에서 시작합니다. 그것이 운동장을 떠나면 실행이 중단됩니다.

제한되지 않은 스토리지의 유일한 소스는 유한 알파벳 (모든 IP (위치, 방향) 쌍의 세트)이있는 스택 (호출 스택)이기 때문에 Modilar SNISP는 PDA 보다 강력 할 수 없습니다 . PDA의 경우 정지 문제를 결정할 수 있으므로이 문제는 항상 가능합니다.

도전

귀하의 목표는 Modilar SNISP 프로그램을 나타내는 문자 매트릭스를 사용하고 정지 여부에 따라 두 가지 고유 한 출력 중 하나를 리턴하는 프로그램을 작성하는 것입니다.

이것은 이므로 가장 짧은 유효한 프로그램 ( 바이트 단위로 측정 )이 이깁니다.

명세서

  • 문자 행렬을 취하는 방식은 유연합니다. 줄 바꿈으로 구분 된 문자열, 문자열 배열, 문자 배열 배열, 2d 문자 배열, 너비를 나타내는 정수를 가진 평면 문자 배열 등이 모두 허용됩니다. 테스트 사례는 이러한 선택 중 첫 번째를 선택합니다.
  • 입력 행렬이 직사각형이고 짧은 행을 채울 필요가 없으며 길이와 너비가 0이 아니라고 가정 할 수 있습니다.
  • 진실 / 거짓뿐만 아니라 두 가지 뚜렷한 결과를 선택할 수 있습니다.
  • 당신은 입력 행렬은 유효한 명령으로 구성된다고 가정 할 수 있습니다 ( \, /, !, @, #, 및 .).
  • 명령이 "다음 명령 건너 뛰기"라고 말하면 건너 뛸 다음 명령이 있다고 가정 할 수 있습니다. 특히, (1) 운동장 가장자리에 있고 (2) IP가 그 가장자리에 직각으로 이동하여 "다음 명령"이 운동장 밖에 놓이는 상황에서는 발생하지 않습니다.

테스트 사례

다음 코드는 언어로 프로그램을 테스트하는 데 사용할 수 있습니다. 여기에 제공된 실제 사양보다 약간 더 허용됩니다 (예 : .no-ops 이외의 문자 허용 ).

function htmlEscape(t){let i=document.createElement("span");return i.innerText=t,i.innerHTML}function tick(){snisp.tick(),snisp.update()}function run(){runButton.style.display="none",stopButton.style.display="",code.style.display="none",executionArea.style.display="",snisp.initialize(),intervalId=setInterval(tick,INTERVAL_MS)}function stop(){runButton.style.display="",stopButton.style.display="none",code.style.display="",executionArea.style.display="none",clearInterval(intervalId)}let TICKS_PER_SECOND=5,INTERVAL_MS=1e3/TICKS_PER_SECOND,runButton=document.getElementById("run-button"),stopButton=document.getElementById("stop-button"),code=document.getElementById("code"),executionArea=document.getElementById("execution-display"),intervalId,snisp={x:null,y:null,direction:null,callStack:null,stopped:null,playfield:null,padRows:function(){let t=Math.max(...this.playfield.map(t=>t.length));for(let i=0;i<this.playfield.length;i++)this.playfield[i]=this.playfield[i].padEnd(t,".")},initialize:function(){this.x=0,this.y=0,this.direction="right",this.callStack=[],this.stopped=!1,this.playfield=code.value.split("\n"),this.padRows(),this.update()},getCurrentChar:function(){let t=this.playfield[this.y];if(void 0!=t)return t[this.x]},backslashMirror:function(){let t={up:"left",right:"down",down:"right",left:"up"};this.direction=t[this.direction]},slashMirror:function(){let t={up:"right",right:"up",down:"left",left:"down"};this.direction=t[this.direction]},forward:function(){switch(this.direction){case"up":this.y-=1;break;case"down":this.y+=1;break;case"left":this.x-=1;break;case"right":this.x+=1;break;default:throw"direction is invalid"}},pushState:function(){this.callStack.push({x:this.x,y:this.y,direction:this.direction})},restoreState:function(){let t=this.callStack.pop();void 0!=t?(this.x=t.x,this.y=t.y,this.direction=t.direction):this.stopped=!0},tick:function(){if(this.stopped)return;let t=this.getCurrentChar();if(void 0!=t){switch(t){case"\\":this.backslashMirror();break;case"/":this.slashMirror();break;case"!":this.forward();break;case"@":this.pushState();break;case"#":this.restoreState(),this.forward()}this.forward()}else this.stopped=!0},generatePlayfieldHTML:function(t,i){let e=[];for(let n=0;n<this.playfield.length;n++){let s=[],l=this.playfield[n];for(let e=0;e<l.length;e++){let a=htmlEscape(l[e]);e==t&&n==i&&(a='<span class="highlight">'+a+"</span>"),s.push(a)}e.push(s.join(""))}return e.join("<br>")},update:function(){let t=[];for(let i=0;i<this.callStack.length;i++){let e=this.callStack[i];t.push(this.generatePlayfieldHTML(e.x,e.y))}t.push(this.generatePlayfieldHTML(this.x,this.y));let i=t.join("<br><br>");executionArea.innerHTML=i}};
#code{font-family:monospace;}#execution-display{font-family:monospace;white-space:pre;}.highlight{background-color:yellow;}
<b>Code:</b><br/><textarea id="code" width="300" height="300"></textarea><br/><button id="run-button" onclick="run()">Run</button><button id="stop-button" onclick="stop()" style="display: none;">Stop</button><br/><div id="execution-display"></div>

ungolfed 양식은 여기 에서 찾을 수 있습니다 .

정지

.

가능한 가장 작은 프로그램. 오른쪽으로 나갑니다.


\\
\/

프로그램을 둘러보고 맨 위로 나갑니다.


.\./.\
.\!/./

루프로 들어갑니다. 트랙의 일부를 서로 다른 두 방향으로 감습니다.


@\!/#
.\@/#

6 가지 명령을 모두 사용합니다.


@.@.@.@.@.@.@.@.@.#

이 프로그램의 실행 시간은의 반복 횟수에 기하 급수적 @.이지만 여전히 정지합니다.


비 보정

!/\
.\/

나는 이것이 가장 짧은 무한 루프라고 생각합니다.


@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.

이것은 트랙 주위를 감아 스택 프레임을 때때로 생성하여 결국 스택 프레임을 무한대로 생성하는 사이클에 걸리게됩니다. 모든 명령이 실제로 사용되는 것은 아닙니다.

.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/

스택 프레임을 계속 생성하지만 반환 프레임은 없습니다.



이 언어는 나에게 훨씬 단순화 된 핵분열을 상기시킨다 .
sundar-복 직원 모니카

1
@sundar Befinge가 Befunge의 하위 집합과 같은 방식으로 Modular SNUSP 의 하위 집합입니다.
Esolanging 과일

답변:


4

파이썬 3 , 639 바이트 630 바이트 593 바이트

def e(I):
 m=[(0,-1),(0,1),(1,1),(1,-1)];a=lambda i:(tuple(i[0]),i[1]);b=lambda s,q:s.s==q.s and s.S&q.S==q.S
 class O():i=[[0,0],2];S=[];A={}
 def z():d=m[O.i[1]];O.i[0][d[0]]+=d[1]
 def y():O.i=O.S.pop();z()
 def x():O.i[1]=[3,2,1,0][O.i[1]]
 def w():O.i[1]=[2,3,0,1][O.i[1]]
 def v():O.S+=[[O.i[0][:],O.i[1]]]
 while 1:
  p=O();p.s=a(O.i);p.S={a(i)for i in O.S};l=O.A.setdefault(p.s,[]);c=any((b(p,s)for s in l));l+=[p];e=O.i[0];d=not((0<=e[0]<len(I))and(0<=e[1]<len(I[0])))or((x,w,z,v,lambda:len(O.S)==0 or y(),lambda:0)["\\/!@#.".find(I[e[0]][e[1]])]()==1);z()
  if d!=c:return not c or d

온라인으로 사용해보십시오!

골프보다 축소 된 소스 인 것 같습니다. 더 좋은 방법이있을 것입니다.

프로그램은 언어에 대한 완전한 통역사로 작동합니다. 다음과 같은 경우에 중지됩니다.

  1. 우리는 프로그램을 종료합니다
  2. 우리는 우리가 루프에 있는지 감지합니다.

루프 감지는 다소 순진하며 메모리가 많이 소모됩니다. 각 움직임을 평가하기 전에 현재 방향, 위치 및 스택을 캐싱합니다. 우리가 이전과 같은 방향으로 움직 인 위치에 왔고 현재 스택이이 위치 + 방향에서 이전 스택의 수퍼 세트 인 경우, 우리는 루프 상태에 있고 스택이 늘어나거나 일정하게 유지됩니다.

편집 1- "패스"를 자르는 Herman L 에게 감사합니다 . 또한 "참"을 자릅니다.

편집 2-Lambda가 일부 기능을 수정했습니다. 반품 횟수 감소 종료하는 경우 "True"를, 종료하지 않는 경우 "False"를 반환합니다. 기존 O 클래스를 추적 객체로 활용하여 N 클래스가 필요 없습니다.


교체 class N():passclass N():0def t():pass함께하는 def t():0작업에 보인다
허먼 L

당신은 대체하여 전체 프로그램에 함수에서 변경 될 수 있습니다 def e(I)I=input(). 그러면 들여 쓰기를 모두 제거 할 수 있습니다. return x문으로 대체 할 수있다 exit(x).
Amphibological

또한 def u():return len(O.S)==0 or y()될 수 u=lambda:len(O.S)==0or y()있습니다. PS 좋은 솔루션!
Amphibological

1

자바 스크립트 (ES6), (258) 254 바이트

p=>(d=>{for(x=y=r=k=1,s=[],v={};w=[--x,--y,d],c=1<<"\\!@/#".indexOf(q=(p[y]||0)[x]),q&&r&&(e=v[w]?v[w].some(u=>!s.some(t=>u+0==t+0)):1);x+=d>>2,y+=d&3)v[w]=[...s],k=k?c&9?d=c&1?d/4|4*d&12:(d+5)%10:c&4?s.push(w):c&16?(r=s.pop())&&!([x,y,d]=r):c-2:1})(9)|e

비어 있지 않은 프로그램을 문자열 배열로 예상합니다. 여기서 각 요소는 Modilar SNISP 라인을 나타냅니다. 1주어진 프로그램이 멈 추면 출력 합니다 0.

@ machina.widmo의 답변 과 동일한 논리 입니다. 대체 방법에 대한 몇 가지 시도로 인해 더 긴 코드가 생성 될 것이라고 결론을 내 렸습니다.

온라인으로 사용해보십시오!

설명

다른 답변과 마찬가지로이 함수는 다음과 같이 종료됩니다.

  • 1 프로그램이 중단 된 경우 (예 : IP가 그리드에서 이동하거나 빈 스택이 튀어 나옴)
  • 0IP가 이미 방문한 위치에 도달 하면 같은 방향으로 이동 하며 이전 방문에 스택 의 상위 집합 이 있습니다.

왜 같은 방향입니까?

 1
!\/

위의 프로그램은 정지하지만 동일한 위치에서 다른 방향으로 같은 위치 (문자 1)에 도달합니다.

왜 스택 크기가 아닌 슈퍼 세트입니까?

  ab4
!/@@.\
.\..#/

이 또한 중단되고 IP는 다음 스택 상태 (스택 *의 상단을 나타냄) 와 함께 일관된 방향에서 4 번 문자 4를 기록합니다 .

  • 크기 = 2 [a, b] *
  • 크기 = 1 [a] *
  • 크기 = 1 [b] *
  • 크기 = 0 [] *

통역사 작동 방식

명령어 ( q)는 c다음과 같이 이진 ( )으로 변환됩니다 ( 다른 모든 문자와 함께 .또는 기타로 nops로 사용).

1 2 4 8 16
\ ! @ / #

방향 ( d)은 비트 필드로 표시됩니다.

9 -> right : 1001
1 -> left  : 0001
6 -> down  : 0110
4 -> up    : 0100

거울 ( \/)은 방향을 변형합니다.

\: 6-> 9 9-> 6 4-> 1 1-> 4

d/4 | 4*d&12

/: 1-> 6 6-> 1 4-> 9 9-> 4

(d+5) % 10

새로운 방향이 위치를 변화시킵니다.

x += d>>2 - 1

y += d&3 - 1

다른 전역 변수

  • x, y: IP 위치
  • r: 스택에서 튀어 나온 값 유지
  • k: 다음 명령을 건너 뛰는 경우 거짓 (예 :에서 !#)
  • s: 스택
  • v: 방문 위치, 방향, 스택 스냅 샷을 캐시
  • w: [x, y, d]스택에 저장되고 키 값으로 사용 된 값v
  • e: 캐시 일치로 인해 프로그램이 중지되지 않으면 거짓

언 골프

p => (d => {                                                  // set initial direction and avoid a verbose `return` statement
    for (
        x = y = r = k = 1,
        s = [],
        v = {};
        w = [--x, --y, d],                                    // decrement positions early so that x,y 
                                                              // do not require a separate assignment to 0
        c = 1 << "\\!@/#".indexOf(q = (p[y]||0)[x]),          // taking an index of undefined produces an error; using 0 does not
        q && r && (
            e = v[w]
                ? v[w].some(u => !s.some(t => u+0 == t+0))    // in order to compare two arrays, must coerce to strings
                : 1
        );
        x += d>>2,
        y += d&3
    )
        v[w] = [...s],                         // clone stack
        k = k
            ?
                c&9                            // if \ or /
                    ? d = c&1
                        ? d/4 | 4*d&12
                        : (d+5) % 10
                : c&4                          // if @
                    ? s.push(w)
                : c&16                         // if #
                    ? (r = s.pop())
                        && !([x, y, d] = r)    // destructure value in stack if any exists
                : c-2                          // 0 if !
            : 1
})(9) | e
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.