Quartieri a spirale


19

Se prendiamo i numeri naturali e li arrotoliamo in senso antiorario in una spirale, finiamo con la seguente spirale 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

Dato un certo numero in quella spirale, il tuo compito è determinare i suoi vicini, ovvero l'elemento sopra, a sinistra, a destra e sotto di esso.

Esempio

Se diamo un'occhiata, 27possiamo vedere che ha i seguenti vicini:

  • sopra: 28
  • sinistra: 10
  • giusto: 52
  • sotto: 26

Quindi l'output sarebbe: [28,10,52,26]

Regole

  • L'input sarà un numero in qualsiasi formato I / O predefiniton0
  • L'output sarà un elenco / matrice / .. dei 4 vicini di quei numeri in qualsiasi ordine (coerente!)
  • Puoi lavorare con una spirale che inizia con 1 invece di 0, tuttavia dovresti specificarlo nella tua risposta

Esempi

L'output è nel formato [above,left,right,below]e utilizza una spirale basata su 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]

Risposte:


6

R , 156 byte

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

Provalo online!

  • pubblicato un'altra risposta R poiché è un approccio leggermente diverso rispetto a @ngn
  • 1-indicizzato
  • i vicini sono sempre ordinati per valore crescente
  • 6 byte salvati rimuovendo rounde usando cospi(x)/sinpi(x)quali sono più precisi che cos(x*pi)/sin(x*pi)nel caso di mezzi numeri ( 0.5, 1.5ecc ...)
  • salvato un altro byte rimuovendo il segno meno su y coordinate poiché il risultato è lo stesso (solo i vicini su / giù sono invertiti)

Spiegazione :

Se osserviamo le coordinate della matrice dei valori, considerando il primo valore 0posizionato in x=0, y=0, sono:

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

Le xcoordinate seguono la sequenza OEIS A174344 con la formula ricorsiva:

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

La stessa formula vale per yle coordinate della matrice, ma con cosanziché sine negato:

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

Quindi, in R possiamo tradurre la formula in questa funzione, prendendo sinpi/cospicome parametro:

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

e generiamo i due vettori di coordinate (non annulliamo le coordinate y poiché avremo lo stesso risultato, solo con i vicini su / giù invertiti):

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

Si noti che abbiamo generato (n+2)^2coordinate, che sono più delle coordinate minime necessarie che contengono entrambi ne i loro vicini (un limite più stretto sarebbe (floor(sqrt(n))+2)^2ma sfortunatamente è meno "golfy").

Pertanto, ora che abbiamo tutte le coordinate, cerchiamo prima le coordinate a,bcorrispondenti al nostro n:

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

infine selezioniamo le posizioni dei loro vicini, ovvero:

  • i vicini su / giù where x == a and y == b+1 or b-1
  • i vicini di destra / sinistra where y == b and x == a+1 or a-1

utilizzando:

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

"leggermente diverso" :)
ngm

@ngm: eheh ... dato che il codice rosetta che hai usato è piuttosto "oscuro" per me, ho pensato che in qualche modo stia generando gli indici di posizione della matrice in un modo diverso ma simile alle mie sequenze OEIS: D
digEmAll

4

Perl 6 , 94 83 byte

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

Provalo online!

sè un elenco pigro e infinito di coordinate a spirale, rappresentate come numeri complessi. È costruito da altre due liste infinite: 1, *i ... *crea la lista 1, i, -1, -i .... 1, 1.5 ... *rende l'elenco 1, 1.5, 2, 2.5, 3, 3.5 .... Zippare queste due liste insieme con la replica lista produce l'elenco dei passi da ogni spirale coordinata a quella successiva: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (Le parti frazionarie degli argomenti di destra per l'operatore di replica elenco vengono scartate.) Effettuando una riduzione di addizione triangolare ( [\+]) in questo elenco (e incollando 0 in primo piano) si ottiene l'elenco delle coordinate a spirale.

Infine, a partire dal numero complesso s[$_]( $_essendo l'unico argomento della funzione), osserviamo i indici ( first :k) nella spirale dei numeri complessi che sono compensati da quel numero da i, -1, 1e -i.


4

Brain-Flak , 238 byte

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

Provalo online!

L'output è nell'ordine sinistra, su, destra, giù.

Spiegazione

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

Molto impressionante! Immagino che non stai generando l'intera spirale come fanno gli altri, vero?
ბიმო

3

MATL , 15 byte

2+1YLtG=1Y6Z+g)

Input e output sono basati su 1.

L'output dà i vicini sinistro, basso, alto e destro in questo ordine.

Provalo online! Oppure verifica tutti i casi di test tranne gli ultimi due, che scadono su 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 ha una spiralfunzione? Quando MATLAB si è trasformato in Mathematica ?!
Sundar - Ripristina Monica il

Sì, l'ho evitato dopo aver visto cosa significava 1YL, e questa voce del codice Rosetta era l'unico posto che ho trovato per confermare che è una cosa MATLAB e non solo una funzione di convenienza MATL. Stavo iniziando a pensare che potesse essere qualcosa che hai aggiunto a MATL per il golf, fino a quando non ho visto quella voce.
Sundar - Ripristina Monica il

@sundar Strano che non sia più documentato
Luis Mendo,

3

R , 172 byte

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

Provalo online!

Questo è R, quindi ovviamente la risposta è indicizzata a 0.

Gran parte del lavoro sta creando la matrice. Codice ispirato a: https://rosettacode.org/wiki/Spiral_matrix#R


2

JavaScript (ES6), 165 byte

Stampa gli indici 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))

Provalo online!

Come?

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

(adattato da questa risposta da math.stackexchange)


Questo sembra funzionare bene con i numeri più piccoli, ma ottengo un errore quando si prova questo con un gran numero come 2000. Errore tio.run: RangeError: Maximum call stack size exceededed errori nella console del browser: InternalError: too much recursion. Sto facendo qualcosa di sbagliato?
Night2

1
4n2

2

Python 2 , 177 164 1 46 144 byte

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]

Provalo online!

Calcola u,l,r,ddirettamente da n.


1

PHP (> = 5.4), 208 byte

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

Per eseguirlo:

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

Esempio:

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

Oppure provalo online!

Appunti:

  • L' -d error_reporting=0opzione viene utilizzata per non generare avvisi / avvisi.
  • Questa spirale inizia con 1.

Come?

Sto generando la spirale con una versione modificata di questa risposta in un array bidimensionale.

Decido sulla dimensione della spirale in base all'input ncon una formula per ottenere sempre un giro extra di numeri nella spirale (garanzia per l'esistenza di sopra / sotto / sinistra / destra). Un giro extra di numeri significa +2in altezza e +2in larghezza della matrice 2 dimensionale.

Quindi se nsi troverà in una spirale con dimensione massima di 3*3, allora sarà la spirale generata 5*5.

La dimensione a spirale è c*cdove c = ceil(sqrt(n)) + k, se ceil(sqrt(n))è dispari, quindi kè 2 e se ceil(sqrt(n))è pari, quindi kè 3.

Ad esempio, la formula sopra si tradurrà in questo:

  • Se n = 1allora c = 3e la dimensione della spirale sarà3*3
  • Se n <= 9allora c = 5e la dimensione della spirale sarà5*5
  • Se n <= 25allora c = 7e la dimensione della spirale sarà7*7
  • Se n <= 49allora c = 9e la dimensione della spirale sarà9*9
  • E così via ...

Durante la generazione della spirale, memorizzo il xe ydi ne dopo la generazione, output gli elementi sopra / sotto / sinistra / destra di esso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.