Spiral ASCII Rekursif

21

Persaingan ini berakhir. Terima kasih atas entri non-esolang yang menarik, dan selamat kepada Jakuje untuk pengajuan JavaScript yang menang.

Dalam tradisi besar Tantangan Seni ASCII di situs ini, inilah satu lagi. Diberikan input, gambar sebuah spiral.

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

Sederhana ya Heh, heh, heh ... Ya ...

(Terinspirasi oleh posting ASCII Dragons Curve , dan posting ASCII Art of the Day dari Optimizer )

Memasukkan

Input akan berupa serangkaian parameter, yang diambil dari argumen STDIN / function / etc, seperti apa pun bahasa Anda, terdiri dari empat bagian. Bagian-bagian ini dapat berupa empat argumen terpisah, empat kali lipat, array ukuran 4, dll. Untuk kesederhanaan dan konsistensi sepanjang tantangan, saya akan mewakili input sebagai satu kata.

  • Integer 2 ≤ x ≤ 20yang menentukan ukuran spiral dalam hal "kotak" dengan masing-masing karakter yang dicetak mewakili satu "kotak" dalam ukuran. Secara teoritis ini bisa sangat besar dalam ruang lingkup, tetapi mengingat bahwa kita menggambar seni ASCII, batas atas yang aman pada ini adalah 20 sehingga cocok agak sopan di layar.
  • Satu huruf d u ratau l, yang menunjukkan gerakan awal dari awal "kotak" (bawah, atas, kanan, kiri).
  • Opsional c, menunjukkan "berlawanan arah jarum jam." Jika cdihilangkan, asumsikan rotasi searah jarum jam untuk spiral.
  • Integer akhir 1 ≤ y ≤ 10yang menentukan berapa kali untuk mengulang gambar spiral, menggunakan "kotak" akhir dari spiral sebelumnya sebagai "kotak" awal dari yang baru. Saya memilih batas atas 10 karena saya ingin gambarnya selesai di beberapa titik.
  • Beberapa contoh input: 20lc5 13d2 2rc1

Yang menarik, perlu dicatat bahwa nilai ganjil untuk input ukuran akan menghasilkan @selalu menjadi pusat yang tepat dari spiral, tetapi bahkan nilai mungkin memiliki awal "kuadrat" di salah satu dari empat arah diagonal, tergantung pada arah awal perjalanan. Ini dapat menghasilkan beberapa ... pola ... menarik. Lihat dua contoh genap di bawah ini.

Input yang tidak mengikuti spesifikasi input (mis., 11q#s) Tidak terdefinisi dan saya sepenuhnya berharap program untuk muntah dengan tepat. :)

Keluaran

Output adalah output ASCII yang dapat dicetak melalui STDOUT setara bahasa, dengan spesifikasi sebagai berikut:

  • Awal "kuadrat" (dari setiap rekursi) harus ditandai dengan tanda-at @.
  • "Kotak" akhir harus ditandai dengan ampersand &. Dalam kasus beberapa rekursi, hanya "kotak" yang paling final yang harus ditandai &.
  • Sudut-sudut jalan spiral perlu "menunjuk" ke arah perjalanan, menggunakan < > v ^.
  • Perjalanan vertikal perlu ditarik oleh pipa |.
  • Perjalanan horizontal perlu digambar dengan garis putus-putus -.
  • "Kotak" yang ditimpa oleh rekursi nanti harus menampilkan arah perjalanan terbaru. Ini akan menghasilkan rekursi "baru" yang tampaknya berlapis-lapis di atas rekursi "lama". Lihat 4rc3contoh di bawah ini.
  • New trailing newline adalah OK, spasi mengarah bisa menjadi suatu keharusan dan diperbolehkan, tetapi spasi tambahan tidak diperbolehkan.
  • Saya tidak akan berlabuh jika Anda menggunakan urutan melarikan diri untuk menggambar seni ASCII pergi ke STDOUT, tapi saya akan diam-diam kecewa pada Anda. (Anda masih berhak menerima hadiah jika Anda menggunakannya)

Contohnya

2d4 = diameter 2, dimulai dengan turun, searah jarum jam, 4 rekursi

&@@@@
^<<<<

Dalam contoh ini, gambar dimulai di kanan atas @, turun satu, kiri, atas satu. Pada titik ini, kami telah menyelesaikan 2dbagiannya, dan mulailah rekursi ke-2, jadi kami memiliki yang lain @, turun satu, kiri satu, naik satu; kemudian rekursi ke-3; lalu tanggal 4 dan akhirnya milik kami &.

4rc3 = diameter 4, dimulai dengan berbelok ke kanan, berlawanan arah jarum jam, 3 rekursi

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

Dalam contoh ini, gambar dimulai di bagian bawah @, ke kanan, ke atas, berputar di sekitar, sampai mencapai tengah @dan menyelesaikan 4rcbagian. Ini kemudian diulangi dua kali lagi untuk mendapatkan 3 kali rekursi yang diminta. Perhatikan bahwa 4rc1hanya akan menjadi blok 4x4 kiri atas dari contoh ini.

7u1 = diameter 7, dimulai dengan naik, searah jarum jam, 1 rekursi (perhatikan sama dengan intro)

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

Menang & Batasan

Ini adalah Code Golf, jadi jawaban terkecil dalam bytes menang. Pengajuan harus dalam bentuk program / fungsi / CJam Code Block / etc. Batasan Standar Loophole Berlaku. Pengemudi profesional di jalur tertutup. Jika iritasi berlanjut, hentikan penggunaan dan konsultasikan dengan dokter Anda.

AdmBorkBork
sumber
3
Spesifikasinya sangat berbeda, tetapi hanya untuk referensi, inilah tantangan menggambar spiral sebelumnya: codegolf.stackexchange.com/questions/52494/… .
Reto Koradi
2
Tantangan yang bagus. +1 untuk "Pengemudi profesional di jalur tertutup"
jrich
3
Itu meminta>> jawaban.
The_Basset_Hound
2
"Ayo, teman-teman ... apakah kamu akan membiarkan Common Lisp menang? ;-)" Itulah alasan paling lucu untuk hadiah yang pernah aku lihat. Terima kasih
coredump
1
Saya duduk di sini tertawa bahwa Common Lisp dan Lua adalah dua bahasa yang berjuang untuk posisi teratas pada pertanyaan kode-golf. :)
AdmBorkBork

