Rebmu : 79 znaków LUB (37 + długość (p1) + 2 * max (długość (p2), długość (p3)))
Najpierw dam 79-znakowe rozwiązanie, które pyta, jakich języków musisz się nauczyć? (entropia 4.0, z wyłączeniem 30 liter ?
) i oferuje sugestie Rebola i [czerwonego] :
DD 11 DD :do dd {dd {p{Which languages must you learn?}qt}} pp{{[RReebdo]l}}
Unikalna taktyka dostępna tutaj, która nie jest w innych językach, wynika z faktu, że nawiasy klamrowe są asymetrycznym ogranicznikiem łańcucha, który może legalnie zagnieżdżać się:
my-string: {"It's cool," said {Dr. Rebmu}, "for MANY reasons--like less escaping."}
To pozwoliło mi stworzyć uogólnione rozwiązanie, które może bez wysiłku działać na każdym programie, który nie używa sekwencji specjalnych. Wersja z 79 znakami była na tyle prosta, że można ją było skrócić, ale aby poprawnie zawierać dowolne źródło programów dla programów p2 i p3, potrzebny byłby pełny szablon. Gdybyśmy tego użyli, byłoby 87 znaków:
DD 11 DD :do dd {dd {p{Which languages must you learn?}qt}} ddoo{{pp{{[RReebdo]l}}}}
Wzorzec używania tej ogólnej formy jest taki, że jeśli masz trzy źródłowe teksty kolejnych znaków o różnych długościach (użyjmy przykładu AAA
:BBBBB
, CCCCCCC
) można zakodować je jako coś wzdłuż linii:
DD 11 DD :do dd {dd {AAAqt}} ddoo{{BCBCBCBCBC C C}}
(Uwaga: Chociaż ten wzorzec nie będzie działał bez poprawiania programów używających znaków zmiany znaczenia, nie jest to poważna wada. Uzyskanie niedopasowanego lewego nawiasu w ciągu ograniczonym nawiasami wymaga czegoś takiego jak {Foo ^{ Bar}
... ale można łatwo przepisać to za pomocą alternatywna notacja strun "Foo { Bar"
i połączone przypadki mogą być zarządzane przez sklejenie ze sobą mieszanki strun nieskalowanych).
Więc ... a może przykład? Po udostępnieniu ogólnej formy, ten program znaków 573 został złożony w zaledwie kilka minut z 3 wcześniejszych rozwiązań golfowych:
DD 11 DD: do dd {dd {rJ N 0% rN Wa1m2j S {\ x /} D00 Hc & [u [Ze? Wa Qs ~ rpKw [isEL00c [skQd2k] [eEV? KQ [tlQ]] pcSeg - b00 [ eZ 1 5] 3] prRJ [si ~ dSPscSqFHs] eZ 1 [s + dCa + wM2cNO]]] Va | [mpAp2j] prSI ~ w { } Ls2w Wl h01tiVsb01n -1 chRVs { } hLceVn01qt}} ddoo {{BrdSz [f] [sn [{N sbeo [tIt0l1eV} 0e5gXN1 01L {5s0} C {1} 0 {0 Do5f0 0bMe1e0r0} 0]]] tMw9C9 Numz Jl [paN + [KperlCJBn [[ba sWS {B noJn Nt]]] {K, j} b P {. } lf EZ - - n [N m {G otothestoreandbuysome more}] {T akeonedownandpasspassitar ound} c B w P lf]]}}
Jeśli ktoś chce spróbować napisać ten program w wybranym przez siebie języku i myśli, że może pokonać 573, daj mi znać. Jeśli to zrobisz, nagrodzę cię dużą reputacją - zakładając, że twoim językiem nie jest Rebmu, ponieważ wiem, że te programy nie są minimalne. :-)
To „marnotrawstwo” odstępów, które dostajesz na końcu, dzieje się, gdy p2 i p3 mają niezrównoważone długości. Ale wszystkie 3 programy mają w tym przypadku różne rozmiary, więc nie ma szczególnie dobrego parowania do wyboru dla p2 / p3. (Wybrałem je, ponieważ nie było danych zewnętrznych jako danych wejściowych, takich jak labirynt itp., Nie dlatego, że miały one podobną długość. Chociaż mogłem napisać nowe programy, które byłyby bardziej optymalne, spędziłem wystarczająco dużo czasu i chodziło o ty nie trzeba pisać nowych programów ...)
Jak to działa
(Uwaga: zacząłem od bardziej „kreatywnego” podejścia, które nie było tak usprawnione, ale bardziej interesujące. Przeniosłem je do wpisu na moim blogu, ponieważ opisywanie tego podejścia jest już długie).
Kluczem tutaj jest sztuczka „eval code as a string”, podobnie jak niektóre inne wpisy, ma ona tylko kartę atutową asymetrycznego ogranicznika łańcucha. Zacznę od wyjaśnienia działania przypadku 80 znaków.
Oto „cały” program, dostosowujący białe znaki do czytelności tego przypadku:
DD 11 ; assign 11 to dd (about to overwrite again)
DD :do ; make dd a synonym for DO (a.k.a. "eval")
; eval a string as source code that ends with QUIT (QT)
dd {dd {p{Which languages must you learn?}qt}}
; we'll never get here, but whatever's here must be legally parseable
pp{{[RReebdo]l}}
Tutaj kończymy ustawianie DD na synonim DO (aka „eval”). Ale sztuczka polega na tym, że gdy uruchomione zostaną połówki programów, uruchamiają kod, którego jedynym efektem jest zdefiniowanie D na nieszkodliwym literale 1.
Oto, co robi kod nieparzystych znaków, ponownie dostosowuje białe znaki:
D 1 ; assign 1 to d
D d ; assign d to itself, so it's still 1
d ; evaluates to integer, no side effect
{d pWihlnugsms o er?q} ; string literal, no side effect
p {Rebol} ; print "Rebol"
A oto kod parzystych znaków:
D 1 ; assign 1 to d
D:od ; URL-literal (foo:...), no side effect
d ; evaluates to integer, no side effect
{{hc agae utyulan}t} ; string literal (well-formed!), no side effect
p {[Red]} ; print "[Red]"
W rzeczywistości w przypadku programu bez połówek program dd {dd {(arbitrary code)qt}}
wykona dowolny kod. Istnieją jednak dwa wezwania do oceny zamiast tylko jednego. Jest tak, ponieważ podczas gdy zagnieżdżone nawiasy klamrowe działają świetnie w przeplecionym kodzie, zaburzają one ewaluacyjne zachowanie DO. Dlatego:
do {{print "Hello"}}
Załaduje ciąg jako program, ale ten program kończy się jako ciąg stały {print "Hello"}
. Zatem sztuczka, której tu używam, polega na wzięciu mojego DD (zachowującego tę samą wartość funkcji co DO) i uruchomieniu go dwa razy. Połówki żują różne części sznurka, ale nie żują obu, jeśli parzystość / nieparzystość jest poprawna dla zawartości, a ponieważ to, co pozostało poza sznurkiem po połówce, jest tylko stałą stałąd
, są nieszkodliwe.
Przy takim wzorcu pisanie zachowania programu nie jest wyzwaniem, gdy nie jest ono przecięte na pół - możesz wstawić wszystko, o ile długość znaków w kodzie jest parzysta (nieparzyste, jeśli liczysz QT, czyli QUIT). Jeśli potrzebujesz uzyskać parzystą liczbę z nieparzystej, wrzuć spację (tak naprawdę w mojej formule powyżej na p1 znajduje się +1 dla nieparzystych długości programu p1) . Wydaje się, że sztuczka polega na napisaniu kodu z przeplotem, który musi przejść przez analizator składni, jeśli nie jest podzielony na pół. (Nie zostanie uruchomiony z powodu QT, ale musi być ŁADOWALNY, zanim zostanie wykonany).
Ta sprawa jest trywialna; pp
ładuje się dobrze jako symbol, mimo że jest niezdefiniowany, i jest podzielony na p
druk w każdym programie połówkowym. Ale możemy zrobić kolejną sztuczkę, ponownie używając literału łańcuchowego. Połówki programów nadal mają DO zdefiniowane normalnie, więc moglibyśmy również powiedzieć:
ddoo{{pp{{[RReebdo]l}}}}
Ponieważ jedyną częścią wybraną przez analizator składni w całym przypadku jest słowo symboliczne ddoo
i literał łańcuchowy, możemy następnie przeplatać dowolne dwa programy, które chcemy w tym łańcuchu literalnym, i nie gniewać parsera. Połówki wersji powiedzą tylko:
do{p{Rebol}}
..i...
do{p{[Red]}}
Jak mówię, ta część wygląda znajomo na inne rozwiązania, które traktują programy jako ciągi znaków i je ewaluują. Ale w przypadku konkurencji, gdy pakowane programy zawierają zagnieżdżone ciągi znaków, to rzuca za nie klucze. Tutaj jedyne rzeczy, które wpędzą cię w kłopoty, to ucieczka przez carets ( ^
) ..., którą można łatwo obejść.
(Mała uwaga „oszukująca”: dodałem QT do „QUIT” w odpowiedzi na ten problem. Właściwie wcześniej celowo usunąłem skrót dla quit… ponieważ jakoś myślałem, że to jest dobre tylko do użycia na konsoli i po prostu biorąc dwuliterowe spacja, jeśli nie było go w REPL. Dodam go, ponieważ widzę, że się myliłem, nie dodając go w tym przypadku w szczególności. Jednak przed tą zmianą byłoby o 2 znaki dłużej. Ponadto, kiedy po raz pierwszy opublikowałem rozwiązanie, w Rebmu wystąpił błąd, który uniemożliwiał jego faktyczne działanie, mimo że powinien mieć ... teraz działa.)
x0=00;;
. Świetne wyzwanie!