-63 bytes gracias a @Arnauld. Guau.
n=>(E=(x,y,d,k,h)=>V[k=[x+=1-(d%=3),y+=~d%3+1,d]]?0:(V[k]=1,h=H.find(h=>h[0]==x&h[1]==y))?(d^(t=2-h[2])?E(x,y,t)||E(x,y,h[2]*2):E(x,y,t+2)):[x,y,0],I=c=>c.map(([x,y,t])=>[x-g(0),y-g(1),t],g=p=>Math.min(...c.map(h=>h[p]))).sort(),S=e=>(V={},e=E(0,0,0))?(--n&&H.pop(H.push(e),S(),S(e[2]=1),S(e[2]=2)),++n):n-1||E[I(c=H)]||[0,0,0,++N,0,0].map(r=>E[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1))(H=[[N=0,0,1]])&&N
Pruébalo en línea!
En primer lugar, respeto a Arnauld, cuya respuesta me inspiró a profundizar. He intentado ser original con mis algoritmos, aunque cambié intencionalmente parte de mi código para usar las mismas variables que Arnauld para que el código pudiera compararse más fácilmente.
Buscando hexes vacíos
La búsqueda de criaturas es:
- Inicialice la lista de mosaicos con el mosaico 1 en 0,0
- Recursivamente:
- Busca un hex vacío que sea necesario para completar la criatura.
- Si se encuentra un hex vacío
- Agregue cada tipo de mosaico 0,1,2 para vaciar hex y recurse
- Si no se encuentra el hex vacío
- Si la criatura es del tamaño correcto y aún no está en el zoológico
- Incrementa el número de criaturas distintas encontradas por uno
- Agrega todas las rotaciones y reflejos de la criatura al zoológico
La búsqueda de hexes vacíos descubrió una simetría interesante. Arnauld descubrió que una de las seis direcciones podría ignorarse, pero de hecho, ¡tres de cada seis pueden ignorarse!
Aquí está la dirección original y la clave de mosaico de Arnauld:
Imagina que comenzamos en el mosaico A del tipo 1 en el punto azul. Parece que tenemos que recurrir en d = 0 yd = 5. Sin embargo, cualquiera que sea la casilla colocada en d = 0, ciertamente tendrá una salida en d = 4, que visitará el mismo hexágono que la ficha A existente en d = 5. Ese es el descubrimiento de Arnauld, y es lo que me hizo pensar.
Darse cuenta de:
Esto significa que solo necesitamos considerar las direcciones 0,2,4. Cualquier salida en las direcciones 1,3,5 se puede ignorar porque los hexes alcanzables en las direcciones 1,3,5 se pueden alcanzar desde un hex adyacente usando las direcciones 0,2 o 4.
¿¡Cuan genial es eso!?
Direcciones reetiquetadas
Así que vuelvo a etiquetar las instrucciones y los mosaicos como este (imagen editada de Arnauld):
Ahora tenemos la siguiente relación entre mosaicos, entradas y salidas:
| t=0 | t=1 | t=2
----+-------+-------+-------
d=0 | 0,2 | 1,2 | 2
d=1 | 0,2 | 0 | 0,1
d=2 | 1 | 1,2 | 0,1
Entonces las salidas son: d + t == 2? (4-t)% 3: 2-t y 2 * t% 3
Rotaciones Hexagonales y Reflexiones
Para rotaciones y reflexiones, decidí probar las coordenadas axiales hexagonales x, y en lugar de las coordenadas del cubo x, y, z.
-1,2 0,2 1,2 2,2
0,1 1,1 2,1
0,0 1,0 2,0 3,0
En este sistema, la rotación y la reflexión fueron más simples de lo que esperaba:
120 Rotation: x=-x-y y=x t=(t+1)%3
Reflection: x=-x-y y=y t=(t*2)%3
Para obtener todas las combinaciones que realicé: putrefacción, putrefacción, putrefacción, reflexión, putrefacción, putrefacción
Código (480 bytes original)
f=n=>(
// H:list of filled hexes [x,y,tile] during search for a complete creature
// N:number of distinct creatures of size n
// B:record of all orientations of all creatures already found
H=[[0,0,1]],N=0,B={},
// E: find an empty hex required to complete creature starting in direction d from x,y
E=(x,y,d,k,h)=>(
x+=1-d,
y+=1-(d+1)%3,
// V: list of visited hexes during this search in E
V[k=[x,y,d]] ?
0
: (V[k]=1, h=H.find(h=>h[0]==x&&h[1]==y)) ?
// this hex is filled, so continue search in 1 or 2 directions
(d==2-h[2] ? E(x,y,(4-h[2])%3) : (E(x,y,2-h[2]) || E(x,y,h[2]*2%3)))
: [x,y,0] // return the empty hex
),
// I: construct unique identifier for creature c by moving it so x>=0 and y>=0
I=c=>(
M=[0,1].map(p=>Math.min(...c.map(h=>h[p]))),
c.map(([x,y,t])=>[x-M[0],y-M[1],t]).sort()
),
// A: add complete creature c to B
A=c=>{
n==1&&!B[I(c)]&&(
// creature is correct size and is not already in B
N++,
[0,0,0,1,0,0].map(
// Add all rotations and reflections of creature into B
// '0' marks a rotation, '1' marks a (vertical) reflection
// rotation: x=-x-y y=x t=(t+1)%3
// reflection: x=-x-y y=y t=(t*2)%3
r=>B[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1)
)
},
// S: recursively search for complete creatures starting with hexes H
S=e=>{
V={};
(e=E(0,0,0)) ?
// e is a required empty hex, so try filling it with tiles 0,1,2
(--n && (H.push(e),S(),S(e[2]=1),S(e[2]=2),H.pop()), ++n)
: A(H) // creature is complete, so add it to B
},
S(),
N
)
Código (Arnauld 417 byte)
Arnauld presentó amablemente un ahorro de 63 bytes que utilizó trucos que me tomaron bastante tiempo para comprender. Como tiene muchas ediciones interesantes, pensé en poner su código a continuación (agregué mis comentarios) para poder compararlo con mi versión.
f=n=>(
// E:find an empty hex required to complete creature starting in direction d from x,y
E=(x,y,d,k,h)=>
V[k=[x+=1-(d%=3),y+=~d%3+1,d]] ?
0
:(V[k]=1,h=H.find(h=>h[0]==x&h[1]==y)) ?
(d^(t=2-h[2]) ? E(x,y,t) || E(x,y,h[2]*2) : E(x,y,t+2))
:[x,y,0],
// I: construct unique identifier for creature c by moving it so x>=0 and y>=0
I=c=>c.map(([x,y,t])=>[x-g(0),y-g(1),t],g=p=>Math.min(...c.map(h=>h[p]))).sort(),
// S: recursively search for complete creatures starting with hexes H
S=e=>
(V={},e=E(0,0,0)) ?
(--n&&H.pop(H.push(e),S(),S(e[2]=1),S(e[2]=2)),++n)
:n-1
||E[I(c=H)]
// creature is the correct size and has not been seen before
// so record all rotations and reflections of creature in E[]
||[0,0,0,++N,0,0].map(r=>E[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1)
)
// This wonderfully confusing syntax initializes globals and calls S()
(H=[[N=0,0,1]]) && N
n=10
TIO". - si ese es un requisito de velocidad de ejecución, utilice code-challenge en lugar de code-golf , este último se refiere a una tarea de optimización de byte puro.