Spirali ASCII ricorsive


21

Questa competizione è finita. Grazie per le interessanti voci non esolang e complimenti a Jakuje per la sua vincente presentazione JavaScript.

Nella grande tradizione di ASCII Art Challenges su questo sito, eccone un'altra. Dato un input, disegna una spirale.

&>----v
||>--v|
|||>v||
|||@|||
||^-<||
|^---<|
^-----<

Semplice? Heh, heh, heh ... Sì ...

(Ispirato al post ASCII Dragons Curve e ai post ASCII Art of the Day di Optimizer )

Ingresso

L'input sarà sotto forma di una serie di parametri, presi dal solito argomento STDIN / funzione / ecc., Qualunque sia il tuo equivalente linguistico, composto da quattro parti. Queste parti possono essere quattro argomenti separati, una quadrupla, una matrice di dimensioni 4, ecc. Per semplicità e coerenza durante la sfida, rappresenterò l'input come una sola parola.

  • Un numero intero 2 ≤ x ≤ 20che specifica la dimensione della spirale in termini di "quadrati" con ciascun carattere stampato che rappresenta un "quadrato" di dimensioni. Teoricamente questo potrebbe essere di portata enorme, ma dato che stiamo disegnando l'arte ASCII, un limite superiore sicuro su questo sarà 20 in modo che si adatti in modo discreto sullo schermo.
  • Una singola lettera di d u ro l, che indica il movimento iniziale dal "quadrato" iniziale (giù, su, destra, sinistra).
  • Un facoltativo c, che indica "in senso antiorario". Se cviene omesso, assumere la rotazione in senso orario per la spirale.
  • Un numero intero finale 1 ≤ y ≤ 10che specifica quante volte ricorrere al disegno a spirale, usando il "quadrato" di finitura della spirale precedente come "quadrato" iniziale di quello nuovo. Sto scegliendo un limite superiore di 10 perché voglio che il disegno finisca ad un certo punto.
  • Alcuni input di esempio: 20lc5 13d2 2rc1

È interessante notare che i valori dispari per l'immissione della dimensione comporteranno @sempre il centro esatto di una spirale, ma i valori pari potrebbero avere l'offset "quadrato" iniziale in una qualsiasi delle quattro direzioni diagonali, a seconda della direzione iniziale viaggio. Ciò può comportare alcuni modelli ... interessanti ... Vedi i due esempi pari di seguito.

L'input che non segue le specifiche di input (ad es. 11q#s) È indefinito e mi aspetto che il programma funzioni correttamente. :)

Produzione

L'output è un output stampabile ASCII tramite STDOUT equivalente in una lingua, con le seguenti specifiche:

  • Il "quadrato" iniziale (di ciascuna ricorsione) deve essere contrassegnato da un segno @.
  • Il "quadrato" finale deve essere contrassegnato da una e commerciale &. In caso di ricorsioni multiple, dovrebbe essere marcato solo il "quadrato" definitivo &.
  • Gli angoli del percorso a spirale devono "puntare" nella direzione di marcia, usando < > v ^.
  • La corsa verticale deve essere disegnata da tubi |.
  • La corsa orizzontale deve essere disegnata con trattini -.
  • I "quadrati" che vengono sovrascritti da successive ricorsioni dovrebbero mostrare la direzione di viaggio più recente. Ciò si tradurrà in ricorsioni "più recenti" che sembrano essere sovrapposte a ricorsioni "più vecchie". Vedi l' 4rc3esempio sotto.
  • Un'ultima riga finale finale è OK, gli spazi iniziali potrebbero essere un must e quindi sono consentiti, ma gli spazi finali non sono consentiti.
  • Non ti attraccherò se usi sequenze di escape per disegnare l'arte ASCII andando su STDOUT, ma rimarrò silenziosamente deluso da te. (Avrai comunque diritto alla taglia se li usi)

Esempi

