Спіральне програмування


14

Напишіть названу функцію або програму, яка приймає одне ціле число N і друкує (STDOUT) або повертає (як рядок) перші N барів спіралі внизу, починаючи з вертикальної смуги в центрі і спіралі за годинниковою стрілкою назовні.

        _______________
       / _____________ \
      / / ___________ \ \
     / / / _________ \ \ \
    / / / / _______ \ \ \ \
   / / / / / _____ \ \ \ \ \
  / / / / / / ___ \ \ \ \ \ \
 / / / / / / / _ \ \ \ \ \ \ \
/ / / / / / / / \ \ \ \ \ \ \ \
| | | | | | | | | | | | | | | |
\ \ \ \ \ \ \___/ / / / / / / /
 \ \ \ \ \ \_____/ / / / / / /
  \ \ \ \ \_______/ / / / / /
   \ \ \ \_________/ / / / /
    \ \ \___________/ / / /
     \ \_____________/ / /
      \_______________/ /

Можна припустити, що 0 <N <= 278. Ваш вихід не може містити пробілів перед самим лівим символом спіралі. Ви необов'язково можете надрукувати один зворотний рядок.

Для входу 10 правильний вихід

   _
  / \ 
  | | 
\___/

Для входу 2 правильний вихід

/
|

Для входу 20 правильний вихід

  ___
 / _ \
/ / \ \ 
| | | |
\___/ /

Вихід, який був би невірним, тому що крайнє лівому символу передує пробіл

       ___
      / _ \
     / / \ \ 
     | | | |
     \___/ /

Переможець - найкоротше подання, в байтах.


Це дивна спіраль, 6/8 сторін збільшуються за оберт, а 2 залишаються розміром 1
Девон Парсонс

1
@DevonParsons Подумайте, що вона має шестикутну спіраль, де вертикальні смуги ( |) є лише найближчим символом, який може представляти зустріч a /і \.
mbomb007

Відповіді:


5

CJam - 156/147

L{[W1]{:I0'|{IIW*:J'/}X*[0J'_]X2*I+*[J0_]I1={\}*{J_'\}X*0I0}%L*3/{~_{[UV@]a3$+}{;@}?V@+:V;U@+:U;}/}A,1>fX]ri=_z::e<2<f{[\\]z::-}$_W=0=)S50*a*\{~3$3$=\tt}/N*

Спробуйте в Інтернеті

Він працює з входами від 1 до 378 включно (на 100 більше, ніж потрібно)

За допомогою останнього скоєного (загальнодоступного в hg), але невипущеного коду CJam під час опублікування цього виклику, рішення можна скоротити до 147 символів:

L{[W1]{:I0'|{IIW*:J'/}X*[0J'_]X2*I+*[J0_]I1={\}*{J_'\}X*0I0}%L*3/{~_{[UV@]a3$+}{;@}?V@+:V;U@+:U;}/}A,1>fX]ri=_:.e<2<f.-$_W=0=)S50*a*\{~3$3$=\tt}/N*

Пояснення:

