L'image ci-dessus montre une grille hexagonale d'hexagones. Chaque cellule de la grille se voit attribuer un index, en partant du centre et en spirale dans le sens antihoraire comme illustré. Notez que la grille continuera indéfiniment - l'image ci-dessus est simplement la première section. L'hexagone suivant serait adjacent à 60 et 37.
Votre tâche consiste à déterminer si deux cellules données sur cette grille sont adjacentes.
Écrivez un programme ou une fonction qui, étant donné deux indices de cellule, imprime / renvoie une valeur véridique si les deux cellules sont adjacentes, et une valeur de falsey dans le cas contraire.
S'il n'est pas limité par des raisons pratiques, votre code devrait théoriquement fonctionner pour toutes les entrées de taille.
Cas de test véridiques:
0, 1
7, 18
8, 22
24, 45
40, 64
64, 65
Cas de test Falsey:
6, 57
29, 90
21, 38
38, 60
40, 63
41, 39
40, 40
Il s'agit de code-golf donc la réponse la plus courte en octets l'emporte. Des explications, même pour les langues non ésotériques, sont encouragées.
la source
MATL ,
4745444341 octetsEssayez-le en ligne! Ou vérifiez tous les cas de test .
En prime, le code génère une spirale hexagonale qui trace les positions des centres cellulaires, ce qui peut être vu graphiquement sur MATL Online en modifiant la dernière partie du code.
Explication
Idée générale Le code construit d'abord une spirale hexagonale suffisamment grande avec un pas unitaire. La spirale est définie comme un vecteur de nombres complexes représentant les positions des centres cellulaires. L'indexation dans ce vecteur avec les nombres d'entrée et le calcul de la différence absolue donne la distance entre les deux cellules indiquées. Les cellules sont adjacentes si et seulement si le résultat est 1. Cependant, en raison d'inexactitudes en virgule flottante, l'arrondi est nécessaire avant de comparer avec 1.
Construire la spirale La spirale aura un nombre de "couches" égal à la somme des deux entrées. Ceci est (beaucoup) plus grand que nécessaire et garantit que les cellules d'entrée seront présentes dans la spirale.
Pour construire la spirale, le nombre complexe j 2/3 (où j est l'unité imaginaire) est d'abord calculé. Augmenter cela aux exposants 1 à 6 donne un ensemble de base de déplacements, de sorte que suivre ces déplacements dans l'ordre tracerait un hexagone. Cet hexagone formerait la couche la plus intérieure de la spirale, sauf qu'il serait "fermé". En fait, nous voulons que cet hexagone "grandisse" à la dernière étape, puis nous traçons un hexagone plus grand, avec deux fois plus de points (alignés en groupes de deux), pour former la couche suivante de la spirale; voir l'illustration ici . La couche suivante aura trois fois plus de points que la première (en groupes de trois); voir ici .
Pour ce faire, le cinquième déplacement par rapport à l'ensemble de base (qui pointe dans la direction sud-est) est choisi comme étape "croissante". La couche k commence par cette étape, suivie des cinq premières étapes de base répétées k fois, suivies par la sixième étape (direction est) répétée k -1 fois. J'espère que cela deviendra plus clair en examinant les deux chiffres liés ci-dessus.
Le vecteur résultant, y compris toutes les couches, représente les déplacements complexes qui traceraient la spirale. La somme cumulée donne les coordonnées réelles des centres cellulaires.
Enfin, la cellule initiale, située à 0, est attachée à l'extrémité de ce vecteur. Cela est dû au fait que MATL utilise l'indexation modulaire basée sur 1 et que l'index 0 fait référence à la dernière entrée d'un tableau.
Test d'adjacence Les deux cellules données par les nombres en entrée sont sélectionnées, leurs coordonnées sont soustraites et la valeur absolue est arrondie et comparée à 1.
Code commenté
la source
05AB1E (hérité) ,
302927 octetsEssayez-le en ligne!
Explication du code:
Explication des mathématiques:
J'ai "perdu" environ 5 heures à faire ce golf. En bref, j'ai commencé à faire un graphique 2D des entrées et à dessiner
X
où elles étaient adjacentes les unes aux autres. Ensuite, j'ai trouvé un motif. Je l'ai cherché sur OEIS et bingo! J'ai trouvé cette séquence et j'ai utilisé la formule indiquée sur le site Web.la source
C (gcc) ,
175173 bytesMerci à Peter Taylor d' avoir attrapé un bug.
Merci à plafondcat pour -2 octets. Cet opérateur ~ reste mon principal angle mort.
Essayez-le en ligne!
Cette approche vise à trouver la ligne et la colonne des deux cellules et à les comparer; les voisins ne peuvent pas voir leurs coordonnées correspondantes différer de plus de 1. En se déplaçant du centre vers l'extérieur, nous observons que chaque couche a 6 cellules de plus que la précédente. Cela signifie que l '"indice" le plus élevé dans chaque couche L est sur la forme 6 * (L * (L - 1) * (L - 2) ...), ou C = 6 * (L 2 + L) / 2 , où C est le numéro de cellule "global". En mélangeant les choses, nous obtenons L 2 + L - C / 3 = 0, ce qui donne des flashbacks mathématiques au lycée. De cela, nous obtenons la formule ceil (sqrt (1/4 / C / 3) + 0,5). En y branchant un index de cellule global, nous recevons la couche dans laquelle se trouve la cellule.
Étant donné que la première cellule de chaque couche est naturellement supérieure à la plus haute de la couche précédente, nous trouvons L start = (6 * (L - 1) 2 + (L - 1)) / 2, ce qui simplifie à 3 * (L 2 - L). De là, nous obtenons l'indice de couche L index = C - L start .
Ensuite, nous voyons que chaque couche est composée de six sections, chacune de longueur L. En partant du nord-est et dans le sens antihoraire, nous voyons que pour les deux premières sections (1 <= indice L <= 2 * L) , nous obtenons la colonne de l - l ' indice . La section suivante L * 2 <L index <= L * 3 a toutes les cellules partageant une seule colonne -L. Les deux sections suivantes sont L * 3 < index L <= L * 5 avec leurs colonnes selon l' indice L - L * 4. Enfin, la sixième section a toutes ses cellules sur la colonne L. Nous pouvons déplacer les limites supérieures d'une étape pour enregistrer quelques octets dans le code.
Alors qu'en est-il des rangées? Pour réutiliser le code, nous tournons la grille de sorte que la cellule 44 soit droite. Ensuite, nous exécutons la même logique que pour les colonnes mais appelons les résultats "lignes" cette fois-ci. Bien sûr, au lieu de tourner une grille, nous faisons juste 1/6 de tour autour d'elle.
la source
Python 3, 150 octets
Ma solution suit fondamentalement la même ligne de pensée que celle de Luis Mendo ci-dessus. S'il est écrit plus lisible, le code est assez explicite:
h
comme suit:i
est le numéro de sonnerie.l
est une concaténation de 6 listes de len (i) fois le pas-vecteur, où le pas-vecteur est 1j ** (2/3) à une certaine puissance. La plage ne commence pas à 0 mais à 4, ce qui provoque une rotation de toute la grille. Cela me permet de faire:l[0]+=1
à la ligne 6, qui est le pas d'un anneau au suivant.L+=l
concatène la liste complète et la liste des sonneries.h(0,0)
ou h (0,1) est pris en charge implicitement, car la somme d'une liste vide est nulle. Si je pouvais être sûr quea<b
, c'est-à-dire que les arguments viendraient dans l'ordre croissant, je pourrais raser encore 14 octets en remplaçantL[min(a,b):max(a,b)]
parL[a:b]
, mais hélas!PS: je ne savais pas que c'était un vieux défi, il est apparu il y a quelques jours et n'a cessé de me harceler depuis :)
la source
Mathematica,
111105104 octetsExplication:
r=Floor[(1+Sqrt[(4#-1)/3])/2]&
définit une fonctionr
qui prend une entrée#
et calcule la distance (en nombre de cellules) à la cellule 0. Elle le fait en exploitant le motif dans les dernières cellules de chaque distance / anneau: 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3), ... et inverser la formule de ce modèle. Notez que pour la cellule 0, il prend en fait le plancher de (1/2) + i * (sqrt (3) / 6), qu'il calcule par composant pour obtenir 0 + 0 * i = 0.Avec
r
défini,r@#
est l'anneau de cellule#
(à l'intérieur de la définition d'une autre fonction).#+3r@#-3(r@#)^2&
n'apparaît pas exactement dans le code, mais il prend le numéro d'une cellule et soustrait le nombre le plus élevé d'une cellule dans l'anneau intérieur suivant, de sorte qu'il donne la réponse à la question "quelle cellule de l'anneau actuel est-ce?" Par exemple, la cellule 9 est la 3ème cellule de l'anneau 2, ainsir[9]
sortirait 2 et#+3r@#-3(r@#)^2&[9]
sortirait 3.Ce que nous pouvons faire avec la fonction ci-dessus, c'est l'utiliser pour trouver l' angle polaire , l' angle anti-horaire du rayon "cellule 0, cellule 17, cellule 58" à la cellule en question. La dernière cellule de chaque anneau est toujours à un angle Pi / 6, et nous contournons un anneau par incréments de Pi / (3 * ring_number). Donc, en théorie, nous devons calculer quelque chose comme Pi / 6 + (which_cell_of_the_current_ring) * Pi / (3 * ring_number). Cependant, la rotation de l'image n'affecte rien, nous pouvons donc éliminer la partie Pi / 6 (pour économiser 6 octets). En combinant cela avec la formule précédente et en simplifiant, nous obtenons
Pi(#/(3r@#)+1-r@#)&
Malheureusement, cela n'est pas défini pour la cellule 0 car son numéro de sonnerie est 0, nous devons donc contourner cela. Une solution naturelle serait quelque chose comme
t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&
. Mais comme nous ne nous soucions pas de l'angle pour la cellule 0 et parce quer@#
c'est répété, nous pouvons réellement enregistrer un octet ici avect=Limit[Pi(#/(3x)+1-x),x->r@#]&
Maintenant que nous avons le numéro d'anneau et l'angle, nous pouvons trouver la position d'une cellule (centre) afin que nous puissions tester l'adjacence. Trouver la position réelle est ennuyeux car les anneaux sont hexagonaux, mais nous pouvons simplement prétendre que les anneaux sont des cercles parfaits afin que nous considérions le numéro de l'anneau comme la distance au centre de la cellule 0. Ce ne sera pas un problème car l'approximation est assez jolie proche. En utilisant la forme polaire d'un nombre complexe , nous pouvons représenter cette position approximative dans le plan complexe avec une fonction simple:
p = r@#*Exp[I*t@#] &;
La distance entre deux nombres complexes sur le plan complexe est donnée par la valeur absolue de leur différence, puis nous pouvons arrondir le résultat pour prendre soin des erreurs de l'approximation et vérifier si cela est égal à 1. La fonction qui finalement fait ce travail n'a pas de nom, mais l'est
Round@Abs[p@#-p@#2]==1&
.Vous pouvez l' essayer en ligne dans le sandbox Wolfram Cloud en collant du code comme celui-ci et en cliquant sur Gear -> "Evaluer la cellule" ou en appuyant sur Maj + Entrée ou sur le pavé numérique Entrée:
Ou pour tous les cas de test:
la source