재귀 ASCII 나선


21

이 경쟁은 끝났습니다. 흥미로운 비 -esolang 항목에 감사하고, JavaScript를 제출 한 Jakuje 에게 축하 를 전합니다.

이 사이트의 ASCII 아트 챌린지의 위대한 전통에서 또 다른 것이 있습니다. 입력이 주어지면 나선을 그립니다.

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

간단 하죠? 허, 허, 허 ... 그래 ...

( ASCII Dragons Curve 게시물 및 Optimizer의 ASCII Art of the Day에서 영감을 얻었습니다. 게시물에서 )

입력

입력은 언어에 상관없이 일반적인 STDIN / 함수 인수 등에서 취한 일련의 매개 변수 형식으로 이루어지며 네 부분으로 구성됩니다. 이 부분들은 4 개의 독립된 인수, 4 배, 크기 4의 배열 등이 될 수 있습니다. 도전을 통한 단순성과 일관성을 위해 입력을 단일 단어로 표현할 것입니다.

  • 정수 2 ≤ x ≤ 20인쇄 된 각 문자가 하나의 "사각형"크기를 나타내는 "사각형"으로 나선의 크기를 지정 입니다. 이론적으로 이것은 범위가 엄청날 수 있지만, ASCII 아트를 그릴 때, 안전한 상한은 20이되어 화면에 다소 맞습니다.
  • 시작 "사각"(아래, 위, 오른쪽, 왼쪽)에서 초기 이동을 나타내는 d u r또는 의 단일 문자 l.
  • c"시계 반대 방향"을 나타내는 옵션 입니다. 를 c생략하면 나선의 시계 방향 회전을 가정합니다.
  • 1 ≤ y ≤ 10이전 나선의 끝 "사각"을 새 나선의 시작 "사각"으로 사용하여 나선 그리기를 반복하는 횟수를 지정하는 최종 정수 . 도면을 어느 시점에서 끝내기를 원하기 때문에 상한을 10으로 지정합니다.
  • 몇 가지 입력 예 : 20lc5 13d2 2rc1

크기 입력에 대한 홀수 값은 @항상 나선의 정확한 중심이되지만 초기 값의 방향에 따라 네 개의 대각선 방향에서 시작 "사각"오프셋이있을 수 있습니다. 여행. 이것은 몇 가지 흥미로운 ... 패턴을 초래할 수 있습니다. 아래의 두 가지 짝수 예를 참조하십시오.

입력 사양을 따르지 않는 입력 (예 11q#s:)은 정의되어 있지 않으며 프로그램이 적절하게 작동 할 것으로 예상합니다. :)

산출

출력은 다음 스펙을 가진 언어와 동등한 STDOUT을 통한 ASCII 인쇄 가능 출력입니다.

  • 각 재귀의 시작 "제곱"은 at-sign으로 표시되어야합니다 @.
  • 최종 "정사각형"은 앰퍼샌드로 표시되어야합니다 &. 여러 재귀의 경우 마지막 "제곱"만 표시해야합니다 &.
  • 나선형 경로의 모서리는를 사용하여 이동 방향을 "지점"으로해야합니다 < > v ^.
  • 수직 이동은 파이프로 그려야합니다 |.
  • 수평 이동은 대시로 그려야 -합니다.
  • 나중에 재귀로 덮어 쓰는 "사각"에는 가장 최근의 이동 방향이 표시되어야합니다. 이것은 "더 오래된"재귀 위에 "더 새로운"재귀가 겹쳐져있는 것처럼 보일 것입니다. 4rc3아래 예를 참조하십시오 .
  • 마지막 후행 줄 바꿈은 정상이며 선행 공백은 필수 일 수 있으므로 허용되지만 후행 공백은 허용되지 않습니다.
  • 이스케이프 시퀀스를 사용하여 ASCII 아트를 STDOUT으로 가져 가면 도킹하지 않지만 조용히 실망 할 것입니다. (바운티를 사용하면 현상금을받을 수 있습니다)

2d4 = 직경 2, 시계 방향으로 내려 가면서 시작, 4 회귀

&@@@@
^<<<<

이 예에서 도면은 오른쪽 상단에서 시작하여 @1 개, 왼쪽, 1 개씩 내려갑니다. 이 시점에서, 우리는 2d부분을 완성했습니다 . 그리고 두 번째 재귀를 시작하십시오. 그래서 우리는 다른 @하나, 왼쪽 하나, 하나 위로; 그런 다음 세 번째 재귀; 그리고 네번째 그리고 마지막으로 우리 &.

4rc3 = 직경 4, 시계 반대 방향으로 3 회 반복으로 시작

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

이 예에서 도면은 맨 아래에서 시작하여 @오른쪽으로 올라갑니다. 하나는 위로 올라가고, 중간에 도달 @하여 4rc부분 이 끝날 때까지 나선을 그 립니다. 그런 다음 전체 재귀를 요청하기 위해 두 번 더 반복합니다. 참고 4rc1이 예제의 바로 왼쪽 상단 4 × 4 블록 될 것이다.

7u1 = 직경 7, 시계 방향, 1 회귀로 시작하여 시작합니다 (참고는 소개와 같습니다)

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

당첨 및 제한

이것은 코드 골프이므로 바이트 단위의 최소 답변이 이깁니다. 제출은 일반적인 형태의 프로그램 / 기능 / CJam 코드 블록 등이어야합니다. 표준 허점 제한이 적용됩니다. 폐쇄 코스의 전문 운전자. 자극이 지속되면 사용을 중단하고 의사와 상담하십시오.


3
구체적인 내용은 매우 다르지만, 단지 참조를 위해, 여기에 이전 나선형 그리기 도전 : codegolf.stackexchange.com/questions/52494/... .
Reto Koradi

2
좋은 도전입니다. "닫은 코스의 전문 운전자"에 대한 +1
jrich

3
> <> 답변을 요청합니다.
The_Basset_Hound

2
"크몬, 얘들 아 ... 당신은 커먼 리스프를 이길 수 있습니까? ;-)"이것이 내가 본 현상금의 가장 유쾌한 이유입니다. 감사
coredump

1
Common Lisp와 Lua가 코드 골프 문제에서 최고의 자리를 차지하기 위해 싸우는 두 언어라는 것을 아는 중입니다. :)
AdmBorkBork