Програма ітераційно конструює всі спіралі як масиви [xy символу], починаючи з [0 0 '|], отримує запитувану спіраль, коригує координати так, щоб мінімум x і y дорівнювали 0, створює матрицю пробілів (з правильною кількістю рядків і 50 стовпців ) потім встановлює символи зі спіралі та з'єднує рядки з новими рядками.

L                   start with an empty array (spiral no. 0)
{…}A,1>fX           for X in 1..9 (A=10)
                    each X represents a full 360° tour with groups of X /'es and \'es
    [W1]{…}%        transform the array [-1 1] (W=-1) applying the block to each item
                    the block generates a series of triplets dx, dy, character
                    note: dx is down, dy is right; -1 handles ↑↗→↘, 1 handles ↓↙←↖
        :I          store the current item in I
        0'|         add 0 and |, which will form a triplet with the previous I
        {…}X*       repeat X times
            IIW*    add I and -I
            :J'/    also store -I in J, and add /
        [0J'_]      make an array [0 J _]
        X2*I+*      repeat the array X*2+I times
        [J0_]       make an array [J 0 0]
                    (a 0 instead of a character means only changing the position)
        I1={\}*     if I=1, swap the two arrays (the position adjustment is different
                    for the upper and lower horizontal sections)
        {…}X*       repeat X times
            J_'\    add J, J and \
        0I0         add 0, I and 0 (another position adjustment)
    L*              flatten the array (since we added a few inner arrays)
    3/              split into [dx dy char] triplets
    {…}/            for each triplet
        ~_          dump the 3 items on the stack and duplicate the character
        {…}         if the character is not 0
            [UV@]   make an array [U V char] (U and V are initially 0)
                    U represents "x" and V represents "y"
            a3$+    add it as an element to a copy of the previous spiral
        {…}         else
            ;@      pop the character and bring the previous spiral to the top
        ?           end if
        V@+:V;      V+=dy
        U@+:U;      U+=dx
]                   put all the spirals in an array
ri=                 read token, convert to integer and get that spiral
_z::e<              copy the spiral and get a triplet with the minimum values
2<                  keep only the first 2 items (xmin and ymin)
f{…}                for each triplet and the array [xmin ymin]
    [\\]z::-        subtract xmin and ymin from x and y in the triplet
                    (in the latest CJam code this is simply ".-")
$                   sort the spiral (putting the triplets in order by x then y)
_W=0=)              get the maximum (updated) x and increment it
S50*                make a string of 50 spaces
a*                  put it in an array and repeat it xmax+1 times
                    this is the initial matrix of spaces
\                   swap with the spiral
{…}/                for each triplet in the spiral
    ~               dump the 3 items (x y char) on the stack
    3$3$=           copy the matrix and x, and get the x'th row
    \t              swap with the character and put that character in the y'th position
    t               put the modified row in the x'th position in the matrix
N*                  join the matrix rows with newlines

8

Пітон 2, 290 289

Напевно, це дуже погано, але я спробував: D

Вихід містить пробіли, але це не заборонено в специфікації.

Оновлення: збережений 1 байт із зміною \nна ;.

