Bairros em espiral

19

Se pegarmos os números naturais e enrolá-los no sentido anti-horário em uma espiral, terminamos com a seguinte 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 um número nessa espiral, sua tarefa é determinar seus vizinhos - significando o elemento acima, esquerdo, direito e abaixo dele.

Exemplo

Se dermos uma olhada 27, podemos ver que ele tem os seguintes vizinhos:

  • acima: 28
  • esquerda: 10
  • certo: 52
  • abaixo: 26

Portanto, a saída seria: [28,10,52,26]

Regras

  • A entrada será um número em qualquer formato de E / S padrãon0
  • A saída será uma lista / matriz / .. dos 4 vizinhos desses números em qualquer ordem (consistente!)
  • Você pode trabalhar com uma espiral que começa com 1 em vez de 0, mas você deve especificar isso em sua resposta

Exemplos

A saída está no formato [above,left,right,below]e usa uma espiral baseada em 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]
ბიმო
fonte
relacionado
ბიმო

Respostas:

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

Experimente online!

  • postou outra resposta R, uma vez que é uma abordagem ligeiramente diferente da @ngn
  • Indexado 1
  • vizinhos são sempre classificados por valor crescente
  • salvou 6 bytes removendo rounde usando, cospi(x)/sinpi(x)que são mais precisos do que cos(x*pi)/sin(x*pi)no caso de meio número ( 0.5, 1.5etc ...)
  • salvou outro byte, removendo as coordenadas menos y, pois o resultado é o mesmo (apenas os vizinhos para cima / para baixo são invertidos)

Explicação:

Se olharmos para as coordenadas da matriz dos valores, considerando o primeiro valor 0colocado em x=0, y=0, elas são:

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

As xcoordenadas seguem a sequência A174344 OEIS com a fórmula recursiva:

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

A mesma fórmula vale para as ycoordenadas da matriz, mas com em cosvez de sine negado:

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

Assim, em R podemos traduzir a fórmula para esta função, tomando sinpi/cospicomo parâmetro:

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

e geramos os dois vetores de coordenadas (não negamos as cordas y, pois obteremos o mesmo resultado, apenas com os vizinhos para cima / para baixo invertidos):

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

Observe que geramos (n+2)^2coordenadas, que são mais do que as coordenadas mínimas necessárias que contêm ambos ne seus vizinhos (um limite mais (floor(sqrt(n))+2)^2estreito seria, mas infelizmente é menos "golfe").

Portanto, agora que temos todas as coordenadas, primeiro pesquisamos as coordenadas a,bcorrespondentes a nossa n:

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

finalmente, selecionamos as posições de seus vizinhos, ou seja:

  • os vizinhos de cima / baixo where x == a and y == b+1 or b-1
  • os vizinhos direito / esquerdo where y == b and x == a+1 or a-1

usando:

which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))
digEmAll
fonte
"ligeiramente diferente" :)
ngm 23/07/19
@ngm: eheh ... desde que o código rosetta você usou é muito "obscura" para mim, eu assumi é de alguma forma gerar os índices de posição da matriz de uma forma diferente, mas semelhante do que meus seqüências OEIS: D
digEmAll
4

Perl 6 , 94 83 bytes

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

Experimente online!

sé uma lista preguiçosa e infinita de coordenadas em espiral, representada como números complexos. Ele é construído a partir de duas outras listas infinitas: 1, *i ... *faz a lista 1, i, -1, -i .... 1, 1.5 ... *faz a lista 1, 1.5, 2, 2.5, 3, 3.5 .... Fechando essas duas listas, juntamente com a replicação lista produz uma lista de passos de cada espiral de coordenadas para a próxima: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (As partes fracionárias dos argumentos do lado direito do operador de replicação de lista são descartadas.) Fazer uma redução de adição triangular ( [\+]) nesta lista (e colar 0 na frente) produz a lista de coordenadas em espiral.

Finalmente, a partir do número complexo s[$_]( $_sendo o único argumento para a função), olhamos para cima os índices ( first :k) na espiral dos números complexos, que são compensados a partir desse número por i, -1, 1, e -i.

Sean
fonte
4

Flacidez cerebral , 238 bytes

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

Experimente online!

A saída está na ordem esquerda, cima, direita, baixo.

Explicação

# 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
fonte
Muito impressionante! Eu acho que você não está gerando toda a espiral como os outros, não é?
ბიმო
3

MATL , 15 bytes

2+1YLtG=1Y6Z+g)

Entrada e saída são baseadas em 1.

A saída mostra os vizinhos esquerdo, baixo, cima e direito nessa ordem.

Experimente online! Ou verifique todos os casos de teste, exceto os dois últimos, que atingem o tempo limite no 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
fonte
2
1YL- MATLAB tem uma spiralfunção? Quando o MATLAB se transformou no Mathematica ?!
sundar - Restabelece Monica
Sim, eu o desviei depois de ver o que 1YL significava, e essa entrada de código do Rosetta foi o único lugar que pude encontrar para confirmar que é uma coisa do MATLAB e não apenas uma função de conveniência do MATL. Eu estava começando a pensar que poderia ser algo que você adicionou ao MATL para jogar golfe, até que vi essa entrada.
sundar - Restabelece Monica
@sundar estranho que não está documentado mais
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]])}

Experimente online!

Este é R, então, obviamente, a resposta é indexada em 0.

A maior parte do trabalho está criando a matriz. Código inspirado em: https://rosettacode.org/wiki/Spiral_matrix#R

ngm
fonte
2

JavaScript (ES6), 165 bytes

Imprime os índices com 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))

Experimente online!

Quão?

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

(adaptado desta resposta de math.stackexchange)

Arnauld
fonte
Isso parece funcionar bem com números menores, mas eu recebo um erro ao testar isso com um grande número como 2000. Erro na tio.run: RangeError: Maximum call stack size exceedede erro no console do navegador: InternalError: too much recursion. Estou fazendo algo errado?
night2
1
4n2
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]

Experimente online!

Calcula u,l,r,ddiretamente de n.

Chas Brown
fonte
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 executá-lo:

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

Exemplo:

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

Ou Experimente online!

Notas:

  • A -d error_reporting=0opção é usada para não emitir avisos / avisos.
  • Essa espiral começa com 1.

Quão?

Estou gerando a espiral com uma versão modificada desta resposta em uma matriz bidimensional.

Eu decido o tamanho da espiral com base na entrada ncom uma fórmula para obter sempre uma rodada extra de números na espiral (garantia de existência de acima / abaixo / esquerda / direita). Uma rodada extra de números significa +2em altura e +2largura da matriz bidimensional.

Portanto, se nestiver localizado em uma espiral com tamanho máximo de 3*3, a espiral gerada será 5*5.

O tamanho da espiral é c*conde c = ceil(sqrt(n)) + k, se ceil(sqrt(n))é ímpar, então ké 2 e se ceil(sqrt(n))é par, então ké 3.

Por exemplo, a fórmula acima resultará neste:

  • Se n = 1então, o c = 3tamanho da espiral será3*3
  • Se n <= 9então, o c = 5tamanho da espiral será5*5
  • Se n <= 25então, o c = 7tamanho da espiral será7*7
  • Se n <= 49então, o c = 9tamanho da espiral será9*9
  • E assim por diante ...

Enquanto que a produção da espiral, que armazenar o xe yde ne após a geração, que os elementos de saída acima / abaixo de / para a esquerda / direita da mesma.

Night2
fonte