Спіральні квартали


19

Якщо ми візьмемо натуральні числа і згортаємо їх лічильниками за годинниковою стрілкою в спіраль, ми закінчимося такою нескінченною спіраллю:

                  ....--57--56
                             |
36--35--34--33--32--31--30  55
 |                       |   |
37  16--15--14--13--12  29  54
 |   |               |   |   |
38  17   4---3---2  11  28  53
 |   |   |       |   |   |   |
39  18   5   0---1  10  27  52
 |   |   |           |   |   |
40  19   6---7---8---9  26  51
 |   |                   |   |
41  20--21--22--23--24--25  50
 |                           |
42--43--44--45--46--47--48--49

Враховуючи деяку кількість цієї спіралі, ваше завдання - визначити її сусідів - означає елемент вгорі, зліва, справа та під ним.

Приклад

Якщо ми подивимось, 27ми можемо побачити, що в ньому є наступні сусіди:

  • вище: 28
  • зліва: 10
  • правильно: 52
  • нижче: 26

Таким чином, вихід буде таким: [28,10,52,26]

Правила

  • Введенням буде число у будь-якому форматі вводу / виводу за замовчуваннямn0
  • Виведенням буде список / матриця / .. 4 сусідів цих чисел у будь-якому (послідовному!) Порядку
  • Ви можете працювати зі спіраллю, яка починається з 1 замість 0, однак слід вказати це у своїй відповіді

Приклади

Вихід у форматі [above,left,right,below]та використовує спіраль на основі 0:

0  ->  [3,5,1,7]
1  ->  [2,0,10,8]
2  ->  [13,3,11,1]
3  ->  [14,4,2,0]
6  ->  [5,19,7,21]
16  ->  [35,37,15,17]
25  ->  [26,24,50,48]
27  ->  [28,10,52,26]
73  ->  [42,72,74,112]
101  ->  [100,146,64,102]
2000  ->  [1825,1999,2001,2183]
1000000  ->  [1004003,1004005,999999,1000001]

Відповіді:


6

R , 156 байт

function(n){g=function(h)c(0,cumsum(h((4*(0:(n+2)^2)+1)^.5%%4%/%1/2)))
x=g(sinpi)
y=g(cospi)
a=x[n]
b=y[n]
which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))}

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

  • опублікував ще одну відповідь R, оскільки це дещо інший підхід, ніж @ngn
  • 1-індексований
  • сусіди завжди сортуються за зростанням значення
  • збережено 6 байт видалення roundі використання , cospi(x)/sinpi(x)які є більш точними , ніж cos(x*pi)/sin(x*pi)у випадку з половиною чисел ( 0.5, і 1.5т.д. ...)
  • збережено ще один байт, видаливши мінус на y координатах, оскільки результат однаковий (просто сусіди вгору / вниз перевернуті)

Пояснення:

Якщо ми подивимося на матричні координати значень, враховуючи перше значення, 0розміщене в x=0, y=0, вони:

x = [0,  1,  1,  0, -1, -1, -1,  0,  1,  2,  2,  2,  2,  1,  0, ...] 
y = [0,  0,  1,  1,  1,  0, -1, -1, -1, -1,  0,  1,  2,  2,  2, ...]

Ці xкоординати слідують послідовність A174344 OEIS з рекурсивної формулою:

a(1) = 0, a(n) = a(n-1) + sin(mod(floor(sqrt(4*(n-2)+1)),4)*pi/2)

Ця ж формула справедлива для yматричних координат, але з cosзамість sinі запереченням:

a(1) = 0, a(n) = a(n-1) - cos(mod(floor(sqrt(4*(n-2)+1)),4)*pi/2)

Отже, в R ми можемо перевести формулу на цю функцію, взявши sinpi/cospiза параметр:

g=function(h)c(0,cumsum(h((4*(0:(n+2)^2)+1)^.5%%4%/%1/2)))

і ми генеруємо два вектори координат (ми не заперечуємо y координати, оскільки ми отримаємо той самий результат, лише якщо сусіди вгору / вниз перевернуті):

x=g(sinpi)
y=g(cospi)

Зауважте, що ми створили (n+2)^2координати, які є мінімальними необхідними координатами, що містять nі їхніх, і їхніх сусідів (більш жорстке обмеження було б, (floor(sqrt(n))+2)^2але, на жаль, менш "гольфі").

