В дусі розв’язання задачі зупинки для Befinge давайте визначимося з іншою двовимірною мовою під назвою Modilar SNISP . Моділар SNISP має наступні шість інструкцій:
\
спрямовує покажчик інструкцій наступним чином:- якщо підійти зверху, йдіть праворуч;
- якщо підійти праворуч, підніміться вгору;
- якщо підійти знизу, йдіть ліворуч;
- якщо підійти зліва, спуститися вниз.
/
спрямовує покажчик інструкцій наступним чином:- якщо підійти зверху, йдіть ліворуч;
- якщо підійти зліва, підніміться вгору;
- якщо підійти знизу, йдіть праворуч;
- якщо підійти праворуч, спустіться вниз.
!
пропускає наступну інструкцію.@
висуває IP-адресу та напрямок на стек виклику.#
з'являється IP-адреса та напрямок зі стеку викликів та відновлює їх, а потім пропускає наступну інструкцію. Якщо стек викликів порожній, виконання зупиняється..
нічого не робить.
Покажчик інструкцій починається у верхньому лівому куті, йдучи праворуч. Якщо він коли-небудь покине поле гри, виконання зупиняється.
Моділярний SNISP не може бути більш потужним, ніж КПК , оскільки єдиним його джерелом необмеженого сховища є стек (стек виклику) з кінцевим алфавітом (набір усіх пар IP (місцезнаходження, напрямок)). Проблема зупинки вирішується для КПК , тому ця проблема завжди повинна бути можливою.
Змагання
Ваша мета - написати програму, яка бере матрицю символів, що представляє програму Modilar SNISP, і повертає один з двох різних виходів, залежно від того, зупиняється вона чи ні.
Це код-гольф , тому виграє найкоротша дійсна програма (вимірюється в байтах ).
Технічні умови
- Те, як ви приймаєте матрицю символів, є гнучким: прийнятний розділений рядок у новому рядку, масив рядків, масив масивів символів, 2d масив символів, плоский масив символів з цілим числом, що представляє ширину тощо. Тестові випадки вибирають перший із них.
- Ви можете припустити, що вхідна матриця буде прямокутною (тому вам не доведеться прокладати короткі рядки) і матиме ненульову довжину та ширину.
- Ви можете вибрати будь-які два різних виходи, а не лише триутюкі / хибні.
- Можна припустити , що вхідні матриця буде складатися тільки з допустимих команд (
\
,/
,!
,@
,#
, і.
). - Коли команду кажуть "пропустити наступну інструкцію", ви можете припустити, що буде наступна інструкція пропустити. Зокрема, його ніколи не зустрінеш за обставин, коли (1) він лежить на краю ігрового поля та (2) IP рухається перпендикулярно до цього краю, таким чином, щоб "наступна інструкція" після того, як вона лежала б поза полем гри.
Випробування
Наступний фрагмент може бути використаний для тестування програм мовою. Зауважте, що він дещо дозвольніший, ніж фактична специфікація, наведена тут (наприклад, дозволяє дозволити символи, відмінні від .
відсутності).
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 форму можна знайти тут .
Зупинка
.
Найменша можлива програма. Виходить праворуч.
\\
\/
Накручується навколо програми і виходить наверх.
.\./.\
.\!/./
Іде в петлі. Вітер проходить через частину колії у двох різних напрямках.
@\!/#
.\@/#
Використовує всі шість команд.
@.@.@.@.@.@.@.@.@.#
Час виконання цієї програми є експоненціальним у кількості повторень @.
, але вона все ще зупиняється.
Неприпинення
!/\
.\/
Я вважаю, що це найкоротший нескінченний цикл.
@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.
Цей вітер навколо доріжки, нерегулярно нерестуючи рамки стека, перш ніж врешті-решт потрапляє в цикл нескінченно генеруючи кадри стека. Не всі команди фактично використовуються.
.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/
Продовжує створювати кадри стека, але жоден з них ніколи не повертається.