Viết một ~ Thông dịch viên ATH


12

Homestuck webcomic phổ biến sử dụng một ngôn ngữ lập trình được gọi là ~ATHđể tiêu diệt vũ trụ. Trong khi thử thách chơi gôn mã này không phải là viết một chương trình để tiêu diệt sự tồn tại của chúng ta, chúng ta sẽ phá hủy một số thực thể thuần hóa (mặc dù ít thú vị hơn): các biến

~ATH(phát âm là "til death", chú ý cách ~ath"tilde ath") hoạt động bằng cách tạo một biến được gọi THIS, thực hiện một lệnh với EXECUTEvà hoàn thành chương trình với THIS.DIE(). Một trang wiki cho việc sử dụng ngôn ngữ trong Homestuck có thể được tìm thấy ở đây . Mục tiêu của thử thách này sẽ là tạo ra một ~ATHphiên dịch viên.

Vì lợi ích của thử thách, tôi sẽ tạo ra một số chi tiết ~ATHkhông thực sự tồn tại nhưng làm cho nó (phần nào) hữu ích.

  • Ngôn ngữ sẽ chỉ hoạt động với số nguyên, được khai báo với import <variable name>;. Biến sẽ tự động được đặt thành giá trị 0. Chỉ có thể nhập một biến tại một thời điểm.
  • Một biến xcó thể được sao chép bằng cách viết bifurcate x[y,z];, nó sẽ xóa biến đó xvà thay thế nó bằng các biến giống nhau yz. Lưu ý rằng nó không thể tạo một biến có cùng tên với biến đã bị xóa. Về cơ bản, một biến được đổi tên, sau đó một bản sao của biến có tên khác được tạo. Điều này có vẻ giống như một tính năng ngu ngốc, nhưng ngu dốt được rất sâu ăn sâu trong Homestuck.
  • Cú pháp để viết một chương trình thực thi mã trên x~ATH(x){EXECUTE(<code>)}. Nếu bạn muốn thực thi mã trên hai biến đồng thời, mã sẽ được lồng vào nhau, như thế này : ~ATH(x){~ATH(y){EXECUTE(<code>)}}. Tất cả các lệnh trong <code>sẽ được thực hiện trên cả xy.
  • Bây giờ hãy chuyển sang các lệnh. +tăng (các) biến có liên quan lên 1 và -giảm chúng đi 1. Và ... đó là nó.
  • Tính năng cuối cùng ~ATHlà nó giết bất cứ thứ gì nó hoạt động. Các biến được in theo định dạng <name>=<value>(theo sau là một dòng mới) tại lệnh [<name>].DIE();. Sau đó, chương trình in từ DIE <name>và dòng mới một số lần bằng giá trị tuyệt đối của giá trị của biến. Khi các biến được giết đồng thời với [<name1>,<name2>].DIE();(bạn có thể có bao nhiêu biến bị giết như bạn muốn, miễn là chúng tồn tại), DIE()lệnh được thực thi trên các biến liên tục.

Chương trình ví dụ

Chương trình 1:

import sollux;                  //calls variable "sollux"
import eridan;                  //calls variable "eridan"
~ATH(sollux){EXECUTE(--)}       //sets the value of "sollux" to -2
~ATH(eridan){EXECUTE(+++++)}    //sets the value of "eridan" to 5
[sollux].DIE();                 //kills "sollux", prints "DIE sollux" twice
~ATH(eridan){EXECUTE(+)}        //sets the value of "eridan" to 6
[eridan].DIE();                 //kills "eridan", prints "DIE eridan" 6 times

Đầu ra:

sollux=-2
DIE sollux
DIE sollux
eridan=6
DIE eridan
DIE eridan
DIE eridan
DIE eridan
DIE eridan
DIE eridan

Chương trình 2:

import THIS;                    //calls variable "THIS"
~ATH(THIS){EXECUTE(++++)}       //sets the value of "THIS" to 4
bifurcate THIS[THIS1,THIS2];    //deletes "THIS", creates variables "THIS1" and "THIS2" both equal to 4
~ATH(THIS1){EXECUTE(++)}        //sets the value of "THIS1" to 6
[THIS1,THIS2].DIE();            //kills "THIS1" and "THIS2", prints "DIE THIS1" 6 times then "DIE THIS2" 4 times

import THAT;                                         //calls variable "THAT"
bifurcate THAT[THESE,THOSE];                         //deletes "THAT", creates variables "THESE" and "THOSE"
~ATH(THESE){~ATH(THOSE){EXECUTE(+++)}EXECUTE(++)}    //sets the value of "THESE" and "THOSE" to 3, then sets the value of "THESE" to 5
[THESE,THOSE].DIE();                                 //kills "THESE" and "THOSE", prints "DIE THESE" 5 times then "DIE THOSE" 3 times

Đầu ra:

