Disegna una curva del drago


19

Compiti per oggi: disegna una curva di drago!

Nel caso in cui non sapessi cos'è una Dragon Curve, ecco un video introduttivo ViHart (Davvero fantastico, per favore guarda!)

Il tuo compito: disegna una curva di drago, ripetuta almeno 9 volte. Non devi mostrare iterazioni da 1 a 9, devi solo mostrare la curva finale prodotta dopo aver completato (almeno) 9 iterazioni. La curva deve essere tracciata come linee rette che collegano i punti sulla curva; l'output deve corrispondere a una delle immagini seguenti che mostrano 9 o più iterazioni (fino a riflessione, rotazione, ridimensionamento e variazione della larghezza della linea, del colore della linea e del colore di sfondo). Il tuo output deve essere abbastanza grande da poter distinguere le singole linee e le "scatole" che formano; se due linee non si intersecano nella curva, non dovrebbero occupare lo stesso o pixel adiacenti nell'output (dovrebbe esserci almeno un pixel dello sfondo visibile tra loro). È possibile visualizzare l'immagine sullo schermo oppure è possibile salvare l'immagine salvata in un file. L'output deve essere grafico - non può essere arte ASCII.

Il codice più corto in byte vince, tuttavia le direttive per le librerie non devono essere incluse nel conteggio dei byte e puoi utilizzare librerie grafiche o altre librerie scritte per la tua lingua preferita se sono state scritte prima della pubblicazione.

Includi un'immagine dell'output del tuo programma.

inserisci qui la descrizione dell'immagine

Salta questo paragrafo se hai guardato il video:Per quelli di voi che hanno deciso di non guardare il video, le prime 12 iterazioni della curva del drago sono mostrate di seguito. Ai fini di questa attività, una curva del drago è una curva generata dalla seguente regola: prendere il punto finale della curva corrente, creare una seconda curva ruotata di 90 gradi attorno a quel punto finale in modo che il punto finale dell'originale curva è il punto iniziale della nuova curva e unisce le due curve in un'unica curva dove si incontrano. Nelle immagini mostrate di seguito, ogni nuova iterazione viene generata ruotando la precedente iterazione di 90 gradi in senso orario attorno al punto finale di ogni iterazione. Quando la curva viene visualizzata sullo schermo, non è ovvio quale fine conta come "punto finale", tuttavia quando la curva è memorizzata come una matrice di punti, è facile definire il "punto finale" come ultimo punto in l'array.

L'arte Ascii è apprezzata, ma non accettata: si tratta di un output grafico, non di ascii-art.


3
Esistono specifiche su dimensionamento, colorazione, ecc.? Come è l'output esatto è un po 'poco chiaro.
R


6
Ho rimosso il tag della curva del drago perché non sembrava aggiungere nulla
Blue


3
Questo non è un duplicato; le tecniche di programmazione per risolverlo sono abbastanza diverse (tranne forse nel carbone). La maggior parte delle risposte utilizza librerie grafiche di tartarughe, che non funzionerebbero affatto in un contesto ASCII.

Risposte:


2

x86, MSDOS, 16 byte

L'ho scritto qualche tempo fa, per quanto ne so, la più piccola routine per produrre un frattale di drago. Non utilizza iterazioni reali, piuttosto traccia direttamente ogni pixel discreto contenuto all'interno del frattale, mostrando l' immagine finale . È incluso con molte altre piccole produzioni in questo pacchetto . La versione a 16 byte è stata la fine del mio sforzo per ottenere il frattale del drago il più piccolo possibile, a partire dal 2014 con questa produzione a 32 byte .

Esadecimale

14 10 19 CA D1 FA 10 DE 01 D1 CD 10 B4 0C EB F0

Codice

S: 
adc al,0x10
sbb dx,cx       
sar dx,0x01 
adc dh,bl
add cx,dx
int 0x10
mov ah,0x0C
jmp short S

immagine dello schermo


1
Questo è ... Incredibile, per non dire altro. Come farei per eseguirlo?
J. Antonio Perez,

