Python 1166 octets
Une quantité considérable d’espaces a été laissée pour des raisons de lisibilité. La taille est mesurée après suppression de cette espaces, et en changeant différents niveaux d'indentation à Tab
, Tab
Space
, Tab
Tab
, etc. J'ai aussi évité tout le golf qui a affecté la performance de manière trop drastique.
T=[]
S=[0]*20,'QTRXadbhEIFJUVZYeijf',0
I='FBRLUD'
G=[(~i%8,i/8-4)for i in map(ord,'ouf|/[bPcU`Dkqbx-Y:(+=P4cyrh=I;-(:R6')]
R=range
def M(o,s,p):
z=~p/2%-3;k=1
for i,j in G[p::6]:i*=k;j*=k;o[i],o[j]=o[j]-z,o[i]+z;s[i],s[j]=s[j],s[i];k=-k
N=lambda p:sum([i<<i for i in R(4)for j in R(i)if p[j]<p[i]])
def H(i,t,s,n=0,d=()):
if i>4:n=N(s[2-i::2]+s[7+i::2])*84+N(s[i&1::2])*6+divmod(N(s[8:]),24)[i&1]
elif i>3:
for j in s:l='UZifVYje'.find(j);t[l]=i;d+=(l-4,)[l<4:];n-=~i<<i;i+=l<4
n+=N([t[j]^t[d[3]]for j in d])
elif i>1:
for j in s:n+=n+[j<'K',j in'QRab'][i&1]
for j in t[13*i:][:11]:n+=j%(2+i)-n*~i
return n
def P(i,m,t,s,l=''):
for j in~-i,i:
if T[j][H(j,t,s)]<m:return
if~m<0:print l;return t,s
for p in R(6):
u=t[:];v=s[:]
for n in 1,2,3:
M(u,v,p);r=p<n%2*i or P(i,m+1,u,v,l+I[p]+`n`)
if r>1:return r
s=raw_input().split()
o=[-(p[-1]in'UD')or p[0]in'RL'or p[1]in'UD'for p in s]
s=[chr(64+sum(1<<I.find(a)for a in x))for x in s]
for i in R(7):
m=0;C={};T+=C,;x=[S]
for j,k,d in x:
h=H(i,j,k)
for p in R(C.get(h,6)):
C[h]=d;u=j[:];v=list(k)
for n in i,0,i:M(u,v,p);x+=[(u[:],v[:],d-1)]*(p|1>n)
if~i&1:
while[]>d:d=P(i,m,o,s);m-=1
o,s=d
Exemple d'utilisation:
$ more in.dat
RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU
$ pypy rubiks.py < in.dat
F3R1U3D3B1
F2R1F2R3F2U1R1L1
R2U3F2U3F2U1R2U3R2U1
F2L2B2R2U2L2D2L2F2
Ceci est une implémentation de l'algorithme de Thistlethwaite, utilisant une recherche IDA * à résoudre pour chaque étape. Étant donné que toutes les tables heuristiques doivent être calculées à la volée, plusieurs compromis ont été faits, divisant généralement une heuristique en deux ou plusieurs parties de taille sensiblement égale. Cela accélère le calcul des tables heuristiques des centaines de fois, tout en ralentissant légèrement la phase de recherche, mais il peut être important en fonction de l'état initial du cube.
Indice variable
T
- la table heuristique principale.
S
- un état de cube résolu. Chaque pièce individuelle est stockée sous forme de masque de bits, représenté par un caractère. Un vecteur d'orientation résolu est défini comme le vecteur zéro.
I
- les différents rebondissements, dans l'ordre dans lequel ils sont éliminés de l'espace de recherche.
G
- les groupes de permutations de torsion, stockés sous forme de paires à échanger. Chaque octet de la chaîne compressée code pour une paire. Chaque torsion nécessite six échanges: trois pour le cycle de bord et trois pour le cycle de coin. La chaîne compressée contient uniquement des caractères ASCII imprimables (caractères 32 à 126).
M
- une fonction qui effectue un mouvement, donné par G.
N
- convertit une permutation de quatre objets en un nombre, à des fins de codage.
H
- calcule la valeur heuristique pour l'état de cube donné, utilisé pour rechercher la profondeur de déplacement à partir de T.
P
- effectuer une recherche à une profondeur unique d'une phase de l'algorithme.
s
- l'état de permutation du cube en entrée.
o
- le vecteur d'orientation du cube en entrée.
Performance
En utilisant le jeu de données de Tomas Rokicki , ce script a enregistré une moyenne de 16,02 twists par résolution (maximum 35), avec un temps moyen de 472 ms (i5-3330 CPU @ 3.0 Ghz, PyPy 1.9.0). Le temps de résolution minimum était de 233 ms avec un maximum de 2,97 secondes, écart type de 0,488. En utilisant les directives de notation du concours (les espaces ne sont pas comptés, les mots-clés et les identifiants comptent pour un octet pour une longueur de 870), le score total aurait été de 13 549.
Pour les 46 derniers cas (les états aléatoires), la moyenne est de 30,83 torsions par résolution, avec un temps moyen de 721 ms.
Notes sur l'algorithme de Thistlethwaite
Pour le bénéfice de tous ceux qui voudraient tenter de mettre en œuvre l'algorithme de Thistlethwaite , voici une brève explication.
L'algorithme fonctionne sur un principe de réduction de l'espace de solution très simple. Autrement dit, réduisez le cube à un état dans lequel un sous-ensemble de torsions n'est pas nécessaire pour le résoudre, réduisez-le à un espace de solution plus petit, puis résolvez le reste en utilisant uniquement les quelques torsions restantes.
Thistlethwaite suggéré à l'origine <L,R,F,B,U,D>
→ <L,R,F,B,U2,D2>
→ <L,R,F2,B2,U2,D2>
→ <L2,R2,F2,B2,U2,D2>
. Cependant, étant donné le format d'entrée, je pense qu'il est plus facile de réduire d'abord à <L,R,F2,B2,U,D>
(pas de quart de tour F
ou B
), et ensuite <L2,R2,F2,B2,U,D>
avant d'atteindre l'état de demi-tour. Au lieu d’expliquer exactement pourquoi, je pense que ce sera évident après la définition des critères pour chaque État.
<L,R,F,B,U,D>
⇒ <L,R,F2,B2,U,D>
Pour éliminer F
et B
quart de tour, seules les arêtes doivent être correctement orientées. Gilles Roux a une très bonne explication sur son site de ce qu'est une orientation "correcte" et "incorrecte", je vais donc lui laisser l'explication. Mais au fond, (ce qui est la raison pour laquelle ce format d'entrée est donc propice au F
et B
élimination), un Cubie de bord est orienté correctement si elle correspond à l'expression rationnelle suivante: [^RL][^UD]
. Une orientation correcte est généralement indiquée avec un 0
et incorrect avec 1
. Fondamentalement U
et D
autocollants peuvent ne pas apparaître sur les R
ou L
faces, ou sur les bords des tout U
ou D
bord petits cubes, ou ils ne peuvent pas être déplacés en place sans avoir besoin d' un F
ouB
quart de tour.
<L,R,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U,D>
Deux critères ici. Tout d' abord, tous les coins doivent être orientés correctement, et d' autre part, chacun des pour petits cubes de couche du milieu ( FR
, FL
, BR
, BL
) doit être quelque part dans la couche intermédiaire. Une orientation de coin est très simplement définie en fonction du format d'entrée: la position du premier U
ou D
. Par exemple, URB
a une orientation 0
(correctement orientée), LDF
a une orientation 1
et LFU
a une orientation 2
.
<L2,R2,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U2,D2>
Les critères sont les suivants: chaque face ne peut contenir que des autocollants collés sur sa face ou directement sur la face opposée. Par exemple, sur le U
visage , il ne peut être U
et D
autocollants, sur le R
visage , il ne peut y avoir R
etL
autocollants, sur le F
visage , il peut seulement être F
et B
autocollants, etc. La façon d' y parvenir est plus facile de vérifier si chaque pièce de bord est en sa "tranche" et chaque coin dans son "orbite". De plus, il faut faire attention à la parité des bords. Bien que, si vous ne vérifiez que la parité d'angle, la parité de bord est également garantie, et inversement.
Comment les rebondissements affectent l'orientation
U
et les D
torsions n’affectent ni l’orientation des bords, ni l’angle des angles. Les pièces peuvent être échangées directement sans mettre à jour le vecteur d’orientation.
R
et les L
torsions n’affectent pas l’orientation des bords, mais l’orientation des coins. Selon la façon dont vous définissez votre cycle, le changement d'orientation des coins sera soit modulaire, +1, +2, +1, +2
soit +2, +1, +2, +1
modulaire 3
. Notez que R2
et L2
torsions ne touchent pas l'orientation du coin, comme +1+2
est égal à zéro modulo 3
, comme +2+1
.
F
et B
affecte à la fois les orientations des bords et les orientations des coins. Les orientations des bords deviennent +1, +1, +1, +1
(mod 2) et les orientations des coins sont les mêmes que pour R
et L
. Notez que F2
et B2
affectent ni les orientations de bord, ni les orientations d'angle.