답변:


6

자바 스크립트, 578, 575, 553, 478, 377 바이트

구타 Lua 후 나는 좀 더 간결한 언어로 전환하고 경쟁을 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,''))}

알고리즘은 동일하지만 더 간결한 언어로 작성되어 악의 Lisp를 이길 수있었습니다. :)

편집 : Lisp에서 다시 도달하고 후행 공백을 제거하기 위해 일부 구조적 변경이 필요했습니다. 그러나 우리는 다시 여기에 있습니다.

Edit2 : 500 이하로 얻기 위해 일부 추상화가 고려되었습니다. 충분히 바랍니다 :)

Edit3 : @Timwi 덕분에 코드는 100 자 더 얇습니다. 아직 설명을 업데이트하지 않았습니다.

테스트 ( 온라인 버전 , 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       >------^

그리고 공정하게 설명하기 위해 공정한 설명이 있습니다.

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, ''))
}

아주 좋아요 규칙에 따라 귀하의 예를 따르면 &optional10 바이트를 절약하기 위해 키워드 (및 공백) 를 제거하기로 결정했습니다. 576 ... 사악한 웃음 (잘, 당신은 조금 더 골프를 칠 수 있다고 말 했으므로 누군가가 Pyth에서 60 바이트 답변을 쓸 때까지 당길 수는 없습니다.)
coredump

@coredump Challenge 허용 :) 예상보다 어렵지만 여전히 가능합니다 :) 나는 당신이 pyth로 할 수 있다고 생각하지만 아무도 그것을 이해하지 못하므로 복잡성이 그러한 언어의 가능성을 넘어서는 것이라고 생각합니다.
Jakuje

3
당신이 과제를 체인 경우 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;당신은 12 바이트 저장할 수 있습니다
SLuck49

2
이 솔루션은 매우 영리합니다. 그러나 골프를 타는 곳을 몇 개 더 발견했습니다. 377 바이트
Timwi

1
@Jakuje 나는 당신이 377 바이트 버전을 가지고 그것을 사용하기 위해 답변을 편집하는 것이 Timwi의 의도라고 생각합니다. ;) (그렇지 않으면 그는 방금 별도의 답변을 게시했을 것입니다.)
Martin Ender

7

일반적인 Lisp, 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)))))

모든 테스트는 여전히 통과합니다. ungolfed 기능도 주석과 마찬가지로 변경 사항을 반영하도록 업데이트되었습니다. remove-duplicates코드를 줄이기 위해 마침내 제거 되었지만 이제 더 많은 바이트를 찾을 수있는 곳을 모르겠습니다. 자쿠 제 잘 했어.

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

&@@@@
^<<<<

20lc10(pastebin) 도 참조하십시오 .

언 골프

여기에는 재귀가 없으며 루프가 있는 기본 거북이 그래픽 방식이 있습니다.

  1. (x y char)트리플을 스택 에 저장하여 메모리에 나선을 그 립니다.
  2. 에 따른 안정 정렬 요소 yx
  3. 중복 (이전 트레이스)을 피하면서 해당 목록을 반복하고 왼쪽 위에서 오른쪽 아래로 인쇄합니다.
(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

루아 5.2, 740 바이트

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

나는 Lisp를 이길 수있는 알고리즘을 구현하는 것이 재미있을 것이지만 Lua는 아마도 최선의 선택이 아닙니다. 나는 그것에 너무 많은 시간을 보냈고, 일부는 너무 튼튼하지만이 해결책은 작동하는 솔루션으로 끝내기 위해 일부 엔지니어링했습니다. 아마도이 알고리즘에서 벗어날 수없는 약 90 문자가 있기 때문에 나중에 Lisp를 이길 다른 언어를 시도 할 것입니다.

테스트 출력 :

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 바이트

나는이 파티에 늦게 도착했다. 내 PHP 솔루션은 가장 작거나 똑똑하지 않습니다. 그냥 작동합니다.

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

실행 방법 :

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

테스트, 설명 및 기타 유용한 정보가 포함 된 자세한 버전은 github 에서 찾을 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.