Isso foi imensamente divertido. Obrigado por postar este desafio.
Divulgação completa: o idioma (Hexagony) não existia no momento em que este desafio foi lançado. No entanto, eu não o inventei e a linguagem não foi projetada para esse desafio (ou qualquer outro desafio específico).
){_2"_{\"{{""}"{'2//_.\><*\"\/_><[\]/3\'\_;|#__/(\2\'3_'}(#:|{$#{>_\//(#={/;01*&"\\_|[##={|}$_#></)]$_##|){*_.>.(/?#//~-="{}<_"=#/\}.>"%<.{#{x\"<#_/=&{./1#_#>__<_'\/"#|@_|/{=/'|\"".{/>}]#]>(_<\'{\&#|>=&{{(\=/\{*'"]<$_
Dispostas hexagonalmente:
) { _ 2 " _ { \ "
{ { " " } " { ' 2 /
/ _ . \ > < * \ " \ /
_ > < [ \ ] / 3 \ ' \ _
; | # _ _ / ( \ 2 \ ' 3 _
' } ( # : | { $ # { > _ \ /
/ ( # = { / ; 0 1 * & " \ \ _
| [ # # = { | } $ _ # > < / ) ]
$ _ # # | ) { * _ . > . ( / ? # /
/ ~ - = " { } < _ " = # / \ } .
> " % < . { # { x \ " < # _ /
= & { . / 1 # _ # > _ _ < _
' \ / " # | @ _ | / { = /
' | \ " " . { / > } ] #
] > ( _ < \ ' { \ & #
| > = & { { ( \ = /
\ { * ' " ] < $ _
Na verdade, o programa não usa as #
instruções, então usei esse caractere para mostrar quais células são genuinamente não utilizadas.
Como é que este programa funciona? Depende. Você quer a versão curta ou a longa?
Breve explicação
Para ilustrar o que quero dizer com "linha" e "segmento" na explicação a seguir, considere esta dissecação da saída pretendida:
segments →
│ │ │ │ │ │x lines
─┼───┼─┼─────────┼─┼───┼─ ↓
│ │ │ │ │xxx│
─┼───┼─┼─────────┼─┼───┘
│ │ │ │x│
─┼───┼─┼─────────┼─┘
│ │ │xxxxxxxxx│
─┼───┼─┼─────────┘
│ │x│
─┼───┼─┘
│xxx│
─┼───┘
x│
Com isso explicado, o programa corresponde ao seguinte pseudocódigo:
n = get integer from stdin
# Calculate the number of lines we need to output.
line = pow(2, n+1)
while line > 0:
line = line - 1
# For all segments except the last, the character to use is spaces.
ch = ' ' (space, ASCII 32)
# The number of segments in each line is
# equal to the line number, counting down.
seg = line
while seg > 0:
seg = seg - 1
# For the last segment, use x’s.
if seg = 0:
ch = 'x' (ASCII 120)
# Calculate the actual segment number, where the leftmost is 1
n = line - seg
# Output the segment
i = pow(3, number of times n can be divided by 2)
i times: output ch
output '\n' (newline, ASCII 10)
end program
Explicação longa
Consulte este diagrama de caminho de código com código de cores.
A execução começa no canto superior esquerdo. A sequência de instruções ){2'"''3''"2}?)
é executada (mais alguns cancelamentos redundantes, como "{
etc.), seguindo um caminho bastante complicado. Começamos com o ponteiro de instrução # 0, destacado em vermelho. No meio, passamos para o número 1, começando no canto superior direito e pintado em verde floresta. Quando o IP 2 inicia em azul centáurea (meio à direita), o layout da memória é o seguinte:
Durante todo o programa, as arestas rotuladas 2a e 2b sempre terão o valor 2
(as usamos para calcular 2ⁿ⁺¹ e dividir por 2, respectivamente) e a aresta rotulada 3 sempre será 3
(usamos isso para calcular 3ⁱ).
Chegamos aos negócios quando entramos em nosso primeiro ciclo, destacado em azul centáurea. Este loop executa as instruções (}*{=&}{=
para calcular o valor 2ⁿ⁺¹. Quando o loop sai, o caminho de sela marrom é percorrido, o que nos leva ao Ponteiro de Instrução # 3. Esse IP apenas se move ao longo da borda inferior para o oeste em amarelo dourado e logo passa o controle para o IP # 4.
O caminho fúcsia indica como o IP # 4, começando no canto inferior esquerdo, prossegue rapidamente para diminuir a linha , defina ch como 32
(o caractere de espaço) e seg como (o novo valor de) linha . É devido ao decréscimo inicial que realmente começamos com 2 start-1 e, finalmente, experimentamos uma última iteração com o valor 0. Em seguida, inserimos o primeiro loop aninhado .
Voltamos nossa atenção para o índigo ramificado, onde, após um breve decréscimo de seg , vemos ch atualizado para x
apenas se seg agora for zero. Depois, n é definido como line - seg para determinar o número real do segmento em que estamos. Imediatamente entramos em outro loop, desta vez na cor clara do tomate.
Aqui, calculamos quantas vezes n (o número do segmento atual) pode ser dividido por 2. Enquanto o módulo nos der zero, incrementamos ie dividimos n por 2. Quando estivermos satisfeitos, n não será mais assim divisível , ramificamos para o cinza ardósia, que contém dois loops: primeiro, aumenta 3 à potência do i calculada e, em seguida, gera ch isso muitas vezes. Observe que o primeiro desses loops contém um[
instrução, que alterna o controle para o IP nº 3 - aquele que estava apenas dando pequenos passos ao longo da borda inferior anteriormente. O corpo do loop (multiplicando por 3 e decrementando) é executado por um IP solitário nº 3, preso em um ciclo interminável de verde azeitona escuro ao longo da borda inferior do código. Da mesma forma, o segundo desses loops em cinza ardósia contém uma ]
instrução que ativa o IP # 5 para gerar ch e decrement, mostrados aqui em vermelho indiano escuro. Nos dois casos, os Indicadores de Instrução presos em servidão obedientemente executam uma iteração de cada vez e devolvem o controle ao IP # 4, apenas para aguardar o momento em que seu serviço seja chamado novamente. Enquanto isso, o cinza ardósia se une a seus irmãos fúcsia e índigo.
Como seg inevitavelmente chega a zero, o loop índigo sai para o caminho verde do gramado, que apenas gera o caractere de nova linha e imediatamente se funde novamente no fúcsia para continuar o loop de linha . Além da iteração final do loop de linha, encontra-se o caminho de ébano curto possível de finalizar o programa.
(,],~3^#@~.)@]
vez de(1,[:,1,"0~3*])
economizar 1 byte. E se você estiver de acordo com!
o char de saída emu:32+
vez de' #'{~
salvar outro.