2d4 = diametro di 2, inizia scendendo, in senso orario, 4 ricorsioni

&@@@@
^<<<<

In questo esempio, il disegno inizia in alto a destra @, scende in basso, uno a sinistra, uno in alto. A questo punto, abbiamo terminato la 2dporzione, quindi iniziamo la seconda ricorsione, quindi ne abbiamo un'altra @, una giù, una sinistra, una su; quindi la 3a ricorsione; quindi il 4 ° e infine il nostro &.

4rc3 = diametro di 4, inizia andando a destra, in senso antiorario, 3 ricorsioni

&--<
v-<|
|@^|<
>--^|
 |@^|<
 >--^|
  |@^|
  >--^

In questo esempio, il disegno inizia nella parte inferiore @, va a destra uno, uno in alto, a spirale attorno, fino a quando non raggiunge il centro @e termina la 4rcporzione. Questo quindi si ripete altre due volte per ottenere le 3 ricorsioni richieste. Si noti che 4rc1sarebbe solo il blocco 4x4 in alto a sinistra di questo esempio.

7u1 = diametro di 7, inizia salendo, in senso orario, 1 ricorsione (nota che è lo stesso dell'intro)

&>----v
||>--v|
|||>v||
|||@|||
||^-<||
|^---<|
^-----<

Vincere e restrizioni

Questo è Code Golf, quindi vince la risposta più piccola in byte. Gli invii devono essere nella solita forma di programma / funzione / CJam Code Block / ecc. Si applicano restrizioni standard sulle scappatoie. Autista professionista su percorso chiuso. Se l'irritazione persiste, interrompere l'uso e consultare il medico.


3
Le specifiche sono piuttosto diverse, ma solo per riferimento, ecco una precedente sfida del disegno a spirale: codegolf.stackexchange.com/questions/52494/… .
Reto Koradi,

2
Bella sfida. +1 per "Autista professionista su percorso chiuso"
jrich

3
Chiede una risposta> <>.
The_Basset_Hound,

2
"Dai ragazzi ... avete intenzione di far vincere Common Lisp? ;-)" Questa è la ragione più esilarante per una taglia che io abbia mai visto. Grazie
coredump

1
Sono seduto qui ridacchiando che Common Lisp e Lua sono le due lingue in lotta per il primo posto in una domanda di code-golf. :)
AdmBorkBork,

Risposte:


6

Javascript, 578, 575, 553, 478, 377 byte

Dopo la battuta Lua sono passato a un linguaggio più compatto e ho spostato la competizione su Javascript:

s=function(w,d,c,r){d="dlur".indexOf(d)
j=i=G=H=I=J=w*r;o=[];for(x=0;x<J*2;x++){o[x]=[]
for(y=0;y<J*2;)o[x][y++]=' '}for(;r--;){a=d;m=l=z=1;o[i][j]="@"
for(k=w*w-1;k--;){G=G<i?G:i;H=H>i?H:i;I=I<j?I:j;J=J>j?J:j
o[i+=(1-a)%2][j+=a?a-2:0]=l++==m?(a+=c=="c"?3:1,m+=z=!z,l=1,"v<^>"[a%=4]):k?"|-"[a%2]:"&"}}for(i=G;i<=H;)console.log(o[i++].slice(I,J+1).join("").replace(/\s+$/g,''))}

L'algoritmo è lo stesso, ma scritto in un linguaggio più compatto quindi sono riuscito a battere il malvagio Lisp :)

Modifica: sono stati necessari alcuni cambiamenti strutturali per raggiungere nuovamente sotto Lisp ed eliminare gli spazi bianchi finali. Ma siamo di nuovo qui.

Edit2: alcune astrazioni prese in considerazione per ottenere meno di 500. Spero che sia abbastanza :)

Edit3: Grazie @Timwi, il codice è più sottile di 100 caratteri. Non ho ancora aggiornato la spiegazione.

