La imagen de arriba muestra una cuadrícula hexagonal de hexágonos. A cada celda de la cuadrícula se le asigna un índice, comenzando desde el centro y girando en sentido antihorario como se muestra. Tenga en cuenta que la cuadrícula continuará indefinidamente: la imagen de arriba es simplemente la primera sección. El siguiente hexágono sería adyacente a 60 y 37.
Su tarea es determinar si dos celdas dadas en esta cuadrícula son adyacentes.
Escriba un programa o función que, dados dos índices de celda, imprima / devuelva un valor verdadero si las dos celdas son adyacentes, y un valor falso si no.
Si no está limitado por razones prácticas, su código debería funcionar teóricamente para entradas de cualquier tamaño.
Casos de prueba de verdad:
0, 1
7, 18
8, 22
24, 45
40, 64
64, 65
Casos de prueba de Falsey:
6, 57
29, 90
21, 38
38, 60
40, 63
41, 39
40, 40
Este es el código de golf, por lo que gana la respuesta más corta en bytes. Se alientan las explicaciones, incluso para los idiomas no esotéricos.
fuente
MATL ,
4745444341 bytesPruébalo en línea! O verificar todos los casos de prueba .
Como beneficio adicional, el código genera una espiral hexagonal que traza las posiciones de los centros celulares, que se pueden ver gráficamente en MATL Online modificando la última parte del código.
Explicación
Idea general El código primero construye una espiral hexagonal suficientemente grande con un paso unitario. La espiral se define como un vector de números complejos que representan las posiciones de los centros celulares. La indexación en ese vector con los números de entrada y el cálculo de la diferencia absoluta da la distancia entre las dos celdas indicadas. Las celdas son adyacentes solo si el resultado es 1. Sin embargo, debido a imprecisiones de coma flotante, es necesario redondear antes de comparar con 1.
Construyendo la espiral La espiral tendrá un número de "capas" igual a la suma de las dos entradas. Esto es (mucho) más grande de lo necesario y asegura que las celdas de entrada estarán presentes en la espiral.
Para construir la espiral, primero se calcula el número complejo j 2/3 (donde j es la unidad imaginaria). Elevar esto a los exponentes 1 a 6 proporciona un conjunto básico de desplazamientos, de modo que seguir esos desplazamientos en orden rastrearía un hexágono. Este hexágono formaría la capa más interna de la espiral, excepto que estaría "cerrada". En realidad, queremos que ese hexágono "crezca" en el último paso y luego trazamos un hexágono más grande, con el doble de puntos (alineados en grupos de dos), para formar la siguiente capa de la espiral; Ver ilustración aquí . La siguiente capa tendrá tres puntos tantos como la primera (en grupos de tres); ver aquí .
Para hacer esto, el quinto desplazamiento del conjunto básico (que apunta en la dirección sureste) se elige como el paso "creciente". La capa k comienza con ese paso, seguido de los primeros cinco pasos básicos repetidos k veces, seguido del sexto paso (dirección este) repetido k −1 veces. Con suerte, esto se vuelve más claro al mirar las dos figuras vinculadas anteriormente.
El vector resultante, incluidas todas las capas, representa los desplazamientos complejos que trazarían la espiral. La suma acumulativa da las coordenadas reales de los centros celulares.
Por último, la celda inicial, ubicada en 0, está unida al final de este vector. Esto se debe a que MATL usa una indexación modular basada en 1, y el índice 0 se refiere a la última entrada de una matriz.
Prueba de adyacencia Se seleccionan las dos celdas dadas por los números de entrada, se restan sus coordenadas y el valor absoluto se redondea y se compara con 1.
Código comentado
fuente
05AB1E (heredado) ,
302927 bytesPruébalo en línea!
Explicación del código:
Explicación de las matemáticas:
"Perdí" alrededor de 5 horas haciendo este golf. En resumen, comencé a hacer un gráfico 2D de las entradas, y dibujé
X
donde estaban adyacentes entre sí. Entonces encontré un patrón. ¡Lo busqué en OEIS y bingo! Encontré esa secuencia y utilicé la fórmula dada en el sitio web.fuente
C (gcc) ,
175173 bytesGracias a Peter Taylor por atrapar un error.
Gracias a ceilingcat por -2 bytes. Ese operador ~ sigue siendo mi punto ciego principal.
Pruébalo en línea!
Este enfoque se centra en encontrar la fila y la columna de las dos celdas y compararlas; cualquier vecino no puede tener sus coordenadas correspondientes diferentes en 1. Moviéndose desde el centro hacia afuera, observamos que cada capa tiene 6 celdas más que la anterior. Esto significa que el "índice" más alto en cada capa L está en la forma 6 * (L * (L - 1) * (L - 2) ...), o C = 6 * (L 2 + L) / 2 , donde C es el número de celda "global". Al barajar las cosas, obtenemos L 2 + L - C / 3 = 0, lo que da retrocesos matemáticos en la escuela secundaria. A partir de eso, obtenemos la fórmula ceil (sqrt (1/4 + C / 3) + 0.5). Al conectar un índice de celda global, recibimos en qué capa se encuentra la celda.
Dado que la primera celda en cada capa es naturalmente una más alta que la más alta de la capa anterior, encontramos L inicio = (6 * (L - 1) 2 + (L - 1)) / 2, que se simplifica a 3 * (L 2 - L). De eso obtenemos el índice de capa L index = C - L start .
A continuación, vemos que cada capa se compone de seis secciones, cada una de longitud L. Comenzando en el noreste y en sentido antihorario, vemos que para las dos primeras secciones (1 <= L índice <= 2 * L) , obtenemos la columna a partir de L - L índice . La siguiente sección L * 2 <L index <= L * 3 tiene todas las celdas que comparten una sola columna -L. Las dos secciones siguientes son L * 3 <L index <= L * 5 con sus columnas de acuerdo con el índice L - L * 4. Y, por último, la sexta sección tiene sus celdas en la columna L. Podemos desplazar los límites superiores un paso a lo largo para guardar algunos bytes en el código.
Entonces, ¿qué pasa con las filas? Para reutilizar el código, giramos la cuadrícula de modo que la celda 44 esté recta Luego ejecutamos la misma lógica que para las columnas pero esta vez llamamos a los resultados "filas". Por supuesto, en lugar de girar una cuadrícula, simplemente caminamos 1/6 de vuelta alrededor.
fuente
Python 3, 150 bytes
Mi solución básicamente sigue la misma línea de pensamiento que la anterior de Luis Mendo. Si se escribe más legible, el código se explica por sí mismo:
h
hace lo siguiente:i
Es el número de anillo.l
es una concatenación de 6 listas de len (i) multiplicado por el vector de pasos, donde el vector de pasos es 1j ** (2/3) con cierta potencia. El rango no comienza en 0 sino en 4, lo que provoca una rotación de toda la cuadrícula. Esto me permite hacer:l[0]+=1
en la línea 6, que es el paso de un anillo al siguiente.L+=l
concatena la lista completa y la lista de anillo.h(0,0)
o h (0,1) se atiende implícitamente, porque la suma de una lista vacía es cero. Si pudiera estar seguro de quea<b
, es decir, los argumentos vendrían en orden creciente, podría eliminar otros 14 bytes reemplazándolosL[min(a,b):max(a,b)]
conL[a:b]
, pero ¡ay!PD: No sabía que este era un desafío tan antiguo, apareció en la parte superior hace unos días, y me fastidiaba desde :)
fuente
Mathematica,
111105104 bytesExplicación:
r=Floor[(1+Sqrt[(4#-1)/3])/2]&
define una funciónr
que toma la entrada#
y calcula la distancia (en número de celdas) a la celda 0. Hace esto explotando el patrón en las últimas celdas de cada distancia / anillo: 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3), ... e invirtiendo la fórmula para ese patrón. Tenga en cuenta que para la celda 0, en realidad toma el piso de (1/2) + i * (sqrt (3) / 6), que calcula por componentes para obtener 0 + 0 * i = 0.Con
r
definido,r@#
es el anillo para la celda#
(dentro de la definición de otra función).#+3r@#-3(r@#)^2&
no aparece exactamente en el código, pero toma el número de una celda y resta el número más alto de una celda en el siguiente anillo interno, de modo que da la respuesta a la pregunta "¿qué celda del anillo actual es esta?" Por ejemplo, la celda 9 es la tercera celda del anillo 2, porr[9]
lo que generaría 2 y#+3r@#-3(r@#)^2&[9]
generaría 3.Lo que podemos hacer con la función anterior es usarla para encontrar el ángulo polar , el ángulo en sentido antihorario desde el rayo "celda 0, celda 17, celda 58" hasta la celda en cuestión. La última celda de cada anillo siempre está en un ángulo Pi / 6, y vamos alrededor de un anillo en incrementos de Pi / (3 * ring_number). Entonces, en teoría, necesitamos calcular algo como Pi / 6 + (which_cell_of_the_current_ring) * Pi / (3 * ring_number). Sin embargo, la rotación de la imagen no afecta nada, por lo que podemos descartar la parte Pi / 6 (para guardar 6 bytes). Combinando esto con la fórmula anterior y simplificando, obtenemos
Pi(#/(3r@#)+1-r@#)&
Desafortunadamente, esto no está definido para la celda 0 ya que su número de anillo es 0, por lo que debemos evitarlo. Una solución natural sería algo así
t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&
. Pero como no nos importa el ángulo de la celda 0 y porquer@#
se repite, podemos guardar un byte aquí cont=Limit[Pi(#/(3x)+1-x),x->r@#]&
Ahora que tenemos el número de anillo y el ángulo, podemos encontrar la posición de una celda (centro) para poder comprobar la adyacencia. Encontrar la posición real es molesto porque los anillos son hexagonales, pero podemos simplemente pretender que los anillos son círculos perfectos para que tratemos el número de anillo como la distancia al centro de la celda 0. Esto no será un problema ya que la aproximación es bastante cerca. Usando la forma polar de un número complejo , podemos representar esta posición aproximada en el plano complejo con una función simple:
p = r@#*Exp[I*t@#] &;
La distancia entre dos números complejos en el plano complejo viene dada por el valor absoluto de su diferencia, y luego podemos redondear el resultado para encargarnos de cualquier error de la aproximación, y verificar si es igual a 1. La función que finalmente ¿Este trabajo no tiene un nombre, pero es
Round@Abs[p@#-p@#2]==1&
.Puede probarlo en línea en el sandbox de Wolfram Cloud pegando código como el siguiente y haciendo clic en Gear -> "Evaluar celda" o presionando Shift + Enter o el teclado numérico Enter:
O para todos los casos de prueba:
fuente