Limpo , 284 279 272 262 bytes
import StdEnv
l=[0,-1,-1,0,1,1]
c(u,v)(p,q)=(u-p)^2+(v-q)^2<2||(u-p)*(q-v)==1
$[h:t]m=hd[[e: $t[(h,e):m]]\\e<-[1..]|and[e<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]]
$(scan(\(a,b)(u,v)=(a-u,b-v))(0,0)[(i,j)\\n<-[1..],i<-[1,1:l]&j<-l,_<-[max(~j<<i)1..n]])[]
Experimente online!
Gera a sequência para sempre.
Mapeamento hexagonal
A maior parte do código destina-se ao mapeamento de hexágonos exclusivamente para (x,y)
coordenadas, para que haja uma função única e simples para determinar a adjacência que é válida para todos os mapeamentos de pontos.
Os pontos mapeados são assim:
---
--- < 2,-2> --- x-axis ___.X'
--- < 1,-2> === < 2,-1> --- /__.X'
< 0,-2> === < 1,-1> === < 2, 0>'
=== < 0,-1> === < 1, 0> ===
<-1,-1> === < 0, 0> === < 1, 1>
=== <-1, 0> === < 0, 1> ===
<-2, 0> === <-1, 1> === < 0, 2>.__
--- <-2, 1> === <-1, 2> --- \ 'Y.___
--- <-2, 2> --- y-axis 'Y.
---
A partir daí, determinar a adjacência é trivial e ocorre quando um dos seguintes:
x1 == x2
e abs(y1-y2) == 1
y1 == y2
e abs(x1-x2) == 1
y1 == y2 - 1
e x2 == x1 - 1
y1 == y2 + 1
e x2 == x1 + 1
x1 == x2
e y1 == y2
Geração de pontos
Observe que, ao atravessar o hexágono em espiral, as diferenças se repetem para cada camada n
:
n
etapas de (1,0)
n-1
etapas de (1,-1)
n
etapas de (0,-1)
n
etapas de (-1,0)
n
etapas de (-1,1)
n
etapas de (0,1)
Isso gera os pontos na ordem correta, somando prefixos dessa sequência:
scan(\(a,b)(u,v)=(a-u,b-v))(0,0)[(i,j)\\n<-[1..],i<-[1,1:l]&j<-l,_<-[max(~j<<i)1..n]]
Reunindo
O código que realmente encontra a sequência da pergunta é apenas:
$[h:t]m=hd[[e: $t[(h,e):m]]\\e<-[1..]|and[e<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]]
Que, por sua vez, é principalmente filtrado por and[r<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]
Esse filtro obtém pontos de m
(a lista de pontos já mapeados) por:
- Ignorando números naturais iguais a qualquer
j
- Para todos os
(i,j)
lugares i
adjacentes ap
- Para cada
(p,q)
onde o valor q
é igual av
- Para todos os
(u,v)
locais u
adjacentes ao ponto atual