Test ( versione online , testato in Chrome):

----| 2d4 |---
s.js:9 &@@@@
s.js:9 ^<<<<
ss.html:7 ----| 4rc3 |---
s.js:9 &--<
s.js:9 v-<|
s.js:9 |@^|<
s.js:9 >--^|
s.js:9  |@^|<
s.js:9  >--^|
s.js:9   |@^|
s.js:9   >--^
ss.html:9 ----| 7u1 |---
s.js:9 &>----v
s.js:9 ||>--v|
s.js:9 |||>v||
s.js:9 |||@|||
s.js:9 ||^-<||
s.js:9 |^---<|
s.js:9 ^-----<
ss.html:11 ----| 8r3 |---
s.js:9       >------v
s.js:9       |>----v|
s.js:9       ||>--v||
s.js:9       |||@v|||
s.js:9    >------v|||
s.js:9    |>----v|<||
s.js:9    ||>--v||-<|
s.js:9    |||@v|||--<
s.js:9 >------v|||
s.js:9 |>----v|<||
s.js:9 ||>--v||-<|
s.js:9 |||@v|||--<
s.js:9 ||^-<|||
s.js:9 |^---<||
s.js:9 ^-----<|
s.js:9 &------<
ss.html:13 ----| 8rc3 |---
s.js:9 &------<
s.js:9 v-----<|
s.js:9 |v---<||
s.js:9 ||v-<|||
s.js:9 |||@^|||--<
s.js:9 ||>--^||-<|
s.js:9 |>----^|<||
s.js:9 >------^|||
s.js:9    |||@^|||--<
s.js:9    ||>--^||-<|
s.js:9    |>----^|<||
s.js:9    >------^|||
s.js:9       |||@^|||
s.js:9       ||>--^||
s.js:9       |>----^|
s.js:9       >------^

E per essere onesti, c'è una spiegazione giusta:

s = function(w, d, c, r) {
    // width, direction, "c" as counter-clockwise and number of repetition
    // transfer direction to internal numerical representation
    d=d=="d"?0:d=="u"?2:d=="l"?1:3;
    // output strings
    x="v<^>"
    y="|-"
    // this is size of our canvas. Could be smaller, but this is shorter
    M = w * r * 2;
    // fill canvas with spaces to have something to build upon
    o = [];
    for (i = 0; i < M; i++) {
        o[i] = [];
        for (j = 0; j < M; j++)
            o[i][j] = ' '
    }
    // i,j is starting position
    // G,H,I,J are current boundaries (maximum and minimum values of i and j during the time)
    j = i = G = H = I = J = M / 2
    for (q = 0; q < r; q++) { // number of repeats
        a = d; // reset original direction
        // m is the expected length of side
        // l counts the of current side length
        m = l = 1;
        z = 0; // counts occurrences of the length
        o[i][j] = "@" // write initial character
        for (k = w * w; k > 1; k--) { // cycle over the whole spiral
            // update boundaries
            G = G < i ? G : i;
            H = H > i ? H : i;
            I = I < j ? I : j;
            J = J > j ? J : j;
            // move to the next position according to direction
            i+=a<3?1-a:0;
            j+=a>0?a-2:0
            if (k == 2) // we reached the end
                o[i][j] = "&"
            else if (l == m) {
                // we reached the corner so we need to count next direction
                a=(c=="c"?a+3:a+1)%4;
                // and write according sign
                o[i][j]=x[a]
                // first occurrence of this length
                if (z == 0)
                    z = 1; // wait for finish of the other
                else {
                    m++; // increase length of side
                    z = 0 // wait again for the first one
                }
                l = 1 // start the side counter over
            } else {
                l++ // another part of this side
                // according side character
                o[i][j] = y[a%2]
            }
        }
    }
    // blow it all out
    for (i = G; i <= H; i++)
        console.log(o[i].slice(I, J + 1).join("").replace(/\s+$/g, ''))
}

