Linh hồn đệ quy ASCII


21

Cuộc thi này đã kết thúc. Cảm ơn các mục nhập phi esolang thú vị và chúc mừng Jakuje đã gửi bài JavaScript chiến thắng.

Trong truyền thống vĩ đại của những thách thức nghệ thuật ASCII trên trang web này, đây là một thử thách khác. Cho một đầu vào, vẽ một hình xoắn ốc.

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

Đơn giản, phải không? Heh, heh, heh ... Yeah ...

(Lấy cảm hứng từ bài viết Đường cong rồng của ASCII và bài đăng Nghệ thuật trong ngày của ASCII )

Đầu vào

Đầu vào sẽ ở dạng một loạt các tham số, được lấy từ STDIN / đối số hàm / v.v. thông thường, bất kể ngôn ngữ của bạn tương đương, bao gồm bốn phần. Các phần này có thể là bốn đối số riêng biệt, một bộ tứ, một mảng có kích thước 4, v.v ... Để đơn giản và nhất quán trong suốt thử thách, tôi sẽ biểu thị đầu vào dưới dạng một từ.

  • Một số nguyên 2 ≤ x ≤ 20 chỉ định kích thước của hình xoắn ốc theo "hình vuông" với mỗi ký tự được in đại diện cho một "hình vuông" có kích thước. Về mặt lý thuyết, điều này có thể rất lớn về phạm vi, nhưng do chúng ta đang vẽ nghệ thuật ASCII, giới hạn trên an toàn cho điều này sẽ là 20 để nó phù hợp với màn hình.
  • Một chữ cái duy nhất d u rhoặc l, cho biết chuyển động ban đầu từ "hình vuông" bắt đầu (xuống, lên, phải, trái).
  • Một tùy chọn c, cho biết "ngược chiều kim đồng hồ." Nếu cđược bỏ qua, giả sử xoay theo chiều kim đồng hồ cho hình xoắn ốc.
  • Một số nguyên cuối cùng 1 ≤ y ≤ 10chỉ định số lần lặp lại bản vẽ xoắn ốc, sử dụng "hình vuông" hoàn thành của hình xoắn ốc trước đó làm "hình vuông" bắt đầu của hình mới. Tôi đang chọn giới hạn trên là 10 vì tôi muốn bản vẽ kết thúc tại một số điểm.
  • Một vài ví dụ đầu vào: 20lc5 13d2 2rc1

Quan tâm, lưu ý rằng các giá trị lẻ cho đầu vào kích thước sẽ dẫn đến @luôn luôn là tâm chính xác của hình xoắn ốc, nhưng các giá trị thậm chí có thể có phần bù "vuông" bắt đầu theo bất kỳ hướng nào trong bốn hướng chéo, phụ thuộc vào hướng ban đầu du lịch. Điều này có thể dẫn đến một số ... mô hình ... thú vị. Xem hai ví dụ thậm chí dưới đây.

