แก้ไขปัญหาการหยุดชะงักสำหรับ Modilar SNISP


10

ในจิตวิญญาณของการแก้ปัญหาลังเลสำหรับ Befingeให้มีกำหนดภาษาอื่นที่เรียกว่า 2D Modilar SNISP Modilar SNISP มีหกคำแนะนำต่อไปนี้:

  • \ ชี้นำตัวชี้คำสั่งดังนี้:
    • หากเข้าหาจากด้านบนไปทางขวา;
    • ถ้าเดินจากทางขวาขึ้นไป;
    • หากเข้าหาจากด้านล่างไปซ้าย;
    • หากเข้าหาจากด้านซ้ายให้ลงไป
  • / ชี้นำตัวชี้คำสั่งดังนี้:
    • ถ้าเข้าหาจากด้านบนไปซ้าย;
    • หากเข้าหาจากด้านซ้ายขึ้นไป;
    • หากเข้าหาจากด้านล่างไปทางขวา;
    • หากเข้าหาจากด้านขวาให้ลงไป
  • ! ข้ามคำแนะนำถัดไป
  • @ ผลักตำแหน่ง IP และทิศทางไปยังสแตกการโทร
  • #ดึงตำแหน่ง IP และทิศทางจาก call stack และเรียกคืนจากนั้นข้ามคำสั่งถัดไป หาก call stack ว่างเปล่าการดำเนินการจะหยุดลง
  • . ไม่ทำอะไรเลย

ตัวชี้คำสั่งเริ่มต้นที่มุมซ้ายบนไปทางขวา หากเคยออกจากสนามแข่งขันการประหารชีวิตจะหยุดลง