Тому, маючи всі координати, ми спочатку шукаємо координати, a,bвідповідні нашим n:

a=x[n]
b=y[n]

нарешті ми вибираємо позиції своїх сусідів, тобто:

  • сусіди вгору / вниз where x == a and y == b+1 or b-1
  • права / ліва сусідка where y == b and x == a+1 or a-1

використовуючи:

which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))

"трохи інше" :)
ngm

@ngm: eheh ... оскільки використаний вами код розетки для мене досить «неясний», я припускав, що якимось чином генерує індекси позицій матриці іншим, але схожим чином, ніж мої послідовності OEIS: D
digEmAll

4

Perl 6 , 94 83 байт

{my \ s = 0, | [+] flat ((1, i ... ) Zxx flat (1..Inf Z 1..Inf)); map {first: k, s [$ _] + $ ^ d, s}, i, -1,1, -i}

{my \s=0,|[\+] flat((1,*i...*)Zxx(1,1.5...*));map {first :k,s[$_]+$^d,s},i,-1,1,-i}

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

s- ледачий, нескінченний список спіральних координат, представлений у вигляді складних чисел. Він побудований з двох інших нескінченних списків: 1, *i ... *складає список 1, i, -1, -i .... 1, 1.5 ... *складає список 1, 1.5, 2, 2.5, 3, 3.5 .... Архівування цих два списки разом з реплікацією списку виробляє список кроків від кожної спіралі координат до наступного: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (Дробові частини правої аргументації оператора реплікації списку відкидаються.) Здійснення зменшення трикутного додавання ( [\+]) у цьому списку (та вставлення 0 на передню частину) створює список спіральних координат.

Нарешті, починаючи від комплексного числа s[$_]( $_будучи єдиним аргументом функції), ми шукаємо індекси ( first :k) в спіралі комплексних чисел , які зміщені від цього числа по i, -1, 1і -i.


4

Мозок-Флак , 238 байт

((){[()]<((({}[((()))]<>)<<>{((([{}]({}))([{}]{})())[()]){({}[()])<>}{}}>)<<>({}<(((({}{})()){}<>({}))()())<>>)<>>()())<>{{}((()()()[({})]){}<>({}<{}>))(<>)}>}{}){<>((((())()())()())()())(<>)}{}{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>

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

Вихід є в порядку вліво, вгору, вправо, вниз.

Пояснення

# If n is nonzero:
((){[()]<

  ((

    # Push 1 twice, and push n-1 onto other stack.
    ({}[((()))]<>)

    # Determine how many times spiral turns up to n, and whether we are on a corner.
    # This is like the standard modulus algorithm, but the "modulus" used
    # increases as 1, 1, 2, 2, 3, 3, ...
    <<>{((([{}]({}))([{}]{})())[()]){({}[()])<>}{}}>

  # Push n-1: this is the number behind n in the spiral.
  )<

    # While maintaining the "modulus" part of the result:
    <>({}<

      # Push n+2k+1 and n+2k+3 on top of n-1, where k is 3 more than the number of turns.
      # n+2k+1 is always the number to the right in the direction travelled.
      # If we are on a corner, n+2k+3 is the number straight ahead.
      (((({}{})()){}<>({}))()())<>

    >)<>

  # Push n+1.  If we are on a corner, we now have left, front, right, and back
  # on the stack (from top to bottom)
  >()())

  # If not on a corner:
  <>{{}

    # Remove n+2k+3 from the stack entirely, and push 6-2k+(n+1) on top of the stack.
    ((()()()[({})]){}<>({}<{}>))

  (<>)}

>}{})

# If n was zero instead:
{

  # Push 1, 3, 5, 7 on right stack, and implicitly use 1 (from if/else code) as k.
  <>((((())()())()())()())

(<>)}{}

# Roll stack k times to move to an absolute reference frame
# (switching which stack we're on each time for convenience)
{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>

Дуже вражає! Я думаю, ви не генеруєте всю спіраль, як це роблять інші, чи не так?
ბიმო

3

MATL , 15 байт

2+1YLtG=1Y6Z+g)

Вхід і вихід на основі 1.

Вихід дає ліві, вниз, вгору та праві сусіди в такому порядку.

Спробуйте в Інтернеті! Або перевірити всі тестові випадки, окрім двох останніх, які закінчуються у TIO.

2+      % Implicit input: n. Add 2. This is needed so that
        % the spiral is big enough
1YL     % Spiral with side n+2. Gives a square matrix
t       % Duplicate
G=      % Compare with n, element-wise. Gives 1 for entry containing n
1Y6     % Push 3×3 mask with 4-neighbourhood
Z+      % 2D convolution, keeping size. Gives 1 for neighbours of the
        % entry that contained n
g       % Convert to logical, to be used as an index
)       % Index into copy of the spiral. Implicit display

