ASCII Curva di Hilbert


23

Dato un noutput intero , l' niterazione della curva di Hilbert in ASCII usando i caratteri _e |.

Ecco le prime 4 iterazioni:

n=1
 _ 
| |

n=2
 _   _ 
| |_| |
|_   _|
 _| |_

n=3
 _   _   _   _ 
| |_| | | |_| |
|_   _| |_   _|
 _| |_____| |_ 
|  ___   ___  |
|_|  _| |_  |_|
 _  |_   _|  _ 
| |___| |___| |

n=4
 _   _   _   _   _   _   _   _ 
| |_| | | |_| | | |_| | | |_| |
|_   _| |_   _| |_   _| |_   _|
 _| |_____| |_   _| |_____| |_ 
|  ___   ___  | |  ___   ___  |
|_|  _| |_  |_| |_|  _| |_  |_|
 _  |_   _|  _   _  |_   _|  _ 
| |___| |___| |_| |___| |___| |
|_   ___   ___   ___   ___   _|
 _| |_  |_|  _| |_  |_|  _| |_ 
|  _  |  _  |_   _|  _  |  _  |
|_| |_| | |___| |___| | |_| |_|
 _   _  |  ___   ___  |  _   _ 
| |_| | |_|  _| |_  |_| | |_| |
|_   _|  _  |_   _|  _  |_   _|
 _| |___| |___| |___| |___| |_ 

chiarimenti

  • La mia domanda è simile a Disegna la curva di Hilbert e Disegna la curva di Hilbert usando le barre .
  • La conversione tra sottolineatura ( _) e barre verticali ( |) è u=2*v-1dove uè il numero di _s ed vè il numero di |s.
  • Per mantenere la coerenza con il mio post originale, la curva deve iniziare e finire in fondo.
  • Puoi avere un programma completo o una funzione.
  • Uscita su stdout (o qualcosa di simile).
  • Puoi avere spazi bianchi iniziali o finali, l'output deve solo allinearsi in modo che assomigli agli esempi.
  • Questo è code-golf, quindi la risposta più breve in byte vince.

3
Potresti includere una definizione della curva di Hilbert nei tuoi post e le specifiche esatte per come viene costruita la versione ASCII?
Loovjo,

@Bobas_Pett: Not kolmogorov-complessità
shooqie


@Loovjo Ho aggiunto un punto sulle lunghezze dei trattini bassi (_) e delle barre verticali (|) sotto "Chiarimenti", se sono ancora necessarie ulteriori informazioni o una definizione rigorosa, per favore, dimmelo.
Bobas_Pett,

@shooqie ho rimosso il tag
Bobas_Pett

Risposte:


5

Befunge, 444 368 323 byte