THIS1=6
DIE THIS1
DIE THIS1
DIE THIS1
DIE THIS1
DIE THIS1
DIE THIS1
THIS2=4
DIE THIS2
DIE THIS2
DIE THIS2
DIE THIS2
THESE=5
DIE THESE
DIE THESE
DIE THESE
DIE THESE
DIE THESE
THOSE=3
DIE THOSE
DIE THOSE
DIE THOSE

Đây là mã golf, vì vậy các quy tắc tiêu chuẩn được áp dụng. Mã ngắn nhất trong byte thắng.


2
Cho đến chết. Tôi thấy những gì bạn đã làm ở đó.
Chấn thương kỹ thuật số

3
@DigitalTrauma Tôi phải chuyển tín dụng cho Andrew Hussie (người viết Homestuck) vì đã đưa ra cái tên này.
Arcturus

1
@sysreq ~ATHsử dụng dấu chấm phẩy như dòng kết thúc cho import, bifurcateDIElệnh. Cả REPL và tập tin đều ổn. Độ nhạy trường hợp được yêu cầu ở cả đầu vào và đầu ra (Tôi đang cố gắng khớp với thực tế ~ATHcàng nhiều càng tốt).
Arcturus

1
@sysreq Tôi đã phải thay đổi một vài thứ để ngôn ngữ thực sự sẽ làm một cái gì đó trong cuộc sống thực, pecs tôi mô tả là tốt.
Arcturus

2
Tôi thực sự ngạc nhiên về câu hỏi này đã không nhận được nhiều câu trả lời hơn, và càng ngạc nhiên hơn khi không có đám phù thủy Perl nào được trang bị những cây đũa phép kỳ diệu
con mèo

Câu trả lời:


3

Python 2.7.6, 1244 1308 1265 1253 1073 1072 1071 1065 1064 1063 byte

Được rồi, tôi sẽ không phá vỡ bất kỳ bản ghi nào ở đây nhưng đây là về Python nhỏ nhất sẽ trở nên vô nghĩa khi đọc tất cả đầu vào cùng một lúc từ một tệp thay vì tuần tự theo thời gian. Tôi sẽ cố gắng thực hiện điều này sau bằng một ngôn ngữ khác (và một trình thông dịch, không chỉ là trình phân tích cú pháp). Cho đến lúc đó, hãy tận hưởng sự quái dị ghê tởm kinh khủng.

Lưu ý : mở một tệp được gọi ttrong thư mục làm việc. Để làm cho nó mở một đối số dòng lệnh, thêm import sysvào đầu tệp và thay đổi 't'thànhsys.argv[1]

n=s='\n';m=',';X='[';Y=']';c=';';A='~ATH';D='import';b,g,k=[],[],[];r=range;l=len;f=open('t','r').read().split(n)
def d(j,u):
 p=[]
 for e in j:
  if e!=u:p.append(e)
 return''.join(p)
for h in r(l(f)):f[h]=f[h].split('//')[0].split()
while[]in f:f.remove([])
for h in r(l(f)):
 i=f[h]
 if i[0]==D and l(i)==2and i[1][l(i[1])-1]==c and d(i[1],c)not in b:g.append(0);b.append(d(i[1],c))
 elif i[0].startswith(A):
  i=i[0].split('){')
  for e in r(l(i)):
   if i[e].startswith(A):
    i[e]=i[e].split('(')
    if i[0][1]in b:g[b.index(i[0][1])]+=(i[1].count('+')-i[1].count('-'))
 elif i[0].startswith('bifurcate')and l(i)==2and i[1][l(i[1])-1]==c:
  i=i[1].split(X)
  if i[0] in b:
   z=d(d(i[1],c),Y).split(m)
   for e in r(l(z)):g.append(g[b.index(i[0])]);b.append(z[e])
   g.remove(g[b.index(i[0])]);b.remove(i[0])
 elif i[0].startswith(X)and i[0].endswith('.DIE();')and l(i)==1:
  z=d(i[0],X).split(Y)[0].split(m)
  for e in r(l(z)):
   k.append((z[e],g[b.index(z[e])]))
for e in r(l(k)):k0=k[e][0];k1=k[e][1];s+=k0+'='+str(k1)+n+('DIE '+k0+n)*abs(k1)
print s

2

Python 2, 447 475 463 443 byte

exec("eNp1UUtrAjEQvu+vCEshiYnrxl7KbqOUVmjvCoUkxUdiG7BRkpW2iP3tTVwrReppMsx8r4l936x9A8JXoN5kmu/2WeCxK0KjrSu8mWmEs0Ad96YI27lDPu/1is7wKqcQ0kBLenM+ty0nilu4zqnPtYCSQcXL2P2LmNvl1i9mjWlBUhwKbRt14uhHjlSvjzVy1tqswO/7AjsSpKtwIpGvt2zALqyNnkf3k/FIolb2ACjlpe2jR6lk8fAUQbKNulx7YIF1IDkqwmZlGwQpxNXGW9cASyCHZKqFVVOCoJQOEhjxABKLO7N5QGmET5qOs/Qfoqq6TGUfb3ZlgKvOnOxTwJKpDq6HSLzsVfK1k7g1iB7Hd9/JWh3T9wclkYwTlY4odP0nnvk0C3RUwj95/ZUq".decode('base64').decode('zip'))

