Popularny komiks Homestuck korzysta z języka programowania zwanego ~ATH
niszczeniem wszechświatów. Podczas gdy wyzwaniem dla golfa kodowego nie jest napisanie programu anihilującego nasze istnienie, zniszczymy nieco więcej oswojonych (choć mniej interesujących) bytów: zmiennych .
~ATH
(wymawiane „aż do śmierci”, zwróć uwagę, jak ~ath
to jest „tylda ath”), tworząc zmienną o nazwie THIS
, wykonując polecenie EXECUTE
i kończąc program THIS.DIE()
. Strona wiki dotycząca użycia języka w Homestuck znajduje się tutaj . Celem tego wyzwania będzie stworzenie ~ATH
tłumacza.
Ze względu na wyzwanie zamierzam stworzyć pewne szczegóły ~ATH
, które tak naprawdę nie istnieją, ale uczynię je (w pewnym stopniu) użytecznymi.
- Język będzie działał tylko z liczbami całkowitymi zadeklarowanymi za pomocą
import <variable name>;
. Zmienna zostanie automatycznie ustawiona na wartość 0. Można importować tylko jedną zmienną na raz. - Zmienną
x
można skopiować, piszącbifurcate x[y,z];
, co spowoduje jej usunięciex
i zastąpienie identycznymi zmiennymiy
orazz
. Zauważ, że nie można utworzyć zmiennej o tej samej nazwie co usunięta. Zasadniczo nazwa zmiennej jest zmieniana, a następnie tworzona jest kopia zmiennej o innej nazwie. To wydaje się głupią cechą, ale głupota jest bardzo głęboko zakorzeniona w Homestuck. - Składnia do pisania programu wykonującego kod
x
jest następująca~ATH(x){EXECUTE(<code>)}
. Jeśli chcesz wykonać kod na dwóch zmiennych jednocześnie, kod zostaje zagnieżdżona w następujący sposób:~ATH(x){~ATH(y){EXECUTE(<code>)}}
. Wszystkie polecenia<code>
będą wykonywane zarówno na, jakx
i nay
. - Teraz przejdźmy do poleceń.
+
zwiększa odpowiednie zmienne o 1 i-
zmniejsza je o 1. I ... to wszystko. - Ostatnią cechą
~ATH
jest to, że zabija wszystko, z czym współpracuje. Zmienne są drukowane w formacie<name>=<value>
(po którym następuje nowa linia) na polecenie[<name>].DIE();
. Następnie program wypisuje słowoDIE <name>
i nowy wiersz kilka razy równe wartości bezwzględnej wartości zmiennej. Kiedy zmienne są zabijane jednocześnie z[<name1>,<name2>].DIE();
(możesz zabić tyle zmiennych, ile chcesz, o ile istnieją),DIE()
polecenie jest wykonywane na zmiennych sekwencyjnie.
Przykładowe programy
Program 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
Wynik:
sollux=-2
DIE sollux
DIE sollux
eridan=6
DIE eridan
DIE eridan
DIE eridan
DIE eridan
DIE eridan
DIE eridan
Program 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
Wynik:
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
To jest kod golfowy, więc obowiązują standardowe zasady. Najkrótszy kod w bajtach wygrywa.
źródło
~ATH
wykorzystuje średników jako linia zakończeń dla osóbimport
,bifurcate
iDIE
poleceń. Zarówno REPL, jak i pliki są w porządku. Czułość wielkości liter jest wymagana zarówno na wejściu, jak i na wyjściu (staram się~ATH
jak najlepiej dopasować do rzeczywistych ).Odpowiedzi:
Python 2.7.6,
1244130812651253107310721071106510641063 bajtówW porządku, nie biję tu żadnych rekordów, ale chodzi o to, że najmniejszy Python przejdzie na tyle, na ile odczytuje dane wejściowe naraz z pliku, a nie sekwencyjnie z czasem. Spróbuję to poprawić później w innym języku (i tłumaczu, nie tylko parserze). Do tego czasu ciesz się obrzydliwie okropną potwornością.
Uwaga : otwiera plik o nazwie
t
w katalogu roboczym. Aby otworzyć argument linii poleceń, dodajimport sys
na górę pliku i zmień't'
nasys.argv[1]
źródło
Python 2,
447475463443 bajtyOkazuje się, że kompresowanie i kodowanie programu base64 nadal powoduje zapisanie bajtów w stosunku do normalnej wersji. Dla porównania, oto normalny:
Zasadniczo pożądane rozwiązanie „regexy różdżki magii”. Wczytuje cały program ze standardowego wejścia jako pojedynczy ciąg, zastępuje wyrażenia ~ ATH wyrażeniami Python wykonującymi opisaną semantykę, a exec () s otrzymany ciąg.
Aby zobaczyć, co robi, spójrz na program w języku Python, na który jest tłumaczony drugi podany program testowy:
Dobrze, że
00 == 0
: POczywiście można zaoszczędzić kilka bajtów, wykorzystując niejednoznaczność reguł. Na przykład nie jest powiedziane, co powinno się zdarzyć, gdy ktoś spróbuje
DIE()
użyć zmiennej, która nie zostałaimport
edytowana lub już zostałabifurcate
d. Domyślam się na podstawie opisu, że powinien wystąpić błąd. Jeśli błąd nie jest wymagany, mógłbym usunąćdel
instrukcję.EDYCJA: Naprawiono błąd, którego nie testowały dostarczone przypadki testowe. Mianowicie, tak jak było, każdy
~ATH
blok resetuje zmienną do zera przed jej zwiększeniem. Naprawienie tego kosztowało mnie 28 bajtów. Jeśli ktoś widzi lepszy sposób na zastąpienie~ATH
bloków, chciałbym to wiedzieć.EDYCJA 2: Zaoszczędzono 12 bajtów, rozwijając pętlę wyrażeń regularnych, czyniąc je wszystkimi subnsami i pozwalając kompresji zająć się powtórzeniem.
EDYCJA 3: Zaoszczędź 20 bajtów, zastępując wewnętrzną
for
pętlę mnożeniem łańcucha.źródło
import sys,re
zamiastimport sys;import re
python ~ath.py < program.~ath