Quartiers en spirale

19

Si nous prenons les nombres naturels et les enroulons dans le sens antihoraire dans une spirale, nous nous retrouvons avec la spirale infinie suivante:

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

Étant donné un certain nombre dans cette spirale, votre tâche consiste à déterminer ses voisins - c'est-à-dire l'élément au-dessus, à gauche, à droite et en dessous.

Exemple

Si nous regardons, 27nous pouvons voir qu'il a les voisins suivants:

  • au dessus: 28
  • la gauche: 10
  • droite: 52
  • au dessous de: 26

La sortie serait donc: [28,10,52,26]

Règles

  • L'entrée sera un nombre dans n'importe quel format d'E / S par défautn0
  • La sortie sera une liste / matrice / .. des 4 voisins de ce nombre dans n'importe quel ordre (cohérent!)
  • Vous pouvez travailler avec une spirale qui commence par 1 au lieu de 0, mais vous devez spécifier cela dans votre réponse

Exemples

La sortie est au format [above,left,right,below]et utilise une spirale basée sur 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]
ბიმო
la source
en relation
ბიმო

Réponses:

6

R , 156 octets

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

Essayez-le en ligne!

  • a posté une autre réponse R car c'est une approche légèrement différente de @ngn
  • 1 indexé
  • les voisins sont toujours triés par valeur croissante
  • économisé 6 octets de suppression roundet d'utilisation cospi(x)/sinpi(x)qui sont plus précis qu'en cos(x*pi)/sin(x*pi)cas de demi-nombres ( 0.5, 1.5etc ...)
  • enregistré un autre octet supprimant le moins sur les coordonnées y car le résultat est le même (seuls les voisins haut / bas sont inversés)

Explication:

Si nous regardons les coordonnées matricielles des valeurs, en considérant la première valeur 0placée à x=0, y=0, elles sont:

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

Les xcoordonnées suivent la séquence OEIS A174344 avec la formule récursive:

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

La même formule s'applique aux ycoordonnées de la matrice, mais avec cosau lieu de sinet inversé:

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

Donc, dans R, nous pouvons traduire la formule en cette fonction, en prenant sinpi/cospicomme paramètre:

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

et nous générons les deux vecteurs de coordonnées (nous ne nions pas les coordonnées y car nous obtiendrons le même résultat, juste avec les voisins haut / bas inversés):

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

Notez que nous avons généré des (n+2)^2coordonnées, qui sont plus que les coordonnées minimales nécessaires contenant à la fois net leurs voisins (une limite plus serrée serait (floor(sqrt(n))+2)^2mais malheureusement moins "golfique").

Par conséquent, maintenant que nous avons toutes les coordonnées, nous recherchons d'abord les coordonnées a,bcorrespondant à notre n:

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

enfin nous sélectionnons les positions de leurs voisins, à savoir:

  • les voisins haut / bas where x == a and y == b+1 or b-1
  • les voisins droit / gauche where y == b and x == a+1 or a-1

en utilisant :

which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))
digEmAll
la source
"légèrement différent" :)
ngm
@ngm: eheh ... étant donné que le code rosetta que vous avez utilisé est assez "obscur" pour moi, j'ai supposé qu'il générait en quelque sorte les index de position de la matrice d'une manière différente mais similaire à mes séquences OEIS: D
digEmAll
4

Perl 6 , 94 83 octets

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

Essayez-le en ligne!

sest une liste paresseuse et infinie de coordonnées en spirale, représentées par des nombres complexes. Il est construit à partir de deux autres listes infinies: 1, *i ... *crée la liste 1, i, -1, -i .... 1, 1.5 ... *fait la liste 1, 1.5, 2, 2.5, 3, 3.5 .... Compresser ces deux listes ainsi que la réplication de liste génère la liste des étapes de chaque spirale de coordonnées à l'autre: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (Les parties fractionnaires des arguments de droite de l'opérateur de réplication de liste sont ignorées.) Une réduction d'addition triangulaire ( [\+]) sur cette liste (et un collage de 0 sur le devant) produit la liste des coordonnées en spirale.