Molto bella. In conformità con le regole e seguendo il tuo esempio, ho deciso di rimuovere la &optionalparola chiave (e uno spazio) per risparmiare 10 byte, il che dà 576 ... risate malvagie (beh, hai detto che potresti golf un po 'di più, quindi questo non dovrebbe essere difficile da battere; fino a quando qualcuno non scriverà una risposta di 60 byte in Pyth, ovviamente).
coredump,

@coredump Challenge accettata :) È più difficile di quanto mi aspettassi, ma è ancora possibile :) Credo che tu possa farlo in Pyth, ma nessuno lo capirà mai, quindi credo che la complessità sia al di sopra delle possibilità di tale linguaggio.
Jakuje,

3
Se i=M/2;j=i;G=i;H=i;I=i;J=i;i=j=G=H=I=J=M/2;m=1;l=1;m=l=1;
incateni

2
Questa soluzione è piuttosto intelligente. Tuttavia, ho trovato molti altri posti che possono essere giocati a golf: 377 byte
Timwi

1
@Jakuje Credo che l'intenzione di Timwi sia stata quella di prendere la versione da 377 byte e modificare la risposta per usarla. ;) (Altrimenti avrebbe appena pubblicato una risposta separata.)
Martin Ender,

7

Lisp comune, 649 617 605 586 576 565 554 527 518

