Напишіть перекладача ~ ATH


12

Популярний webcomic Homestuck використовує мову програмування, покликану ~ATHзнищувати всесвіти. Хоча ця проблема з гольф-кодом полягає не в тому, щоб написати програму, щоб знищити наше існування, ми знищимо ще кілька ручних (хоча і менш цікавих) сутностей: змінних

~ATH(вимовляється "til death", помічайте, як ~athпрацює "tilde ath"), створюючи змінну, яку називають THIS, виконуючи команду з EXECUTEі закінчуючи програму THIS.DIE(). Сторінку вікі для використання мови в Homestuck можна знайти тут . Метою цього виклику буде створення ~ATHперекладача.

Заради виклику я збираюся створити деякі деталі ~ATH, які насправді не існують, але зробити їх (дещо) корисними.

  • Мова працюватиме лише з цілими числами, які задекларовані за допомогою import <variable name>;. Змінна автоматично буде встановлена ​​у значення 0. Лише одна змінна одночасно може бути імпортована.
  • Змінна xможе бути скопійована шляхом запису bifurcate x[y,z];, яка видалить змінну xта замінить її ідентичними змінними yта z. Зауважте, що він не може створити змінну з тим самим іменем, що і видалену. По суті, змінна перейменована, потім створюється копія змінної з іншим іменем. Це здається дурною особливістю, але дурість дуже глибоко вкорінена в Homestuck.
  • Синтаксис для написання програми , яка виконує код на xце ~ATH(x){EXECUTE(<code>)}. Якщо ви хочете , щоб виконати код від двох змінних одночасно, код стає вкладеним, як це: ~ATH(x){~ATH(y){EXECUTE(<code>)}}. Всі команди в <code>буде виконуватися і на, xі на y.
  • Тепер перейдемо до команд. +приріст відповідних змінних (-ів) на 1 і -зменшення їх на 1. І ... це все.
  • Кінцева особливість компанії ~ATHполягає в тому, що вона вбиває все, з чим працює. Змінні друкуються у форматі <name>=<value>(за ним новий рядок) за командою [<name>].DIE();. Після цього програма друкує слово DIE <name>та новий рядок кілька разів, що дорівнює абсолютній величині значення змінної. Коли змінні вбиваються одночасно з [<name1>,<name2>].DIE();(ви можете мати стільки змінних, скільки хочете, до тих пір, поки вони існують), DIE()команда виконується над змінними послідовно.

Приклад програм

Програма 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

Вихід:

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

Програма 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

Вихід:

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

Це кодовий гольф, тому застосовуються стандартні правила. Виграє найкоротший код у байтах.


2
До смерті. Я бачу, що ви там робили.
Цифрова травма

3
@DigitalTrauma Я повинен передати заслугу Ендрю Хуссі (хлопцю, який пише Homestuck) за те, що він придумав ім'я.
Арктур

1
@sysreq ~ATHвикористовує точку з коми в якості лінійних закінчень для import, bifurcateі DIEкоманд. І REPL, і файли чудово. Чутливість до регістру потрібна як у вході, так і у виході (я намагаюся максимально відповідати фактичному ~ATH).
Арктур

1
@sysreq Мені довелося змінити кілька речей, щоб мова насправді щось зробила в реальному житті.
Арктур

2
Я чесно здивований, це питання не отримало більше відповідей, а ще більше здивовано, що немає орди чарівників Перла, озброєних регекси-магічними паличками
кіт

Відповіді:


3

Python 2.7.6, 1244 1308 1265 1253 1073 1072 1071 1065 1064 1063 байт

Гаразд, я тут не б'ю жодних записів, але мова йде про найменший Python, якщо читати вхід відразу з файлу, а не послідовно протягом часу. Я спробую пізніше розширити це іншою мовою (і перекладачем, а не просто парсером). До цього часу насолоджуйтесь огидно жахливою жахливістю.

Примітка : відкриває файл, викликаний tу робочому каталозі. Щоб відкрити аргумент командного рядка, додайте import sysу верхній частині файлу та змініть 't'наsys.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 байт

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

Виявляється, застебнення та кодування програми base64 все ще економить байти над звичайною версією. Для порівняння, ось звичайний:

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])

В основному, "регекси-палички магії", яке було бажано. Читає у всій програмі від stdin як єдину рядок, замінює ~ ATH-вирази на вирази Python, які виконують описану семантику, та exec () s отриману рядок.

Щоб побачити, що це робить, подивіться на програму python, на яку переводиться друга надана тестова програма:

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])                                 

Добре, що 00 == 0: P

Очевидно, кілька байтів можна зберегти, скориставшись неоднозначністю в правилах. Наприклад, не сказано, що має статися у випадку, коли хтось спробує DIE()змінну, яка не була importредактована, або що вже було bifurcated. Моя здогадка на основі опису полягала в тому, що повинна бути помилка. Якщо помилка не потрібна, я можу видалити delзаяву.

EDIT: Виправлена ​​помилка, на яку не були перевірені передбачені тестові випадки. А саме, таким, яким він був, кожен ~ATHблок скидає змінну до нуля, перш ніж збільшувати її. Це коштувало мені 28 байт, щоб виправити це. Якщо хтось бачить кращий спосіб заміни ~ATHблоків, я хотів би це знати.

EDIT 2: Збережено 12 байтів, розгорнувши цикл регулярних виразів, зробивши їх усіма підзаговорами та дозволивши стисненню подбати про повторення.

EDIT 3: Збережено ще 20 байт, замінивши внутрішній forцикл на множення рядка.


Гей, нарешті регекси-палички магії! Я не зможу це перемогти, але молодець!
кіт

Моя реалізація повністю ігнорує речі, явно не охоплені правилами, а це означає, що ви добре не помилятися і просто ігнорувати ці випадки.
кіт

ви можете зберегти кілька байт, скориставшись, import sys,reа неimport sys;import re
cat

1
підсвічування синтаксису робить це набагато простішим для читання
кішка

1
@cat вибач, що я забув відповісти тобі так давно. ви запускаєте його з командного рядка та python ~ath.py < program.~ath
передаєте
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.