En el espíritu de Resolver el problema de detención de Befinge , definamos otro lenguaje 2D llamado Modilar SNISP . Modilar SNISP tiene las siguientes seis instrucciones:
\
dirige el puntero de instrucciones de la siguiente manera:- si te acercas desde la cima, ve a la derecha;
- si se aproxima desde la derecha, sube;
- si te acercas desde abajo, ve a la izquierda;
- si te acercas por la izquierda, baja.
/
dirige el puntero de instrucciones de la siguiente manera:- si te acercas desde arriba, ve a la izquierda;
- si se acerca desde la izquierda, sube;
- si te acercas desde abajo, ve a la derecha;
- si te acercas por la derecha, baja.
!
salta la siguiente instrucción.@
empuja la ubicación y dirección IP en la pila de llamadas.#
muestra una ubicación y dirección IP de la pila de llamadas y las restaura, luego salta la siguiente instrucción. Si la pila de llamadas está vacía, la ejecución se detiene..
no hace nada.
El puntero de instrucciones comienza en la esquina superior izquierda hacia la derecha. Si alguna vez sale del campo de juego, la ejecución se detiene.
El SNISP modular no puede ser más poderoso que un PDA , porque su única fuente de almacenamiento ilimitado es una pila (la pila de llamadas) con un alfabeto finito (el conjunto de todos los pares de IP (ubicación, dirección)). El problema de detención es decidible para las PDA , por lo que este desafío siempre debería ser posible.
El reto
Su objetivo es escribir un programa que tome una matriz de caracteres que represente un programa Modilar SNISP y devuelva una de las dos salidas distintas dependiendo de si se detiene o no.
Este es el código de golf , por lo que gana el programa válido más corto (medido en bytes ).
Especificaciones
- La forma en que toma una matriz de caracteres es flexible: se aceptan una cadena separada por una nueva línea, una matriz de cadenas, una matriz de matrices de caracteres, una matriz 2D de caracteres, una matriz plana de caracteres con un número entero que representa el ancho, etc. Los casos de prueba optan por la primera de esas opciones.
- Puede suponer que la matriz de entrada será rectangular (por lo que no tiene que rellenar filas cortas) y será de longitud y ancho distintos de cero.
- Puede elegir dos salidas distintas, no solo verdadero / falso.
- Se puede suponer que la matriz de entrada consistirá solamente de comandos válidos (
\
,/
,!
,@
,#
, y.
). - Cuando se dice que un comando "omite la siguiente instrucción", puede suponer que habrá una próxima instrucción que omitir. En particular, nunca se encontrará en circunstancias en las que (1) se encuentre en el borde del campo de juego y (2) la IP se mueva perpendicular a ese borde, de modo que la "siguiente instrucción" después de que se encuentre fuera del campo de juego.
Casos de prueba
El siguiente fragmento se puede utilizar para probar programas en el idioma. Tenga en cuenta que es un poco más permisivo que la especificación real dada aquí (por ejemplo, permite caracteres que .
no sean como 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>
La forma no golfizada se puede encontrar aquí .
Vacilante
.
El programa más pequeño posible. Sale por la derecha.
\\
\/
Se enrolla alrededor del programa y sale por la parte superior.
.\./.\
.\!/./
Entra en un bucle. Vientos a través de parte de la pista en dos direcciones diferentes.
@\!/#
.\@/#
Utiliza los seis comandos.
@.@.@.@.@.@.@.@.@.#
El tiempo de ejecución de este programa es exponencial en el número de repeticiones de @.
, pero aún se detiene.
Sin parar
!/\
.\/
Creo que este es el bucle infinito más corto.
@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.
Esto se enrolla alrededor de la pista, generando cuadros de pila ocasionalmente, antes de quedar atrapado en un ciclo que genera infinitamente cuadros de pila. No todos los comandos se utilizan realmente.
.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/
Sigue creando marcos de pila, pero ninguno de ellos regresa.