Im Sinne von Lösen des Halteproblems für Befinge definieren wir eine andere 2D-Sprache namens Modilar SNISP . Modilar SNISP hat die folgenden sechs Anweisungen:
\
lenkt den Befehlszeiger wie folgt:- Wenn Sie sich von oben nähern, gehen Sie nach rechts.
- Wenn Sie sich von rechts nähern, gehen Sie nach oben.
- Wenn Sie sich von unten nähern, gehen Sie nach links.
- Wenn Sie sich von links nähern, gehen Sie nach unten.
/
lenkt den Befehlszeiger wie folgt:- Wenn Sie sich von oben nähern, gehen Sie nach links.
- Wenn Sie sich von links nähern, gehen Sie nach oben.
- Wenn Sie sich von unten nähern, gehen Sie nach rechts.
- Wenn Sie sich von rechts nähern, gehen Sie nach unten.
!
überspringt die nächste Anweisung.@
schiebt den IP-Speicherort und die IP-Richtung auf den Aufrufstapel.#
Entfernt einen IP-Speicherort und eine IP-Richtung aus dem Aufrufstapel, stellt sie wieder her und überspringt dann die nächste Anweisung. Wenn der Aufrufstapel leer ist, wird die Ausführung angehalten..
tut nichts.
Der Anweisungszeiger beginnt in der oberen linken Ecke und geht nach rechts. Wenn es jemals das Spielfeld verlässt, wird die Ausführung angehalten.
Modilares SNISP kann nicht leistungsfähiger sein als ein PDA , da seine einzige Quelle für unbegrenzten Speicher ein Stapel (der Aufrufstapel) mit einem endlichen Alphabet (die Menge aller IP-Paare (Standort, Richtung)) ist. Das Problem des Anhaltens ist für PDAs entscheidbar , daher sollte diese Herausforderung immer möglich sein.
Die Herausforderung
Ihr Ziel ist es, ein Programm zu schreiben, das eine Zeichenmatrix verwendet, die ein Modilar-SNISP-Programm darstellt, und eine von zwei unterschiedlichen Ausgaben zurückgibt, je nachdem, ob es angehalten wird oder nicht.
Dies ist Code-Golf , also gewinnt das kürzeste gültige Programm (gemessen in Bytes ).
Spezifikationen
- Die Art und Weise, wie Sie eine Zeichenmatrix verwenden, ist flexibel: Eine durch Zeilenumbrüche getrennte Zeichenfolge, ein Zeichenfolgenarray, ein Array von Zeichenarrays, ein 2D-Zeichenarray, ein flaches Zeichenarray mit einer Ganzzahl, die die Breite darstellt usw. sind zulässig. Die Testfälle entscheiden sich für die erste dieser Optionen.
- Sie können davon ausgehen, dass die Eingabematrix rechteckig ist (Sie müssen also keine kurzen Zeilen auffüllen) und eine Länge und Breite ungleich Null hat.
- Sie können zwei verschiedene Ausgänge auswählen, nicht nur wahr / falsch.
- Sie können davon ausgehen , dass die Eingangsmatrix nur gültiger Befehle bestehen (
\
,/
,!
,@
,#
, und.
). - Wenn ein Befehl "die nächste Anweisung überspringen" soll, können Sie davon ausgehen, dass eine nächste Anweisung übersprungen werden muss. Insbesondere wird es niemals auftreten, wenn (1) es am Rand des Spielfelds liegt und (2) sich die IP senkrecht zu diesem Rand bewegt, so dass der "nächste Befehl" danach außerhalb des Spielfelds liegen würde.
Testfälle
Das folgende Snippet kann zum Testen von Programmen in der Sprache verwendet werden. Beachten Sie, dass es etwas freizügiger ist als die hier angegebene tatsächliche Spezifikation (z. B. erlaubt es andere Zeichen .
als 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>
Die ungolfed Form finden Sie hier .
Anhalten
.
Das kleinstmögliche Programm. Geht rechts raus.
\\
\/
Windet sich um das Programm und geht nach oben.
.\./.\
.\!/./
Geht in einer Schleife. Windet sich durch einen Teil der Strecke in zwei verschiedene Richtungen.
@\!/#
.\@/#
Verwendet alle sechs Befehle.
@.@.@.@.@.@.@.@.@.#
Die Ausführungszeit dieses Programms ist exponentiell in der Anzahl der Wiederholungen von @.
, aber es wird immer noch angehalten.
Nicht anhalten
!/\
.\/
Ich glaube, dies ist die kürzeste Endlosschleife.
@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.
Dies windet sich um die Spur und erzeugt gelegentlich Stapelrahmen, bevor es schließlich in einen Zyklus gerät, der unendlich Stapelrahmen erzeugt. Nicht alle Befehle werden tatsächlich verwendet.
.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/
Erstellt weiterhin Stapelrahmen, aber keiner von ihnen kehrt jemals zurück.