Đầu vào không tuân theo thông số kỹ thuật đầu vào (ví dụ 11q#s:) không được xác định và tôi hoàn toàn mong đợi chương trình sẽ được xử lý phù hợp. :)

Đầu ra

Đầu ra là đầu ra có thể in ASCII thông qua STDOUT tương đương với ngôn ngữ, với các thông số kỹ thuật sau:

  • "Hình vuông" bắt đầu (của mỗi lần đệ quy) phải được đánh dấu bằng dấu hiệu @.
  • "Hình vuông" cuối cùng phải được đánh dấu bằng dấu và &. Trong trường hợp có nhiều lần thu hồi, chỉ nên đánh dấu "hình vuông" cuối cùng &.
  • Các góc của đường xoắn ốc cần "chỉ" theo hướng di chuyển, sử dụng < > v ^.
  • Du lịch dọc cần được vẽ bằng đường ống |.
  • Du lịch ngang cần được vẽ bằng dấu gạch ngang -.
  • "Hình vuông" được ghi đè bởi các lần thu hồi sau sẽ hiển thị hướng di chuyển gần đây nhất. Điều này sẽ dẫn đến việc thu hồi "mới hơn" dường như được xếp chồng lên trên các lần thu hồi "cũ" hơn. Xem 4rc3ví dụ dưới đây.
  • Một dòng mới cuối cùng là OK, không gian hàng đầu có thể là phải và vì vậy được phép, nhưng không gian dấu không được phép.
  • Tôi sẽ không cập bến bạn nếu bạn sử dụng các chuỗi thoát để vẽ nghệ thuật ASCII sang STDOUT, nhưng tôi sẽ thất vọng trong bạn. (Bạn vẫn sẽ đủ điều kiện nhận tiền thưởng nếu bạn sử dụng chúng)

Ví dụ

2d4 = đường kính 2, bắt đầu bằng cách đi xuống, theo chiều kim đồng hồ, 4 lần thu hồi

&@@@@
^<<<<

Trong ví dụ này, bản vẽ bắt đầu ở phía trên bên phải @, đi xuống một, trái một, lên một. Tại thời điểm này, chúng tôi đã hoàn thành 2dphần này, và vì vậy bắt đầu đệ quy thứ 2, vì vậy chúng tôi có một phần khác @, xuống một, còn lại một, lên một; sau đó là đệ quy thứ 3; sau đó lần thứ 4 và cuối cùng của chúng tôi &.

4rc3 = đường kính 4, bắt đầu bằng cách đi bên phải, ngược chiều kim đồng hồ, 3 lần thu hồi

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

Trong ví dụ này, bản vẽ bắt đầu ở phía dưới @, đi bên phải, lên một, xoắn ốc xung quanh, cho đến khi nó đến giữa @và hoàn thành 4rcphần. Điều này sau đó lặp lại hai lần nữa để có đủ 3 lần thu hồi được yêu cầu. Lưu ý rằng đó 4rc1sẽ chỉ là khối 4x4 phía trên bên trái của ví dụ này.

7u1 = đường kính 7, bắt đầu bằng cách đi lên, theo chiều kim đồng hồ, 1 đệ quy (lưu ý giống như phần giới thiệu)

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

Chiến thắng & Hạn chế

Đây là Code Golf, vì vậy câu trả lời nhỏ nhất trong byte thắng. Đệ trình phải ở dạng thông thường của chương trình / chức năng / Khối mã CJam / v.v. Hạn chế lỗ hổng tiêu chuẩn áp dụng. Lái xe chuyên nghiệp trên khóa học khép kín. Nếu kích thích vẫn còn, ngừng sử dụng và tham khảo ý kiến ​​bác sĩ của bạn.


3
Các chi tiết cụ thể khá khác nhau, nhưng chỉ để tham khảo, đây là một thử thách vẽ xoắn ốc trước đó: codegolf.stackexchange.com/questions/52494/ Lỗi .
Reto Koradi

2
Thử thách đẹp. +1 cho "Trình điều khiển chuyên nghiệp trong khóa học khép kín"
jrich

3
Nó yêu cầu một câu trả lời> <>.
The_Basset_Hound

2
"Thôi nào, các bạn ... bạn có muốn cho Common Lisp thắng không? ;-)" Đó là lý do vui nhộn nhất cho một tiền thưởng tôi từng thấy. Cảm ơn
coredump

1
Tôi đang ngồi đây cười khúc khích rằng Common Lisp và Lua là hai ngôn ngữ đấu tranh cho vị trí hàng đầu trong câu hỏi về môn đánh gôn. :)
admBorkBork

Câu trả lời:


6

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

Sau khi Lua bị đánh bại, tôi chuyển sang một số ngôn ngữ nhỏ gọn hơn và chuyển cạnh tranh sang 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,''))}

Thuật toán là như nhau, nhưng được viết bằng ngôn ngữ nhỏ gọn hơn nên tôi đã xoay sở để đánh bại Lisp độc ác :)

Chỉnh sửa: Một số thay đổi cấu trúc là cần thiết để đạt được dưới Lisp một lần nữa và để loại bỏ các khoảng trắng theo sau. Nhưng chúng tôi lại ở đây.

Edit2: Một số tóm tắt được đưa vào tài khoản để có được dưới 500. Hy vọng nó sẽ đủ :)

