To jest Tygodniowe Wyzwanie # 2. Temat: Tłumaczenie
Napisz program lub funkcję, która pobiera kod źródłowy dla programu w Preludium i wypisuje kod dla równoważnego programu w Befunge-93 . Aby program był równoważny, powinien, dla dowolnego wejścia, generować takie same dane wyjściowe jak program Preludium i zatrzymywać się wtedy i tylko wtedy, gdy program Prelude zatrzyma się.
Język wprowadzania: Preludium
Tłumacz języka Python:
Program Preludium składa się z wielu „głosów”, które wykonują instrukcje jednocześnie. Instrukcje dla każdego głosu znajdują się w osobnej linii. Każdy głos ma osobny stos, który jest inicjowany nieskończoną ilością zer. Egzekucja rozpoczyna się od lewej kolumny i przesuwa o jedną kolumnę w prawo po każdym tiku, chyba że wpływ )
lub (
instrukcje. Program kończy się po osiągnięciu ostatniej kolumny.
Preludium dla tego wyzwania:
Digits 0-9 Push onto the stack a number from 0 to 9. Only single-digit
numeric literals can be used.
^ Push onto the stack the top value of the stack of the above
voice.
v Push onto the stack the top value of the stack of the below
voice.
# Remove the top value from the stack.
+ Pop the top two integers from the stack and push their sum.
- Pop the top two integers from the stack, subtract the topmost
from the second, and push the result.
( If the top of the stack is 0, jump to the column after the
matching `)` after the current column executes.
) If the top of the stack is not 0, jump to the column after
the matching `(` after the current column executes.
? Read an integer from STDIN.
! Pop one value from the stack and print it to STDOUT as an
integer.
<space> No-op
Notatki
v
i^
działają cyklicznie, więcv
głos dolny skopiuje element stosu głosu górnego, a^
głos górny skopiuje głos dolny. Następstwo: Zarównov
i^
duplikuj górę stosu w programie z jednym głosem.- A
(
i jego dopasowanie)
może znajdować się na różnych liniach. Jednak a)
zawsze będzie patrzeć na stos głosu, w którym(
został umieszczony odpowiedni, a nie na stos, na którym)
umieszczony jest sam. - Wartości wygenerowane przez instrukcje
^
iv
działają na wartościach obecnych przed zakończeniem jakichkolwiek innych operacji w tej samej kolumnie. ?
i!
działają inaczej niż specyfikacja znaleziona na stronie esolangs.org, więc koniecznie przetestuj nieco zmodyfikowany interpreter podany w tym poście.
Gwarantowane wejście ma:
- Pasujące nawiasy
- Nie więcej niż jeden nawias w kolumnie
- Ta sama liczba znaków w każdej linii
- Co najmniej jedna linia
- Brak kolumny z więcej niż jedną instrukcją We / Wy (
!
lub?
) - Jeden znak kanału po instrukcjach dla każdego głosu
- Żadnych znaków innych niż wymienione powyżej
Język wyjściowy: Befunge-93
Befunge jest językiem stosowym, którego licznik programów (PC; wskaźnik do bieżącej instrukcji) porusza się swobodnie na dwuwymiarowej siatce. Zaczyna się w lewym górnym rogu, przesuwając w prawo. Pole gry jest toroidalne, tzn. Ruch PC owija się wokół obu krawędzi. Befunge ma również stos, który jest inicjowany do nieskończonej liczby zer. Befunge ma następujące operacje:
Możesz założyć następujące cechy kompilatora / interpretera Befunge-93:
- Liczby całkowite są nieograniczoną precyzją.
- Umożliwia siatki o dowolnym rozmiarze.
- Współrzędne siatki (dla
g
ip
) są oparte na 0.
Punktacja
Aby zapobiec przesyłaniu, które po prostu tworzą interpreter Preludium w Befunge i zakoduje w nim źródło Prelude, celem będzie zminimalizowanie rozmiaru wynikowego kodu źródłowego Befunge.
Poniżej podano kilka programów Preludium. Twój tłumacz będzie działał na wszystkich tych urządzeniach. Twój wynik jest sumą rozmiarów programów Befunge, pod warunkiem, że wszystkie są ważne.
Twój tłumacz nie powinien być zoptymalizowany specjalnie pod kątem tych przypadków testowych (np. Przez zakodowanie dla nich ręcznie napisanych programów Befunge). Jeśli podejrzewam jakąkolwiek odpowiedź, zastrzegam sobie prawo do zmiany danych wejściowych lub tworzenia dodatkowych.
Przykładowe dane wejściowe
Wydrukuj n-1
do 0
:
?(1-^!)
Logiczne ORAZ:
? (0)
?(0 )
1 !
Logiczne LUB:
? (0)
? (0)
1 1 !
Sprawdź parzystość wejścia (tj. Moduł 2) liczby nieujemnej:
?(1-)
^ v
v1-^^-!
Kwadrat wejściowy:
^
^+ !
?(1-)
Wydrukuj n- ty numer Fibonacciego, gdzie n = 0
odpowiada 0 i n = 1
odpowiada 1:
0 v+v!
1 ^
?(1-)
Signum:
1) v # - !
vv (##^v^+)
?(# ^ ##
Podział na dane nieujemne:
1 (# 1) v # - 1+)
vv (##^v^+)
? v-(0 # ^ #
?
1+ 1-!
Oczywiście, twój program musi wykazywać to samo zachowanie dla wszystkich przypadków, nawet jeśli zachowanie przykładowego programu dla liczb ujemnych nie jest określone.
Twój tłumacz nie powinien być zbyt długi:
- Musi być zawarty w poście stosu wymiany
- Powinien przetworzyć przykładowe dane wejściowe w niecałe 10 minut na typowym komputerze stacjonarnym.
Zauważ, że dane liczbowe dla Preludium lub Befunge są podawane jako opcjonalny znak minus, po którym następuje jedna lub więcej cyfr dziesiętnych, a następnie nowa linia. Inne dane wejściowe to niezdefiniowane zachowanie.
Możesz napisać tłumacza w dowolnym języku. Najkrótszy przetłumaczony kod Befunge wygrywa.
Tabela liderów
- Sp3000 : 16430 bajtów
1
Jest w pętli, więc nie można go popychać . 0 może pochodzić z nieskończonej liczby zer, które zaczynają się na stosach.Odpowiedzi:
Python 3, zdobędzie później
Biegnij jak
py -3 prefunge.py <input filename> <output filename>
.To był dla mnie powolny tydzień, więc w końcu nudziłem się, by odpowiedzieć na to sześciomiesięczne pytanie. Zapytałbym, dlaczego nikt inny nie próbował, ale wciąż odczuwam ból podczas debugowania (i prawdopodobnie nadal pozostały błędy).
Pytanie nie zapewnia interpretera Befunge-93, więc użyłem tego , który nieco różni się od specyfikacji. Dwie kluczowe różnice to:
Jeśli znak nie istnieje w danym wierszu programu, nie możesz pisać do tego wiersza. Oznacza to , że musisz nacisnąć Enter kilka razy, aby na końcu wprowadzić wystarczającą liczbę nowych linii . Jeśli widzisz
NaN
s na wyjściu, jest to najbardziej prawdopodobna przyczyna.Komórki siatki nie są wstępnie inicjowane do zera - dla wygody umieściłem trochę wstępnej inicjalizacji w wynikach Befunge, ale ponieważ nie jest to konieczne, mogę to zabrać, gdy zacznę punktować.
Podstawowy układ programów wyjściowych jest następujący:
Miejsce na stosie znajduje się poza programem, stąd nowy wiersz komentarza Enter-spam z wcześniejszego.
Podstawową ideą jest przypisanie każdemu głosowi wiersza, który służy jako jego stos. Aby zachować te stosy, mamy również specjalny rząd długości stosu, w którym długość każdego stosu jest rejestrowana w komórce wzdłuż tego rzędu. Program zawiera wtedy wiele
g
ets ip
uts, np. Do drukowania proces to:y = stack_row[stack], x = stack_length[stack]
.91+,
, tj. Wydrukuj jako liczbę całkowitą, a następnie wydrukuj nowy wierszstack_length[stack]
Aby wykonać jednoczesną ocenę kolumny, wszystkie niezbędne komórki są odczytywane, a ich wartości są przechowywane na stosie przed zapisaniem jakichkolwiek komórek (np. W przykładzie drukowania może być więcej instrukcji pomiędzy pierwszym a drugim krokiem).
`
, który jest większy niż, służy do upewnienia się, że długości stosu nigdy nie są ujemne, oraz do wypychania zer, gdy stos jest pusty. Stąd pochodzi wyraźnie widoczne rozgałęzienie, ale mam pomysł, który usunie rozgałęzienie, które powinno usunąć sporo białych znaków z pierwszego i trzeciego wiersza.W przypadku pętli, ponieważ pętle Prelude mogą przeskakiwać w obie strony, używamy dwóch wierszy na pętlę w konfiguracji takiej jak ta:
Pętle te stanowią obecnie większość bajtów, ale można je łatwo zagrać w golfa, umieszczając je w pudełku kodowym
p
, co planuję zrobić po tym, jak cieszę się, że tłumacz działa poprawnie.Oto kilka przykładowych danych wyjściowych
?(1-^!)
, np. Wydrukujn-1
do0
:Kwadrat wejściowy:
Podział (zalecane są małe nakłady):
Jest też kilka innych drobnych optymalizacji, które przychodzą na myśl, jak zastępowanie
07p07g
z:07p
, ale biorę ten jeden krok na raz :)źródło
Will score later
2 lata i wciąż rośnie! :)