递归ASCII螺旋


21

这场比赛结束了。感谢您提供有趣的非eolang条目,并祝贺Jakuje赢得了JavaScript提交。

按照此站点上ASCII艺术挑战赛的悠久传统,这是另一个。给定输入,绘制螺旋。

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

很简单,是吗?呵呵呵呵...是的...

(灵感来自ASCII Dragons Curve帖子和Optimizer的ASCII Art of the Day帖子)

输入项

输入将采用一系列参数的形式,这些参数取自通常的STDIN /函数自变量/等,无论您使用哪种语言,均由四个部分组成。这些部分可以是四个单独的参数,一个四元组,一个大小为4的数组等。为了在整个挑战中保持简洁和一致,我将输入表示为单个单词。

  • 一个整数2 ≤ x ≤ 20,以“正方形”指定螺旋的大小,每个打印字符代表一个“正方形”的大小。从理论上讲,它的范围可能很大,但是考虑到我们正在绘制ASCII艺术,此值的安全上限为20,因此它在屏幕上的显示效果相当不错。
  • d u r或的单个字母l,表示从开始的“正方形”(向下,向上,向右,向左)的初始移动。
  • 可选的c,指示“逆时针”。如果c省略,则假定螺线为顺时针旋转。
  • 最后一个整数1 ≤ y ≤ 10,用于指定将螺旋图形递归多少次,使用前一个螺旋的完成“正方形”作为新螺旋的开始“正方形”。我选择上限为10,因为我想在某个时候完成绘图。
  • 一些示例输入: 20lc5 13d2 2rc1

有趣的是,请注意,输入尺寸的奇数值将@始终始终是螺旋的精确中心,但是偶数值可能会在四个对角线方向的任何一个上具有起始“平方”偏移量,具体取决于初始方向旅行。这可能会导致某些有趣的模式。请参阅下面的两个偶数示例。

未遵循输入规范的输入(例如11q#s)是未定义的,我完全希望程序能够正确发出信号。:)

输出量

输出是通过与语言等效的STDOUT的ASCII可打印输出,具有以下规范:

  • (每次递归的)起始“平方”必须标有at-符号@
  • 最后的“正方形”必须标有“&”号&。在多次递归的情况下,仅应标记最后一个“正方形” &
  • 螺旋路径的角需要使用来“指向”行进方向< > v ^
  • 垂直行程需要用管道来绘制|
  • 水平行程需要用破折号绘制-
  • 被以后的递归覆盖的“平方”应该显示最近的行进方向。这将导致“较新”的递归似乎在“较旧”的递归之上。请参见4rc3下面的示例。
  • 最后一个换行符是可以的,前导空格可能是必须的,因此可以允许,但不允许尾随空格。
  • 如果您使用转义序列来绘制将输入到STDOUT的ASCII艺术字,那么我不会停靠您,但是我会让您感到非常失望。(如果使用它们,您仍然有资格获得赏金)

例子

2d4 =直径2,开始时顺时针向下旋转4次递归

&@@@@
^<<<<

在此示例中,图形从右上角开始@,向下一幅,向左一幅,向上一幅。至此,我们已经完成了该2d部分,然后开始第二次递归,所以我们有了另一个@,向下一个,向左一个,向上一个;然后是第三次递归;然后第四,最后是我们的&

4rc3 =直径4,从逆时针向右开始,进行3次递归

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

在此示例中,图形从底部开始@,向右上移,向上向上,向上旋转,直到到达中间@并完成该4rc部分。然后再重复两次以获得请求的全部3个递归。注意,4rc1这只是本示例的左上4x4块。

7u1 =直径7,从顺时针向上旋转1次递归开始(请注意,与简介相同)

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

获胜与限制

这是Code Golf,因此以字节为单位的最小答案将获胜。提交内容应采用程序/功能/ CJam代码块等的常规形式。适用标准漏洞限制。封闭路线上的专业驾驶员。如果刺激仍然存在,请停止使用并咨询医生。


3
具体细节完全不同,但是仅供参考,这是一个较早的螺旋图形挑战:codegolf.stackexchange.com/questions/52494/…
Reto Koradi

2
很好的挑战。为“封闭路线上的专业驾驶员” +1
jrich

3
它要求一个> <>答案。
The_Basset_Hound 2015年

2
“来吧,伙计们……您要让Common Lisp赢吗?;-)”这是我见过的赏金最搞笑的原因。谢谢
coredump

1
我坐在这里笑着说,Common Lisp和Lua是争夺代码高尔夫球问题上头号人物的两种语言。:)
AdmBorkBork 2015年

Answers:


6

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

非常好。按照规则并按照您的示例,我决定删除&optional关键字(和空格)以节省10个字节,从而得到576 ... 邪恶的笑声(嗯,您说您可以打更多的高尔夫球,所以这应该不难被击败;当然,除非有人用Pyth写下60字节的答案)。
coredump

@coredump接受挑战:)比我预想的要困难得多,但仍然有可能:)我相信您可以在pyth中做到这一点,但是没人能理解它,因此我相信复杂性超出了这种语言的可能性。
雅库耶2015年

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我相信Timwi的意图是让您采用377字节版本并编辑您的答案以使用它。;)(否则他将只发布一个单独的答案。)
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)))))

所有测试仍然通过。取消注释的功能也已更新,以反映所做的更改,注释也是如此。我终于remove-duplicates为了缩短代码而放弃了,但是现在我不知道在哪里可以找到更多的字节。干得好Jakuje。

例子

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

不打高尔夫球

这里没有涉及递归,只有带有循环的基本Turtle图形方法:

  1. 通过将(x y char)三元组存储在堆栈中来绘制内存中的螺旋线。
  2. 根据y和的稳定排序元素x
  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

Lua 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可能不是最佳选择。我花了太多时间在它上面,过度设计了一些零件,以这个笨拙但可行的解决方案结束。也许以后我会尝试使用其他语言来击败Lisp,因为我无法从该算法中删除大约90个字符。

测试输出:

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上找到。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.