Twoje wyzwanie jest proste. Napisz dwa programy, które nie mają wspólnych znaków.
Przykład
Dwa programy P i Q wzajemnie się wykluczają, jeżeli:
- P wyjścia Q
- Wyjścia Q P
- Nie ma znaku c, który należy zarówno do P, jak i Q
- Każdy program P i Q są odpowiednimi quinesami
- Liczone są puste znaki i znaki, które czytają własny (lub inny) kod źródłowy jako niepoprawny .
Więcej zasad
- Wygrywa najkrótsza łączna długość tych programów. Oznacza to, że rozmiar ( P ) + rozmiar ( Q ) to Twój wynik, a najniższy wynik wygrywa.
- Oba programy są w tym samym języku
- Każdy program może być pełnym programem lub funkcją i nie musi być taki sam.
- Na przykład P może być pełnym programem, a Q może być funkcją.
Weryfikacja
Ten Spróbuj online! Snippet tutaj może sprawdzić, czy dwa programy wykluczają się wzajemnie. Dane wejściowe są umieszczane w pierwszych dwóch argumentach.
code-challenge
quine
Conor O'Brien
źródło
źródło
Odpowiedzi:
> <> , Wynik: 41 + 41 = 82
Edycja: oba zawierały 3. Naprawiono
i
Wypróbuj online! (zamień linie, aby uzyskać inne wyjście) Tym razem z weryfikacją!
><>
jest tutaj szczególnie trudnym językiem, ponieważ istnieje tylko jeden sposób na wyprowadzenie znaków - polecenieo
. Na szczęście możemy użyć polecenia p ut, aby umieścićo
kod źródłowy podczas wykonywania, tak jak w mojej odpowiedzi „ Programowanie w nieskazitelnym świecie” .Ten wymagał wielu prób i błędów. Zacząłem od dwóch wzajemnie wykluczających się programów:
i
Każdy transformuje siebie i swoje dane przez N, pierwszy odejmuje, a drugi dodaje. Następnie wysyła to w odwrotnej kolejności. Chodzi o to, że dane po każdym programie jest inny program w odwrotnej, przesunięty przez N. (
X
jest to liczba komórek, gdzie potrzeby programu, aby umieścićo
i Y jest komórka, gdzie wskaźnik pętle z powrotem.?
Gdzie jesto
to put) .Oba mają tę samą strukturę, reprezentowaną na różne sposoby. Działają one dosłownie na całym łańcuchu, dodając go do stosu. Odtworzyli używane przez siebie dosłowne ciągi znaków i umieścili je na dole stosu. Zapętlają stos, dodając / odejmując N do każdego znaku i drukując je.
Pierwszy program używa
'
literału ciągów, a prostyd3*}
do utworzenia wartości 39 i wypchnięcia jej na dół stosu. Drugi używa"
jako literału ciąg z tą samą funkcją. Tor
everses stos,g
ETS znak w komórce 0,0 i odwraca stos ponownie. Następnieg
przyjmuje wartość do komórki 4,0 (g
) i dodaje 8, aby ją pobrać,o
i umieszcza ją w X.Oba programy używają innej metody zapętlania. Pierwszy program używa komendy skip (
!
) do uruchomienia tylko połowy instrukcji podczas jazdy w lewo, odwraca kierunek i uruchamia drugą połowę. Drugi używa polecenia skoku (.
), aby przejść wstecz do początku pętli w komórce Y. Oba działają, dopóki na stosie nie będzie więcej elementów i nie wystąpią błędy programu.Wpadłem na wiele problemów z większością niższych wartości N, ponieważ przesunięcie jednego znaku zmieniłoby go w inny znak niezbędny dla tego programu (i dlatego nie mógłby być użyty jako dane dla innego programu) lub dwóch znaków z dwa programy zmieniłyby się w tę samą postać. Na przykład:
+
+1 =,
=-
-1.
+2 =0
*
=-
-3g
+4 =k
=o
-4itp.
W końcu dotarłem do 10 (
a
), gdzie mogłem uniknąć tych problemów. Może istnieć krótsza wersja, w której przesunięcia są odwrócone, a pierwszy program dodaje N, a drugi go odejmuje. Może być jednak gorzej, ponieważ pierwszy program znajduje się ogólnie w dolnej części skali ASCII, więc odejmowanie jest lepsze, aby uniknąć konfliktów.źródło
Dalej (64-bitowy little-endian gforth) , 428 + 637 = 1065 bajtów
Wypróbuj online!
Skrypt weryfikacyjny
Dzięki @Nathanielowi za pomysł użycia Fortha - przypomniał mi w komentarzach, że Forth nie rozróżnia wielkości liter . Potem nastały wahania nastroju - znajdowałem powody, dla których to nie zadziałało, a następnie wielokrotnie rozwiązywałem te problemy. Wszystko to podczas kręcenia moim treningowym rowerem treningowym jak obustronny i zniekształcony fidget spinner (wystarczy chwycić jeden koniec kierownicy i lekko go przechylić).
Przed napisaniem tych programów opracowałem, jakie znaki mogą być używane przez dany program. W szczególności drugi program może używać tylko wielkich liter, cyfr dziesiętnych, tabulatorów i przecinków. Oznaczałoby to, że pierwszy program składa się wyłącznie z małych liter, ale użyłem kilku wielkich liter dla ich wartości ASCII.
Ponieważ tabulatory są nieporęczne, zamiast tego użyję spacji w objaśnieniu.
Pierwszy program ma formę
s" code"code
-s"
zaczyna literał ciąg, który jest następnie przetwarzany przez drugą kopię kodu - standardową strukturę quine. Jednak zamiast wypisywać własny kod źródłowy, utworzy inny program, który wygląda następująco:HERE
64-bit-number-literal ,
length-of-the-string
115 EMIT 34 EMIT 9 EMIT 2DUP TYPE 34 EMIT TYPE
To wykorzystuje przestrzeń danych Fortha.
HERE
zwraca wskaźnik na koniec aktualnie przydzielonego obszaru przestrzeni danych i,
dołącza do niego komórkę wypełnioną liczbą. Dlatego pierwsze trzy punkty wypunktowania można traktować jak dosłowny ciąg utworzony za pomocąs"
. Aby zakończyć drugi program:EMIT
wypisuje znak ze względu na jego wartość ASCII, więc:115 EMIT
drukuje małe literys
34 EMIT
drukuje znak zapytania"
9 EMIT
drukuje zakładkę2DUP
duplikuje dwa górne elementy na stosie( a b -- a b a b )
, tutaj jest to wskaźnik do i długość łańcuchaTYPE
wypisuje ciąg, aby wypisać pierwszą kopię kodu34 EMIT
drukuje cytat końcowy"
i na koniecTYPE
wypisuje drugą kopię koduZobaczmy, jak działa pierwszy program. W wielu przypadkach należy unikać liczb, co odbywa się za pomocą
'x
rozszerzenia składni gforth dla literałów znaków, a czasami odejmując wartość ASCII spacji, którą można uzyskać za pomocąbl
:Aby to zakończyć, chciałbym powiedzieć, że próbowałem użyć
EVALUATE
, ale drugi program staje się większy niż oba przedstawione powyżej. W każdym razie tutaj jest:Jeśli uda ci się zagrać w golfa na tyle, by prześcignąć moje
s" ..."...
podejście, śmiało i opublikuj to jako własną odpowiedź.źródło
Perl,
(311 + 630 = 941 bajtów)190 + 198 = 388 bajtówOba programy drukują na standardowe wyjście.
Pierwszy program perla zawiera głównie drukowalne znaki ASCII i znaki nowej linii i kończy się dokładnie jedną nową linią, ale dwie litery ÿ oznaczają bajt inny niż ASCII \ xFF:
Drugi zawiera w większości bajty spoza ASCII, w tym kilka znaków o wysokiej kontroli, które są zastąpione gwiazdkami w tym poście i nie ma w nich żadnych znaków nowej linii:
Zrzut heksowy pierwszego programu z
xxd
:A zrzut heksadru drugiego programu to:
W drugim programie cytowany ciąg znaków (długość 189 bajtów, rozdzielany znakami tyldy) jest całym pierwszym programem z wyjątkiem ostatniego nowego wiersza, zakodowanego jedynie bitowo, uzupełniając każdy bajt. Drugi program po prostu dekoduje ciąg, uzupełniając każdy z bajtów, co
~
robi operator w perlu. Program drukuje zdekodowany ciąg, po którym następuje nowa linia (say
metoda dodaje nową linię).W tej konstrukcji dekoder drugiego programu wykorzystuje tylko sześć różnych znaków ASCII, więc pierwszy program może być praktycznie dowolny, o ile zawiera tylko znaki ASCII i wyklucza te sześć znaków. Nie jest trudno napisać program perlowy bez użycia tych pięciu znaków. Rzeczywista logika quine znajduje się zatem w pierwszym programie.
W pierwszym programie logika quine używa słownika o długości 11 słów
@f
i łączy dane wyjściowe z tych słów. Pierwsze słowa powtarzają większość kodu źródłowego pierwszego programu. Reszta słów to określone pojedyncze znaki. Na przykład słowo 5 jest tyldą, która jest ogranicznikiem dwóch literałów łańcuchowych w drugim programie. Lista liczb w nawiasach to przepis na słowa, które należy wydrukować w jakiej kolejności. Jest to dość zwyczajna ogólna metoda konstruowania quinów, jedyną niespodzianką w tym przypadku jest to, że pierwsze słowa słownika są drukowane z bajtami uzupełnianymi bitowo.źródło
Haskell , 306 + 624 = 930 bajtów
Program 1: Anonimowa funkcja przyjmująca fikcyjny argument i zwracająca ciąg znaków.
Wypróbuj online!
Program 2:
q[[40,...]]
na końcu jest anonimowa funkcja przyjmująca fikcyjny argument i zwracająca ciąg znaków.Wypróbuj online!
Zestaw znaków 1 (zawiera spację):
Zestaw znaków 2 (zawiera nowy wiersz):
Ponieważ tylko zestaw 1 zawiera znaki spoza ASCII, ich bajty UTF-8 są również rozłączne.
Jak to działa
Program 1 jest ogólnie napisany z wyrażeniami lambda, spacjami i nawiasami, swobodnym użyciem wbudowanych funkcji alfanumerycznych oraz danymi quine jako literałami łańcuchowymi na końcu.
a
lubb
, które tworzą prawidłowe sekwencje specjalne, które przechodzą w drugą stronęshow
.a
,b
ic
są tylko małe litery, których kody ASCII są mniej niż 100, oszczędzając cyfra w kodowaniu liczbowej wykorzystywanego przez program 2.Program 2 jest na ogół napisany z równaniami funkcji najwyższego poziomu (z wyjątkiem ostatniego anonimowego), literałami znaków i liczbami dziesiętnymi, składnią list / zakresu i operatorami, a także danymi quine jako listą
Int
s na końcu.Przewodnik, program 1
b
ic
są wartościami literałów łańcuchowych odpowiednio dla programu 2 i 1, podanymi jako ostateczne argumenty wyrażenia lambda.()
jest fikcyjnym argumentem mającym jedynie na celu spełnienie zasady PPCG, zgodnie z którą program powinien definiować funkcję.foldr(\a->map pred)b(show()>>c)
dekoduje ciągb
do kodu podstawowego programu 2, stosującmap pred
do niego liczbę razy równą długościshow()>>c == c++c
lub182
.tail(show c)
konwertuje ciągc
do kodu podstawowego programu 1, dołączając końcowy podwójny cudzysłów.:pure b
łączy to na liście z ciągiem znakówb
.map(map fromEnum)$
konwertuje ciągi znaków na listy punktów kodowych.`mappend`show(...)
serializuje wynikową listę list i ostatecznie dołącza ją do podstawowego kodu programu 2.Przewodnik, program 2
z~z=[[['@','0'..]!!4..]!!z]
to funkcja konwertująca punkty kodowe z powrotem na znaki (konieczne do napisania, ponieważ nie wszystkie znakitoEnum
są dostępne).z
. Znacznik lenistwa~
nie działa w tej pozycji, ale unika znaku spacji.['@','0'..]
jest zakresem wstecznej listy kroków, zaczynając od kodu ASCII 64, a następnie zeskakując 16 w dół na każdym kroku.!!4
do tego nadaje\NUL
charakter.[ ..]
zakresie daje listę wszystkich znaków, które!!z
indeksuje.z
na listach przy użyciu=<<
zamiast niedostępnychmap
i<$>
.q[x,q]_=z=<<x++q++[34,34]++x
to funkcja konstruująca program 1 z listy danych quine.x
to dane dla rdzenia programu 1 (w tym końcowy podwójny cudzysłów), a wewnętrznaq
to zaciemnione dane dla rdzenia programu 2._
to kolejny fałszywy argument wyłącznie po to, aby końcowa anonimowa funkcja była funkcją zamiast tylko łańcucha.x++q++[34,34]++x
łączy elementy, w tym dwa znaki podwójnego cudzysłowu z kodem ASCII 34.z=<<
konstruuje program 1 poprzez odwzorowaniez
konkatenacji w celu konwersji punktów kodowych na znaki.q[[40,...]]
to anonimowa funkcja łącząca sięq
z danymi quine.źródło
Galaretka ,
128 90 87 86 85 7916 + 32 = 48 bajtówWypróbuj online!
Wypróbuj online!
Pierwszy program wykonuje następujące czynności:
Pozostawia to łańcuchy
79,7806,8318,7885,7769,338,115
iỌṘ
jako dwa argumenty łańcucha, które są domyślnie konkatenowane i drukowane na końcu.Drugi program oblicza
chr
(Ọ
) z listy liczb, które zwracaOṾ⁾ọṙŒs
.Ṙ
wypisuje“OṾ⁾ọṙŒs”
(z cudzysłowami) i zwraca dane wejściowe, pozostawiając“OṾ⁾ọṙŒs”OṾ⁾ọṙŒs
jako pełne dane wyjściowe.źródło
Gol> <> ,
23 + 23 = 4622 + 22 = 4420 + 20 = 40 bajtówWypróbuj online!
Wypróbuj online!
Sprawdź to online!
Jak oni pracują
Na podstawie odpowiedzi Jo King> <> . Mając o wiele więcej alternatywnych poleceń dla wyjścia i powtarzania, nie było potrzeby
g
lubp
, a dwa główne ciała stały się znacznie krótsze.Inna główna różnica polega na tym, że generuję ofertę przeciwnika bezpośrednio na górze stosu. W ten sposób nieco łatwiej było utrzymać niezmiennik
quote + my code + opponent code(reversed and shifted)
.źródło