Modilar SNISP ไม่สามารถมีประสิทธิภาพมากกว่าPDAได้เพราะแหล่งเดียวของที่เก็บข้อมูลที่ไม่ได้ จำกัด คือสแต็ก (call call) ที่มีตัวอักษรที่ จำกัด (คู่ของ 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 สามารถพบได้ที่นี่

ที่ลังเล

.

โปรแกรมที่เล็กที่สุดเท่าที่จะเป็นไปได้ ออกไปทางขวา


\\
\/

ลมไปรอบ ๆ โปรแกรมและออกไปด้านบน


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

ไปในวง ลมผ่านส่วนหนึ่งของแทร็กในสองทิศทางที่แตกต่างกัน


@\!/#
.\@/#

ใช้ทั้งหกคำสั่ง


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

เวลาดำเนินการของโปรแกรมนี้เป็นเลขชี้กำลังในจำนวนการทำซ้ำของ@.แต่มันก็ยังคงหยุดทำงาน


แบบไม่ลังเล

!/\
.\/

ฉันเชื่อว่านี่เป็นวงที่สั้นที่สุด


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

สิ่งนี้หมุนรอบแทร็กวางไข่เฟรมสแต็กเป็นครั้งคราวก่อนที่ในที่สุดจะติดอยู่ในวงจรที่สร้างเฟรมสแต็คอย่างไม่สิ้นสุด ไม่ใช่คำสั่งทั้งหมดที่ใช้จริง

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

คงการสร้างเฟรมสแต็ก แต่ไม่มีใครกลับมาเลย


Sandbox (ตอนนี้ถูกลบ)
กำลังผลไม้

ภาษาทำให้ฉันนึกถึงฟิชชันที่ง่ายขึ้นมาก
sundar - Reinstate Monica

1
@sundar มันเป็นเซตย่อยของModular SNUSPเช่นเดียวกับ Befinge คือ (ชนิด) เซตย่อยของ Befunge
แยกผลไม้

คำตอบ:


4

Python 3 , 639 bytes 630 bytes 593 bytes

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

ลองออนไลน์!

ฉันรู้สึกว่านี่เป็นแหล่งที่ลดขนาดได้มากกว่ากอล์ฟ ... ฉันแน่ใจว่ามีวิธีที่ดีกว่าในการไปที่นั่น

โปรแกรมทำงานเป็นล่ามเต็มรูปแบบสำหรับภาษา มันหยุดทั้งเมื่อ:

  1. เราออกจากโปรแกรม
  2. เราตรวจพบว่าเรากำลังวนซ้ำ

การตรวจจับลูปค่อนข้างไร้เดียงสา (และหน่วยความจำหนัก) ก่อนที่เราจะประเมินการเคลื่อนไหวแต่ละครั้งเราจะทำการปิดทิศทางทิศทางตำแหน่งและสแต็กปัจจุบันของเรา ถ้าเราเห็นว่าเรามาถึงตำแหน่งที่เราเคยไปมาแล้วการเคลื่อนที่ไปในทิศทางเดียวกันและสแต็กปัจจุบันของเราคือชุดซุปเปอร์สแต็กก่อนหน้านี้ที่ตำแหน่ง + ทิศทางนี้แล้วเรารู้ว่าเราอยู่ในวงและ สแต็คมีการเติบโต (หรืออยู่อย่างต่อเนื่อง)

แก้ไข 1 - ขอบคุณHerman Lสำหรับการตัด "pass" ตัด "True" ด้วย

แก้ไข 2 - Lambda-ified ฟังก์ชั่นบางอย่าง ลดจำนวนผลตอบแทน ส่งคืน "True" สำหรับการยกเลิกและ "False" สำหรับการไม่สิ้นสุด ยกระดับคลาส O ที่มีอยู่เป็นวัตถุการติดตามทำให้ไม่จำเป็นต้องใช้คลาส N


แทนที่class N():passด้วยclass N():0และdef t():passด้วยdef t():0ดูเหมือนว่าจะทำงาน
เฮอร์แมน L

คุณสามารถเปลี่ยนจากการทำงานไปยังโปรแกรมเต็มรูปแบบโดยการแทนที่ด้วยdef e(I) I=input()วิธีนี้ช่วยให้คุณสามารถลบการเยื้องทั้งหมด งบสามารถถูกแทนที่ด้วยreturn x exit(x)
สะเทินน้ำสะเทินบก

นอกจากนี้ยังอาจจะกลายเป็นdef u():return len(O.S)==0 or y() u=lambda:len(O.S)==0or y()PS ทางออกที่ดี!
สะเทินน้ำสะเทินบก

1

JavaScript (ES6), 258 254 ไบต์

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

คาดว่าโปรแกรมที่ไม่ว่างเปล่าเป็นอาร์เรย์ของสตริงโดยที่แต่ละองค์ประกอบแสดงถึงบรรทัดของ Modilar SNISP เอาท์พุต1หากโปรแกรมที่กำหนดหยุดการทำงานและ 0อื่น ๆ

ตรรกะเดียวกับคำตอบของ @ machina.widmo ความพยายามที่ล้มเหลวเล็กน้อยในวิธีการทางเลือกทำให้ฉันสรุปได้ว่าพวกเขาต้องการสร้างโค้ดที่ยาวกว่าอยู่แล้ว!

ลองออนไลน์!

คำอธิบาย

คล้ายกับคำตอบอื่น ๆ ฟังก์ชั่นนี้ออกด้วย:

  • 1 ถ้าโปรแกรมหยุดทำงาน (เช่น IP เคลื่อนออกจากกริดหรือสแต็กเปล่าถูกเปิด)
  • 0หาก IP ไปถึงตำแหน่งที่ได้เข้าชมไปแล้วให้ย้ายไปในตำแหน่งเดิม ทิศทางและมีการเซ็ตของสแต็คในปัจจุบันในการเข้าชมก่อนหน้านี้

ทำไมต้องไปในทิศทางเดียวกัน

 1
!\/

โปรแกรมด้านบนหยุดการทำงาน แต่โดนตำแหน่งเดียวกัน (อักขระ 1) ด้วยสแต็กที่เหมือนกัน แต่มาจากทิศทางที่แตกต่างกัน

ทำไมต้องเป็น superset และไม่เพียง แต่สแต็กขนาด?

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

สิ่งนี้จะหยุดลงและ IP จะไปที่อักขระ 4 จากทิศทางที่สอดคล้องกันสี่ครั้งโดยมีสถานะสแต็กต่อไปนี้ (*ระบุด้านบนของสแต็ก):

  • ขนาด = 2 [a, b] *
  • ขนาด = 1 [a] *
  • ขนาด = 1 [b] *
  • ขนาด = 0 [] *

การทำงานของล่าม

คำแนะนำ ( q) ถูกแปลเป็นไบนารี่ ( c) ดังต่อไปนี้ (พร้อมกับตัวละครอื่น ๆ ทั้งหมด.หรืออื่น ๆ ที่ทำหน้าที่เป็นนพ):

1 2 4 8 16
\ ! @ / #

Direction ( d) แสดงเป็นฟิลด์บิต:

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

กระจก (\/ ) เปลี่ยนทิศทาง:

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

d/4 | 4*d&12

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

(d+5) % 10

ทิศทางใหม่เปลี่ยนตำแหน่ง:

x += d>>2 - 1

y += d&3 - 1

ตัวแปรโกลบอลอื่น ๆ

  • x, y : ตำแหน่ง IP
  • r: เก็บค่าที่ดึงออกจากสแต็ก
  • k: falsy ถ้าข้ามคำสั่งถัดไป (เช่นจาก !# )
  • s: ซ้อนกัน
  • v: แคชตำแหน่งที่เข้าชมทิศทางภาพรวมของสแต็ก
  • w: [x, y, d]ค่าที่เก็บไว้ในสแต็กและใช้เป็นค่าคีย์สำหรับv
  • e: 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.