Il modo più veloce sarebbe un DosBox online, twt86.co?c=FBAZytH6EN4B0c0QtAzr8A%3D%3D Puoi copiare il sorgente qui e compilarlo da te. Il modo classico è scaricare DosBox (0.74) da soli ed eseguirlo lì. Il modo più reale è quello di ottenere un MSDos o FreeDos Bootstick (Rufus) ed eseguirlo per il vero #noemu;)
HellMood,

9

Python 2/3, 169 167 150 111 98 78 byte

Si noti che l'importazione non è inclusa nel conteggio dei byte, secondo le specifiche della sfida.

Grazie a @AlexHall per aver salvato 39 (!) Byte e @ nedla2004 per altri 13

from turtle import*
o=[90]
for z in o*9:o+=[90]+[-x for x in o[::-1]]
fd(5)
for i in o:rt(i);fd(5)

Inizia generando un elenco di curve a destra (90) e a sinistra (-90), quindi scorre l'elenco e sposta la tartaruga.

Uscita generata: inserisci qui la descrizione dell'immagine

EDIT: Se questo è troppo noioso, guarda, aggiungi speed(0)subito prima del primo fd(5). Funzionerà allo stesso modo, tranne che la tartaruga si muoverà molto più velocemente.


Una foto sarebbe bella :)
Kritixi Lithos il

Potresti pubblicare una foto o uno screenshot dell'output? Non è nemmeno chiaro che questo codice stampa qualcosa sullo schermo
J. Antonio Perez,

L'immagine è stata tagliata
J. Antonio Perez,

Ora dovrebbe essere risolto :)
Theo

@AlexHall Grazie! Sapevo che doveva esserci stato un modo per rendere quel ciclo più breve :)
Theo

8

Logo, 43 byte

for[i 1 512][fd 9 lt :i/(bitand :i -:i)*90]

Prova con l'interprete su http://www.calormen.com/jslogo/#

Questo utilizza lo stesso principio della mia precedente risposta sull'arte ASCII e la formula su wikipedia, tranne per il fatto che ho invertito la direzione in modo che corrisponda all'immagine nella domanda:

Innanzitutto, esprimi n nella forma in k*(2^m)cui k è un numero dispari. La direzione dell'ennesima svolta è determinata da k mod 4, ovvero il resto a sinistra quando k è diviso per 4. Se k mod 4 è 1, l'ennesima svolta è R L; se k mod 4 è 3, l'ennesima curva è L R

bitand :i -:itrova il bit meno significativo di i. Dividiamo iper questo a shitft igiusto l'importo richiesto, dando il numero dispari richiesto k. Non è necessario distinguere tra svolta a destra e a sinistra; giriamo a sinistra per k*90gradi e facciamo affidamento sul fatto che la rotazione è un modulo 360 per eseguire il modulo per noi.

Produzione

usare htper nascondere la tartaruga, se necessario.

inserisci qui la descrizione dell'immagine

Uscita (modificata)

Quanto segue mostra come la curva sia un singolo filamento.

bk 6 for[i 1 512][fd 6 rt :i/(bitand :i -:i)%4*45-90 fd 3 rt :i/(bitand :i -:i)%4*45-90]

inserisci qui la descrizione dell'immagine


4

LindenMASM , 51 byte

LindenMASM era una lingua che ho creato per una sfida qualche tempo fa che vivrà per sempre nella Sandbox. Fa uso del concetto di sistemi Lindenmayer per disegnare cose come curve di drago, piante frattali, triangoli di Sierpinski, ecc.

Il codice sorgente è il seguente:

STT
AXI FX
INC 9
SET F 0
RPL X X+YF+
RPL Y -FX-Y
END

Per impostare questo n = 6ad esempio:

STT
AXI FX
INC 6
SET F 0
RPL X X+YF+
RPL Y -FX-Y
END

Questo produce la seguente immagine tramite Python 3 turtle:

6 generazioni

Potrebbe esserci una leggera differenza di numerazione per le iterazioni, poiché nel sistema Lindenmayer la prima iterazione è una riga singola. Ecco come si presenta n = 10:

10 generazioni

Solo per divertimento, ecco come appare con 15 generazioni (con un'istruzione aggiunta MOV 2per renderlo un po 'più piccolo):

15 generazioni