Edit3: Cảm ơn @Timwi, mã này là một ký tự mỏng hơn 100 ký tự. Tôi chưa cập nhật lời giải thích nào.

Các thử nghiệm ( phiên bản trực tuyến , đã thử nghiệm trong 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       >------^

Và để công bằng, có lời giải thích công bằng:

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

Rất đẹp. Theo các quy tắc và làm theo ví dụ của bạn, tôi đã quyết định xóa &optionaltừ khóa (và một khoảng trắng) để tiết kiệm 10 byte, điều này mang lại cho 576 ... tiếng cười xấu xa (tốt, bạn nói rằng bạn có thể chơi gôn nhiều hơn một chút, vì vậy điều này không nên khó đánh bại, cho đến khi ai đó viết câu trả lời 60 byte bằng Pyth, tất nhiên).
coredump

@coredump Thử thách được chấp nhận :) Khó khăn hơn tôi mong đợi, nhưng vẫn có thể :) Tôi tin rằng bạn có thể làm điều đó trong pyth, nhưng không ai sẽ hiểu nó vì vậy tôi tin rằng sự phức tạp là vượt quá khả năng của ngôn ngữ đó.
Jakuje

3
Nếu bạn xâu chuỗi các bài tập i=M/2;j=i;G=i;H=i;I=i;J=i;vào i=j=G=H=I=J=M/2;m=1;l=1;vào, m=l=1;bạn có thể tiết kiệm được 12 byte
SLuck49

2
Giải pháp này khá thông minh. Tuy nhiên, tôi đã tìm thấy một số địa điểm khác có thể chơi gôn: 377 byte
Timwi

1
@Jakuje Tôi tin rằng đó là ý định của Timwi khi bạn lấy phiên bản 377 byte và chỉnh sửa câu trả lời của bạn để sử dụng nó. ;) (Nếu không, anh ta sẽ chỉ đăng một câu trả lời riêng.)
Martin Ender

7

Lisp thông thường, 649 617 605 586 576 567 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)))))

Tất cả các bài kiểm tra vẫn vượt qua. Chức năng không được chỉnh sửa cũng được cập nhật để phản ánh các thay đổi, cũng như các bình luận. Cuối cùng tôi đã thoát khỏi remove-duplicatesđể rút ngắn mã, nhưng bây giờ tôi không biết tìm thêm byte ở đâu. Jakuje làm tốt lắm.

Ví dụ

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

&@@@@
^<<<<

Xem thêm 20lc10(pastebin).

Ung dung

Không có đệ quy liên quan ở đây, chỉ là một cách tiếp cận đồ họa Rùa cơ bản với các vòng lặp:

  1. Vẽ các hình xoắn ốc trong bộ nhớ bằng cách lưu trữ (x y char)ba lần trong một ngăn xếp.
  2. Các yếu tố ổn định sắp xếp theo yx
  3. Lặp lại danh sách đó trong khi tránh trùng lặp (dấu vết trước đó) và in từ trên cùng bên trái sang dưới cùng bên phải.
(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

Tôi mặc dù sẽ rất vui khi thử thực hiện một số thuật toán để đánh bại Lisp, nhưng Lua có lẽ không phải là lựa chọn tốt nhất. Tôi dành quá nhiều thời gian cho nó, thiết kế quá mức một số phần để kết thúc với giải pháp này, nhưng giải pháp hiệu quả. Có lẽ tôi sẽ thử các ngôn ngữ khác nhau sau đó để đánh bại Lisp vì có khoảng 90 ký tự mà tôi không thể lấy ra khỏi thuật toán này.

Kiểm tra kết quả đầu ra:

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

Tôi đến muộn trong bữa tiệc này. Giải pháp PHP của tôi không phải là nhỏ nhất, cũng không phải thông minh nhất. Nó chỉ hoạt động.

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

Làm thế nào để chạy 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||
|||@|||
||^-<||
|^---<|
^-----<

Phiên bản chi tiết với các bài kiểm tra, giải thích và các tính năng khác có thể được tìm thấy trên github .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.