A imagem acima exibe uma grade hexagonal de hexágonos. Cada célula da grade recebe um índice, começando do centro e girando no sentido anti-horário, como mostrado. Observe que a grade continuará indefinidamente - a imagem acima é simplesmente a primeira seção. O próximo hexágono seria adjacente a 60 e 37.
Sua tarefa é determinar se duas células nessa grade são adjacentes.
Escreva um programa ou função que, dados dois índices de células, imprima / retorne um valor verdadeiro se as duas células forem adjacentes e um valor falsey se não.
Se não for limitado por razões práticas, seu código deve funcionar teoricamente para qualquer tamanho de entrada.
Casos de teste de verdade:
0, 1
7, 18
8, 22
24, 45
40, 64
64, 65
Casos de teste de Falsey:
6, 57
29, 90
21, 38
38, 60
40, 63
41, 39
40, 40
Isso é código-golfe, então a resposta mais curta em bytes vence. Explicações, mesmo para idiomas não esotéricos, são incentivadas.
fonte
MATL ,
4745444341 bytesExperimente online! Ou verifique todos os casos de teste .
Como bônus, o código gera uma espiral hexagonal que rastreia as posições dos centros celulares, que podem ser vistas graficamente no MATL Online , modificando a última parte do código.
Explicação
Ideia geral O código primeiro constrói uma espiral hexagonal suficientemente grande com uma etapa unitária. A espiral é definida como um vetor de números complexos que representam as posições dos centros celulares. A indexação nesse vetor com os números de entrada e a diferença absoluta calculam a distância entre as duas células indicadas. As células são adjacentes se, e somente se, o resultado for 1. No entanto, devido às imprecisões do ponto flutuante, o arredondamento é necessário antes da comparação com 1.
Construindo a espiral A espiral terá um número de "camadas" iguais à soma das duas entradas. Isso é (muito) maior que o necessário e garante que as células de entrada estejam presentes na espiral.
Para construir a espiral, o número complexo j 2/3 (onde j é a unidade imaginária) é primeiro calculado. Aumentar isso para os expoentes 1 a 6 fornece um conjunto básico de deslocamentos, de modo que seguir esses deslocamentos em ordem traçaria um hexágono. Esse hexágono formaria a camada mais interna da espiral, exceto que seria "fechada". Na verdade, queremos que o hexágono "cresça" no último passo e depois traçamos um hexágono maior, com o dobro de pontos (alinhados em grupos de dois), para formar a próxima camada da espiral; veja a ilustração aqui . A próxima camada terá três vezes mais pontos que o primeiro (em grupos de três); veja aqui .
Para fazer isso, o quinto deslocamento do conjunto básico (que aponta na direção sudeste) é escolhido como o passo "crescente". A camada k começa com esse passo, seguido pelos cinco primeiros passos básicos repetidos k vezes, seguidos pelo sexto passo (direção leste) repetido k -1 vezes. Esperamos que isso fique mais claro, observando os dois números acima.
O vetor resultante, incluindo todas as camadas, representa os deslocamentos complexos que rastreariam a espiral. A soma cumulativa fornece as coordenadas reais dos centros celulares.
Por fim, a célula inicial, localizada em 0, é anexada ao final desse vetor. Isso ocorre porque o MATL usa indexação modular com base em 1 e o índice 0 refere-se à última entrada de uma matriz.
Teste de adjacência As duas células fornecidas pelos números de entrada são selecionadas, suas coordenadas são subtraídas e o valor absoluto é arredondado e comparado com 1.
Código comentado
fonte
05AB1E (herdado) ,
302927 bytesExperimente online!
Explicação do código:
Explicação da matemática:
Eu "desperdicei" cerca de 5 horas fazendo este golfe. Em resumo, comecei a fazer um gráfico 2D das entradas e desenhar
X
onde elas estavam adjacentes umas às outras. Então eu encontrei um padrão. Eu procurei no OEIS e no bingo! Eu encontrei essa sequência e usei a fórmula dada no site.fonte
C (gcc) ,
175173 bytesAgradecimentos a Peter Taylor por pegar um bug.
Obrigado ao ceilingcat por -2 bytes. Esse operador continua sendo meu principal ponto cego.
Experimente online!
Essa abordagem está focada em encontrar a linha e a coluna das duas células e compará-las; quaisquer vizinhos não podem ter suas coordenadas correspondentes diferindo em mais de 1. Movendo-se do centro para fora, observamos que cada camada tem mais 6 células que a anterior. Isso significa que o "índice" mais alto em cada camada L está no formato 6 * (L * (L - 1) * (L - 2) ...) ou C = 6 * (L 2 + L) / 2 , onde C é o número de célula "global". Ao embaralhar as coisas, obtemos L 2 + L - C / 3 = 0, o que fornece flashbacks de matemática do ensino médio. A partir disso, obtemos a fórmula ceil (sqrt (1/4 + C / 3) + 0,5). Ao conectar um índice global de células, recebemos em qual camada a célula está.
Como a primeira célula de cada camada é naturalmente uma mais alta que a mais alta da camada anterior, encontramos L start = (6 * (L - 1) 2 + (L - 1)) / 2, o que simplifica para 3 * (L 2 - L). A partir disso, obtemos o índice de camada L index = C - L start .
Em seguida, vemos que cada camada é composta por seis seções, cada uma com comprimento L. Começando no nordeste e indo no sentido anti-horário, vemos que nas duas primeiras seções (1 <= L index <= 2 * L) , obtemos a coluna de L - L índice . A próxima seção L * 2 <L index <= L * 3 possui todas as células que compartilham uma única coluna -L. As duas próximas seções são L * 3 <L índice <= L * 5 com suas colunas de acordo com o índice L - L * 4. E, por fim, a sexta seção tem todas as células na coluna L. Podemos mudar os limites superiores um passo adiante para salvar alguns bytes no código.
Então e as linhas? Para reutilizar o código, giramos a grade para que a célula 44 fique reta. Em seguida, executamos a mesma lógica das colunas, mas desta vez chamamos os resultados de "linhas". É claro que, em vez de realmente virar uma grade, apenas andamos 1/6 de volta em volta dela.
fonte
Python 3, 150 bytes
Minha solução segue basicamente a mesma linha de pensamento que a de Luis Mendo acima. Se escrito mais legível, o código é bastante auto-explicativo:
h
faz o seguinte:i
é o número do toque.l
é uma concatenação de 6 listas de len (i) vezes o vetor escalonado, onde o vetor escalonado é de 1j ** (2/3) a alguma potência. O intervalo não começa em 0, mas em 4, o que causa uma rotação de toda a grade. Isso me permite fazer:l[0]+=1
na linha 6, que é a etapa de um toque para o próximo.L+=l
concatena a lista completa e a lista de toques.h(0,0)
ou h (0,1) é tratado implicitamente, porque a soma de uma lista vazia é zero. Se eu pudesse ter certeza de quea<b
, ou seja, os argumentos viriam em ordem crescente, eu poderia cortar outros 14 bytes substituindoL[min(a,b):max(a,b)]
porL[a:b]
, mas infelizmente!PS: Eu não sabia que esse era um desafio tão antigo, apareceu no topo há alguns dias e continuou me incomodando desde :)
fonte
Mathematica,
111105104 bytesExplicação:
r=Floor[(1+Sqrt[(4#-1)/3])/2]&
define uma funçãor
que recebe entrada#
e calcula a distância (em número de células) para a célula 0. Faz isso explorando o padrão nas últimas células de cada distância / anel: 0 = 3 (0 ^ 2 + 0), 6 = 3 (1 ^ 2 + 1), 18 = 3 (2 ^ 2 + 2), 36 = 3 (3 ^ 2 + 3), ... e invertendo a fórmula para esse padrão. Observe que para a célula 0, na verdade, é usado o piso de (1/2) + i * (sqrt (3) / 6), que calcula em componentes para obter 0 + 0 * i = 0.Com
r
definido,r@#
é o anel para célula#
(dentro da definição de outra função).#+3r@#-3(r@#)^2&
não aparece exatamente no código, mas pega o número de uma célula e subtrai o número mais alto de uma célula no próximo anel interno, para que ele responda à pergunta "qual célula do anel atual é essa?" Por exemplo, a célula 9 é a terceira célula do anel 2; portantor[9]
, a saída 2 e a#+3r@#-3(r@#)^2&[9]
saída 3.O que podemos fazer com a função acima é usá-la para encontrar o ângulo polar , no sentido anti-horário, do raio "célula 0, célula 17, célula 58" para a célula em questão. A última célula de cada anel está sempre em um ângulo Pi / 6 e contornamos um anel em incrementos de Pi / (3 * número do anel). Portanto, em teoria, precisamos calcular algo como Pi / 6 + (qual_cell_of_the_current_ring) * Pi / (3 * ring_number). No entanto, a rotação da imagem não afeta nada, portanto podemos descartar a parte Pi / 6 (para economizar 6 bytes). Combinando isso com a fórmula anterior e simplificando, obtemos
Pi(#/(3r@#)+1-r@#)&
Infelizmente, isso não é definido para a célula 0, pois seu número de toque é 0, por isso precisamos contornar isso. Uma solução natural seria algo parecido
t=If[#==0,0,Pi(#/(3r@#)+1-r@#)]&
. Mas como não nos importamos com o ângulo da célula 0 e, comor@#
é repetida, podemos salvar um byte aqui comt=Limit[Pi(#/(3x)+1-x),x->r@#]&
Agora que temos o número do anel e o ângulo, podemos encontrar a posição de uma célula (centro) para testar a adjacência. Encontrar a posição real é irritante porque os anéis são hexagonais, mas podemos simplesmente fingir que os anéis são círculos perfeitos, para que tratemos o número do anel como a distância do centro da célula 0. Isso não será um problema, pois a aproximação é bastante Fechar. Usando a forma polar de um número complexo , podemos representar esta posição aproximada no plano complexo com uma função simples:
p = r@#*Exp[I*t@#] &;
A distância entre dois números complexos no plano complexo é dada pelo valor absoluto de sua diferença, e então podemos arredondar o resultado para resolver quaisquer erros da aproximação e verificar se isso é igual a 1. A função que finalmente este trabalho não tem nome, mas é
Round@Abs[p@#-p@#2]==1&
.Você pode experimentá-lo on-line na caixa de proteção Wolfram Cloud colando código como o seguinte e clicando em Equipamento -> "Avaliar célula" ou pressionando Shift + Enter ou o teclado numérico Enter:
Ou para todos os casos de teste:
fonte