Barrios espirales

19

Si tomamos los números naturales y los enrollamos en sentido antihorario en una espiral, terminamos con la siguiente espiral infinita:

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

Dado un número en esa espiral, su tarea es determinar sus vecinos, es decir, el elemento arriba, izquierda, derecha y debajo de él.

Ejemplo

Si echamos un vistazo 27, podemos ver que tiene los siguientes vecinos:

  • encima: 28
  • izquierda: 10
  • Derecha: 52
  • abajo: 26

Entonces la salida sería: [28,10,52,26]

Reglas

  • La entrada será un número en cualquier formato de E / S predeterminadonorte0 0
  • La salida será una lista / matriz / ... de los 4 vecinos de esos números en cualquier orden (¡consistente!)
  • Puede trabajar con una espiral que comienza con 1 en lugar de 0, sin embargo, debe especificar eso en su respuesta

Ejemplos

La salida está en el formato [above,left,right,below]y utiliza una espiral basada en 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]
ბიმო
fuente
relacionado
ბიმო

Respuestas:

6

R , 156 bytes

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

Pruébalo en línea!

  • publicó otra respuesta R ya que es un enfoque ligeramente diferente al de @ngn
  • 1 indexado
  • los vecinos siempre se ordenan por valor ascendente
  • guardado 6 bytes eliminando roundy usando, cospi(x)/sinpi(x)que son más precisos que cos(x*pi)/sin(x*pi)en el caso de números medios ( 0.5, 1.5etc.)
  • guardó otro byte eliminando las coordenadas menos en y ya que el resultado es el mismo (solo se invierten los vecinos arriba / abajo)

Explicacion:

Si observamos las coordenadas de la matriz de los valores, considerando el primer valor 0colocado en x=0, y=0, son:

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, ...]

Las xcoordenadas siguen la secuencia A174344 OEIS con la fórmula recursiva:

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

La misma fórmula es válida para ylas coordenadas de matriz, pero con en coslugar de siny negado:

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

Entonces, en R podemos traducir la fórmula a esta función, tomando sinpi/cospicomo parámetro:

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

y generamos los dos vectores de coordenadas (no negamos las coordenadas y, ya que obtendremos el mismo resultado, solo con los vecinos arriba / abajo invertidos):

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

Tenga en cuenta que hemos generado (n+2)^2coordenadas, que son más que las coordenadas mínimas necesarias que contienen a ambos ny sus vecinos (un límite más estrecho sería, (floor(sqrt(n))+2)^2pero desafortunadamente es menos "golf").

Por lo tanto, ahora que tenemos todas las coordenadas, primero buscamos las coordenadas a,bcorrespondientes a nuestro n:

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

finalmente seleccionamos las posiciones de sus vecinos, es decir:

  • los vecinos arriba / abajo where x == a and y == b+1 or b-1
  • los vecinos derecho / izquierdo where y == b and x == a+1 or a-1

utilizando :

which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))
digEmAll
fuente
"ligeramente diferente" :)
ngm
@ngm: eheh ... dado que el código de rosetta que usaste es bastante "oscuro" para mí, supuse que de alguna manera generaba los índices de posición de la matriz de una manera diferente pero similar a mis secuencias OEIS: D
digEmAll
4

Perl 6 , 94 83 bytes