Hóa ra việc nén và mã hóa chương trình base64 vẫn lưu byte qua phiên bản bình thường. Để so sánh, đây là một bình thường:

import sys,re
d={}
s=sys.stdin.read()
s,n=re.subn(r"//.*?$",'',s,0,8)
s,n=re.subn(r"import (.*?);",r"d['\1']=0;",s,0,8)
s,n=re.subn(r"bifurcate (.*?)\[(.*?),(.*?)\];",r"d['\2']=d['\3']=d['\1'];del d['\1'];",s,0,8)
s,n=re.subn(r"([+-])",r"\g<1>1",s,0,8)
s,n=re.subn(r"EXECUTE\((.*?)\)",r"0\1",s,0,8)
s,n=re.subn(r"\[(.*?)\]\.DIE\(\);",r"for i in '\1'.split(','):print i+'='+`d[i]`+('\\n'+'DIE '+i)*abs(d[i])",s,0,8)
n=1
s=s[::-1]
while n:s,n=re.subn(r"\}([+-01]*);?([^}]*?)\{\)(.*?)\(HTA~",r";\g<2>0+\1=+]'\3'[d;\1",s,0,8)
exec(s[::-1])

Về cơ bản là giải pháp "regexy wands of Magic" mong muốn. Đọc trong toàn bộ chương trình từ stdin dưới dạng một chuỗi, thay thế các biểu thức ATH bằng các biểu thức Python thực hiện ngữ nghĩa được mô tả và exec () là chuỗi kết quả.

Để xem những gì nó đang làm, hãy xem chương trình python, chương trình thử nghiệm được cung cấp thứ hai được dịch sang:

d['THIS']=0;                    
0+1+1+1+1;d['THIS']+=0+1+1+1+1+0;       
d['THIS1']=d['THIS2']=d['THIS'];del d['THIS'];    
0+1+1;d['THIS1']+=0+1+1+0;        
for i in 'THIS1,THIS2'.split(','):print i+'='+`d[i]`+('\n'+'DIE '+i)*abs(d[i])            

d['THAT']=0;                                         
d['THESE']=d['THOSE']=d['THAT'];del d['THAT'];                         
0+1+1;d['THESE']+=0+1+1+00+1+1+1;d['THOSE']+=0+1+1+1+0;    
for i in 'THESE,THOSE'.split(','):print i+'='+`d[i]`+('\n'+'DIE '+i)*abs(d[i])                                 

Đó là một điều tốt mà 00 == 0: P

Rõ ràng, một vài byte có thể được lưu bằng cách khai thác sự mơ hồ trong các quy tắc. Chẳng hạn, người ta không nói điều gì sẽ xảy ra trong trường hợp ai đó cố gắng DIE()biến một biến chưa được chỉnh sửa importhoặc đó đã là bifurcated. Tôi đoán dựa trên mô tả là sẽ có lỗi. Nếu không có lỗi được yêu cầu, tôi có thể loại bỏ deltuyên bố.

EDIT: Đã sửa lỗi mà các trường hợp kiểm tra được cung cấp không kiểm tra. Cụ thể, theo cách của nó, mọi ~ATHkhối đặt lại biến về 0 trước khi tăng nó. Tôi mất 28 byte để sửa nó. Nếu bất cứ ai nhìn thấy một cách tốt hơn để thay thế ~ATHcác khối, tôi rất muốn biết điều đó.

EDIT 2: Đã lưu 12 byte bằng cách hủy bỏ vòng lặp regex, làm cho tất cả chúng trở thành subns và để cho phép nén đảm nhiệm việc lặp lại.

EDIT 3: Đã lưu thêm 20 byte bằng cách thay thế forvòng lặp bên trong bằng phép nhân chuỗi.


Này, cuối cùng là phép thuật regexy! Tôi sẽ không thể đánh bại điều này nhưng cũng được thực hiện!
con mèo

Việc triển khai của tôi hoàn toàn bỏ qua những điều không được quy định rõ ràng bởi các quy tắc, điều đó có nghĩa là bạn không bị lỗi và chỉ bỏ qua những trường hợp đó.
mèo

bạn có thể lưu một số byte bằng cách thực hiện import sys,rethay vìimport sys;import re
cat

1
làm nổi bật cú pháp làm cho điều này dễ đọc hơn rất nhiều
con mèo

1
@cat xin lỗi tôi đã quên trả lời bạn từ rất lâu rồi. bạn chạy nó từ dòng lệnh và chuyển đầu vào vào từ một tệp:python ~ath.py < program.~ath
quintopia
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.