Jawaban:

6

Javascript, 578, 575, 553, 478, 377 Bytes

Setelah kalah Lua saya beralih ke beberapa bahasa yang lebih kompak dan pindah kompetisi ke 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,''))}

Algoritmanya sama, tetapi ditulis dalam bahasa yang lebih ringkas jadi saya berhasil mengalahkan si jahat :)

Sunting: Beberapa perubahan struktural diperlukan untuk mencapai di bawah Lisp lagi dan untuk menghilangkan spasi putih. Tapi kita di sini lagi.

Sunting2: Beberapa abstraksi diperhitungkan untuk mendapatkan di bawah 500. Semoga itu akan cukup :)

Sunting3: Terima kasih @Timwi, kodenya adalah 100 karakter lebih ramping. Saya belum memperbarui penjelasannya.

Tes ( versi online , diuji di 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       >------^

Dan agar adil, ada penjelasan yang adil:

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, ''))
}
Jakuje
sumber
Sangat bagus. Sesuai dengan aturan dan mengikuti contoh Anda, saya memutuskan untuk menghapus &optionalkata kunci (dan spasi) untuk menghemat 10 byte, yang memberikan 576 ... tawa jahat (well, Anda bilang Anda bisa bermain golf sedikit lagi, jadi ini seharusnya tidak sulit untuk dikalahkan, sampai seseorang menulis jawaban 60-byte dalam Pyth, tentu saja).
coredump
@coredump Challenge diterima :) Ini lebih sulit dari yang saya harapkan, tapi masih mungkin :) Saya percaya Anda bisa melakukannya dengan keras, tetapi tidak ada yang akan pernah memahaminya jadi saya percaya kompleksitasnya ada pada kemungkinan bahasa tersebut.
Jakuje
3
Jika Anda 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;
mengaitkan
2
Solusi ini cukup pintar. Namun, saya menemukan beberapa tempat lagi yang bisa
bermain golf
1
@ Jakuje Saya percaya itu adalah niat Timwi bagi Anda untuk mengambil versi 377 byte dan mengedit jawaban Anda untuk menggunakannya. ;) (Kalau tidak, dia hanya akan mengirim jawaban yang terpisah.)
Martin Ender
7

Gangguan umum, 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)))))

Semua tes masih berlalu. Fungsi ungolfed juga diperbarui untuk mencerminkan perubahan, seperti komentar. Saya akhirnya menyingkirkan remove-duplicatesuntuk mempersingkat kode, tetapi sekarang saya tidak tahu di mana menemukan lebih banyak byte. Jakuje dilakukan dengan baik.

Contohnya

(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)

&@@@@
^<<<<

Lihat juga 20lc10(pastebin).

Tidak disatukan

Tidak ada rekursi yang terlibat di sini, hanya pendekatan grafis Turtle dasar dengan loop:

  1. Gambarlah spiral dalam memori dengan menyimpan (x y char)tiga kali lipat dalam tumpukan.
  2. Elemen-elemen yang stabil menurut ydanx
  3. Iterasi daftar itu sambil menghindari duplikat (jejak sebelumnya) dan cetak dari kiri atas ke kanan bawah.
(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)))
coredump
sumber
4

Lua 5.2, 740 Bytes

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

Saya pikir itu akan menyenangkan untuk mencoba mengimplementasikan beberapa algoritma untuk mengalahkan Lisp, tetapi Lua mungkin bukan pilihan terbaik. Saya menghabiskan terlalu banyak waktu untuk itu, merekayasa secara berlebihan beberapa bagian untuk berakhir dengan yang jelek ini, tetapi merupakan solusi yang baik. Mungkin saya akan mencoba bahasa lain nanti untuk mengalahkan Lisp karena ada sekitar 90 karakter yang tidak dapat saya ambil dari algoritma ini.

Output pengujian:

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||
|||@|||
||^-<||
|^---<|
^-----<
Jakuje
sumber
2

PHP, 524 byte

Saya datang terlambat di pesta ini. Solusi PHP saya bukanlah yang terkecil, maupun yang paling cerdas. Itu hanya bekerja.

$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";}

Cara menjalankannya:

$ 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||
|||@|||
||^-<||
|^---<|
^-----<

Versi terperinci dengan tes, penjelasan, dan barang lainnya dapat ditemukan di github .

aksioma
sumber