Dada uma n
saída inteira, a n
iteração da Curva de Hilbert em ASCII usando os caracteres _
e |
.
Aqui estão as primeiras 4 iterações:
n=1
_
| |
n=2
_ _
| |_| |
|_ _|
_| |_
n=3
_ _ _ _
| |_| | | |_| |
|_ _| |_ _|
_| |_____| |_
| ___ ___ |
|_| _| |_ |_|
_ |_ _| _
| |___| |___| |
n=4
_ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _
| |___| |___| |_| |___| |___| |
|_ ___ ___ ___ ___ _|
_| |_ |_| _| |_ |_| _| |_
| _ | _ |_ _| _ | _ |
|_| |_| | |___| |___| | |_| |_|
_ _ | ___ ___ | _ _
| |_| | |_| _| |_ |_| | |_| |
|_ _| _ |_ _| _ |_ _|
_| |___| |___| |___| |___| |_
Esclarecimentos
- Minha pergunta é semelhante a Draw the Hilbert Curve e Draw the Hilbert curve usando barras .
- A conversão entre sublinhados (
_
) e as barras verticais (|
) éu=2*v-1
ondeu
está o número de_
s ev
é o número de|
s. - Para manter a consistência com o meu post original, a curva deve começar e terminar na parte inferior.
- Você pode ter um programa completo ou uma função.
- Saída para stdout (ou algo semelhante).
- Você pode ter espaços em branco à esquerda ou à direita; a saída só precisa ser alinhada para parecer com os exemplos.
- Este é o código-golfe, pelo que a resposta mais curta em bytes vence.
Respostas:
Befunge,
444368323 bytesExperimente online!
A abordagem típica para desenhar a curva de Hilbert é seguir o caminho como uma série de traços e curvas, renderizando o resultado em um bitmap ou em alguma área da memória e, em seguida, gravando essa renderização quando o caminho estiver completo. Isso não é viável no Befunge quando temos apenas 2000 bytes de memória para trabalhar, e isso inclui a fonte do próprio programa.
Portanto, a abordagem que adotamos aqui é criar uma fórmula que nos diga exatamente qual caractere produzir para uma determinada coordenada x, y. Para entender como isso funciona, é mais fácil de ignorar a prestação ASCII para começar, e apenas pensar na curva como composta de caracteres de caixa:
┌
,┐
,└
,┘
,│
, e─
.Quando olhamos para a curva assim, podemos ver imediatamente que o lado direito é um espelho exato do lado esquerdo. Os caracteres à direita podem ser simplesmente determinados procurando o parceiro à esquerda e refletindo-o horizontalmente (ou seja, ocorrências de
┌
e┐
são trocadas, como são└
e┘
).Então, olhando para o canto inferior esquerdo, novamente podemos ver que a metade inferior é um reflexo da metade superior. Assim, os caracteres na parte inferior são simplesmente determinados procurando o parceiro acima e refletindo-o verticalmente (ou seja, ocorrências de
┌
e└
são trocadas, como são┐
e┘
).A metade restante deste canto é um pouco menos óbvia. O bloco do lado direito pode ser derivado de uma reflexão vertical do bloco na diagonal adjacente a ele.
E o bloco da mão esquerda pode ser derivado de uma reflexão vertical do bloco no canto superior esquerdo da curva completa.
Neste ponto, tudo o que resta é o canto superior esquerdo, que é apenas mais uma curva de Hilbert uma iteração mais baixa. Em teoria, agora precisamos repetir o processo novamente, mas há um problema - nesse nível, as metades esquerda e direita do bloco não são espelhos exatos uma da outra.
Portanto, em qualquer coisa que não seja o nível superior, os caracteres do canto inferior precisam ser tratados como um caso especial, onde o
┌
caractere é refletido como─
e o│
caractere é refletido como└
.Mas, fora isso, podemos realmente repetir esse processo recursivamente. No último nível, codificamos o caractere superior esquerdo como
┌
e o caractere abaixo dele como│
.Agora que temos uma maneira de determinar a forma da curva em uma determinada coordenada x, y, como podemos traduzir isso na renderização ASCII? Na verdade, é apenas um mapeamento simples que traduz cada bloco possível em dois caracteres ASCII.
┌
torna-se_
(espaço mais sublinhado)┐
torna-se└
torna-se|_
(barra vertical mais sublinhado)┘
torna-se|
(barra vertical mais espaço)│
torna-se|
(novamente uma barra vertical mais espaço)─
torna-se__
(dois sublinhados)Esse mapeamento não é intuitivo a princípio, mas você pode ver como ele funciona quando olha duas renderizações correspondentes lado a lado.
E isso é basicamente tudo o que existe. Na verdade, implementar esse algoritmo no Befunge é outro problema, mas deixarei essa explicação para outro momento.
fonte
C, 267 bytes
Experimente online!
h()
usa recursão para gerar os traços da curva hlibert.t()
somente imprime o caractere de traçado se a posição da canetap
for igual à posição de saída atualq
.Isso é ineficiente, mas simples.
Se a curva começar no canto superior esquerdo, o código poderá ser reduzido para 256 bytes.
fonte
puts("")
vez deputchar(10)
e em"..."+l*8+d*2
vez de&"..."[l*8+d*2]
e emn--?h(d+r...-r,n):0
vez den--&&(h(d+r...-r,n))