Una volta che ottieni fino a 20 generazioni (con MOV 0.5) non puoi più vedere le linee e ci vogliono MOLTI passaggi per creare (le coppie di +-e -+non sono ottimizzate). Ecco cosa ottieni:

20 generazioni

Si noti che l'attuale interprete può presentare problemi grafici per piccole quantità di generazioni, vale a dire forse non disegnare sullo schermo. Sfortunatamente quando questo interprete è stato creato non c'erano problemi, un possibile cambiamento in Python 3 avrebbe potuto causare questo o potrebbe essere solo il mio sistema


4

Sottocarico, 196 byte

()()(<svg width="99" height="147">)S(<g transform="translate):S((33,33)">)S((3,0)rotate)*a(*a(~*)*~("><path d="M0h3" stroke="#"/>)~*a(*)**:(-90)a~^~(90)a~^)*::*:**:*^S(</g>)(:*)::*:**:*^S(</svg>)S

Ho pensato che potesse essere interessante provare questa sfida in un esolang a bassa potenza; Underload funziona abbastanza bene per una lingua con un numero di comandi così basso.

L'output è un file SVG con tag fortemente nidificati e alcune scorciatoie da golf. Finora non ho trovato un browser in grado di visualizzarlo (Firefox si blocca per diversi minuti nel tentativo di caricarlo e sia Firefox che Chromium danno uno schermo vuoto). La maggior parte dei programmi di elaborazione delle immagini non può nemmeno caricarlo (rendendo difficile la conversione in un altro formato), ma sono riuscito a caricarlo nel visualizzatore di immagini Eye of Gnome (che fa parte dell'installazione predefinita su Ubuntu). Quindi ho fatto uno screenshot dell'immagine in modo che tu possa vederlo (l'immagine reale ha uno sfondo trasparente, ma non puoi davvero fare uno screenshot trasparente):

Schermata di una curva del drago in Underload

Dobbiamo specificare esplicitamente la dimensione dell'immagine. Scegliere un orientamento appropriato per l'immagine, disegnare tutto alla minima dimensione legale e fare il numero minimo di iterazioni specificato dalla sfida, ci dà un'immagine che si adatta a soli 99 pixel di larghezza, salvando un byte. È bello quando le cose vanno così.

L'algoritmo generale utilizzato per disegnare immagine è di mantenere due variabili (sottocarico non nomina variabili, ma ho pensato di loro come x ed y ), sia inizialmente vuota. Quindi sostituiamo ripetutamente ( x , y ) con ( x , gira a sinistra e avanza, y ) e ( x , gira a destra e avanza, y ). Dopo dieci iterazioni, sia x ed y tenere una curva drago nove iterazione.

Ci sono anche alcune micro-ottimizzazioni e trucchi specifici per il sottocarico. Al fine di evitare troppa guai con la parte superiore della pila, ogni iterazione del ciclo, iniziamo combinando x ed y nella funzione "restituire la stringa creata concatenando: x , un'istruzione volta, l'argomento della funzione, un movi- istruzioni avanti e y ". Questa funzione occupa solo uno spazio sulla pila, in modo da poter duplicare, chiama con -90come argomento, scambiare il valore restituito sotto il duplicato, e chiamare con 90come argomento, per entrare in possesso di nuovi valori per x ed ysenza mai dover toccare più dei primi due elementi della pila (che sono di gran lunga i più comunemente accessibili). Questa funzione è generata dal codice in fase di esecuzione. Il generatore stesso è anche generato dal codice in fase di runtime, al fine di consentirgli di riutilizzare la stringa <g transform="translateutilizzata anche per impostare l'origine dell'immagine. Generiamo prima tutti i tag aperti, e quindi poiché tutti i tag di chiusura sono giusti </g>, possiamo generare 1024 tag di chiusura semplicemente ripetendo la stringa, senza preoccuparci di abbinarli ai tag aperti. (Scrivere i numeri in modo efficiente in Underload è un problema interessante a sé stante; (:*)::*:**:*è probabilmente il modo più efficiente per scrivere 1024, tuttavia, traducendo in "2 alla potenza di (1 + 2 × 2) × 2".

