-63 octets grâce à @Arnauld. Sensationnel.
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
Essayez-le en ligne!
Tout d'abord, respectez Arnauld dont la réponse m'a donné l'inspiration pour creuser plus profondément. J'ai beaucoup essayé d'être original avec mes algorithmes, bien que j'ai intentionnellement changé une partie de mon code pour utiliser les mêmes variables qu'Arnauld afin que le code puisse être plus facilement comparé.
Recherche d'hexagones vides
La recherche de créatures est:
- Initialiser la liste des tuiles avec la tuile 1 à 0,0
- Récursivement:
- Cherchez un hex vide qui est nécessaire pour terminer la créature
- Si un hex vide est trouvé
- Ajoutez chaque type de tuile 0,1,2 à l'hex vide et recurse
- Si un hex vide n'est pas trouvé
- Si la créature est de la bonne taille et n'est pas déjà au zoo
- Augmente le nombre de créatures distinctes trouvées par une
- Ajoutez toutes les rotations et reflets de la créature au zoo
La recherche d'hexagones vides a révélé une symétrie intéressante. Arnauld a découvert que l'une des six directions pouvait être ignorée, mais en fait trois sur six peuvent être ignorées!
Voici la direction d'origine et la clé de tuile d'Arnauld:
Imaginez que nous commençons à la tuile A de type 1 au point bleu. Il semble que nous devions reprendre en d = 0 et d = 5. Cependant, quelle que soit la tuile placée en d = 0, elle aura certainement une sortie en d = 4, qui visitera le même hex que la tuile A sortant en d = 5. C'est la découverte d'Arnauld, et c'est ce qui m'a fait réfléchir.
Remarquerez que:
Cela signifie que nous devons seulement considérer les directions 0,2,4. Toutes les sorties dans les directions 1,3,5 peuvent être ignorées car les hexs accessibles dans les directions 1,3,5 peuvent à la place être atteints à partir d'un hex adjacent en utilisant les directions 0,2 ou 4.
À quel point cela est cool!?
Directions réétiquetées
J'ai donc réétiqueté les directions et les tuiles comme ceci (image d'Arnauld modifiée):
Nous avons maintenant la relation suivante entre les tuiles, les entrées et les sorties:
| 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
Les sorties sont donc: d + t == 2? (4-t)% 3: 2-t et 2 * t% 3
Rotations et réflexions hexagonales
Pour les rotations et les réflexions, j'ai décidé d'essayer les coordonnées axiales hexagonales x, y au lieu des coordonnées du cube 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
Dans ce système, la rotation et la réflexion étaient plus simples que ce à quoi je m'attendais:
120 Rotation: x=-x-y y=x t=(t+1)%3
Reflection: x=-x-y y=y t=(t*2)%3
Pour obtenir toutes les combinaisons que j'ai effectuées: pourriture, pourriture, pourriture, réflexion, pourriture, pourriture
Code (480 octets d'origine)
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
)
Code (Arnauld 417 octets)
Arnauld a gentiment soumis une économie de 63 octets qui a utilisé des astuces qui m'ont pris un certain temps pour envelopper ma tête. Puisqu'il a beaucoup de modifications intéressantes, j'ai pensé mettre son code ci-dessous (j'ai ajouté mes commentaires) afin qu'il puisse être contrasté avec ma version.
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." - s'il s'agit d'une exigence de vitesse d'exécution, veuillez utiliser code-challenge au lieu de code-golf , ce dernier faisant référence à une tâche d'optimisation d'octets purs.