m=x=y=c=0
l,f=1,[31*[' ']for t in[0]*31]
for i in[0]*input():
 k=m%4;f[14+y+(2<m<6)][14+x-(m>3)],x,y,c='|/_\\'[k],x+(k>0)*(2*(4>m)-1),y+(k!=2)*(2*(2<m<6)-1),c+1
 if(c==l)*(m%2)+(k==0)+(k==2)*(c==2*l-1+m//3):m,c,l=(m+1)%8,0,l+m//7
print'\n'.join(''.join(e[16-l*2:])for e in f if[' ']*31!=e)

Трейлінг простору чудово. Я це перевірив. Хороша робота!
Rainbolt

4

JavaScript (ES6) 257 288 321

Кроки редагування об’єднані.
Відредагуйте код Golfed, щоб вирізати ще декілька знаків

Побудуйте вихід ітераційно в масив r, відстежуючи поточне положення x і y та напрямок струму. Коли позиція x або y <0, весь масив r регулюється.

Основні змінні:

  • r масив результатів або рядки
  • x, y поточне положення.
  • s поточний напрямок (0..7) (або поточний стан)
  • d поточний символ для малювання (0..3) -> '| \ _ /'
  • l позиція запуску в поточній послідовності (до 0)
  • w поточний радіус спіралі (більше або менше)
F=n=>
  (w=>{
    for(r=b=[],s=y=x=d=0;n--;
      d&&--l||((s=s+1&7,d=s&3)?l=d-2?w:s/2-2+w+w:w+=!s))
      s>0&s<4?++x:s>4?x?--x:r=r.map(v=>' '+v):b+='  ',
      q=r[s>2&s<6?++y:y]||b,
      r[y]=(q+b).slice(0,x)+'|/_\\'[d]+q.slice(x+1),
      s<2|s>6?y?--y:r=[,...r]:x+=!d*2,x-=!d
  })(1)||r.join('\n')

Безумовно

F=n=>{
  var r=[], s,x,y,d,w,l, q
  for(l=w=1, s=x=y=d=0; n--;)
  {
    if (s>2 && s<6) ++y; // right side, inc y before drawing

    if (x < 0) // too left, adjust
    {
      r = r.map(v=>' '+v) // shift all to right
      ++x; // move current position to right
    }
    if (y < 0) // too up
    {
      r = [q='',...r] // shift all to bottom
      ++y; // move current position to bottom
    }
    q = r[y] || ''; // current row, if undefined convert to empty string
    r[y] = (q+' '.repeat(x)).slice(0,x) + '|/_\\'[d] + q.slice(x+1); // add current symbol in the x column

    if (s<2 || s>6) --y; // left side, dec y after drawing

    if (s>0 && s<4) // always change x after drawing
      ++x;
    else if (s > 4)
      --x;

    --l; // decrement current run
    if (l == 0) // if 0, need to change direction
    {
      s = (s+1) % 8; // change direction
      d = s % 4; // change symbol
      if (d == 0)
      { 
        // vertical direction, adjust x and if at 0 increase radius
        l = 1 // always 1 vertical step
        if (s == 0)
          ++x, ++w
        else
          --x
      }
      else
      {
        if (d != 2)
        {
          l = w; // diaagonal length is always w
        }
        else if (s == 2)
        {
          l = w+w-1 // top is radius * 2 -1
        }
        else
        {
          l = w+w+1 // bottom is radius * 2 +1
        }
      }
    }
  }    
  return r.join('\n')
}  

Тест на консолі Firefox / FireBug (або JSFiddle thx @Rainbolt)

;[1, 2, 10, 20, 155, 278].forEach(x=>console.log(F(x)))

Вихідні дані

|

/
|

   _
  / \
  | |
\___/

  ___
 / _ \
/ / \ \
| | | |
\___/ /

      ___________
     / _________ \
    / / _______ \ \
   / / / _____ \ \ \
  / / / / ___ \ \ \ \
 / / / / / _ \ \ \ \ \
/ / / / / / \ \ \ \ \ \
| | | | | | | | | | | |
\ \ \ \ \___/ / / / /
 \ \ \ \_____/ / / /
  \ \ \_______/ / /
   \ \_________/ /
    \___________/

        _______________
       / _____________ \
      / / ___________ \ \
     / / / _________ \ \ \
    / / / / _______ \ \ \ \
   / / / / / _____ \ \ \ \ \
  / / / / / / ___ \ \ \ \ \ \
 / / / / / / / _ \ \ \ \ \ \ \
/ / / / / / / / \ \ \ \ \ \ \ \
| | | | | | | | | | | | | | | |
\ \ \ \ \ \ \___/ / / / / / / /
 \ \ \ \ \ \_____/ / / / / / /
  \ \ \ \ \_______/ / / / / /
   \ \ \ \_________/ / / / /
    \ \ \___________/ / / /
     \ \_____________/ / /
      \_______________/ /

Я перевірив це, і це працює. Ось jsfiddle, що показує, що ваша відповідь працює. Не соромтеся включити це у свою відповідь.
Rainbolt

2

Pyth, 166 165

Я щойно переклав свою відповідь Python на Pyth, маючи не великі навички Pyth. Отримана блювота знаходиться нижче.

Jm*31]d*31dK0=G0=H0=Y1VQ X@J++14H&<2K<K6+14-G<3K@"|/_\\"%K4~G*<0%K4-*2>4K1~H*n2%K4-*2&<2K>6K1~Z1I||&qZY%K2!%K4&q2%K4qZ+-*2Y1/K3~Y/K7=K%+1K8=Z0;jbmj>d-16*2Ykfn*31]dTJ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.