Underload non ha librerie grafiche, quindi produco SVG usando una combinazione di linee di disegno in una posizione fissa e ruotando l'immagine attorno a un determinato punto; invece di girare la penna, giriamo la carta. L'idea è che disegnando una linea, ruotando l'intera immagine, disegnando un'altra linea, ruotando di nuovo l'immagine, ecc., Possiamo simulare efficacemente la grafica delle tartarughe senza dover fare alcuna aritmetica o utilizzare librerie grafiche, poiché tutte le linee sono disegnate nella stessa posizione. Ovviamente, ciò significa che abbiamo alcuni tag di rotazione dell'immagine fortemente nidificati, che confondono molti visualizzatori SVG.

Lo stile dell'immagine conterebbe rispetto al conteggio dei byte, quindi dovevo fornire lo stile minimo necessario per visualizzare l'immagine. Questo risulta essere stroke="#", che più o meno si traduce come "la linea deve essere un po 'di colore"; questo sembra essere espanso per disegnarlo in nero. (Normalmente dovresti specificare il colore come, ad esempio, "# 000".) Lo sfondo è trasparente per impostazione predefinita. Non specifichiamo la larghezza del tratto, ma la scelta scelta da Eye of Gnome lascia tutto visibile.

Molti interpreti di Underload hanno difficoltà con questo programma, ad esempio quello su Try It Online si arresta in modo anomalo perché genera internamente stringhe molto grandi. L'interprete online Underload originale funziona, tuttavia. (È interessante notare che il primo interprete era online, quindi la lingua era utilizzabile online prima che fosse utilizzabile offline.)

Qualcosa di cui sono leggermente a disagio è che qui sembrano esserci solo 1023 segmenti di linea, e ci aspetteremmo 1024. Potrebbe essere che uno dei segmenti alla fine non sia disegnato con questo algoritmo (sarebbe disegnato invece sulla prossima iterazione). Se questo è squalificante, potrebbe essere possibile adattare il programma, ma potrebbe finire molto più a lungo. (Non è che questa sfida vincerà comunque la competizione; ci sono già diverse voci più brevi.)


4

MATL , 26 byte

0J1_h9:"tPJ*h]hYsXG15Y01ZG

Se vengono accettate scale diverse nei due assi, il codice può essere ridotto a 19 byte:

0J1_h9:"tPJ*h]hYsXG

Le figure seguenti corrispondono alla versione in scala uguale (26 byte).

Il codice sopra produce la nona iterazione (basata su 0), ovvero la decima immagine della sfida:

inserisci qui la descrizione dell'immagine

Per altri valori, modificare il 9nel codice o sostituirlo iper prendere il numero come input dell'utente. Ad esempio, il risultato per 13è:

inserisci qui la descrizione dell'immagine

Spiegazione

Questo utilizza un ciclo per costruire gradualmente una matrice dei passi seguiti dalla curva nel piano complesso. Ad esempio, i primi due passaggi sono 1j(su) e -1(a sinistra).

In ogni iterazione, l'array di passaggi finora viene copiato. La copia dell'array viene invertita , moltiplicata per 1j(per ruotare di 90 gradi) e concatenata all'originale.

Dopo il ciclo, una somma cumulativa dei passaggi fornisce i punti effettivi, che vengono quindi tracciati nel piano complesso.

0                          % Push 0
 J1_h                      % Push array [1j, -1]. This defines the first two steps
     9:                    % Push [1, 2, ..., 9]
       "                   % For each
        t                  %   Duplicate the array of steps so far
         P                 %   Reverse
          J*               %   Multiply by 1j
            h              %   Concatenate horizontally to previous steps
             ]             % End
              h            % Concatenate with the initial 0
               Ys          % Cumulative sum
                 XG        % Plot. Complex numbers are plotted with real and imag as x and y
                   15Y0    % Push string 'equal'
                       1ZG % Set equal scale in the two axes

La tua risposta è impressionante :) ti dispiace fornire una spiegazione del codice?
J. Antonio Perez,

@Jorge Grazie! Fatto
Luis Mendo, il

Le versioni "19 byte" e "26 byte" fornite sono identiche. Presumo che ci sia un errore di copia e incolla qui?

@ ais523 In effetti! Ora corretto, grazie per averlo notato. A proposito, può essere visto in azione qui (compilatore sperimentale; potrebbe essere necessario aggiornare la pagina)
Luis Mendo,