{my \ s = 0, | [+] flat ((1, i ... ) Zxx flat (1..Inf Z 1..Inf)); mapa {primero: 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}

Pruébalo en línea!

ses una lista perezosa e infinita de coordenadas espirales, representada como números complejos. Está construido a partir de otras dos listas infinitas: 1, *i ... *hace la lista 1, i, -1, -i .... 1, 1.5 ... *hace que la lista 1, 1.5, 2, 2.5, 3, 3.5 .... Comprimir estas dos listas junto con la replicación lista produce la lista de pasos de cada espiral de coordenadas a la siguiente: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (Las partes fraccionarias de los argumentos de la derecha para el operador de replicación de listas se descartan). Hacer una reducción de suma triangular ( [\+]) en esta lista (y pegar 0 en el frente) produce la lista de coordenadas en espiral.

Por último, a partir del número complejo s[$_]( $_siendo el único argumento de la función), miramos hacia arriba los índices ( first :k) en la espiral de los números complejos que están desplazados de ese número por i, -1, 1, y -i.

Sean
fuente
4

Brain-Flak , 238 bytes

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

Pruébalo en línea!

La salida está en el orden izquierda, arriba, derecha, abajo.

Explicación

# 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)
{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>
Nitrodon
fuente
¡Muy impresionante! Supongo que no estás generando toda la espiral como lo hacen los demás, ¿verdad?
ბიმო
3

MATL , 15 bytes

2+1YLtG=1Y6Z+g)

La entrada y la salida están basadas en 1.

La salida muestra los vecinos izquierdo, inferior, superior y derecho en ese orden.

Pruébalo en línea! O verifique todos los casos de prueba, excepto los dos últimos, que caducan en 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
Luis Mendo
fuente
2
1YL- MATLAB tiene una spiralfunción? ¿Cuándo MATLAB se convirtió en Mathematica?
sundar - Restablecer Monica
Sí, lo modifiqué después de ver lo que significaba 1YL, y esta entrada de código de Rosetta fue el único lugar que pude encontrar para confirmar que es una cosa de MATLAB y no solo una función de conveniencia de MATL. Estaba empezando a pensar que podría ser algo que agregaste a MATL para jugar al golf, hasta que vi esa entrada.
sundar - Restablecer Monica
@sundar Raro que ya no está documentado
Luis Mendo
3

R , 172 bytes

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

Pruébalo en línea!

Esto es R, por lo que obviamente la respuesta está indexada en 0.

La mayor parte del trabajo es crear la matriz. Código inspirado en: https://rosettacode.org/wiki/Spiral_matrix#R

ngm
fuente
2

JavaScript (ES6), 165 bytes

Imprime los índices con 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))

Pruébalo en línea!

¿Cómo?

X,yZyoX,y

UNX,y=El |El |XEl |-El |yEl |El |+El |XEl |+El |yEl |
SX,y={1,Si yX-1,Si y<X
yoX,y=UNX,y2+(UNX,y+X+y)×SX,y

(adaptado de esta respuesta de math.stackexchange)

Arnauld
fuente
Esto parece funcionar bien con un número menor, pero me da un error al probar esto con un gran número como 2000. error en tio.run: RangeError: Maximum call stack size exceededy el error en la consola del navegador: InternalError: too much recursion. ¿Estoy haciendo algo mal?
Noche2
1
4 4norte2
2

Python 2 , 177 164 1 46 144 bytes

def f(n):N=int(n**.5);S=N*N;K=S+N;F=4*N;return[n+[F+3,[-1,1-F][n>K]][n>S],n+[F+5,-1][n>K],n+[[1,3-F][n<K],-1][0<n==S],n+[F+7,1][n<K]][::1-N%2*2]

Pruébalo en línea!

Calcula u,l,r,ddirectamente desde n.

Chas Brown
fuente
1

PHP (> = 5.4), 208 bytes

<?$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].' ';

Para ejecutarlo:

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

Ejemplo:

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

O Pruébelo en línea!

Notas:

  • La -d error_reporting=0opción se utiliza para no generar avisos / advertencias.
  • Esta espiral comienza con 1.

¿Cómo?

Estoy generando la espiral con una versión modificada de esta respuesta en una matriz de 2 dimensiones.

Decido el tamaño de la espiral en función de la entrada ncon una fórmula para obtener siempre una ronda adicional de números en la espiral (garantía de existencia de arriba / abajo / izquierda / derecha). Una ronda adicional de números significa +2en altura y +2en ancho de la matriz bidimensional.

Entonces, si nse ubicará en una espiral con un tamaño máximo de 3*3, entonces la espiral generada será 5*5.

El tamaño de la espiral es c*cdonde c = ceil(sqrt(n)) + k, si ceil(sqrt(n))es impar, entonces kes 2 y si ceil(sqrt(n))es par, entonces kes 3.

Por ejemplo, la fórmula anterior dará como resultado esto:

  • Si n = 1entonces c = 3y el tamaño en espiral será3*3
  • Si n <= 9entonces c = 5y el tamaño en espiral será5*5
  • Si n <= 25entonces c = 7y el tamaño en espiral será7*7
  • Si n <= 49entonces c = 9y el tamaño en espiral será9*9
  • Y así ...

Mientras que la generación de la espiral, almaceno la xy yde ny después de la generación, la salida I los elementos anteriores / abajo / izquierda / derecha de la misma.

Noche2
fuente