Giải quyết vấn đề tạm dừng cho SNISP Modilar


10

Theo tinh thần Giải quyết vấn đề tạm dừng cho Befinge , hãy xác định một ngôn ngữ 2D khác có tên Modilar SNISP . Modilar SNISP có sáu hướng dẫn sau:

  • \ chỉ dẫn con trỏ lệnh như sau:
    • nếu tiếp cận từ trên xuống, đi bên phải;
    • nếu tiếp cận từ bên phải, đi lên;
    • nếu tiếp cận từ dưới lên, đi bên trái;
    • nếu tiếp cận từ bên trái, đi xuống.
  • / chỉ dẫn con trỏ lệnh như sau:
    • nếu tiếp cận từ trên xuống, đi bên trái;
    • nếu tiếp cận từ bên trái, đi lên;
    • nếu tiếp cận từ dưới lên, đi bên phải;
    • nếu tiếp cận từ bên phải, đi xuống.
  • ! bỏ qua hướng dẫn tiếp theo
  • @ đẩy vị trí và hướng IP lên ngăn xếp cuộc gọi.
  • #bật một vị trí và hướng IP từ ngăn xếp cuộc gọi và khôi phục chúng, sau đó bỏ qua hướng dẫn tiếp theo. Nếu ngăn xếp cuộc gọi trống, thực thi dừng lại.
  • . Không lam gi cả.

Con trỏ lệnh bắt đầu ở góc trên bên trái đi bên phải. Nếu nó rời khỏi sân chơi, hãy dừng lại.

Modilar SNISP không thể mạnh hơn một thiết bị PDA , vì nguồn lưu trữ không giới hạn duy nhất của nó là một ngăn xếp (ngăn xếp cuộc gọi) với một bảng chữ cái hữu hạn (tập hợp tất cả các cặp IP (vị trí, hướng)). Vấn đề tạm dừng là có thể quyết định đối với các thiết bị PDA , vì vậy thách thức này luôn luôn có thể xảy ra.

Các thách thức

Mục tiêu của bạn là viết một chương trình lấy một ma trận các ký tự đại diện cho chương trình SNISP Modilar và trả về một trong hai đầu ra riêng biệt tùy thuộc vào việc nó có dừng hay không.

Đây là , vì vậy chương trình hợp lệ ngắn nhất (tính bằng byte ) sẽ thắng.

