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]

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

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


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)
{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>

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

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


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)


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.


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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.