Nello spirito di Solve the Halting Problem for Befinge , definiamo un altro linguaggio 2D chiamato Modilar SNISP . Modilar SNISP ha le seguenti sei istruzioni:
\
dirige il puntatore all'istruzione come segue:- se avvicinato dall'alto, vai a destra;
- se avvicinato da destra, vai su;
- se avvicinato dal basso, vai a sinistra;
- se avvicinato da sinistra, scendi.
/
dirige il puntatore all'istruzione come segue:- se avvicinato dall'alto, vai a sinistra;
- se avvicinato da sinistra, vai su;
- se avvicinato dal basso, vai a destra;
- se avvicinato da destra, scendi.
!
salta la prossima istruzione.@
inserisce la posizione e la direzione IP nello stack di chiamate.#
estrae una posizione IP e una direzione dallo stack di chiamate e li ripristina, quindi salta sull'istruzione successiva. Se lo stack di chiamate è vuoto, l'esecuzione si interrompe..
non fa nulla.
Il puntatore dell'istruzione inizia nell'angolo in alto a sinistra andando a destra. Se mai lascia il campo di gioco, l'esecuzione si interrompe.
Il SNISP moderno non può essere più potente di un PDA , poiché la sua unica fonte di archiviazione illimitata è uno stack (lo stack di chiamate) con un alfabeto finito (l'insieme di tutte le coppie IP (posizione, direzione)). Il problema dell'arresto è decidibile per i PDA , quindi questa sfida dovrebbe essere sempre possibile.
La sfida
Il tuo obiettivo è scrivere un programma che accetta una matrice di caratteri che rappresentano un programma SNISP Modilar e restituisce uno dei due output distinti a seconda che si fermi o meno.
Questo è code-golf , quindi vince il programma valido più breve (misurato in byte ).
specificazioni
- Il modo in cui prendi una matrice di caratteri è flessibile: sono accettabili una stringa separata da una nuova riga, una matrice di stringhe, una matrice di matrici di caratteri, una seconda matrice di caratteri, una matrice piatta di caratteri con un numero intero che rappresenta la larghezza, ecc. I casi di test optano per la prima di queste scelte.
- Puoi presumere che la matrice di input sia rettangolare (quindi non devi riempire le righe corte) e sarà di lunghezza e larghezza diverse da zero.
- Puoi scegliere due uscite distinte, non solo verità / falsità.
- Si può assumere che la matrice di ingresso consisterà solo comandi validi (
\
,/
,!
,@
,#
, e.
). - Quando un comando dice "salta la prossima istruzione", puoi presumere che ci sarà una prossima istruzione da saltare. In particolare, non si incontrerà mai in circostanze in cui (1) si trova sul bordo del campo di gioco e (2) l'IP si sta muovendo perpendicolarmente a quel bordo, in modo tale che le "istruzioni successive" dopo si troverebbero al di fuori del campo di gioco.
Casi test
Il seguente frammento può essere utilizzato per testare programmi nella lingua. Si noti che è leggermente più permissivo rispetto alle specifiche effettive fornite qui (ad esempio, consente caratteri diversi da .
quelli non consentiti ).
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 non golfata può essere trovata qui .
Esitante
.
Il più piccolo programma possibile. Esce a destra.
\\
\/
Si snoda attorno al programma e esce in cima.
.\./.\
.\!/./
Va in loop. Si snoda attraverso parte della pista in due direzioni diverse.
@\!/#
.\@/#
Utilizza tutti e sei i comandi.
@.@.@.@.@.@.@.@.@.#
Il tempo di esecuzione di questo programma è esponenziale nel numero di ripetizioni di @.
, ma si ferma ancora.
Non-Arrestare
!/\
.\/
Credo che questo sia il ciclo infinito più breve.
@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.
Questo si snoda intorno alla pista, generando occasionalmente frame di stack, prima di essere catturato in un ciclo generando infinitamente frame di stack. Non tutti i comandi sono effettivamente utilizzati.
.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/
Continua a creare frame di stack, ma nessuno di essi ritorna mai.