Thông số kỹ thuật

  • Cách bạn lấy một ma trận ký tự là linh hoạt: một chuỗi phân tách dòng mới, mảng chuỗi, mảng mảng ký tự, mảng ký tự 2d, mảng ký tự phẳng có số nguyên biểu thị chiều rộng, v.v ... đều được chấp nhận. Các trường hợp thử nghiệm lựa chọn cho sự lựa chọn đầu tiên.
  • Bạn có thể giả sử rằng ma trận đầu vào sẽ là hình chữ nhật (vì vậy bạn không phải đệm các hàng ngắn) và sẽ có chiều dài và chiều rộng khác không.
  • Bạn có thể chọn bất kỳ hai kết quả đầu ra khác biệt, không chỉ là sự thật / giả.
  • Bạn có thể giả định rằng ma trận đầu vào sẽ chỉ gồm các lệnh hợp lệ ( \, /, !, @, #, và .).
  • Khi một lệnh được cho là "bỏ qua hướng dẫn tiếp theo", bạn có thể cho rằng sẽ có một lệnh tiếp theo để bỏ qua. Đặc biệt, nó sẽ không bao giờ gặp phải trong trường hợp (1) nó nằm ở rìa của sân chơi và (2) IP di chuyển vuông góc với cạnh đó, sao cho "hướng dẫn tiếp theo" sau khi nó nằm bên ngoài sân chơi.

Các trường hợp thử nghiệm

Đoạn mã sau có thể được sử dụng để kiểm tra các chương trình bằng ngôn ngữ. Lưu ý rằng nó được cho phép hơn một chút so với thông số kỹ thuật thực tế được đưa ra ở đây (ví dụ: nó cho phép các ký tự không phải .là không có op).

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>

Các hình thức vô danh có thể được tìm thấy ở đây .

Ngừng

.

Chương trình nhỏ nhất có thể. Đi ra bên phải.


\\
\/

Gió quanh chương trình và đi ra khỏi đầu.


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

Đi trong một vòng lặp. Gió qua một phần của đường đua theo hai hướng khác nhau.


@\!/#
.\@/#

Sử dụng tất cả sáu lệnh.


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

Thời gian thực hiện của chương trình này là theo cấp số nhân của số lần lặp lại @., nhưng nó vẫn dừng lại.


Không dừng lại

!/\
.\/

Tôi tin rằng đây là vòng lặp vô hạn ngắn nhất.


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

Thỉnh thoảng điều này xoay quanh đường đua, sinh ra các khung stack, trước khi cuối cùng bị cuốn vào một chu kỳ tạo ra các khung stack. Không phải tất cả các lệnh thực sự được sử dụng.

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

Tiếp tục tạo khung stack, nhưng không ai trong số họ từng quay lại.


Sandbox (hiện đã bị xóa)
Esolanging Fruit 19/07/18

Ngôn ngữ làm tôi nhớ đến một Phân hạch đơn giản hóa hơn nhiều .
- Phục hồi Monica

1
@sundar Đó là một tập hợp con của Mô-đun SNUSP , giống như cách Befinge là (loại) một tập hợp con của Befunge.
Esolanging Fruit 19/07/18

Câu trả lời:


4

Con trăn 3 , 639 byte 630 byte 593 byte

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

Hãy thử trực tuyến!

Tôi cảm thấy như đây là nguồn thu nhỏ hơn là golf ... Tôi chắc chắn có cách tốt hơn để đến đó.

Chương trình hoạt động như một thông dịch viên đầy đủ cho ngôn ngữ. Nó dừng lại khi:

  1. Chúng tôi thoát khỏi chương trình
  2. Chúng tôi phát hiện chúng tôi trong một vòng lặp.

Phát hiện vòng lặp có phần ngây thơ (và bộ nhớ nặng). Trước khi chúng tôi đánh giá từng di chuyển, chúng tôi lưu trữ bộ đệm Hướng, Vị trí và Ngăn xếp hiện tại của chúng tôi. Nếu chúng ta thấy chúng ta đã đến một vị trí mà chúng ta đã từng đến trước đó, di chuyển cùng hướng và ngăn xếp hiện tại của chúng ta là một tập hợp siêu chồng trước đó ở vị trí + hướng này, thì chúng ta biết rằng chúng ta đang ở trong một vòng lặp và ngăn xếp đang phát triển (hoặc không đổi).

Chỉnh sửa 1 - Cảm ơn Herman L vì đã cắt "pass". Cũng cắt "Đúng".

Chỉnh sửa 2 - Lambda-ified một số chức năng. Giảm số lượng lợi nhuận. Trả về "Đúng" khi kết thúc và "Sai" khi không kết thúc. Tận dụng lớp O hiện tại làm đối tượng theo dõi, loại bỏ sự cần thiết của lớp N.


Thay thế class N():passvới class N():0def t():passvới def t():0dường như công việc
Herman L

Bạn có thể thay đổi từ một chức năng thành một chương trình đầy đủ bằng cách thay thế def e(I)bằng I=input(). Điều này cho phép bạn loại bỏ tất cả các vết lõm. Các return xbáo cáo có thể được thay thế bằng exit(x).
Lưỡng cư

Cũng def u():return len(O.S)==0 or y()có thể trở thành u=lambda:len(O.S)==0or y(). PS giải pháp tốt đẹp!
Lưỡng cư

1

JavaScript (ES6), 258 254 byte

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

Yêu cầu một chương trình không trống dưới dạng một chuỗi các chuỗi, trong đó mỗi phần tử đại diện cho một dòng của Modilar SNISP. Đầu ra 1nếu chương trình đã cho dừng lại, và 0nếu không.

Logic tương tự như câu trả lời của @ machina.widmo . Một vài lần thất bại ở các phương pháp thay thế đã khiến tôi kết luận rằng dù sao họ cũng sẽ tạo ra mã dài hơn!

Hãy thử trực tuyến!

Giải trình

Tương tự như câu trả lời khác, hàm này thoát với:

  • 1 nếu chương trình tạm dừng (ví dụ: IP di chuyển khỏi lưới hoặc ngăn xếp trống được bật lên)
  • 0nếu IP đạt đến một vị trí mà nó đã truy cập, di chuyển theo cùng một hướng và với một siêu khối của ngăn xếp có trong lần truy cập trước.

Tại sao cùng hướng?

 1
!\/

Chương trình trên dừng lại, nhưng đạt cùng một vị trí (ký tự 1), với một ngăn xếp giống hệt nhau, nhưng từ một hướng khác.

Tại sao một superset và không chỉ đơn thuần là kích thước ngăn xếp?

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

Điều này cũng tạm dừng và IP chạm ký tự 4 từ một hướng nhất quán bốn lần, với các trạng thái ngăn xếp sau ( *biểu thị đỉnh của ngăn xếp):

  • kích thước = 2 [a, b] *
  • kích thước = 1 [a] *
  • kích thước = 1 [b] *
  • kích thước = 0 [] *

Thông dịch viên làm việc như thế nào

Các hướng dẫn ( q) được dịch thành nhị phân ( c) như sau (với tất cả các ký tự khác, .hoặc nếu không, đóng vai trò là nops):

1 2 4 8 16
\ ! @ / #

Hướng ( d) được biểu diễn dưới dạng trường bit:

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

Gương ( \/) biến đổi hướng:

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

d/4 | 4*d&12

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

(d+5) % 10

Hướng mới chuyển đổi vị trí:

x += d>>2 - 1

y += d&3 - 1

Các biến toàn cầu khác

  • x, y: Vị trí IP
  • r: giữ giá trị bật ra khỏi ngăn xếp
  • k: giả mạo nếu bỏ qua hướng dẫn tiếp theo (ví dụ từ !#)
  • s: cây rơm
  • v: lưu trữ vị trí truy cập, hướng, ảnh chụp của ngăn xếp
  • w: [x, y, d], giá trị được lưu trữ trên ngăn xếp và được sử dụng làm giá trị khóa chov
  • e: giả mạo nếu chương trình không dừng do khớp bộ đệm

Ung dung

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.