Modilar SNISP için Durdurma Sorununu Çözme


10

Befinge için Durma Problemini Çöz ruhuyla, Modilar SNISP adlı başka bir 2D dil tanımlayalım . Modilar SNISP aşağıdaki altı talimatı içerir:

  • \ yönerge işaretçisini aşağıdaki gibi yönlendirir:
    • yukarıdan yaklaşılırsa, sağa gidin;
    • sağdan yaklaşılırsa yukarı çıkın;
    • alttan yaklaşılırsa sola gidin;
    • soldan yaklaşırsa aşağı in.
  • / yönerge işaretçisini aşağıdaki gibi yönlendirir:
    • yukarıdan yaklaşılırsa sola gidin;
    • soldan yaklaşılırsa yukarı çıkın;
    • aşağıdan yaklaşılırsa, sağa git;
    • eğer sağdan yaklaşırsa aşağı in.
  • ! sonraki talimatı atlar.
  • @ IP konumunu ve yönünü çağrı yığını üzerine iter.
  • #çağrı yığınından bir IP konumu ve yönü açar ve bunları geri yükler, ardından bir sonraki talimatın üzerinden atlar. Çağrı yığını boşsa, yürütme durur.
  • . hiç birşey yapmıyor.

Talimat işaretçisi sol üst köşeden sağa doğru başlar. Oyun alanından ayrılırsa, yürütme durur.

Modilar SNISP bir daha güçlü olamaz PDA sınırsız depolama onun sadece kaynak sonlu alfabe (tüm IP (konum, yön) çiftler grubu) sahip bir istif (çağrı yığın) olduğu için,. Durma problemi PDA'lar için kararlıdır , bu nedenle bu zorluk her zaman mümkün olmalıdır.

Meydan okuma

Amacınız, bir Modilar SNISP programını temsil eden bir karakter matrisi alan ve durup durmadığına bağlı olarak iki ayrı çıktıdan birini döndüren bir program yazmaktır.

Bu , bu nedenle ( bayt cinsinden ölçülen ) en kısa geçerli program kazanır.

