Python 1166 bytes
Se ha dejado una cantidad considerable de espacio en blanco en aras de la legibilidad. El tamaño se mide después de la eliminación de este espacio en blanco, y el cambio de varios niveles de sangría a Tab
, Tab
Space
, Tab
Tab
, etc. También he evitado todo el golf que afectó el rendimiento demasiado drástica.
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
Uso de la muestra:
$ 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
Esta es una implementación del Algoritmo de Thistlethwaite, usando una búsqueda IDA * para resolver cada paso. Debido a que todas las tablas heurísticas deben calcularse sobre la marcha, se han hecho varios compromisos, generalmente dividiendo una heurística en dos o más partes de tamaño bastante igual. Esto hace que el cálculo de las tablas heurísticas sea cientos de veces más rápido, mientras que ralentiza la fase de búsqueda, generalmente solo un poco, pero puede ser significativo dependiendo del estado inicial del cubo.
Índice variable
T
- La tabla heurística principal.
S
- un estado de cubo resuelto. Cada pieza individual se almacena como una máscara de bits, representada como un personaje. Un vector de orientación resuelto se define como el vector cero.
I
- los diversos giros, en el orden en que se eliminan del espacio de búsqueda.
G
- los grupos para permutaciones de torsión, almacenados como pares para ser intercambiados. Cada byte en la cadena comprimida codifica para un par. Cada giro necesita seis intercambios: tres para el ciclo de borde y tres para el ciclo de esquina. La cadena comprimida contiene solo ascii imprimible (caracteres 32 a 126).
M
- una función que realiza un movimiento, dada por G.
N
- Convierte una permutación de cuatro objetos en un número, con fines de codificación.
H
- calcula el valor heurístico para el estado del cubo dado, utilizado para buscar profundidad de movimiento desde T.
P
- realice una búsqueda a una sola profundidad de una sola fase del algoritmo.
s
- el estado de permutación del cubo de entrada.
o
- el vector de orientación del cubo de entrada.
Actuación
Utilizando el conjunto de datos de Tomas Rokicki , este script promedió 16.02 giros por resolución (máximo 35), con un tiempo promedio de 472 ms (CPU i5-3330 a 3.0 Ghz, PyPy 1.9.0). El tiempo mínimo de resolución fue de 233 ms con un máximo de 2.97 s, desviación estándar de 0.488. Utilizando las pautas de puntuación del concurso (no se cuentan los espacios en blanco, las palabras clave y los identificadores cuentan como un byte para una longitud de 870), la puntuación general habría sido 13.549.
Para los últimos 46 casos (los estados aleatorios), promedió 30.83 giros por resolución, con un tiempo promedio de 721 ms.
Notas sobre el algoritmo de Thistlethwaite
Para el beneficio de cualquiera que quiera intentar una implementación del Algoritmo de Thistlethwaite , aquí hay una breve explicación.
El algoritmo funciona en un principio de reducción de espacio de solución muy simple. Es decir, reduzca el cubo a un estado en el que no sea necesario un subconjunto de giros para resolverlo, reduzca a un espacio de solución más pequeño y luego resuelva el resto utilizando solo los pocos giros restantes.
Thistlethwaite sugirió originalmente <L,R,F,B,U,D>
→ <L,R,F,B,U2,D2>
→ <L,R,F2,B2,U2,D2>
→ <L2,R2,F2,B2,U2,D2>
. Sin embargo, dado el formato de entrada, creo que es más fácil reducir primero a <L,R,F2,B2,U,D>
(sin cuarto de vuelta F
o B
), y luego <L2,R2,F2,B2,U,D>
antes de finalmente alcanzar el estado de media vuelta. En lugar de explicar exactamente por qué esto es así, creo que será evidente después de definir los criterios para cada estado.
<L,R,F,B,U,D>
⇒ <L,R,F2,B2,U,D>
Para eliminar F
y B
cuartos de vuelta, solo los bordes deben estar orientados correctamente. Gilles Roux tiene una muy buena explicación en su sitio de lo que es la orientación 'correcta' e 'incorrecta', así que le dejaré la explicación. Pero, básicamente, (y esto es por qué este formato de entrada es tan propicio para F
y B
eliminación), un borde Cubie está orientado correctamente si coincide con la siguiente expresión regular: [^RL][^UD]
. Una orientación correcta generalmente se indica con ay 0
incorrecta con 1
. Básicamente U
y D
pegatinas pueden no aparecer en las R
o L
caras, o en los bordes de los alguna U
o D
borde cubitos, o pueden no ser movido en su lugar sin necesidad de una F
oB
cuarto de giro
<L,R,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U,D>
Dos criterios aquí. En primer lugar, todas las esquinas deben ser orientados correctamente, y segundo, cada uno de los cubitos para la capa media ( FR
, FL
, BR
, BL
) deben estar en algún lugar en la capa media. La orientación de una esquina se define de manera muy simple dado el formato de entrada: la posición de la primera U
o D
. Por ejemplo, URB
tiene orientación 0
(correctamente orientada), LDF
tiene orientación 1
y LFU
tiene orientación 2
.
<L2,R2,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U2,D2>
El criterio aquí es el siguiente: cada cara solo puede contener pegatinas de su cara o de la cara directamente opuesta. Por ejemplo, en la U
cara solo puede haber U
y D
calcomanías, en la R
cara solo puede haber R
y L
calcomanías, en la F
cara solo puede haber F
y B
calcomanías, etc. La forma más fácil de asegurarse de esto es verificar si cada pieza del borde está su 'corte', y cada pieza de esquina en su 'órbita'. Además, uno debe prestar atención a la paridad de esquina de borde. Sin embargo, si marca solo la paridad de esquina, la paridad de borde también está garantizada y viceversa.
Cómo los giros afectan la orientación
U
y los D
giros no afectan ni a la orientación del borde ni a la orientación de la esquina. Las piezas pueden intercambiarse directamente sin actualizar el vector de orientación.
R
y los L
giros no afectan la orientación del borde, pero sí afectan la orientación de la esquina. Dependiendo de cómo defina su ciclo, el cambio en la orientación de la esquina será +1, +2, +1, +2
o +2, +1, +2, +1
, todo el módulo 3
. Tenga en cuenta que R2
y los L2
giros no afectan la orientación de la esquina, como +1+2
es el módulo cero 3
, como es +2+1
.
F
y B
afectan tanto las orientaciones de los bordes como las orientaciones de las esquinas. Las orientaciones de los bordes se vuelven +1, +1, +1, +1
(mod 2) y las orientaciones de las esquinas son las mismas que para R
y L
. Tenga en cuenta que F2
y B2
afecta ni las orientaciones de bordes, ni orientaciones de esquina.