Спиральные окрестности


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-индексированных
  • соседи всегда сортируются по возрастанию
  • удаление roundи использование 6 байтов, 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: эхе ... так как код розетты, который вы использовали, для меня довольно "неясен", я предположил, что он каким-то образом генерирует индексы положения матрицы иначе, чем мои последовательности 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}, я, -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

Brain-Flak , 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, и эта запись в коде Розетты была единственным местом, где я смог найти подтверждение того, что это MATLAB, а не просто удобная функция MATL. Я начинал думать, что это может быть то, что вы добавили в MATL для игры в гольф, пока я не увидел эту запись.
sundar - Восстановить Монику

@sundar Странно, что это больше не задокументировано
Луис Мендо

3

R 172 байта

function(x,n=2*x+3,i=cumsum(rep(rep(c(1,n,-1,-n),l=2*n-1),n-seq(2*n-1)%/%2))){F[i]=n^2-1:n^2
m=matrix(F,n,n,T)
j=which(m==x,T)
c(m[j[1],j[2]+c(-1,1)],m[j[1]+c(-1,1),j[2]])}

Попробуйте онлайн!

Это R, поэтому очевидно, что ответ 0-индексирован.

Большая часть работы заключается в создании матрицы. Код вдохновлен: https://rosettacode.org/wiki/Spiral_matrix#R


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

Попробуйте онлайн!

Как?

Икс,YZяИкс,Y

AИкс,Yзнак равно||Икс|-|Y||+|Икс|+|Y|
SИкс,Yзнак равно{1,если YИкс-1,если Y<Икс
яИкс,Yзнак равноAИкс,Y2+(AИкс,Y+Икс+Y)×SИкс,Y

(адаптировано из этого ответа из math.stackexchange)


Это , кажется, работает нормально с меньшими номерами, но я получаю сообщение об ошибке при тестировании этого с большим количеством как 2000. Ошибка на tio.run: RangeError: Maximum call stack size exceededи ошибки в консоли браузера: InternalError: too much recursion. Я делаю что-то неправильно?
Night2

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))четный, тоk 3.

Например, приведенная выше формула приведет к этому:

  • Если 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.