(lambda(r v z c &aux(m 0)s(c(if c 1 -1))o p(x 0)i(y 0)j u)(#8=dotimes(_ z)(#7=setf p(aref"ruld"v)i(1-(abs(- p 2)))j(- 1(abs(1- p)))s'@)(#8#($(1- r))#5=(#7#m(min m x)o(cons`(,x,y,s)o)s(aref"-|-|"p)x(+ x i)y(+ y j))#2=(#7#s(*(- c)j)j(* i c)i s p(mod(+ p c)4)s(aref">^<v"p)u(#8#(_(1+ $))#5#))#2#))(#7#s'& u #5#o(#4=stable-sort(#4#o'< :key'car)'> :key'cadr)y(cadar o)x m)(dolist(k o)(do()((>=(cadr k)y))(#7#y(1- y)x m)(terpri))(do()((<=(car k)x))#9=(incf x)(princ" "))(and(=(cadr k)y)(=(car k)x)#9#(princ(caddr k)))))

Tutti i test continuano a passare. Anche la funzione non golfata è stata aggiornata per riflettere le modifiche, così come i commenti. Mi sono finalmente liberato remove-duplicatesper abbreviare il codice, ma ora non so dove trovare più byte. Ben fatto Jakuje.

Esempi

(funcall *fun* 8 #\r 3 nil)

      >------v
      |>----v|
      ||>--v||
      |||@v|||
   >------v|||
   |>----v|<||
   ||>--v||-<|
   |||@v|||--<
>------v|||
|>----v|<||
||>--v||-<|
|||@v|||--<
||^-<|||
|^---<||
^-----<|
&------<

(funcall *fun* 8 #\r 3 t) ;; counter-clockwise

&------<
v-----<|
|v---<||
||v-<|||
|||@^|||--<
||>--^||-<|
|>----^|<||
>------^|||
   |||@^|||--<
   ||>--^||-<|
   |>----^|<||
   >------^|||
      |||@^|||
      ||>--^||
      |>----^|
      >------^

(funcall *fun* 7 #\u 1 nil)

&>----v
||>--v|
|||>v||
|||@|||
||^-<||
|^---<|
^-----<

(funcall *fun* 2 #\d 4 nil)

&@@@@
^<<<<

Vedi anche 20lc10(pastebin).

Ungolfed

Non vi è alcuna ricorsione in questo caso, solo un approccio grafico di base alla tartaruga con loop:

  1. Disegna le spirali in memoria memorizzando le (x y char)triple in una pila.
  2. Elementi di ordinamento stabile secondo yex
  3. Passa da un elenco all'altro evitando i duplicati (tracce precedenti) e stampa da in alto a sinistra a in basso a destra.
(lambda
    (r v z c
     &aux
       (m 0)       ; minimal x
       s           ; symbol to print (a character)
       (c          ; 1 if clockwise, -1 otherwise
        (if c
            1
            -1))
       o           ; stack of (x y char) traces
       p           ; position of s in ">^<v"
       i           ; move direction of x
       j           ; move direction of y
       (x 0)       ; position in x
       (y 0)       ; position in y
       u           ; auxiliary variable
       )
  ;; repeat for each recursive step
  (dotimes (_ z)
    ;; initialize spiral parameters
    (setf s '@            ; start spiral with @
          p (position v"ruld") ; initialize p according to input V

          ;; Set initial direction in I and J.
          i (1-(abs(- p 2))) ; i(0..3) = ( 1, 0, -1, 0 )
          j (- 1(abs(1- p))) ; j(0..3) = ( 0, 1, 0, -1 )

    ;; Iterate with increasing diameter $. For each iteration, draw a
    ;; "L"-shape that extends previous shape. Here is roughly what
    ;; happens at each step:
    ;;
    ;;   3334
    ;;   3124
    ;;   3224
    ;;   4444
    ;;
    (dotimes($(1- r))

      ;;
      ;; Assign the form to the reader variable #1# in order to
      ;; copy-paste later. This is like declaring a local function,
      ;; but shorter: push trace into list O and move forward.
      ;;
      #1=(setf m (min m x)
               o (cons `(,x ,y ,s) o)
               s (aref "-|-|" p)
               x (+ x i)
               y (+ y j))

      ;;
      ;; Helper function #2#: rotate and draw a line of length $.
      ;;

      #2=(setf u (* (- c) j) ; rotation as a vectorial                   
               j (* i c)     ; product of (i j 0) with (0 0 c).
               u i           ; At first I used PSETF, but now I reuse
                             ; the existing SETF with an auxiliary 
                             ; variable U to shorten the code and get
                             ; rid of PROGN. That's also why I affect
                             ; the result of DOTIMES to U (no need
                             ; for two forms and a PROGN, just SETF).

               p (mod(+ p c)4)   ; ">^<v" is sorted counter-clockwise, which 
               s (aref ">^<v" p) ; means that adding P and C (modulo 4) gives 
                                 ; the next symbol after rotation.

               ;; trace a line by repeatedly invoking code snippet #1#
               u (dotimes(_(1+ $)) #1#))
      ;; 
      ;; Rotate and draw a second line, hence drawing a "L"-shape.
      ;;
      #2#))

  ;; Finally, draw the final symbol &
  (setf s '&)
  #1#

  (setf o

        ;; From inside-out:
        ;;
        ;; - stable sort O according to X
        ;;   (from lowest (left) to highest (right))
        ;;
        ;; - stable sort the result according to Y
        ;;   (from highest (top) to lowest (bottom))
        ;;
        (stable-sort (stable-sort o '< :key 'car) '> :key 'cadr)

        ;; initialize Y with the first Y in O, which is also the
        ;; minimum of all Y.
        y (cadar o)

        ;; initialize X with the minimum of all X
        x m) 

  ;; For each trace in O
  (dolist (k o)

    ;; Add as many lines as needed to advance Y to current trace's Y.
    (do ()
      ((<= y (cadr k)))
      (setf y (1- y)
            x m)
      (terpri))

    ;; Add as many spaces as needed to advance X to current trace's X.
    (do () ((>= x (car k))) (incf x) (princ " "))

    ;; Then, print current trace's character and increment X.
    ;; This happens only when we have a "new" trace, not another
    ;; trace at the same point (which was being overwritten).
    (and(=(car k)x)(=(cadr k)y)(incf x)(princ(caddr k)))

4

Lua 5.2, 740 byte

s=io.read W=io.write Z=math.max A=math.min
D="d"U="u"L="l"R="r"function n()G=A(G,i)H=Z(H,i)I=A(I,j)J=Z(J,j)i=(a==D and i+1 or a==U and i-1 or i)j=(a==R and j+1 or a==L and j-1 or j)end
w=s"*n"d=s(1)c=s(1)r=(c=="c")and s"*n"or c
c=c=="c"M=w*(r+1)o={}for i=1,M do o[i]={}for j=1,M do o[i][j]=" "end end
i=M/2 j=i G=i H=i I=i J=i
for q=1,r do a=d m=1 l=1 z=0
o[i][j]="@"for k=3,w^2 do
n()if l==m then
a=c and(a==D and R or a==U and L or a==L and D or a==R and U)or(a==D and L or a==U and R or a==L and U or a==R and D)o[i][j]=(a==D and"v"or a==U and"^"or a==L and"<"or a==R and">")
if z==0 then z=1 else m=m+1;z=0 end
l=1
else
l=l+1
o[i][j]=(a==D or a==U)and"|"or"-"end end
n()o[i][j]="&"end
for i=G,H do for j=I,J do
W(o[i][j])end W("\n")end

Ho pensato che sarebbe stato divertente provare a implementare un algoritmo per battere Lisp, ma Lua probabilmente non è l'opzione migliore. Ci dedico troppo tempo, ho ingegnerizzato alcune parti per finire con questa soluzione brutta ma funzionante. Probabilmente proverò più lingue in un secondo momento per battere Lisp poiché ci sono circa 90 caratteri che non riesco a togliere da questo algoritmo.

Test delle uscite:

jakuje@E6430:/tmp$ echo "2d4" | lua s.lua 
&@@@@
^<<<<
jakuje@E6430:/tmp$ echo "4rc3" | lua s.lua 
&--<  
v-<|  
|@^|< 
>--^| 
 |@^|<
 >--^|
  |@^|
  >--^
jakuje@E6430:/tmp$ echo "7u1" | lua s.lua 
&>----v
||>--v|
|||>v||
|||@|||
||^-<||
|^---<|
^-----<

2

PHP, 524 byte

Sono arrivato tardi a questa festa. La mia soluzione PHP non è né la più piccola né la più intelligente. Funziona e basta.

$a=$argv;
$b=[['|','^',0,-1],['-','>',1,0],['|',v,0,1],['-','<',-1,$x=$y=$o=$p=$q=$r=0]];
for($t=$a[4];$t;$t--){$d=strpos(urdl,$a[2]);$c=$b[$d];$m[$y][$x]='@';
for($s=0;++$s<$a[1];){for($k=3;--$k;){for($i=$s;--$i;)
$m[$y+=$c[3]][$x+=$c[2]]=$c[0];$x+=$c[2];$y+=$c[3];$c=$b[$d=($d+($a[3]==c?3:1))%4];
$m[$y][$x]=$c[1];}$o=min($x,$o);$p=max($p,$x);$q=min($y,$q);$r=max($r,$y);}
for($i=$s;--$i;)$m[$y+=$c[3]][$x+=$c[2]]=$c[0];$m[$y][$x]='&';}
for($y=$q;$y<=$r;$y++){$l='';for($x=$o;$x<=$p;$x++)$l.=$m[$y][$x]?:' ';
echo rtrim($l)."\n";}

Come eseguirlo:

$ php -d error_reporting=0 recursive-ascii-spirals.php 4 r c 3
&--<
v-<|
|@^|<
>--^|
 |@^|<
 >--^|
  |@^|
  >--^
$ php -d error_reporting=0 recursive-ascii-spirals.php 7 u '' 1
&>----v
||>--v|
|||>v||
|||@|||
||^-<||
|^---<|
^-----<

La versione dettagliata con test, spiegazioni e altre chicche può essere trovata su github .

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.