2
1YL- MATLAB має spiralфункцію? Коли MATLAB перетворився на Mathematica ?!
sundar

Так, я каченяк-ед, побачивши, що означає 1YL, і цей запис коду Rosetta був єдиним місцем, де я міг знайти, щоб підтвердити, що це MATLAB річ, а не просто функція зручності MATL. Я починав думати, що це може бути щось, що ви додали в MATL для гри в гольф, поки я не побачив цього запису.
sundar

@sundar Дивно, що це більше не зафіксовано
Луїс Мендо


2

JavaScript (ES6), 165 байт

Друкує індекси за допомогою alert().

f=(n,x=w=y=n+2)=>y+w&&[0,-1,0,1].map((d,i)=>(g=(x,y,A=Math.abs)=>(k=A(A(x)-A(y))+A(x)+A(y))*k+(k+x+y)*(y>=x||-1))(x+d,y+~-i%2)-n||alert(g(x,y)))|f(n,x+w?x-1:(y--,w))

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

Як?

x,yZIx,y

Ax,y=||x||y||+|x|+|y|
Sx,y={1,if yx1,if y<x
Ix,y=Ax,y2+(Ax,y+x+y)×Sx,y

(адаптовано з цієї відповіді від math.stackexchange)


Здається, це працює добре з меншими числами, але я отримую помилку при тестуванні цього з великою кількістю, наприклад 2000. Помилка на tio.run: RangeError: Maximum call stack size exceededта помилка в консолі браузера : InternalError: too much recursion. Я щось роблю не так?
Ніч2

1
4n2


1

PHP (> = 5,4), 208 байт

<?$n=$argv[1];for(;$i++<($c=ceil(sqrt($n))+($c%2?2:3))**2;$i!=$n?:$x=-$v,$i!=$n?:$y=+$h,${hv[$m&1]}+=$m&2?-1:1,$k++<$p?:$p+=$m++%2+$k=0)$r[-$v][+$h]=$i;foreach([0,1,0,-1]as$k=>$i)echo$r[$x+$i][$y+~-$k%2].' ';

Щоб запустити його:

php -n -d error_reporting=0 <filename> <n>

Приклад:

php -n -d error_reporting=0 spiral_neighbourhoods.php 2001

Або спробуйте в Інтернеті!

Примітки:

  • Ця -d error_reporting=0опція використовується для виведення сповіщень / попереджень.
  • Ця спіраль починається з 1.

Як?

Я генерую спіраль із модифікованою версією цієї відповіді у двовимірному масиві.

Я вирішую розмір спіралі на основі введення nз формулою, щоб завжди отримувати додатковий раунд чисел у спіралі (гарантія існування вгорі / внизу / вліво / вправо). Додатковий раунд чисел означає +2висоту та +2ширину двовимірного масиву.

Тож якщо nвін буде розташований у спіралі з максимальним розміром 3*3, то генерована спіраль буде 5*5.

Розмір спіралі - це те, c*cде c = ceil(sqrt(n)) + k, якщо ceil(sqrt(n))непарне, то k2, а якщо ceil(sqrt(n))парне, то k3.

Наприклад, наведена вище формула призведе до цього:

  • Якщо n = 1тоді c = 3і розмір спіралі буде3*3
  • Якщо n <= 9тоді c = 5і розмір спіралі буде5*5
  • Якщо n <= 25тоді c = 7і розмір спіралі буде7*7
  • Якщо n <= 49тоді c = 9і розмір спіралі буде9*9
  • І так далі ...

При генерації спіралі, я зберігати xі yз nі після генерації, я виводити вище / нижче елементів / вліво / вправо від нього.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.