Özellikler

  • Bir karakter matrisini alma şekliniz esnektir: satırsonu ile ayrılmış bir dize, dize dizisi, karakter dizisi, 2d karakter dizisi, genişliği temsil eden tamsayıya sahip düz karakter dizisi vb. Kabul edilebilir. Test senaryoları bu seçeneklerden ilkini tercih eder.
  • Giriş matrisinin dikdörtgen olacağını (yani kısa satırları doldurmak zorunda kalmayacağınızı) ve sıfır olmayan uzunluk ve genişlikte olacağını varsayabilirsiniz.
  • Sadece doğru / falsili değil, iki farklı çıktı da seçebilirsiniz.
  • Sen girdi matrisi tek geçerli komutların oluşacaktır varsayabiliriz ( \, /, !, @, #, ve .).
  • Bir komutun "sonraki talimatı atlaması" söylendiğinde, atlanacak bir sonraki talimatın olacağını varsayabilirsiniz. Özellikle, (1) oyun alanının kenarında bulunduğu ve (2) IP'nin bu kenara dikey hareket ettiği durumlarda, bu oyun alanının dışında kalan “bir sonraki talimat” olacak şekilde karşılaşılmayacaktır.

Test Durumları

Aşağıdaki snippet, dildeki programları test etmek için kullanılabilir. Burada verilen gerçek spesifikasyondan biraz daha izin verici olduğunu unutmayın (örn .. Op olmayanlar dışındaki karakterlere izin verir ).

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>

Solmamış form burada bulunabilir .

aksak

.

Mümkün olan en küçük program. Doğru dışarı çıkıyor.


\\
\/

Programın etrafında rüzgarlar ve zirveye çıkıyor.


.\./.\
.\!/./

Bir döngüye girer. İki farklı yöne pistin bir kısmı boyunca rüzgarlar.


@\!/#
.\@/#

Altı komutun tümünü kullanır.


@.@.@.@.@.@.@.@.@.#

Bu programın yürütme süresi, yineleme sayısında @.üsteldir, ancak yine de durur.


Sigara durduruluyor

!/\
.\/

Bunun en kısa sonsuz döngü olduğuna inanıyorum.


@!\\#/@\!\
//@//.#./.
.\#.!\./\.
#.\!@!\@//
/..@.@\/#!
\.@.#.\/@.

Bu, sonunda sonsuz sayıda yığın çerçeveleri üreten bir döngüye yakalanmadan önce, zaman zaman yığın kareleri yumurtlayarak pistin etrafına sarılır. Tüm komutlar aslında kullanılmaz.

.!/@.@.@.@.@.\
/.@.@.@.@.@.@/
\@.@.@.@.@.@.\
/.@.@.@.@.@.@/
.@\@.@.@.@.@.\
\.@.@.@.@.@.@/

Yığın kareleri oluşturmaya devam eder, ancak hiçbiri geri dönmez.


Sandbox (artık silindi)
Esolanging Fruit

Dil bana çok basitleştirilmiş bir Bölünmeyi hatırlatıyor .
sundar - Monica'yı eski haline

1
@sundar Modüler SNUSP'nin bir altkümesi, Befinge'nin bir Befunge altkümesi gibi.
Esolanging Fruit

Yanıtlar:


4

Python 3 , 639 bayt 630 bayt 593 bayt

def e(I):
 m=[(0,-1),(0,1),(1,1),(1,-1)];a=lambda i:(tuple(i[0]),i[1]);b=lambda s,q:s.s==q.s and s.S&q.S==q.S
 class O():i=[[0,0],2];S=[];A={}
 def z():d=m[O.i[1]];O.i[0][d[0]]+=d[1]
 def y():O.i=O.S.pop();z()
 def x():O.i[1]=[3,2,1,0][O.i[1]]
 def w():O.i[1]=[2,3,0,1][O.i[1]]
 def v():O.S+=[[O.i[0][:],O.i[1]]]
 while 1:
  p=O();p.s=a(O.i);p.S={a(i)for i in O.S};l=O.A.setdefault(p.s,[]);c=any((b(p,s)for s in l));l+=[p];e=O.i[0];d=not((0<=e[0]<len(I))and(0<=e[1]<len(I[0])))or((x,w,z,v,lambda:len(O.S)==0 or y(),lambda:0)["\\/!@#.".find(I[e[0]][e[1]])]()==1);z()
  if d!=c:return not c or d

Çevrimiçi deneyin!

Bunun golften çok küçültülmüş bir kaynak olduğunu hissediyorum ... Eminim oraya gitmenin daha iyi bir yolu var.

Program, dil için tam bir tercüman olarak çalışır. Şu durumlarda durur:

  1. Programdan çıkıyoruz
  2. Bir döngüde olduğumuzu tespit ediyoruz.

Döngü algılama biraz naiftir (ve bellek ağırdır). Her hareketi değerlendirmeden önce mevcut Yönümüzü, Konumumuzu ve Yığını önbelleğe alırız. Daha önce bulunduğumuz bir konuma geldiğimizi, aynı yönde ilerlediğimizi görürsek ve mevcut yığımız, bu konumda + yönde önceki bir yığının süper bir kümesidir, o zaman bir döngüde olduğumuzu biliyoruz ve yığın ya büyüyor (ya da sabit kalıyor).

Edit 1 - Herman L'ye "pass" kesimi için teşekkürler . Ayrıca "Doğru" kesin.

Edit 2 - Lambda-ified bazı fonksiyonlar. Azaltılmış geri dönüş sayısı. Sonlandırma için "Doğru" ve sonlandırma için "Yanlış" değerini döndürür. N sınıfı ihtiyacını ortadan kaldırarak mevcut O sınıfından izleme nesnesi olarak yararlanıldı.


Değiştirme class N():passile class N():0ve def t():passile def t():0işe görünüyor
Herman L

Sen değiştirerek tam programa bir işlevinden değişebilir def e(I)ile I=input(). Bu, tüm girintileri kaldırmanıza olanak tanır. return xİfadeleri ile değiştirilebilir exit(x).
Amfibolojik

Ayrıca def u():return len(O.S)==0 or y()olabilirdi u=lambda:len(O.S)==0or y(). PS güzel bir çözüm!
Amfibolojik

1

JavaScript (ES6), 258 254 bayt

p=>(d=>{for(x=y=r=k=1,s=[],v={};w=[--x,--y,d],c=1<<"\\!@/#".indexOf(q=(p[y]||0)[x]),q&&r&&(e=v[w]?v[w].some(u=>!s.some(t=>u+0==t+0)):1);x+=d>>2,y+=d&3)v[w]=[...s],k=k?c&9?d=c&1?d/4|4*d&12:(d+5)%10:c&4?s.push(w):c&16?(r=s.pop())&&!([x,y,d]=r):c-2:1})(9)|e

Boş olmayan bir programı bir dizi dizi olarak bekler, burada her eleman bir Modilar SNISP satırını temsil eder. Çıkışlar 1verilen programı alıkoymalarla ve eğer 0aksi.

@ Machina.widmo'nun cevabı ile aynı mantık . Alternatif yöntemlere yönelik birkaç başarısız girişim, zaten daha uzun kod üretecekleri sonucuna varmamı sağladı!

Çevrimiçi deneyin!

açıklama

Diğer cevaba benzer şekilde, bu fonksiyon şunlardan çıkar:

  • 1 program durursa (örneğin IP ızgaradan çıkarsa veya boş bir yığın açılırsa)
  • 0IP, daha önce ziyaret ettiği bir konuma ulaşırsa , aynı yönde hareket eder ve bir önceki ziyarette yığının üst kümesi bulunur.

Neden aynı yön?

 1
!\/

Yukarıdaki program durur, ancak aynı konuma (karakter 1), aynı yığınla, ancak farklı bir yönden vurur.

Neden bir üst küme ve yalnızca yığın boyutu değil?

  ab4
!/@@.\
.\..#/

Bu da durur ve IP, aşağıdaki yığın durumlarıyla (yığının *üstünü gösterir) karakter 4'ü dört kez tutarlı bir yönden vurur :

  • boyut = 2 [a, b] *
  • boyut = 1 [a] *
  • boyut = 1 [b] *
  • boyut = 0 [] *

Tercüman nasıl çalışır

Talimatlar ( q) caşağıdaki gibi binary ( ) biçimine çevrilir ( diğer tüm karakterlerle .veya başka şekilde nops işlevi görür):

1 2 4 8 16
\ ! @ / #

Direction ( d) bir bit alanı olarak temsil edilir:

9 -> right : 1001
1 -> left  : 0001
6 -> down  : 0110
4 -> up    : 0100

Aynalar ( \/) yönü dönüştürür:

\: 6-> 9 9-> 6 4-> 1 1-> 4

d/4 | 4*d&12

/: 1-> 6 6-> 1 4-> 9 9-> 4

(d+5) % 10

Yeni yönler konumu değiştirir:

x += d>>2 - 1

y += d&3 - 1

Diğer küresel değişkenler

  • x, y: IP konumu
  • r: değeri yığına atmış tutar
  • k: Falsy sonraki talimat atlama (örn dan eğer !#)
  • s: yığın
  • v: ziyaret edilen pozisyonları, yönü, yığının anlık görüntüsünü önbelleğe alır
  • w: [x, y, d], yığın üzerinde depolanan ve anahtar değeri olarak kullanılan değerv
  • e: önbellek eşleşmesi nedeniyle program durmazsa falsy

Ungolfed

p => (d => {                                                  // set initial direction and avoid a verbose `return` statement
    for (
        x = y = r = k = 1,
        s = [],
        v = {};
        w = [--x, --y, d],                                    // decrement positions early so that x,y 
                                                              // do not require a separate assignment to 0
        c = 1 << "\\!@/#".indexOf(q = (p[y]||0)[x]),          // taking an index of undefined produces an error; using 0 does not
        q && r && (
            e = v[w]
                ? v[w].some(u => !s.some(t => u+0 == t+0))    // in order to compare two arrays, must coerce to strings
                : 1
        );
        x += d>>2,
        y += d&3
    )
        v[w] = [...s],                         // clone stack
        k = k
            ?
                c&9                            // if \ or /
                    ? d = c&1
                        ? d/4 | 4*d&12
                        : (d+5) % 10
                : c&4                          // if @
                    ? s.push(w)
                : c&16                         // if #
                    ? (r = s.pop())
                        && !([x, y, d] = r)    // destructure value in stack if any exists
                : c-2                          // 0 if !
            : 1
})(9) | e
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.