Enfin, à partir du nombre complexe s[$_]($_ étant le seul argument à la fonction), nous regardons les index ( first :k) dans la spirale des nombres complexes qui sont décalée par rapport à ce nombre par i, -1, 1et -i.

Sean
la source
4

Brain-Flak , 238 octets

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

Essayez-le en ligne!

La sortie est dans l'ordre gauche, haut, droite, bas.

Explication

# 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
la source
Très impressionnant! Je suppose que vous ne générez pas toute la spirale comme les autres, n'est-ce pas?
2018
3

MATL , 15 octets

2+1YLtG=1Y6Z+g)

L'entrée et la sortie sont basées sur 1.

La sortie donne les voisins gauche, bas, haut et droit dans cet ordre.

Essayez-le en ligne! Ou vérifiez tous les cas de test à l'exception des deux derniers, qui expirent sur 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
la source
2
1YL- MATLAB a une spiralfonction? Quand MATLAB est-il devenu Mathematica?!
sundar
Ouais, je l'ai édité après avoir vu ce que signifiait 1YL, et cette entrée de code Rosetta était le seul endroit que je pouvais trouver pour confirmer que c'était une chose MATLAB et pas seulement une fonction de commodité MATL. Je commençais à penser que cela pourrait être quelque chose que vous avez ajouté à MATL pour le golf, jusqu'à ce que je voie cette entrée.
sundar
@sundar Bizarre que ce ne soit plus documenté
Luis Mendo
3

R , 172 octets

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

Essayez-le en ligne!

C'est R, donc évidemment la réponse est indexée 0.

La plupart du travail consiste à créer la matrice. Code inspiré de: https://rosettacode.org/wiki/Spiral_matrix#R

ngm
la source
2

JavaScript (ES6), 165 octets

Imprime les index avec 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))

Essayez-le en ligne!

Comment?

X,yZjeX,y

UNEX,y=||X|-|y||+|X|+|y|
SX,y={1,si yX-1,si y<X
jeX,y=UNEX,y2+(UNEX,y+X+y)×SX,y

(adapté de cette réponse de math.stackexchange)

Arnauld
la source
Cela semble fonctionner très bien avec de plus petits nombres, mais je reçois une erreur lors du test de cela avec un grand nombre comme 2000. Erreur sur tio.run: RangeError: Maximum call stack size exceededet l' erreur dans la console du navigateur: InternalError: too much recursion. Est-ce que je fais quelque chose de mal?
Night2
1
4n2
2

Python 2 , 177 164 1 46 144 octets

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]

Essayez-le en ligne!

Calcule u,l,r,ddirectement à partir de n.

Chas Brown
la source
1

PHP (> = 5,4), 208 octets

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

Pour l'exécuter:

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

Exemple:

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

Ou essayez-le en ligne!

Remarques:

  • le -d error_reporting=0 option est utilisée pour ne pas générer d'avis / avertissements.
  • Cette spirale commence par 1.

Comment?

Je génère la spirale avec une version modifiée de cette réponse dans un tableau à 2 dimensions.

Je décide de la taille de la spirale en fonction de l'entrée navec une formule pour toujours obtenir un tour supplémentaire de nombres dans la spirale (garantie de l'existence de dessus / dessous / gauche / droite). Un rond supplémentaire de nombres signifie +2en hauteur et +2en largeur du tableau à 2 dimensions.

Donc, si nsera situé dans une spirale avec une taille maximale de 3*3, alors la spirale générée sera 5*5.

La taille de la spirale est c*cc = ceil(sqrt(n)) + k, si ceil(sqrt(n))est impair, alors kest 2 et si ceil(sqrt(n))est pair, alorsk est 3.

Par exemple, la formule ci-dessus se traduira par ceci:

  • Si n = 1alors c = 3et la taille de la spirale sera3*3
  • Si n <= 9alors c = 5et la taille de la spirale sera5*5
  • Si n <= 25alors c = 7et la taille de la spirale sera7*7
  • Si n <= 49alors c = 9et la taille de la spirale sera9*9
  • Etc ...

Lors de la génération de la spirale, je stocke le xet yde net après la génération, j'émets les éléments au-dessus / en dessous / à gauche / à droite de celui-ci.

Nuit2
la source