Befingeの停止問題を解決するという精神で、Modilar SNISPと呼ばれる別の2D言語を定義しましょう。Modilar SNISPには、次の6つの手順があります。
\
命令ポインタを次のように指示します。- 上から近づいた場合は右に進みます。
- 右から近づいたら上へ。
- 下から近づいた場合は左に進みます。
- 左から近づいたら下へ。
/
命令ポインタを次のように指示します。- 上から近づいた場合は左へ。
- 左から近づいたら上へ。
- 下から近づいた場合は右に進みます。
- 右から近づいたら下がる。
!
次の命令をスキップします。@
IPの場所と方向を呼び出しスタックにプッシュします。#
呼び出しスタックからIPの場所と方向をポップして復元し、次の命令をスキップします。呼び出しスタックが空の場合、実行は停止します。.
何もしません。
命令ポインタは、左上隅から右に向かって始まります。それがプレイフィールドを離れると、実行は停止します。
Modilar SNISPはPDAよりも強力ではありません。無制限のストレージの唯一のソースは有限のアルファベット(すべてのIP(場所、方向)ペアのセット)を持つスタック(呼び出しスタック)であるためです。停止の問題はPDAで決定できるため、この課題は常に可能です。
チャレンジ
あなたの目標は、Modilar SNISPプログラムを表す文字のマトリックスを受け取り、停止するかどうかに応じて2つの異なる出力の1つを返すプログラムを作成することです。
これはcode-golfなので、有効な最短のプログラム(バイト単位)が優先されます。
仕様書
- 文字のマトリックスを取る方法は柔軟です。改行で区切られた文字列、文字列の配列、文字の配列の配列、2次元の文字の配列、幅を表す整数を持つ文字のフラットな配列などはすべて受け入れられます。テストケースでは、最初の選択肢を選択します。
- 入力行列は長方形で(短い行にパディングする必要がないため)、長さと幅がゼロでないと想定できます。
- 真実/偽物だけでなく、2つの異なる出力を選択できます。
- あなたが入力行列が唯一の有効なコマンドで構成されることを前提とすることができます(
\
、/
、!
、@
、#
、および.
)。 - コマンドが「次の命令をスキップする」と言われた場合、スキップする次の命令があると想定できます。特に、(1)IPがプレイフィールドのエッジにあり、(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>
非ゴルフフォームはここにあります。
停止
.
可能な最小のプログラム。右に出ます。
\\
\/
プログラムに巻き付き、トップを出ます。
.\./.\
.\!/./
ループに入ります。トラックの一部を2つの異なる方向に巻き付けます。
@\!/#
.\@/#
6つのコマンドすべてを使用します。
@.@.@.@.@.@.@.@.@.#
このプログラムの実行時間は、の繰り返し数で指数関数的です@.
が、それでも停止します。
停止しない
!/\
.\/
これが最短の無限ループだと思います。
@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.
これはトラックを巻き、たまにスタックフレームを生成し、最終的には無限にスタックフレームを生成するサイクルに巻き込まれます。すべてのコマンドが実際に使用されるわけではありません。
.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/
スタックフレームを作成し続けますが、どれも戻りません。