3

Mathematica 86 byte

{1,-1}
r=Reverse;Graphics@Line@Nest[Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&,{{0,0},%},9]

Come funziona: {1,-1}uscite {1,-1}. Fondamentalmente "lo spinge in pila". Questo valore può essere richiamato con %. r=Reversefondamentalmente rinomina solo la funzione Reverse perché la uso due volte nel codice. La Graphics@Line@vuole solo un elenco di punti e disegna una linea che li collega. La vera carne del problema avviene in questo segmento di codice: Nest[Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&,{{0,0},%},9]. Fammi sapere che quel segmento è complicato come f ****** ck. Ecco cosa Nestfa: Nest[f,x,9]genera il risultato della chiamata f[f[f[f[f[f[f[f[f[x]]]]]]]]].

Nel mio codice, questo primo argomento fè :, Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&il secondo argomento xè {{0,0},%}(che valuta {{0,0},{1,-1}}), e il terzo argomento è n, che è solo 9 (che applicherà il primo argomento al secondo argomento 9 volte).

La parte più complessa di tutte è questa prima argomentazione: Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&che è un enorme pasticcio di zucchero sintattico quasi puro. Stavo davvero abusando dello zucchero sintattico di matematica per questo. Quella riga di codice rappresenta la versione di matematica di una funzione anonima, tranne per abbreviare le cose che in realtà ho definito due funzioni anonime separate all'interno di quella funzione anonima. Sì, è legale, gente. Analizziamolo.

Joinaccetta due argomenti. Il primo è l=Last@#;h=#-l&/@#e il secondo è r[r@#%&/@h].

Il primo argomento di Join: all'interno della funzione "principale" anonima, #è un elenco di tutti i punti dell'attuale iterazione nella curva. Quindi l=Last@#;significa "Prendi il punto nell'elenco dei punti che hai ricevuto come input e assegna quel punto alla variabile l. Il segmento successivo h=#-l&/@#, è un po 'più complesso. Significa" Hai una funzione. Questa funzione prende un punto come input, sottrae lda essa e restituisce il risultato. Ora applica quella funzione a tutti gli elementi dell'elenco di punti che hai ricevuto come input per generare un elenco di punti spostati e assegna quel nuovo elenco alla variabile h.

