Mini-Flak, 6851113 ciclos
O programa (literalmente)
Eu sei que a maioria das pessoas provavelmente não espera que um quine Mini-Flak use caracteres não imprimíveis e até caracteres de vários bytes (tornando a codificação relevante). No entanto, esse quine sim, e os não imprimíveis, combinados com o tamanho do quine (93919 caracteres codificados como 102646 bytes de UTF-8), tornam bastante difícil colocar o programa nesta postagem.
No entanto, o programa é muito repetitivo e, como tal, compacta muito bem. Para que todo o programa esteja disponível literalmente no Stack Exchange, existe um xxd
hexdump reversível de uma gzip
versão compactada do quine completo, oculta por trás do recolhível abaixo:
00000000: 1f8b 0808 bea3 045c 0203 7175 696e 652e .......\..quine.
00000010: 6d69 6e69 666c 616b 00ed d9db 6a13 4118 miniflak....j.A.
00000020: 0060 2f8b f808 0d64 a1c1 1dc8 4202 c973 .`/....d....B..s
00000030: 4829 4524 0409 22e2 5529 a194 1242 1129 H)E$..".U)...B.)
00000040: d2d7 ca93 f9cf 4c4c d45b 9536 e6db 6967 ......LL.[.6..ig
00000050: 770e 3bc9 ffed eca9 edb7 b1a4 9ad2 6a1d w.;...........j.
00000060: bfab 75db c6c6 6c5f 3d4f a5a6 8da6 dcd8 ..u...l_=O......
00000070: 465b d4a5 5a28 4bd9 719d 727b aa79 f9c9 F[..Z(K.q.r{.y..
00000080: 43b6 b9d7 8b17 cd45 7f79 d3f4 fb65 7519 C......E.y...eu.
00000090: 59ac 9a65 bfdf 8f86 e6b2 69a2 bc5c 4675 Y..e......i..\Fu
000000a0: d4e4 bcd9 5637 17b9 7099 9b73 7dd3 fcb2 ....V7..p..s}...
000000b0: 4773 b9bc e9bd b9ba 3eed 9df7 aeaf 229d Gs......>.....".
000000c0: e6ed 5eae 3aef 9d46 21b2 5e4d bd28 942e ..^.:..F!.^M.(..
000000d0: 6917 d71f a6bf 348c 819f 6260 dfd9 77fe i.....4...b`..w.
000000e0: df86 3e84 74e4 e19b b70e 9af0 111c fa0d ..>.t...........
000000f0: d29c 75ab 21e3 71d7 77f6 9d8f f902 6db2 ..u.!.q.w.....m.
00000100: b8e1 0adf e9e0 9009 1f81 f011 18d8 1b33 ...............3
00000110: 72af 762e aac2 4760 6003 1bd8 698c c043 r.v...G``...i..C
00000120: 8879 6bde 9245 207c 04ae 5ce6 2d02 e1bb .yk..E |..\.-...
00000130: 7291 4540 57f8 fe0d 6546 f89b a70b 8da9 r.E@W...eF......
00000140: f5e7 03ff 8b8f 3ad6 a367 d60b f980 679d ......:..g....g.
00000150: d3d6 1c16 f2ff a767 e608 57c8 c27d c697 .......g..W..}..
00000160: 4207 c140 9e47 9d57 2e50 6e8e c215 b270 B..@.G.W.Pn....p
00000170: bdf6 9926 9e47 9d05 ce02 0ff0 5ea7 109a ...&.G......^...
00000180: 8ba6 b5db 880b 970b 9749 2864 47d8 1b92 .........I(dG...
00000190: 39e7 9aec 8f0e 9e93 117a 6773 b710 ae53 9........zgs...S
000001a0: cd01 17ee b30e d9c1 15e6 6186 7a5c dc26 ..........a.z\.&
000001b0: 9750 1d51 610a d594 10ea f3be 4b7a 2c37 .P.Qa.......Kz,7
000001c0: 2f85 7a14 8fc4 a696 304d 4bdf c143 8db3 /.z.....0MK..C..
000001d0: d785 8a96 3085 2acc 274a a358 c635 8d37 ....0.*.'J.X.5.7
000001e0: 5f37 0f25 8ff5 6854 4a1f f6ad 1fc7 dbba _7.%..hTJ.......
000001f0: 51ed 517b 8da2 4b34 8d77 e5b2 ec46 7a18 Q.Q{..K4.w...Fz.
00000200: ffe8 3ade 6fed b2f2 99a3 bae3 c949 9ab5 ..:.o........I..
00000210: ab75 d897 d53c b258 a555 1b07 63d6 a679 .u...<.X.U..c..y
00000220: 4a51 5ead a23a 6a72 9eb6 d569 960b f3dc JQ^..:jr...i....
00000230: 9ceb 53fa 658f 345f ad07 6f6f efce 06ef ..S.e.4_..oo....
00000240: 0677 b791 cef2 f620 57bd 1b9c 4521 b241 .w..... W...E!.A
00000250: 4d83 2894 2eaf a140 8102 050a 1428 50a0 M.(....@.....(P.
00000260: 4081 0205 0a14 2850 a040 8102 050a 1428 @.....(P.@.....(
00000270: 50a0 4081 0205 0a14 2850 a040 8102 050a P.@.....(P.@....
00000280: 1428 50a0 4081 0205 0a14 2850 a040 8102 .(P.@.....(P.@..
00000290: 050a 1428 50a0 4081 0205 0a14 2850 a040 ...(P.@.....(P.@
000002a0: 8102 050a 1428 50a0 4081 0205 0a14 2850 .....(P.@.....(P
000002b0: a040 8102 050a 1428 50a0 4081 0205 0a14 .@.....(P.@.....
000002c0: 2850 a040 8102 050a 1428 50a0 4081 0205 (P.@.....(P.@...
000002d0: 0a14 2850 a040 8102 050a 1428 50a0 4081 ..(P.@.....(P.@.
000002e0: 0205 0a14 2850 a040 8102 050a 1428 50a0 ....(P.@.....(P.
000002f0: 4081 0205 0a14 2850 a040 8102 050a 1428 @.....(P.@.....(
00000300: 50a0 4081 0205 0a14 2850 a040 8102 050a P.@.....(P.@....
00000310: 1428 50a0 4081 0205 0a14 2850 a040 8102 .(P.@.....(P.@..
00000320: 050a 1428 50a0 4081 0205 0a14 2850 a040 ...(P.@.....(P.@
00000330: 8102 050a 1428 50a0 4081 0205 0a14 2850 .....(P.@.....(P
00000340: a040 8102 050a 1428 50a0 4081 0205 0a14 .@.....(P.@.....
00000350: 2850 a040 8102 050a 1428 50a0 4081 0205 (P.@.....(P.@...
00000360: 0a14 2850 a040 8102 050a 1428 50a0 4081 ..(P.@.....(P.@.
00000370: 0205 0a14 2850 a01c 14ca 7012 cbb4 a6e9 ....(P....p.....
00000380: e6db e6b1 e4b1 9e4c 4ae9 d3be f5f3 745b .......LJ.....t[
00000390: 37a9 3d6a af49 7489 a6e9 ae5c 96dd 488f 7.=j.It....\..H.
000003a0: d31f 5da7 fbad 5d56 3e73 5277 7cf5 aa7b ..]...]V>sRw|..{
000003b0: 3fbc df7c e986 c3ba 5ee4 3c6f 74f7 c3e1 ?..|....^.<ot...
000003c0: 301a bb45 d795 9afb fbdc 1495 65d5 6d9b 0..E........e.m.
000003d0: baf7 a5b4 a87d 4a5b d7fd b667 b788 ec27 .....}J[...g...'
000003e0: c5d8 28bc b96a 9eda 7a50 524d 290a a5cb ..(..j..zPRM)...
000003f0: cbef 38cb c3ad f690 0100 ..8.......
(Sim, é tão repetitivo que você pode até ver as repetições depois de compactadas).
A pergunta diz: "Eu também recomendo não executar seu programa no TIO. O TIO não é apenas mais lento que o interpretador de desktop, mas também atingirá o tempo limite em cerca de um minuto. Seria extremamente impressionante se alguém conseguisse pontuar baixo o suficiente para executar o programa antes do tempo limite do TIO ". Eu posso fazer isso! Demora cerca de 20 segundos para executar no TIO, usando o intérprete Ruby: Experimente online!
O programa (facilmente)
Agora, eu forneci uma versão do programa que os computadores podem ler, vamos tentar uma versão que os humanos possam ler. Eu converti os bytes que compõem o quine na página de códigos 437 (se eles tiverem o conjunto de bits alto) ou imagens de controle Unicode (se forem códigos de controle ASCII), espaço em branco adicionado (qualquer espaço em branco pré-existente foi convertido para controlar imagens) ), codificado pelo comprimento da execução usando a sintaxe «string×length»
e alguns bits pesados de dados elididos:
␠
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
(«()×35» («()×44» («()×44» («()×44» («()×44» («()×45»
… much more data encoded the same way …
(«()×117»(«()×115»(«()×117»
«000010101011┬â┬ … many more comment characters … ┬â0┬â┬à00␈␈
)[({})(
([({})]({}{}))
{
((()[()]))
}{}
{
{
({}(((({}())[()])))[{}()])
}{}
(({}))
((()[()]))
}{}
)]{}
%Wwy$%Y%ywywy$wy$%%%WwyY%$$wy%$$%$%$%$%%wy%ywywy'×almost 241»
,444454545455┬ç┬ … many more comment characters … -a--┬ü␡┬ü-a␡┬ü
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
(O "quase 241" ocorre porque a 241ª cópia está ausente no final '
, mas é idêntica à outra 240.)
Explicação
Sobre os comentários
A primeira coisa a explicar é: o que há com caracteres não imprimíveis e outros itens indesejados que não são comandos do Mini-Flak? Você pode pensar que adicionar comentários ao quine apenas dificulta as coisas, mas isso é uma competição de velocidade (não uma competição de tamanho), o que significa que os comentários não prejudicam a velocidade do programa. Enquanto isso, o Brain-Flak e, portanto, o Mini-Flak, apenas despejam o conteúdo da pilha na saída padrão; se você tivesse que garantir que a pilha contivesse apenasos caracteres que compunham os comandos do seu programa, você teria que gastar ciclos limpando a pilha. Assim, o Brain-Flak ignora a maioria dos caracteres, desde que asseguremos que os elementos da pilha de lixo eletrônico não sejam comandos válidos para o Brain-Flak (tornando-o um poliglota do Brain-Flak / Mini-Flak) e não sejam negativos ou externos No intervalo Unicode, podemos apenas deixá-los na pilha, permitir que sejam exibidos e colocar o mesmo caractere em nosso programa no mesmo local para manter a propriedade quine.
Existe uma maneira particularmente importante de tirar vantagem disso. O quine funciona usando uma cadeia de dados longa e, basicamente, toda a saída do quine é produzida formatando a cadeia de dados de várias maneiras. Há apenas uma sequência de dados, apesar do programa ter várias partes; portanto, precisamos poder usar a mesma sequência de dados para imprimir diferentes partes do programa. O truque "dados indesejados não importa" nos permite fazer isso de uma maneira muito simples; armazenamos os caracteres que compõem o programa na cadeia de dados adicionando ou subtraindo um valor para ou de seu código ASCII. Especificamente, os caracteres que compõem o início do programa são armazenados como seu código ASCII + 4, os caracteres que compõem a seção repetida quase 241 vezes como seu código ASCII - 4,todos os caracteres da sequência de dados com um deslocamento; se, por exemplo, imprimi-lo com 4 adicionados a cada código de caractere, obtemos uma repetição da seção repetida, com alguns comentários antes e depois. (Esses comentários são simplesmente as outras seções do programa, com os códigos de caracteres alterados para que não formem nenhum comando válido do Brain-Flak, porque o deslocamento incorreto foi adicionado. Temos que desviar dos comandos do Brain-Flak, não apenas do Mini- Comandos Flak, para evitar violar a parte de origem restrita da questão; a escolha dos deslocamentos foi projetada para garantir isso.)
Devido a esse truque de comentário, na verdade, precisamos apenas produzir a sequência de dados formatada de duas maneiras diferentes: a) codificada da mesma maneira que na fonte, b) como códigos de caracteres com um deslocamento especificado adicionado a cada código. Essa é uma enorme simplificação que faz com que o comprimento adicionado valha totalmente a pena.
Estrutura do programa
Este programa consiste em quatro partes: a introdução, a sequência de dados, o formatador da sequência de dados e o outro. A introdução e o outro são basicamente responsáveis por executar a sequência de dados e seu formatador em um loop, especificando o formato apropriado a cada vez (ou seja, se deseja codificar ou compensar e qual deslocamento usar). A sequência de dados é apenas dados, e é a única parte do quine para a qual os caracteres que a compõem não são especificados literalmente na sequência de dados (fazer isso seria obviamente impossível, pois teria que ser mais longo que ele); assim, é escrito de uma maneira particularmente fácil de se regenerar. O formatador de cadeia de dados é composto por 241 partes quase idênticas, cada uma das quais formata um dado específico dos 241 na cadeia de dados.
Cada parte do programa pode ser produzida através da cadeia de dados e seu formatador, da seguinte maneira:
- Para produzir o outro, formate a sequência de dados com deslocamento +8
- Para produzir o formatador de cadeia de dados, formate-a com deslocamento +4, 241 vezes
- Para produzir a sequência de dados, formate a sequência de dados codificando-a no formato de origem
- Para produzir a introdução, formate a sequência de dados com o deslocamento -4
Então, tudo o que precisamos fazer é observar como essas partes do programa funcionam.
A sequência de dados
(«()×35» («()×44» («()×44» («()×44» («()×44» («()×45» …
Precisamos de uma codificação simples para a sequência de dados, pois precisamos poder reverter a codificação no código Mini-Flak. Você não pode ficar muito mais simples que isso!
A idéia principal por trás desse quine (além do truque dos comentários) é observar que há basicamente apenas um lugar para armazenar grandes quantidades de dados: as "somas de comando retornam valores" nos vários níveis de aninhamento da fonte do programa. (Isso é comumente conhecido como a terceira pilha, embora o Mini-Flak não tenha uma segunda pilha, então "pilha de trabalho" provavelmente é um nome melhor no contexto do Mini-Flak.) As outras possibilidades de armazenamento de dados seriam a pilha principal / primeira (que não funciona porque é para onde nossa saída precisa ir e não podemos mover a saída além do armazenamento de maneira remotamente eficiente) e codificada em um bignum em um único elemento de pilha (o que não é adequado para esse problema, pois leva um tempo exponencial para extrair dados dele); quando você os elimina, a pilha de trabalho é o único local restante.
Para "armazenar" dados nessa pilha, usamos comandos desbalanceados (neste caso, a primeira metade de um (…)
comando), que serão balanceados no formatador de sequência de dados posteriormente. Cada vez que fechamos um desses comandos no formatador, ele envia a soma de um dado retirado da sequência de dados e os valores de retorno de todos os comandos nesse nível de aninhamento no formatador; podemos garantir que este último seja zero, para que o formatador veja apenas valores únicos retirados da sequência de dados.
O formato é muito simples (
:, seguido por n cópias de ()
, em que n é o número que queremos armazenar. (Observe que isso significa que podemos armazenar apenas números não negativos e o último elemento da sequência de dados precisa ser positivo.)
Um ponto pouco intuitivo sobre a sequência de dados é em qual ordem ela está. O "início" da sequência de dados é o fim mais próximo do início do programa, ou seja, o nível de aninhamento mais externo; essa parte é formatada por último (à medida que o formatador é executado dos níveis de aninhamento mais interno para mais externo). No entanto, apesar de ter sido formatado por último, ele é impresso primeiro, porque os valores inseridos na pilha primeiro são impressos por último pelo interpretador Mini-Flak. O mesmo princípio se aplica ao programa como um todo; primeiro precisamos formatar o outro, depois o formatador da sequência de dados, a sequência de dados e a introdução, ou seja, o inverso da ordem em que eles são armazenados no programa.
O formatador de cadeia de dados
)[({})(
([({})]({}{}))
{
((()[()]))
}{}
{
{
({}(((({}())[()])))[{}()])
}{}
(({}))
((()[()]))
}{}
)]{}
O formatador da cadeia de dados é composto de 241 seções, cada uma com código idêntico (uma seção possui um comentário marginalmente diferente), cada uma das quais formata um caractere específico da cadeia de dados. (Não foi possível usar um loop aqui: precisamos de um desequilíbrio )
para ler a sequência de dados através da correspondência do desequilibrado (
, e não podemos colocar um desses dentro de um {…}
loop, a única forma de loop que existe. Então, em vez disso, nós " desenrole "o formatador e simplesmente obtenha a introdução / outro para gerar a sequência de dados com o deslocamento do formatador 241 vezes.)
)[({})( … )]{}
A parte mais externa de um elemento do formatador lê um elemento da sequência de dados; a simplicidade da codificação da cadeia de dados leva a um pouco de complexidade na leitura. Começamos fechando o inigualável (…)
na sequência de dados e depois negamos ( […]
) dois valores: o dado que acabamos de ler da sequência de dados ( ({})
) e o valor de retorno do restante do programa. Copiamos o valor de retorno do restante do elemento formatador com (…)
e adicionamos a cópia à versão negada com {}
. O resultado final é que o valor de retorno do elemento da string de dados e do elemento formatador juntos é o dado menos o dado menos o valor de retorno mais o valor de retorno, ou 0; isso é necessário para que o próximo elemento da cadeia de dados produza o valor correto.
([({})]({}{}))
O formatador usa o elemento da pilha superior para saber em qual modo ele está (0 = formato na formatação da cadeia de dados, qualquer outro valor = o deslocamento para saída). No entanto, depois de ler a sequência de dados, o dado está no topo do formato na pilha e queremos que seja o contrário. Este código é uma variante mais curta do código de permuta de cérebro-Flak, tendo um acima b a b acima um + b ; não apenas é mais curto, como também (nesse caso específico) é mais útil, porque o efeito colateral de adicionar b a a não é problemático quando b é 0 e quando b não é 0, ele faz o cálculo de deslocamento para nós.
{
((()[()]))
}{}
{
…
((()[()]))
}{}
O Brain-Flak possui apenas uma estrutura de controle de fluxo; portanto, se queremos algo além de um while
loop, será preciso um pouco de trabalho. Essa é uma estrutura "negativa"; se houver um 0 no topo da pilha, ele o remove; caso contrário, coloca um 0 no topo da pilha. (Funciona de maneira bem simples: contanto que não haja um 0 no topo da pilha, pressione 1 - 1 para a pilha duas vezes; quando terminar, clique no elemento superior da pilha.)
É possível colocar o código dentro de uma estrutura negativa, como pode ser visto aqui. O código será executado apenas se a parte superior da pilha for diferente de zero; portanto, se tivermos duas estruturas negativas, supondo que os dois principais elementos da pilha não sejam zero, eles se cancelarão, mas qualquer código dentro da primeira estrutura será executado apenas se o elemento superior da pilha for diferente de zero e o código dentro a segunda estrutura será executada apenas se o elemento da pilha superior for zero. Em outras palavras, isso é equivalente a uma instrução if-then-else.
Na cláusula "then", que é executada se o formato for diferente de zero, na verdade não temos nada a fazer; o que queremos é enviar os dados + offset para a pilha principal (para que possam ser impressos no final do programa), mas já estão lá. Portanto, apenas temos que lidar com o caso de codificar o elemento da cadeia de dados no formato de origem.
{
({}(((({}())[()])))[{}()])
}{}
(({}))
Aqui está como fazemos isso. A {({}( … )[{}()])}{}
estrutura deve estar familiarizada como um loop com um número específico de iterações (que funciona movendo o contador de loop para a pilha de trabalho e mantendo-o lá; estará seguro de qualquer outro código, porque o acesso à pilha de trabalho está vinculado a o nível de aninhamento do programa). O corpo do loop é ((({}())[()]))
, que faz três cópias do elemento da pilha superior e adiciona 1 à mais baixa. Em outras palavras, ele transforma um 40 no topo da pilha em 40 acima de 40 acima de 41, ou visto como ASCII, (
em (()
; executar isso repetidamente se (
transformará (()
em (()()
into (()()()
e assim por diante, e, portanto, é uma maneira simples de gerar nossa cadeia de dados (supondo que já esteja (
no topo da pilha).
Quando terminarmos o loop, (({}))
duplique a parte superior da pilha (para que agora comece ((()…
ao invés de (()…
. O líder (
será usado pela próxima cópia do formatador de cadeia de dados para formatar o próximo caractere (ele será expandido para (()(()…
então (()()(()…
, e assim por diante, para que isso gere a separação (
na sequência de dados).
%Wwy$%Y%ywywy$wy$%%%WwyY%$$wy%$$%$%$%$%%wy%ywywy'
Há um último interesse no formatador de cadeias de dados. OK, então este é apenas o outro deslocamento de 4 pontos de código para baixo; no entanto, esse apóstrofo no final pode parecer fora de lugar. '
(ponto de código 39) mudaria para +
(ponto de código 43), que não é um comando Brain-Flak, então você deve ter adivinhado que ele existe para algum outro propósito.
A razão pela qual isso está aqui é porque o formatador de cadeia de dados espera que já exista um (
na pilha (ele não contém um literal 40 em lugar nenhum). o'
na verdade, é o início do bloco que é repetido para compor o formatador de sequência de dados, não o final. Portanto, depois que os caracteres do formatador de sequência de dados foram inseridos na pilha (e o código está prestes a passar para a impressão da sequência de dados) próprio), o outro ajusta os 39 no topo da pilha em 40, prontos para o formatador (o formatador em execução desta vez, não sua representação na fonte) para usá-lo. É por isso que temos "quase 241" cópias do formatador; a primeira cópia está faltando seu primeiro caractere. E esse caractere, o apóstrofo, é um dos três únicos caracteres na sequência de dados que não correspondem ao código Mini-Flak em algum lugar do programa; está lá puramente como um método de fornecer uma constante.
A introdução e outro
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
…
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
A introdução e o outro são conceitualmente a mesma parte do programa; a única razão pela qual fazemos uma distinção é que o outro precisa ser produzido antes da sequência de dados e seu formatador (para que seja impresso após eles), enquanto a introdução precisa ser produzida após eles (impressão antes deles).
(((()()()()){}))
Começamos colocando duas cópias de 8 na pilha. Esse é o deslocamento para a primeira iteração. A segunda cópia é porque o loop principal espera que exista um elemento indesejado no topo da pilha acima do deslocamento, deixado para trás no teste que decide se existe o loop principal e, portanto, precisamos colocar um elemento indesejado para que não joga fora o elemento que realmente queremos; uma cópia é a maneira mais rápida (portanto, mais rápida de gerar) de fazer isso.
Existem outras representações do número 8 que não são mais longas que esta. No entanto, ao optar pelo código mais rápido, essa é definitivamente a melhor opção. Por um lado, o uso ()()()()
é mais rápido do que, digamos, (()()){}
porque, apesar de ambos terem 8 caracteres, o primeiro é um ciclo mais rápido, porque (…)
é contado como 2 ciclos, mas ()
apenas como um. Porém, salvar um ciclo é insignificante em comparação com uma consideração muito maior para um quine : (
e )
possui pontos de código muito menores que {
e }
, portanto, gerar o fragmento de dados para eles será muito mais rápido (e o fragmento de dados ocupará menos espaço no código, também).
{{} … }{}{}
O loop principal. Isso não conta as iterações (é um while
loop, não um for
loop e usa um teste para interromper). Depois que sai, descartamos os dois principais elementos da pilha; o elemento superior é um 0 inofensivo, mas o elemento abaixo será o "formato a ser usado na próxima iteração", que (sendo um deslocamento negativo) é um número negativo e se houver algum número negativo na pilha quando o Mini -Flak programa sai, o intérprete falha ao tentar produzi-los.
Como esse loop usa um teste explícito para interromper, o resultado desse teste será deixado na pilha, então o descartamos como a primeira coisa que fazemos (seu valor não é útil).
(({})[(()()()())])
Esse código empurra 4 e f - 4 acima de um elemento de pilha f , enquanto deixa esse elemento no lugar. Estamos calculando o formato para a próxima iteração com antecedência (enquanto temos os 4 constantes à mão) e simultaneamente colocando a pilha na ordem correta para as próximas partes do programa: usaremos f como o formato para essa iteração e o 4 é necessário antes disso.
(({})( … )[{}])
Isso salva uma cópia do f -4 na pilha de trabalho, para que possamos usá-lo na próxima iteração. (O valor de f ainda estará presente nesse ponto, mas ele estará em um lugar estranho na pilha, e mesmo se pudéssemos manobrar para o lugar correto, teríamos que gastar ciclos subtraindo 4 dele, e ciclos de impressão do código para fazer essa subtração. Muito mais fácil simplesmente armazená-lo agora.)
{{}{}((()[()]))}{}
Um teste para ver se o deslocamento é 4 (ou seja, f - 4 é 0). Se estiver, estamos imprimindo o formatador de sequência de dados, portanto, precisamos executar a sequência de dados e seu formatador 241 vezes, em vez de apenas uma vez nesse deslocamento. O código é bastante simples: se f -4 for diferente de zero, substitua f -4 e o próprio 4 por um par de zeros; em ambos os casos, pop o elemento superior da pilha. Agora temos um número acima de f na pilha, 4 (se quisermos imprimir essa iteração 241 vezes) ou 0 (se quisermos imprimi-la apenas uma vez).
(
((((((({})){}){}{})){}{}){}){}
()
)
Esse é um tipo interessante de constante Brain-Flak / Mini-Flak; a fila longa aqui representa o número 60. Você pode estar confuso com a falta de ()
, que normalmente está em todo o lugar nas constantes Brain-Flak; esse não é um número regular, mas um numeral da igreja, que interpreta os números como uma operação de duplicação. Por exemplo, o número da Igreja para 60, visto aqui, faz 60 cópias de suas contribuições e as combina em um único valor; no Brain-Flak, as únicas coisas que podemos combinar são números regulares, além disso, por isso, acabamos adicionando 60 cópias do topo da pilha e multiplicando o topo da pilha por 60.
Como observação lateral, você pode usar um localizador de números Underload , que gera números de Igreja na sintaxe Underload, para encontrar também o número apropriado no Mini-Flak. Os números de subcarga (exceto zero) usam as operações "elemento duplicado da pilha superior" :
e "combinar os dois principais elementos da pilha" *
; ambos existem essas operações em Brain-Flak, então você apenas traduzir :
para )
, *
para {}
, incluir um {}
, e adicione o suficiente (
no início para o equilíbrio (isto é usando uma mistura estranha da pilha principal e pilha de trabalho, mas funciona).
Esse fragmento de código específico usa o número da igreja 60 (efetivamente um trecho "multiplique por 60"), junto com um incremento, para gerar a expressão 60 x + 1. Portanto, se tivéssemos um 4 da etapa anterior, isso nos dará um valor de 241, ou se tivéssemos um 0, obtemos apenas o valor 1, ou seja, isso calcula corretamente o número de iterações necessárias.
A escolha de 241 não é coincidência; foi um valor escolhido para ser a) aproximadamente a duração em que o programa terminaria de qualquer maneira eb) 1 mais que 4 vezes o número da rodada. Os números redondos, 60 neste caso, tendem a ter representações mais curtas como números da Igreja, porque você tem mais flexibilidade nos fatores para copiar. O programa contém preenchimento posteriormente para elevar o comprimento até 241 exatamente.
{
({}(
…
)[{}()])
}{}
Este é um loop for, como o visto anteriormente, que simplesmente executa o código dentro dele várias vezes igual ao topo da pilha principal (que consome; o contador de loop é armazenado na pilha de trabalho, mas a visibilidade de isso está vinculado ao nível de aninhamento do programa e, portanto, é impossível que qualquer coisa, exceto o próprio loop for, interaja com ele). Na verdade, isso executa a sequência de dados e seu formatador 1 ou 241 vezes e, como agora exibimos todos os valores que estávamos usando para o cálculo do fluxo de controle da pilha principal, temos o formato a ser usado em cima dela, pronto para o formatador a ser usado.
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
O comentário aqui não é inteiramente sem interesse. Por um lado, existem alguns comandos do Brain-Flak; o )
no final é gerado naturalmente como um efeito colateral da maneira como as transições entre os vários segmentos do programa funcionam; portanto, (
no início foi adicionado manualmente para equilibrá-lo (e, apesar da duração do comentário, colocar um comentário no interior um ()
comando ainda é um ()
comando, então tudo o que faz é adicionar 1 ao valor de retorno da sequência de dados e de seu formatador, algo que o loop for ignora completamente).
Mais notavelmente, esses caracteres NUL no início do comentário claramente não são compensados com nada (mesmo a diferença entre +8 e -4 não é suficiente para transformar um (
em NUL). Esses são um puro preenchimento para elevar a cadeia de dados de 239 elementos até 241 elementos (que se pagam facilmente: seriam precisos muito mais que dois bytes para gerar 1 vs. 239 em vez de 1 vs. 241 ao calcular o número de iterações necessárias ) NUL foi usado como caractere de preenchimento porque possui o menor ponto de código possível (tornando o código-fonte da cadeia de dados mais curto e, portanto, mais rápido para a saída).
{}({}())
Solte o elemento da pilha superior (o formato que estamos usando), adicione 1 ao próximo (o último caractere a ser produzido, ou seja, o primeiro caractere a ser impresso, da seção do programa que acabamos de formatar). Não precisamos mais do formato antigo (o novo formato está oculto na pilha de trabalho); e o incremento é inofensivo na maioria dos casos, e altera a '
extremidade da representação de origem do formatador de cadeia de dados em um (
(necessário na pilha para a próxima vez em que executar o formatador, para formatar a própria cadeia de dados). Precisamos de uma transformação como essa no outro ou na introdução, porque forçar o início de cada elemento formatador de cadeia de dados (
o tornaria um pouco mais complexo (pois precisaríamos fechar o (
e depois desfazer seu efeito posteriormente), ede alguma forma, precisamos gerar um extra em (
algum lugar, porque só temos quase 241 cópias do formatador, não todas as 241 (por isso é melhor que um personagem inofensivo '
seja o que está faltando).
(({})(()()()()){})
Finalmente, o teste de saída do loop. A parte superior atual da pilha principal é o formato necessário para a próxima iteração (que acabou de sair da pilha de trabalho). Isso o copia e adiciona 8 à cópia; o valor resultante será descartado na próxima vez em que ocorrer o loop. No entanto, se apenas imprimirmos a introdução, o deslocamento será -4, portanto o deslocamento para a "próxima iteração" será -8; -8 + 8 é 0, então o loop sairá em vez de continuar na iteração posteriormente.