Rebmu: 79 chars OR (37 + length(p1) + 2 * max(length(p2), length(p3)))
First I'll give a 79 character solution that asks Which languages must you learn? (entropy 4.0, 30 letters not including ?
) and offers you the suggestions of Rebol and [Red]:
DD 11 DD :do dd {dd {p{Which languages must you learn?}qt}} pp{{[RReebdo]l}}
A unique tactic available here that isn't in other languages comes from taking advantage of the fact that curly braces are an asymmetric string delimiter, that can nest legally:
my-string: {"It's cool," said {Dr. Rebmu}, "for MANY reasons--like less escaping."}
That let me produce a generalized solution, that can work effortlessly on any program that doesn't use escape sequences. The 79 character version was simple enough to shortcut, but to properly contain arbitrary program source for programs p2 and p3 you'd need the full template. Had we used that, it would have been 87 characters:
DD 11 DD :do dd {dd {p{Which languages must you learn?}qt}} ddoo{{pp{{[RReebdo]l}}}}
The pattern for using this general form is that if you have three source texts of sequential characters of variable lengths (let's use an example like AAA
, BBBBB
, CCCCCCC
) you can encode them as something along the lines of:
DD 11 DD :do dd {dd {AAAqt}} ddoo{{BCBCBCBCBC C C}}
(Note: Although this pattern won't work without tweaking on programs that use escape characters, this is not a fatal flaw. Getting an unmatched left brace in a string delimited by braces requires something like {Foo ^{ Bar}
...but you could easily rewrite that using the alternative string notation "Foo { Bar"
, and combined cases can be managed with gluing together a mixture of unescaped strings.)
So...how about an example? Once the general form was available, this 573 character program was assembled in only a couple of minutes from 3 prior code golf solutions:
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 [fcebC[sn[{N sbeo[tIt0l1eV}0e5gXN1 01L{5s0}C{1}0{0 Do5f0 0bMe1e0r0}0]]]tMw9C9 Numz Jl[paN+[KperlCJBn[[ba sWS{B noJn Nt0h0e] jw]aJlnl]}aCd{K,j } b P { . } l f E Z - - n [ N m { G o t o t h e s t o r e a n d b u y s o m e m o r e } ] { T a k e o n e d o w n a n d p a s s i t a r o u n d } c B w P l f ] ] }}
If anyone wants to try writing that program in their language of choice, and thinks they can beat 573, let me know. I will bounty you a heavy amount of reputation if you do--assuming your language of choice is not Rebmu, because I know those programs aren't minimal. :-)
That "wasteful" spacing you get at the end is what happens when p2 and p3 are of imbalanced lengths. But all 3 programs are different sizes in this case so there isn't a particular good pairing to pick for p2/p3. (I picked these because there was no external data as input, such as a maze or whatever, not that they were of similar lengths. While I could have written new programs that were more optimal, I've spent enough time and the point was you don't have to write new programs...)
How it works
(Note: I started with a more "creative" approach that was not as streamlined but more interesting-looking. I moved it to an entry on my blog as describing this approach is already long.)
A key here is the "eval code as a string" trickery like some other entries, it just has the trump card of the asymmetric string delimiter. I'll start by explaining the workings of the 80 character case.
Here's the "whole" program, adjusting the whitespace for this case's readability:
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}}
Aqui, definimos DD como sinônimo de DO (também conhecido como "eval"). Mas o truque é que, quando os programas cortados pela metade são executados, eles acabam executando código cujo único efeito é definir D para o literal inofensivo 1.
Aqui está o que o código de caracteres ímpares cria, o espaço em branco ajustado novamente:
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"
E aqui está o código de caracteres pares:
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]"
Na verdade, é o caso de que, para o programa não dividido pela metade, dd {dd {(arbitrary code)qt}}
ele executará o código que você desejar. No entanto, existem duas chamadas para avaliar em vez de apenas uma. Isso ocorre porque, enquanto os aparelhos aninhados funcionam muito bem no código intercalado, eles atrapalham o comportamento de avaliação do DO. Porque:
do {{print "Hello"}}
Carregará a string como um programa, mas esse programa acaba sendo apenas a constante da string {print "Hello"}
. Portanto, o truque que uso aqui é pegar meu DD (mantendo o mesmo valor de função que DO) e executá-lo duas vezes. As metades mastigam as diferentes partes da cadeia, mas não as duas se a par / ímpar for correta para o conteúdo, e porque o que resta fora da cadeia após a divisão pela metade é apenas a constante integrald
elas são inofensivas.
Com esse padrão, não há nenhum desafio em escrever o comportamento do programa quando ele não é cortado pela metade - você pode colocar qualquer coisa, desde que o comprimento do caractere do código seja par (estranho se você estiver contando o QT, que é QUIT). Se você precisar obter o número par de um número ímpar, jogue um espaço (para que haja um +1 na minha fórmula acima na p1 para comprimentos ímpares do programa de p1) . O truque parece escrever esse código intercalado posteriormente, que deve passar o analisador se for dividido pela metade. (Não será executado por causa do QT, mas precisa ser CARREGADO antes de ser executado.)
Este caso é trivial; pp
carrega bem como um símbolo, mesmo indefinido, e é dividido p
para impressão em cada meio programa. Mas podemos fazer outro truque usando uma string literal novamente. Os programas cortados pela metade ainda têm DO definido normalmente, então também poderíamos ter dito:
ddoo{{pp{{[RReebdo]l}}}}
Tendo a única parte escolhida pelo analisador no caso todo, seja a palavra simbólica ddoo
e uma literal de cadeia, podemos então intercalar quaisquer dois programas que desejamos dentro dessa literal de cadeia e não irritar o analisador. As versões reduzidas ao meio dirão apenas:
do{p{Rebol}}
..e...
do{p{[Red]}}
Como eu disse, esta parte parece familiar para outras soluções que tratam programas como seqüências de caracteres e os avaliam. Mas, no caso da competição, quando os programas que você está embalando contêm seqüências aninhadas, isso é uma chave para eles. Aqui, as únicas coisas que o colocam em problemas são o uso de escapes por sinal de intercalação ( ^
) ... que podem ser facilmente contornados.
(Pequena nota 'trapaça': eu adicionei QT para "QUIT" em resposta a esse problema. Na verdade, eu havia removido propositalmente a abreviação de desistir antes ... porque, de alguma forma, achei que era bom apenas para o uso do console e apenas ocupar o espaço de duas letras se não estivesse em um REPL. Estou adicionando porque vejo que estava errado, não o adicionando para este caso em particular. No entanto, antes dessa alteração, seriam 2 caracteres a mais. quando publiquei a solução pela primeira vez, havia um bug no Rebmu que a impedia de funcionar, mesmo que devesse ter ... agora funciona.)
x0=00;;
. Grande desafio!