Il secondo argomento di Join: r[r@#%&/@h] ha letteralmente la sintassi più complessa che abbia mai scritto. Non riesco a credere che qualsiasi segmento di codice possa contenere qualcosa del genere @#%&/@- sembra che sto imprecando come un personaggio dei cartoni animati nel mezzo di un programma! Ma è possibile scomporlo. Ricorda: r[x]prende un elenco di punti e restituisce tale elenco in ordine inverso. r@#%&è una funzione anonima che inverte il suo input, quindi lo moltiplica per il valore riportato %(che è {1,-1}) e restituisce il risultato. Fondamentalmente ruota il suo input di 90 gradi, ma con un codice il più breve possibile. Quindi r@#%&/@hsignifica "Invia un nuovo elenco che è ogni punto hruotato di 90 gradi".

Quindi, nel complesso, Join[l=Last@#;h=#-l&/@#,r[r@#*%&/@h]]&è una funzione che accetta un elenco di punti come input e aggiunge lo stesso elenco di punti ruotati di 90 gradi per ottenere la successiva iterazione della curva. Questo viene ripetuto 9 volte per ottenere la curva del drago. Quindi è l'elenco risultante di punti viene disegnato sullo schermo come una linea. E l'output:

inserisci qui la descrizione dell'immagine


3
Ho appena trovato il trucco più strano per scrivere un vettore null: 0{,}... funziona perché 0 xè 0per quasi tutti xed {,}è zucchero sintattico per {Null,Null}.
Martin Ender,

3

Python 2, 43 byte

Questa risposta è di 43 byte senza includere la dichiarazione di importazione ed è in gran parte basata sulla risposta del Logo di Level River St e sul loro uso i/(i&-i)nel loro codice. Provalo online su trinket.io

from turtle import*
for i in range(1,513):fd(9);rt(90*i/(i&-i))

Ecco una foto dell'output.

inserisci qui la descrizione dell'immagine


Per quanto ne so, è necessario includere il conteggio dei byte dall'istruzione import nel conteggio dei byte totali.
Theo,

1
@Theo, citando solo le specifiche della sfida:The shortest code in bytes wins, however include directives for libraries shouldn't be included in the byte count, and you may use graphics libraries or other libraries written for your language of choice if they were written before the posting.
Sherlock9,

3

Mathematica, 56 55 byte

Graphics@Line@AnglePath[Pi/2JacobiSymbol[-1,Range@512]]

inserisci qui la descrizione dell'immagine

Spiegazione: OEIS A034947

Solo per divertimento, ecco una versione colorata della diciannovesima iterazione.

inserisci qui la descrizione dell'immagine


2

Mathematica, 63 byte

utilizzando AnglePath

Graphics@Line@AnglePath[Pi/2Nest[Join[#,{1},-Reverse@#]&,{},9]]

Nove iterazioni


1

HTML + JavaScript, 182

<canvas id=C></canvas><script>c=C.getContext("2d")
C.width=C.height=400
s=n=9
x=y=200
for(i=d=0;i<=1<<n;d+=++i/(i&-i))
c.lineTo(x,y),
d&1?y+=d&2?s:-s:x+=d&2?-s:s
c.stroke()</script>


0

Haskell + diagrammi, 179 byte

import Diagrams.Prelude
import Diagrams.Backend.SVG
d 1=hrule 1<>vrule 1
d n=d(n-1)<>d(n-1)#reverseTrail#rotateBy(1/4)
main=renderSVG"d"(mkWidth 99)$strokeT(d 9::Trail V2 Double)

L'output è un file svg di 99 pixel di larghezza con sfondo trasparente (un'immagine di 9 pixel di larghezza avrebbe un tratto troppo spesso per riconquistare qualcosa). Qui è riscalato e composto su uno sfondo bianco:

Drago numero nove


0

tosh , 518 byte

tosh è Scratch , ma con testo anziché blocchi. Con 518 byte, questa risposta è probabilmente anche peggiore di Java.

Questa risposta usa la stessa logica della risposta Python di @ Theo , ma con stringhe di "L" e "R" anziché numeri, dato che le capacità dell'elenco di Scratch (e quindi di tosh) sono terribili.

Puoi eseguirlo come progetto Scratch qui . (tosh compila in progetti Scratch)

when flag clicked
set path to "R"
go to x: -50 y: 100
point in direction 90
pen down
set pen size to 2
clear
repeat 9
    set path copy to path
    set path to join (path) "R"
    set i to length of path copy
    repeat length of path copy
        if letter i of path copy = "R" then
            set path to join (path) "L"
        else
            set path to join (path) "R"
        end
        change i by -1
    end
end
set i to 0
repeat length of path
    change i by 1
    if letter i of path = "R" then
         turn cw 90 degrees
    else
         turn ccw 90 degrees
    end
    move 7 steps
end  

Spiegazione:

when flag clicked
set path to "R"
go to x: -50 y: 100
point in direction 90
pen down
set pen size to 2
clear

Questa prima parte fa eseguire il programma quando si fa clic sulla bandiera verde ( when flag clicked), imposta la variabile del percorso su "R" e riporta lo sprite e lo stage nello stato corretto per essere pronti a disegnare.

repeat 9
    set path copy to path
    set path to join (path) "R"
    set i to length of path copy
    repeat length of path copy
        if letter i of path copy = "R" then
            set path to join (path) "L"
        else
            set path to join (path) "R"
        end
        change i by -1
    end
end

Ora arriviamo al codice di generazione del percorso. Utilizza la stessa logica della risposta Python di @ Theo , tranne con le stringhe di "R" e "L" anziché i numeri, e usiamo i cicli nidificati invece della comprensione dell'elenco.

set i to 0
repeat length of path
    change i by 1
    if letter i of path = "R" then
         turn cw 90 degrees
    else
         turn ccw 90 degrees
    end
    move 7 steps
end  

Infine, tracciamo il percorso esaminando ciascuna lettera della variabile del percorso e girando a sinistra o a destra a seconda della lettera.

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.