&1>\1-:v
0v^*2\<_$00p>
_>:10p\:20pv^_@#-*2g00:+1,+55$
^!-<v*2g000<>$#<0>>-\:v
g2*^>>10g20g+v \ ^*84g_$:88+g,89+g,\1+:00
v#*!-1g02!g01_4^2_
>::00g2*-!\1-:10g-\20g-++>v
87+#^\#p01#<<v!`g01/2\+76:_
vv1-^#1-g01:\_$:2/20g`!
_ 2/^>:10g#vv#`g02/4*3:\+77
v>0p^^/2:/2_
<^2-1-g02</2`#*3:
0g+10p2*:^*3_1
! "#%$
%$"#!
 !!##%
|||_
 _ __

Provalo online!

L'approccio tipico per disegnare la curva di Hilbert è quello di seguire il percorso come una serie di tratti e curve, trasformando il risultato in una bitmap o un'area di memoria e quindi scrivendo quel rendering quando il percorso è completo. Questo non è fattibile in Befunge quando abbiamo solo 2000 byte di memoria con cui lavorare, e questo include la fonte del programma stesso.

Quindi l'approccio che abbiamo adottato qui è quello di elaborare una formula che ci dica esattamente quale carattere emettere per una determinata coordinata x, y. Per capire come funziona questo, è più facile ignorare il rendering ASCII per iniziare, e basti pensare alla curva di resa da caratteri della scatola: , , , , , e .

Quando osserviamo la curva in questo modo, possiamo immediatamente vedere che il lato destro è uno specchio esatto del lato sinistro. I personaggi a destra possono essere determinati semplicemente guardando il loro partner a sinistra e riflettendolo in senso orizzontale (cioè le occorrenze di e vengono scambiate, così come sono e ).

Curva di Hilbert di livello 3 che mostra il riflesso sull'asse verticale

Quindi, guardando l'angolo in basso a sinistra, possiamo ancora vedere che la metà inferiore è un riflesso della metà superiore. Quindi i personaggi in basso sono semplicemente determinati guardando in alto il loro partner e riflettendolo verticalmente (cioè le occorrenze di e vengono scambiate, così come sono e ).

Curva di Hilbert di livello 3 che mostra il riflesso sull'asse orizzontale nell'angolo in basso a sinistra

La restante metà di questo angolo è un po 'meno ovvia. Il blocco di destra può essere derivato da una riflessione verticale del blocco in diagonale adiacente ad esso.

Curva di Hilbert di livello 3 che mostra come derivare il blocco in alto a destra dell'angolo in basso a sinistra

E il blocco a sinistra può essere derivato da un riflesso verticale del blocco nella parte superiore sinistra dell'intera curva.

Curva di Hilbert di livello 3 che mostra come derivare il blocco in alto a sinistra dell'angolo in basso a sinistra

A questo punto, ci rimane solo l'angolo in alto a sinistra, che è solo un'altra curva di Hilbert una iterazione in basso. In teoria, ora dovremmo semplicemente ripetere di nuovo il processo, ma c'è un po 'di problema: a questo livello, le metà sinistra e destra del blocco non sono specchi esatti l'uno dell'altro.

Quindi, a qualsiasi cosa diversa dal livello superiore, i personaggi nell'angolo inferiore devono essere gestiti come un caso speciale, in cui il personaggio viene riflesso e il personaggio viene riflesso come .

Curva di Hilbert di livello 3 che mostra come derivare il blocco in alto a sinistra dell'angolo in basso a sinistra

Ma a parte questo, possiamo davvero ripetere questo processo in modo ricorsivo. All'ultimo livello codifichiamo il carattere in alto a sinistra come e il carattere sotto di esso come .

Sequenza di immagini che mostrano come derivano le parti rimanenti della curva

Ora che abbiamo un modo per determinare la forma della curva in corrispondenza di una particolare coordinata x, y, come possiamo tradurla nel rendering ASCII? In realtà è solo una semplice mappatura che traduce ogni possibile riquadro in due caratteri ASCII.

  • diventa  _(spazio più trattino basso)
  • diventa   (due spazi)
  • diventa |_(barra verticale più trattino basso)
  • diventa (barra verticale più spazio)
  • diventa (di nuovo una barra verticale più spazio)
  • diventa __(due trattini bassi)

Questa mappatura all'inizio non è intuitiva, ma puoi vedere come funziona guardando due rendering corrispondenti fianco a fianco.

Curva di Hilbert di livello 2 rappresentata come arte ASCII e con personaggi box

E questo è praticamente tutto quello che c'è da fare. In realtà implementare questo algoritmo in Befunge è un altro problema, ma lascerò quella spiegazione per un'altra volta.


2

C, 267 byte

const n=4,s=1<<n,a[]={1,-s,-1,s};l,p,q;
t(d){d&=3;p-q||printf("%.2s",&"__|      _|       |___ _|_| | | "[l*8+d*2]);p+=a[l=d];}
h(d,r,n){n--&&(h(d+r,-r,n),t(d+r),h(d,r,n),t(d),h(d,r,n),t(d-r),h(d-r,-r,n));}
main(){for(;p=s*s-s,l=1,q<s*s;++q%s||putchar(10))h(0,1,n),t(3);}

Provalo online!

h()usa la ricorsione per generare i tratti della curva di Hlibert. t()stampa il carattere del tratto solo se la posizione della penna pè uguale alla posizione di output corrente q.

Questo è inefficiente ma semplice.

Se la curva inizia in alto a sinistra, il codice può essere ridotto a 256 byte.


Suggerisci puts("")invece di putchar(10)e "..."+l*8+d*2invece di &"..."[l*8+d*2]e n--?h(d+r...-r,n):0invece din--&&(h(d+r...-r,n))
ceilingcat il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.