Python 1166 byte
È stata lasciata una notevole quantità di spazio bianco per motivi di leggibilità. Il formato è misurato dopo la rimozione di questo spazio vuoto, e la modifica di vari livelli di rientro a Tab
, Tab
Space
, Tab
Tab
, ecc ho anche evitato qualsiasi golf che ha colpito le prestazioni troppo drasticamente.
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
Esempio di utilizzo:
$ 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
Questa è un'implementazione dell'algoritmo di Thistlethwaite, usando una ricerca IDA * per risolvere ogni passo. Poiché tutte le tabelle euristiche devono essere calcolate al volo, sono stati fatti diversi compromessi, di solito suddividendo un'euristica in due o più parti di dimensioni abbastanza uguali. Questo rende il calcolo delle tabelle euristiche molte centinaia di volte più veloce, mentre rallenta la fase di ricerca, di solito solo leggermente, ma può essere significativo a seconda dello stato iniziale del cubo.
Indice variabile
T
- la tabella euristica principale.
S
- uno stato del cubo risolto. Ogni singolo pezzo è memorizzato come una maschera di bit, rappresentata come un personaggio. Un vettore di orientamento risolto è definito come vettore zero.
I
- i vari colpi di scena, nell'ordine in cui vengono eliminati dallo spazio di ricerca.
G
- i gruppi per permutazioni di rotazione, memorizzati come coppie da scambiare. Ogni byte nella stringa compressa codifica per una coppia. Ogni giro ha bisogno di sei scambi: tre per il ciclo del bordo e tre per il ciclo dell'angolo. La stringa compressa contiene solo ascii stampabili (carattere da 32 a 126).
M
- una funzione che esegue una mossa, data da G.
N
- converte una permutazione di quattro oggetti in un numero, a scopo di codifica.
H
- calcola il valore euristico per il dato stato del cubo, utilizzato per cercare la profondità di spostamento da T.
P
- esegue una ricerca a una sola profondità di una singola fase dell'algoritmo.
s
- lo stato di permutazione del cubo di input.
o
- il vettore di orientamento del cubo di input.
Prestazione
Utilizzando il set di dati di Tomas Rokicki , questo script ha registrato una media di 16,02 colpi di scena per soluzione (massimo 35), con un tempo medio di 472 ms (CPU i5-3330 a 3,0 Ghz, PyPy 1.9.0). Il tempo minimo di risoluzione è stato di 233 ms con un massimo di 2,97 s, deviazione standard 0,488. Utilizzando le linee guida per il punteggio del concorso (lo spazio bianco non viene conteggiato, le parole chiave e gli identificatori contano come un byte per una lunghezza di 870), il punteggio complessivo sarebbe stato di 13.549.
Negli ultimi 46 casi (gli stati casuali), ha una media di 30,83 colpi di scena per soluzione, con un tempo medio di 721 ms.
Note sull'algoritmo di Thistlethwaite
A beneficio di chiunque voglia tentare di implementare l'algoritmo di Thistlethwaite , ecco una breve spiegazione.
L'algoritmo funziona secondo un principio di riduzione dello spazio della soluzione molto semplice. Ossia, ridurre il cubo a uno stato in cui non è necessario un sottoinsieme di colpi di scena per risolverlo, ridurlo in uno spazio di soluzione più piccolo e quindi risolvere il resto utilizzando solo i pochi colpi di scena rimanenti.
Originariamente Thistlethwaite suggeriva <L,R,F,B,U,D>
→ <L,R,F,B,U2,D2>
→ <L,R,F2,B2,U2,D2>
→ <L2,R2,F2,B2,U2,D2>
. Tuttavia, dato il formato di input, penso che sia più facile ridurre prima a <L,R,F2,B2,U,D>
(senza un quarto di giro F
o B
), e poi <L2,R2,F2,B2,U,D>
prima di raggiungere finalmente lo stato di mezzo giro. Invece di spiegare esattamente perché, penso che sarà evidente dopo aver definito i criteri per ogni stato.
<L,R,F,B,U,D>
⇒ <L,R,F2,B2,U,D>
Per eliminare F
e un B
quarto di giro, solo i bordi devono essere orientati correttamente. Gilles Roux ha una spiegazione molto valida sul suo sito su quale sia l'orientamento 'corretto' e 'errato', quindi lascerò la spiegazione a lui. Ma fondamentalmente, (e questo è il motivo per cui questo formato di ingresso è così adatto allo F
ed B
eliminazione), un cubetto di bordo sia orientata correttamente se corrisponde alla seguente espressione regolare: [^RL][^UD]
. Un orientamento corretto è generalmente indicato con un 0
e non corretto con 1
. Fondamentalmente U
e D
adesivi non possono essere visualizzati sul R
o L
facce, o sui bordi delle eventuali U
o D
bordo cubetti, o non possono essere spostate in posizione senza richiedere una F
oB
quarto di giro.
<L,R,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U,D>
Due criteri qui. In primo luogo, tutti gli angoli devono essere orientate correttamente e secondo, ciascuno dei cubetti di strato intermedio ( FR
, FL
, BR
, BL
) devono essere in qualche luogo nello strato centrale. L'orientamento dell'angolo è definito in modo molto semplice dato il formato di input: la posizione del primo U
o D
. Ad esempio, URB
ha orientamento 0
(correttamente orientato), LDF
ha orientamento 1
e LFU
orientamento 2
.
<L2,R2,F2,B2,U,D>
⇒ <L2,R2,F2,B2,U2,D2>
I criteri qui sono i seguenti: ogni faccia può contenere solo adesivi dalla sua faccia, o dalla faccia direttamente di fronte. Ad esempio, sul U
viso potrebbero esserci solo U
e D
adesivi, sul R
viso potrebbero esserci solo R
e L
adesivi, sul F
viso potrebbero esserci solo F
e B
adesivi, ecc. Il modo più semplice per assicurarsi che questo sia verificare se ciascun bordo è inserito la sua "fetta" e ogni angolo nella sua "orbita". Inoltre, è necessario prestare attenzione alla parità edge-corner. Tuttavia, se si controlla solo la parità degli angoli, viene garantita anche la parità dei bordi e viceversa.
In che modo i colpi di scena influenzano l'orientamento
U
e le D
torsioni non influiscono né sull'orientamento del bordo, né sull'orientamento degli angoli. I pezzi possono essere scambiati direttamente senza aggiornare il vettore di orientamento.
R
e le L
torsioni non influiscono sull'orientamento del bordo, ma influenzano l'orientamento degli angoli. A seconda di come definisci il tuo ciclo, la modifica dell'orientamento dell'angolo sarà +1, +2, +1, +2
o +2, +1, +2, +1
, tutto il modulo 3
. Si noti che R2
e L2
torsioni non influenzano l'orientamento angolo, come +1+2
è zero modulo 3
, come è +2+1
.
F
e B
influisce sia sugli orientamenti dei bordi che sugli orientamenti degli angoli. Gli orientamenti dei bordi diventano +1, +1, +1, +1
(mod 2) e gli orientamenti degli angoli sono gli stessi di R
e L
. Si noti che F2
e B2
influenzano né gli orientamenti bordo, né gli orientamenti angolari.