Scrivi un ~ ATH Interpreter


12

Il popolare webcomic Homestuck fa uso di un linguaggio di programmazione chiamato ~ATHa distruggere gli universi. Mentre questa sfida al golf del codice non è quella di scrivere un programma per annientare la nostra esistenza, distruggeremo alcune entità più mansuete (anche se meno interessanti): le variabili

~ATH(pronunciato "fino alla morte", nota come funziona ~ath"tilde ath") creando una variabile chiamata THIS, eseguendo un comando con EXECUTEe terminando il programma con THIS.DIE(). Una pagina wiki per l'uso della lingua in Homestuck è disponibile qui . L'obiettivo di questa sfida sarà quello di creare un ~ATHinterprete.

Per il bene della sfida, creerò alcuni dettagli ~ATHche in realtà non esistono ma che renderanno (in qualche modo) utili.

  • La lingua funzionerà solo con numeri interi, che sono dichiarati con import <variable name>;. La variabile verrà automaticamente impostata su un valore pari a 0. È possibile importare solo una variabile alla volta.
  • Una variabile xpuò essere copiata scrivendo bifurcate x[y,z];, che eliminerà la variabile xe la sostituirà con variabili identiche ye z. Si noti che non è possibile creare una variabile con lo stesso nome di quella eliminata. In sostanza, viene rinominata una variabile, quindi viene creata una copia della variabile con un nome diverso. Questo mi sembra una caratteristica stupido, ma la stupidità è molto profondamente radicato in Homestuck.
  • La sintassi per la scrittura di un programma che esegue il codice xè ~ATH(x){EXECUTE(<code>)}. Se si desidera eseguire codice da due variabili contemporaneamente, il codice diventa nidificato, in questo modo: ~ATH(x){~ATH(y){EXECUTE(<code>)}}. Tutti i comandi in <code>verranno eseguiti su entrambi xe y.
  • Ora passiamo ai comandi. +incrementa le variabili rilevanti di 1 e le -diminuisce di 1. E ... questo è tutto.
  • La caratteristica finale di ~ATHè che uccide qualunque cosa funzioni. Le variabili sono stampate nel formato <name>=<value>(seguito da una nuova riga) al comando [<name>].DIE();. Successivamente, il programma stampa la parola DIE <name>e una nuova riga un numero di volte uguale al valore assoluto del valore della variabile. Quando le variabili vengono uccise contemporaneamente [<name1>,<name2>].DIE();(è possibile avere tutte le variabili uccise che si desidera, purché esistano), il DIE()comando viene eseguito in sequenza sulle variabili.

Programmi di esempio

Programma 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

Produzione:

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

Programma 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

Produzione:

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

Questo è il golf del codice, quindi si applicano le regole standard. Vince il codice più breve in byte.


2
Fino alla morte. Vedo quello che hai fatto là.
Trauma digitale il

3
@DigitalTrauma Devo passare il merito ad Andrew Hussie (il ragazzo che scrive Homestuck) per aver inventato il nome.
Arturo il

1
@sysreq ~ATHutilizza virgola come terminatore per la import, bifurcatee DIEcomandi. Sia REPL che i file vanno bene. La distinzione tra maiuscole e minuscole è richiesta sia in ingresso che in uscita (sto cercando di abbinare il ~ATHpiù possibile l'effettivo ).
Arcturus,

1
@sysreq Ho dovuto cambiare alcune cose in modo che la lingua potesse effettivamente fare qualcosa nella vita reale, i peccati che ho descritto vanno bene.
Arturo il

2
Sono sinceramente sorpreso che questa domanda non abbia ottenuto più risposte, e ancora più sorpresa che non ci sia un'orda di maghi Perl armati di bacchette magiche regexy
cat

Risposte:


3

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

Va bene, non sto battendo alcun record qui, ma si tratta del più piccolo Python che andrà nella misura in cui leggerà l'input tutto in una volta da un file piuttosto che in sequenza nel tempo. Proverò a risolverlo più tardi in una lingua diversa (e un interprete, non solo un parser). Fino ad allora, goditi la mostruosità disgustosamente orribile.

Nota : apre un file chiamato tnella directory di lavoro. Per farlo aprire un argomento della riga di comando, aggiungi import sysall'inizio del file e cambia 't'insys.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'))

Si scopre che zippare e codificare il programma base64 salva ancora i byte rispetto alla versione normale. Per confronto, ecco quello normale:

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

Fondamentalmente la soluzione "bacchette regexy della magia" che era desiderata. Legge l'intero programma da stdin come una singola stringa, sostituisce le espressioni ~ ATH con le espressioni Python che eseguono la semantica descritta ed eseguono () la stringa risultante.

Per vedere cosa sta facendo, guarda il programma python in cui viene tradotto il secondo programma di test fornito:

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

È una buona cosa che 00 == 0: P

Ovviamente, alcuni byte potrebbero essere salvati sfruttando l'ambiguità nelle regole. Ad esempio, non si dice cosa dovrebbe accadere nel caso in cui qualcuno provi a DIE()una variabile che non è stata modificata importo che è già stata bifurcated. La mia ipotesi basata sulla descrizione era che ci dovrebbe essere un errore. Se non è richiesto alcun errore, potrei rimuovere la deldichiarazione.

EDIT: corretto un bug per il quale i casi di test forniti non erano stati testati. Vale a dire, com'era, ogni ~ATHblocco azzera la variabile prima di incrementarla. Mi è costato 28 byte per risolverlo. Se qualcuno vede un modo migliore per sostituire i ~ATHblocchi, mi piacerebbe saperlo.

EDIT 2: salvato 12 byte srotolando il ciclo regex, rendendoli tutti sottotitoli e lasciando che la compressione si occupi della ripetizione.

EDIT 3: salvato altri 20 byte sostituendo il forloop interno con una moltiplicazione di stringhe.


Ehi, finalmente le bacchette regexy della magia! Non sarò in grado di battere questo, ma ben fatto!
cat

La mia implementazione ignora completamente le cose non esplicitamente coperte dalle regole, il che significa che va bene per te non gettare un errore e ignorare anche quei casi.
cat

potresti salvare alcuni byte facendo import sys,repiuttosto cheimport sys;import re
cat

1
l'evidenziazione della sintassi rende questo molto più facile da leggere
cat

1
@cat scusa ho dimenticato di risponderti tanto tempo fa. lo esegui dalla riga di comando e python ~ath.py < program.~ath
convoglia
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.