Skoro nie mamy dość golfów z ezoterycznym językiem, prawda?
/// - wyraźne ukośniki - to zabawny, mały język oparty na s///
funkcji zastępowania wyrażeń regularnych w słowie Perla. Zawiera tylko dwa znaki specjalne, ukośnik /
i ukośnik odwrotny \
. Pełny artykuł na ten temat można znaleźć na wiki esolangs , ale odtworzę opis języka poniżej, a także kilka przykładów.
Krótko mówiąc, działa poprzez identyfikację /pattern/repl/rest
w programie i dokonanie podstawienia tyle razy, ile to możliwe. Żadne znaki nie są wyjątkowe, z wyjątkiem /
i \
: /
wyznacza wzory i zamienniki w programie, a jednocześnie \
pozwala wstawiać literały /
lub \
znaki w kodzie. W szczególności nie są to wyrażenia regularne, tylko zwykłe podstawienia ciągów.
Wyzwanie polega na stworzeniu interpretera dla języka ///, jako programu odczytującego STDIN lub funkcji przyjmującej argument ciągu, w jak najmniejszej liczbie znaków.
Możesz używać dowolnego języka oprócz samego ///. Nie wolno używać bibliotek, które interpretują ///; możesz jednak użyć wyrażeń regularnych, bibliotek wyrażeń regularnych lub bibliotek dopasowujących ciągi znaków.
Wykonanie
Istnieją cztery stany: druk , wzór , zamiana i zamiana . W każdym stanie oprócz substytucji :
- Jeśli program jest pusty, wykonywanie zostaje zatrzymane.
- W przeciwnym razie, jeśli pierwszym znakiem jest
\
, zrób coś z następnym znakiem (jeśli jest obecny) i usuń oba z programu. - W przeciwnym razie, jeśli pierwszym znakiem jest
/
, usuń go i przejdź do następnego stanu. - W przeciwnym razie zrób coś z pierwszym znakiem i usuń go z programu.
- Powtarzać.
Stany przechodzą kolejno przez drukowanie , wzór , zastępowanie i zastępowanie w kolejności.
- W trybie drukowania „zrób coś” oznacza wypisanie znaku.
- W trybie wzorca „zrób coś” oznacza dodanie znaku do bieżącego wzorca.
- W trybie zastępczym „zrób coś” oznacza dodać znak do bieżącej zamiany .
W trybie zastępczym przestrzegasz innego zestawu zasad. Wielokrotnie zastępuj pierwsze wystąpienie bieżącego Wzorca bieżącym Zastąpieniem w programie, dopóki nie będzie już możliwe zastąpienie. W tym momencie wyczyść wzór i zamiennik i wróć do trybu drukowania .
W programie /foo/foobar/foo foo foo
dzieje się:
/foo/foobar/foo foo foo
foo foo foo
foobar foo foo
foobarbar foo foo
foobarbarbar foo foo
...
Zapętla się na zawsze i nigdy nie wychodzi z trybu zastępowania . Podobnie, jeśli wzorzec jest pusty, to pierwsze wystąpienie pustego ciągu - na początku programu - zawsze pasuje, więc tryb podstawiania zapętla się na zawsze, nigdy się nie zatrzymując.
Przykłady
no
Wyjście: no
.
/ world! world!/Hello,/ world! world! world!
Wyjście: Hello, world!
.
/foo/Hello, world!//B\/\\R/foo/B/\R
Wyjście: Hello, world!
.
a/ab/bbaa/abb
Wyjście: a
. Program się nie zatrzymuje.
//
Wyjście: brak.
///
Wyjście: brak. Program się nie zatrzymuje.
/\\/good/\/
Wyjście: good
.
Na wiki znajduje się również quine, którą możesz wypróbować.
źródło
/-/World//--/Hello//--W/--, w/---!
Czego nie kochać? (Spróbuj usunąć myślniki od końca)\
Postać ucieka każdej następującej po niej postaci, w tym/
, która później może być używana normalnie. Chociaż nie wygląda to zbyt wiele, powoduje to, że /// Turing jest kompletny .///
IDE, które tworzę!Odpowiedzi:
APL (133)
Jest to funkcja, która przyjmuje
///
kod za właściwy argument.Bez golfa, z wyjaśnieniem:
źródło
///
i//foo/
pętle na zawsze)?/
nadal pozostałyby w tym momencie.J -
181190170 znakówTo był koszmar. Przepisałem go od zera, dwa razy, bo mnie to ciągle wkurzało. Jest to funkcja pobierająca argument z pojedynczym ciągiem, wysyłająca dane do STDOUT.
Aby wyjaśnić, podzielę to na podwyrażenia.
i
(skrót od iterate ) to przysłówek. Przyjmuje argument czasownika po lewej stronie i zwraca czasownik(f)i
, który po zastosowaniu do argumentu stosuje sięf
wielokrotnie do argumentu, dopóki nie wydarzy się jedna z dwóch rzeczy: znajdzie on stały punkt (y = f y
) lub zgłasza błąd. Zachowanie stałym punktem jest nieodłącznym^:_
i::]
czyni obsługę błędów.parse
tokenizuje dane wejściowe do formy, którą nazywam półparsowaną , a następnie odcina ją w nieokreślonym „/”. Łączy ucieczkowe ukośniki z ich postaciami, ale nie pozbywa się ukośników odwrotnych - więc możemy je cofnąć lub zakończyć w zależności od tego, czego chcemy.Większość interesujących prac występuje w
;:
. Jest to prymitywny interpreter maszyn sekwencyjnych, zawierający opis maszyny ((0;(0,:~1 0,.2);'\';&<1 0)
) po lewej stronie i coś do analizy po prawej. To powoduje tokenizację. Zwrócę uwagę, że ta konkretna maszyna faktycznie traktuje pierwszy znak jako niespecjalny, nawet jeśli jest to\
i powinien się związać. Robię to z kilku powodów: (1) tablica stanu jest prostsza, więc można grać w golfa dalej; (2) możemy z łatwością dodać atrapę z przodu, aby uniknąć problemu; oraz (3) ta postać-manekin zostaje przeanalizowana do połowy bez dodatkowych kosztów, więc mogę użyć jej do przygotowania do fazy cięcia.Używamy również
<;._1
do wycinania tokenizowanego wyniku na nieskalowanym/
(który wybrałem jako pierwszy znak). Jest to przydatne do wyciągania wyjścia, wzorca i zamiany zeout/patt/repl/rest
wszystkich w jednym kroku, ale niestety również tnie resztę programu, gdzie potrzebujemy,/
aby pozostały nietknięte. Łączę je z powrotem podczaseval
, ponieważ<;._1
pozostawienie ich w spokoju kosztuje znacznie więcej.Widelec
(eval [ print)
wykonujeprint
wynik zparse
jego efektów ubocznych, a następnie uruchamia sięeval
.print
jest prostym czasownikiem, który otwiera pierwsze okno (ten, który na pewno wiemy, jest wyjściem), kończy parsowanie i wysyła je do STDOUT. Korzystamy również z okazji, aby zdefiniować czasownik użytkowyp
.p
jest zdefiniowany jako>@{.@[
, więc bierze lewy argument (działa jak tożsamość, jeśli podano tylko jeden argument), bierze pierwszy element tego (tożsamość, gdy podano skalar) i rozpakowuje go (tożsamość, jeśli jest już rozpakowany). Będzie to bardzo przydatnesub
.eval
ocenia pozostałą część przetworzonego programu. Jeśli nie mamy pełnego wzorca lub pełnego zamiennika,eval
wyrzuca go i po prostu zwraca pustą listę, która kończy ocenę, popełniając błąd;:
(odparse
) przy następnej iteracji. W przeciwnym razie weval
pełni analizuje wzorzec i zamiennik, koryguje pozostałą część źródła, a następnie przekazuje oba dosub
. Przez wybuch:sub
ma miejsce jedna (być może nieskończona) runda podstawień. Ze względu na sposób konfiguracjieval
źródło jest właściwym argumentem, a wzorzec i zamiennik są zgrupowane po lewej stronie. Ponieważ argumenty są uporządkowane w ten sposób i wiemy, że wzorzec i zamiana nie zmieniają się w ciągu rundy podstawień, możemy użyć innej funkcjii
- faktu, że modyfikuje tylko właściwy argument i wciąż przesyła ten sam lewy - do delegowania J trzeba martwić się o śledzenie stanu.Istnieją jednak dwa problemy. Po pierwsze, czasowniki J mogą mieć co najwyżej dwa argumenty, więc nie mamy łatwego sposobu na dostęp do tych, które są spakowane razem, takich jak wzorzec i zamiana, tutaj. Dzięki sprytnemu użyciu
p
zdefiniowanego przez nas narzędzia nie stanowi to większego problemu. W rzeczywistości możemy uzyskać dostęp do wzorca w jednym znaku, po prostu używającp
, ze względu na jego>@{.@[
definicję: Unbox pierwszego elementu Left arg. Uzyskanie zastępstwa jest szybsze, ale najkrótszą drogą byłobyp&|.
, 2 znaki krótsze niż ręczne wyciągnięcie go.Drugi problem polega na tym, że
i
kończy się na stałych punktach zamiast zapętlać na zawsze, a jeśli wzorzec i zamiana są równe i dokonujesz podstawienia, wygląda to na stały punkt na J. Zajmujemy się tym, wprowadzając nieskończoną pętlę negacji 1 ponad i skończymy, jeśli wykryjemy, że są równe: to-i@=`p@.~:~/
część zastępującap&|.
.Cykl ten powtarza się z powodu użycia
i
, aż do momentu wykrycia czegoś pozasub
błędami. O ile mi wiadomo, może się to zdarzyć tylko wtedy, gdy brakuje nam postaci lub wyrzucamy niekompletny zestaw wzorców i zamienników.Zabawne fakty na temat tego golfa:
;:
jest krótsze niż ręczne iterowanie ciągu.0{
powinien mieć szansę na błąd, zanimsub
przejdzie do nieskończonej pętli, więc powinno działać dobrze, jeśli wzorzec pasuje do zamiennika, ale nigdy nie pojawia się w pozostałej części źródła. Jednak może to być, ale nie musi, nieokreślone zachowanie, ponieważ nie mogę znaleźć żadnego cytatu w dokumentach. Whoopsie.i
błędy te również zostają uwięzione. W zależności od tego, kiedy naciśniesz Ctrl + C, możesz:sub
pętli, próbując połączyć liczbę z ciągiem, a następnie kontynuuj interpretację ///, jakbyś zakończył podstawianie łańcucha nieskończoną liczbę razy.sub
połowie i kontynuuj interpretację wyrażenia / sub-subbed ///.Przykładowe użycie:
źródło
/\\/good/\/
przypadku testowego; debugowanie mówi mi, że problemem jest moje użycie1!:2&4
, ponieważ jqt nie ma standardowego wejścia / wyjścia. Zbada. Jakie są twoje9!:12''
i9!:14''
?9!:12''
ma 6 lat i9!:14''
jest j701 / 2011-01-10 / 11: 25.Perl - 190
Czyta
///
program od standardowego wejścia do EOF.źródło
m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/s
naraz - takie same wyniki, wzorzec i zamiana - wszystko na raz - stanowiłoby krótszy golf? Sam nie znam żadnego Perla./a/\0/a
Pip ,
100102 bajtówNigdy nie udowodniłem, że Pip jest kompletny w Turinga (choć jest to całkiem oczywiste), i zamiast iść zwykłą drogą BF, pomyślałem, że /// będzie interesujący. Kiedy już znalazłem rozwiązanie, pomyślałem, że zagram w golfa i opublikuję tutaj.
101 bajtów kodu, +1 dla
-r
flagi:Oto moja nie golfowa wersja z obfitymi komentarzami:
Wypróbuj online! (Zauważ, że TIO nie daje żadnych danych wyjściowych, gdy program się nie kończy, a także ma limit czasowy. W przypadku większych przykładów i nieskończonych pętli zaleca się uruchomienie Pip z wiersza poleceń.)
źródło
pip + -r
101 bajtówC ++: Visual C ++ 2013 = 423, g ++ 4.9.0 = 442
To nigdy nie wygra, ale odkąd zdecydowałem, że wszystkie moje przyszłe projekty oprogramowania zostaną napisane w tym niesamowitym języku, potrzebowałem do tego tłumacza i pomyślałem, że równie dobrze mogę podzielić się tym, który zrobiłem ...
Różnica w wynikach polega na tym, że Visual C ++ nie potrzebuje pierwszego dołączenia, ale g ++ tak. Wynik zakłada, że zakończenia linii liczą się jako 1.
źródło
if(!o[i]);
jakoif(P
, aby zapisać znaki, albo ja nieporozumienie jak #define działa?P
inmain
ma po nim spację, więc możesz zapisać postać, zastępując je spacjami średnikami i usuwając je#define
. Następnie, jeśli możesz użyć#define
s wewnątrz innych, możesz zaoszczędzić trochę więcej, przepisującN(x)
jako(92==P
zamiasto[i]==92
iO
podobnie.N(x)
jakP;else if(n<x)(P==92?
i zmiana połączeń doN
odpowiednio mógłby zaoszczędzić kilka bajtów.Python 2 (236), Python 3 (198?)
Nazywany jako
d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R""")
. Potrójne cytaty są potrzebne tylko wtedy, gdy///
program zawiera znaki nowej linii: w przeciwnym razie proste cytaty są w porządku.EDYCJA: Ten interpreter drukuje teraz rzeczy zgodnie z oczekiwaniami (poprzednio drukowane tylko na samym końcu, patrz komentarze). W przypadku Python 3 usuń pierwszy wiersz (ale nie mam Python 3 na mojej starożytnej instalacji, więc nie mogę się upewnić, że nie ma innych zmian).
źródło
/a/ab/bbaa/abb
./a/ab/bbaa/abb
utknie w nieskończonej pętli bez drukowania czegokolwiek, ponieważ pierwszą substytucją jesta
=>ab
. Prawidłowea/ab/bbaa/abb
działa zgodnie z reklamą.-u
aby wymusić buforowanie bufora wyjściowego.Kobra - 226
źródło
Rubin ,
119110 bajtówKończy się z wyjątkiem
Wypróbuj online!
Kończy się czysto (116 bajtów)
Wypróbuj online!
źródło
Python 2/3 (211 bajtów)
Poniższy kod, oparty na odpowiedzi Bruno Le Flocha , jest zgodny z Python 2 i Python 3.
Co więcej, ponieważ jest iteracyjny, a nie rekurencyjny, nie ryzykuje osiągnięcia maksymalnej głębokości rekurencji w Pythonie.
źródło
in(0,1,2)
w golfa doin 0,1,2
i[""]*2+[1]
do["","",1]
, co daje 211 bajtów .BaCon ,
391387395 bajtówZ materiałów zamieszczonych na tej stronie mam tylko program Python do pracy. Inne działają dla niektórych próbek /// lub w ogóle nie działają. Dlatego zdecydowałem się dodać moją wersję, która jest implementacją w języku BASIC.
Udział w konkursie CodeGolf z BASICem nie jest łatwy, ponieważ BASIC używa długich słów jako oświadczeń. Jedynym skrótem powszechnie występującym w języku BASIC jest „?” znak, co oznacza DRUKUJ.
Poniższy program może nigdy nie wygrać, ale przynajmniej działa z całym kodem demonstracyjnym na tej stronie Codegolf i na Wiki Esolangs . W tym wszystkie wersje „99 butelek piwa”.
źródło