Solve Rubik's cube

Write the shortest program that solves Rubik's cube (3*3*3) within a reasonable amount of time and moves (say, max. 5 seconds on your machine and less than 1000 moves).

The input is in the format:

UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR


(this particular input represents the solved cube).
First 12 2-character strings are the edges in the UF, UR, ... BL positions (U=up, F=front, R=right, B=back, L=left, D=down), then the next 8 3-character strings are the corners in the UFR, URB, ... DBR positions.

The output should give a sequence of moves in this format:

D+ L2 U+ F+ D+ L+ D+ F+ U- F+


Where D1 or D+ represents turning the D (down) face clockwise 90 degrees, L2 is turning the L face 180 degrees, U3 or U- represents turning the U face counterclockwise 90 degrees.
Letters are case-insensitive and spaces are optional.

For example, the output above is correct for the following input:

RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU


For more details, please refer to Tomas Rokicki's cube contest, except scoring will be done directly by file size like a normal code golfing problem. An online tester is included too.

For reference, the shortest solution already written is the last entry in the list of cube contest winners

For those struggling to visualise the layout format:

0-1 2-3 4-5 6-7 8-9 10-11 12-13 14-15 16-17 18-19 20-21 22-23 24-25-26 27-28-29 30-31-32 33-34-35 36-37-38 39-40-41 42-43-44 45-46-47
UF  UR  UB  UL  DF   DR    DB   DL    FR    FL     BR    BL     UFR      URB      UBL      ULF      DRF      DFL      DLB      DBR

Front:

+-------+-------+-------+
/       /       /       /|
/  30   /   4   /  27   / |
+-------+-------+-------+  |
/       /       /       /|28+
/   6   /       /   2   / | /|
+-------+-------+-------+  |/ |
/       /       /       /|3 +  |
/  33   /   0   /  24   / | /|21+
+-------+-------+-------+  |/ | /|
|       |       |       |26+  |/ |
|  35   |   1   |   25  | /|  +  |
|       |       |       |/ | /|47+
+-------+-------+-------+  |/ | /
|       |       |       |17+  |/
|  18   |       |  16   | /|11+
|       |       |       |/ | /
+-------+-------+-------+  |/
|       |       |       |37+
|  40   |   9   |  38   | /
|       |       |       |/
+-------+-------+-------+

Hidden faces:

+-------+-------+-------+
/|       |       |       |
/ |  31   |   5   |  29   |
+  |       |       |       |
/|32+-------+-------+-------+
/ | /|       |       |       |
+  |/ |  22   |       |  20   |
/|7 +  |       |       |       |
/ | /|23+-------+-------+-------+
+  |/ | /|       |       |       |
|34+  |/ |  44   |  13   |  46   |
| /|  +  |       |       |       |
|/ | /|43+-------+-------+-------+
+  |/ | /       /       /       /
|19+  |/  42   /  12   /  45   /
| /|15+-------+-------+-------+
|/ | /       /       /       /
+  |/  14   /       /  10   /
|41+-------+-------+-------+
| /       /       /       /
|/  39   /   8   /   36  /
+-------+-------+-------+

• Are languages other than C/C++/Java/Perl/Python accepted? Commented Mar 12, 2013 at 10:00
• @EgorSkriptunoff In here yes, use whatever you like, just no cube-solving libraries. Commented Mar 12, 2013 at 11:24
• And what about scoring? Usual code-golf scoring (bytes in program) or complex scoring like in 2004 contest? Commented Mar 12, 2013 at 11:32
• @jdstankosky, I've added a diagram. Commented Apr 12, 2013 at 13:36
• Are we allowed to pull off the stickers and move them around?
– Iszi
Commented Dec 24, 2013 at 18:59

C++ - 1123

Since nobody posted any answer so far, I decided to simplify and golf my 2004 solution. It's still far behind the shortest one I mentioned in the question.

#include<iostream>
#include<vector>
#define G(i,x,y)for(int i=x;i^y;i++)
#define h(x)s[a[x]/q*q+(a[x]+j)%q-42]
#define B(x)D=x;E=O.substr(j*3,3);G(i,0,3)E+=F[5-F.find(E[2-i])];G(i,0,D.length())D[i]=E[F.find(D[i++])];m.push_back(D);
#define P(a,b)G(i,0,6)G(k,49,52){e[0]=F[i];e[1]=k;m.push_back(e);}G(j,0,24){B(a)B(b)}
#define T C();z=m.size();for(b=c;b;){d=s;G(i,o=w=1,4){w*=z;if(o)G(j,0,w)if(o){s=d;u=j;G(k,0,i){f=m[u%z];G(x,0,f.length()){a=M[F.find(f[x++])];G(i,0,f[x]-48)G(l,0,2){q=3-l;p=4*l;G(j,0,q){t=h(p+3);G(k,-3,0)h(p-k)=h(p-1-k);h(p)=t;}}}u/=z;}C();if(c<b){u=j;G(k,0,i){std::cout<<m[u%z];u/=z;}b=c;o=0;}}}}
std::string s,a,D,E,d,f,e="  ",S="UFURUBULDFDRDBDLFRFLBRBLUFRURBUBLULFDRFDFLDLBDBR",F="ULFBRD",M[]={"KHEB*0.,","KRTI0<8@","KDNS*;2=","IVXG/@7>","BGWP,>4:","QNWT2468"},O=S.substr(24)+"FDRFRUFULFLDRDBRBURUFRFDBDLBLUBURBRDLDFLFULUBLBD";std::vector<std::string>m;int
w,X=8,Y=16,o,c,u,b,z,p,q,t;void C(){c=0;G(i,X,Y)c+=s[i]!=S[i];}main(int
g,char**v){G(i,1,g)s+=v[i];P("U2F1R1L3U2L1R3F1U2","L3R1F3L1R3D2L3R1F3L1R3");T;Y=24;T;X=0;T;m.clear();P("R3D3R1D3R3D2R1L1D1L3D1L1D2L3","R1F3L3F1R3F3L1F1");G(I,5,9){Y=I*6;T}}


It's not random, but it also doesn't proceed straightforwardly. It solves the edges first, then the corners. At each step, it tries various combinations of up to 4 algorithms and simple face turns (sequentially, not randomly), till it finds an improvement in the number of solved pieces, then repeats until solved. It uses 2 algorithms for edges and 2 for corners, translated to all cube positions.

Example output for RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU:

L2F3B2F3B1U3F1B3R2F3B1U3F1B3D2F2L3D2L1U2B1L1R3U2R1L3B1U2R1U2L1F1B3U2B1F3L1U2L3R1D3L1R3B2L3R1D3L1R3L3R1D3L1R3B2L3R1D3L1R3B3F1D3B1F3R2B3F1D3B1F3U2F3L3R1B3L1R3U2L3R1B3L1R3F1D2F1L1R3D2R1L3F1D2F3L2U1B1F3L2F1B3U1L2R3L1F3R1L3U2R3L1F3R1L3U1F2U1L1R3F2R1L3U1F2U3L3U3L1U3L3U2L1R1U1R3U1R1U2R3F3U3F1U3F3U2F1B1U1B3U1B1U2B3L1B3R3B1L3B3R1B1B3D3B1D3B3D2B1F1D1F3D1F1D2F3R1F3L3F1R3F3L1F1R3B3R1B3R3B2R1L1B1L3B1L1B2L3R1D3L3D1R3D3L1D1B3D3B1D3B3D2B1F1D1F3D1F1D2F3U3R3U1R3U3R2U1D1R1D3R1D1R2D3

(234 moves, 0.3 sec here)

• What do you know... another answer was posted within seconds :) Commented Mar 19, 2013 at 10:28
• Although this is longer than the Ruby solution, I feel that it better fits the problem criteria "within a reasonable amount of time and moves." I'd still like to see a solution which averages under ~50 moves, though. Commented Mar 20, 2013 at 6:51
• @primo Thanks :) My original code averaged over 50 moves, for under 50 I think you either need more (cube) algorithms or a different approach such as Thistlethwaite's method. However, efficiency (in no. of moves) is not very compatible with golfing. Anyway, for alternative solutions check out the winners of Tomas Rokicki's contest. Commented Mar 20, 2013 at 8:09

Python 1166 bytes

A considerable amount of whitespace has been left for the sake of readability. Size is measured after removing this whitespace, and changing various indentation levels to Tab, Tab Space, Tab Tab, etc. I've also avoided any golfing which affected the performance too drastically.

T=[]
I='FBRLUD'

G=[(~i%8,i/8-4)for i in map(ord,'ouf|/[bPcUDkqbx-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


Sample usage:

$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


This is an implementation of Thistlethwaite's Algorithm, using an IDA* search to solve for each step. Because all of the heuristic tables need to be calculated on the fly, several compromises have been made, usually breaking a heuristic into two or more fairly equal size parts. This makes the computation of the heuristic tables many hundreds of times faster, while slowing down the search phase, usually only slightly, but it can be significant depending on the initial cube state.

Variable Index

• T - the main heuristic table.
• S - a solved cube state. Each individual piece is stored as a bit mask, represented as a character. A solved orientation vector is defined as the zero vector.
• I - the various twists, in the order that they are eliminated from the search space.
• G - the groups for twist permutations, stored as pairs to be swapped. Each byte in the compressed string encodes for one pair. Each twist needs six swaps: three for the edge cycle, and three for the corner cycle. The compressed string contains only printable ascii (char 32 to 126).
• M - a function that performs a move, given by G.
• N - converts a permutation of four objects to a number, for encoding purposes.
• H - calculates the heuristic value for the given cube state, used to lookup move depth from T.
• P - perform a search at a single depth of a single phase of the algorithm.
• s - the input cube's permutation state.
• o - the input cube's orientation vector.

Performance

Using Tomas Rokicki's data set, this script averaged 16.02 twists per solve (maximum 35), with an average time of 472ms (i5-3330 CPU @ 3.0 Ghz, PyPy 1.9.0). Minimum solve time was 233ms with a maximum of 2.97s, standard deviation 0.488. Using the scoring guidelines from the contest (white space is not counted, keywords and identifiers count as one byte for a length of 870), the overall score would have been 13,549.

For the last 46 cases (the random states), it averaged 30.83 twists per solve, with an average time of 721ms.

Notes on Thistlethwaite's Algorithm

For the benefit of anyone who might want to attempt an implementation of Thistlethwaite's Algorithm, here is a brief explanation.

The algorithm works on a very simple solution space reduction principle. That is, reduce the cube to a state in which a subset of twists are not necessary to solve it, reduce it to a smaller solution space, and then solve the remainder using only the few twists remaining.

Thistlethwaite originally suggested <L,R,F,B,U,D><L,R,F,B,U2,D2><L,R,F2,B2,U2,D2><L2,R2,F2,B2,U2,D2>. However, given the input format, I think it is easier to first reduce to <L,R,F2,B2,U,D> (no quarter turn F or B), and then <L2,R2,F2,B2,U,D> before finally reaching the half turn state. Instead of explaining exactly why this is, I think it will be evident after defining the criteria for each state.

<L,R,F,B,U,D> ⇒ <L,R,F2,B2,U,D>

In order to eliminate F and B quarter turns, only the edges must be oriented correctly. Gilles Roux has a very good explanation on his site of what 'correct' and 'incorrect' orientation is, so I'll leave the explaining to him. But basically, (and this is why this input format is so condusive to F and B elimination), an edge cubie is correctly oriented if it matches the following regex: [^RL][^UD]. A correct orientation is typically signified with a 0 and incorrect with 1. Basically U and D stickers may not appear on the R or L faces, or on the edges of the any U or D edge cubies, or they cannot be moved into place without requiring an F or B quarter twist.

<L,R,F2,B2,U,D> ⇒ <L2,R2,F2,B2,U,D>

Two criteria here. First, all corners must be oriented correctly, and second, each of the for middle layer cubies (FR, FL, BR, BL) must be somewhere in the middle layer. A corner orientation is very simply defined given the input format: the position of the first U or D. For example, URB has orientation 0 (correctly oriented), LDF has orientation 1, and LFU has orientation 2.

<L2,R2,F2,B2,U,D> ⇒ <L2,R2,F2,B2,U2,D2>

The criteria here is as follows: each face may only contain stickers from its face, or from the face directly opposite it. For example, on the U face there may only be U and D stickers, on the R face there may only be R and L stickers, on the F face there may only be F and B stickers, etc. The easiest way to ensure this is to check if each edge piece is in its 'slice', and each corner piece in its 'orbit'. Additionally, one needs to pay attention to edge-corner parity. Although, if you check only for corner parity, edge parity is also guaranteed, and vice versa.

How twists affect orientation

U and D twists affect neither the edge orientation, nor the corner orientation. The pieces may be swapped directly without updating the orientation vector.

R and L twists do not affect the edge orientation, but they do affect the corner orientation. Depending on how you define your cycle, the change in corner orientation will either be +1, +2, +1, +2 or +2, +1, +2, +1, all modulo 3. Note that R2 and L2 twists do not affect the corner orientation, as +1+2 is zero modulo 3, as is +2+1.

F and B affect both the edge orientations and corner orientations. Edge orientations become +1, +1, +1, +1 (mod 2), and corner orientations are the same as for R and L. Note that F2 and B2 affect neither the edge orientations, nor corner orientations.

• Great writeup. Have you heard of Kociemba's algorithm? Commented Mar 27, 2013 at 10:57
• I have. In principle, it's the same algorithm, except instead of four phases, it has only two: <L,R,F,B,U,D> -> <L2,R2,F2,B2,U,D> -> <I>. It requires a maximum of 29 twists to solve a cube (instead of 52 for Thistlethwaite's), but it also requires very large lookup tables, which would be impractical to generate 'on the fly'. Commented Mar 27, 2013 at 11:00
• @P0W the input format is a bit confusing, I suspect you may have an error there. Every case I've verified results in a solution. Commented Jan 15, 2015 at 7:32
• @primo Would you mind publishing a link to the non-golfed code if you have it? Commented Apr 9, 2018 at 12:48

Ruby, 742 characters

r=->y{y.split.map{|x|[*x.chars]}}
G=r['UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR']
o=r[gets]
x=[];[[%w{U UU UUU L LL LLL}+D=%w{D DD DDD},0],[%w{FDFFF RFDFFFRRR}+D,12],[%w{DDDRRRDRDFDDDFFF DLDDDLLLDDDFFFDF}+D,8],[%w{DFLDLLLDDDFFF RDUUUFDUUULDUUUBDUUU}+D,4],[%w{LDDDRRRDLLLDDDRD RRRDLDDDRDLLLDDD LFFFLLLFLFFFLLLF},16]].map{|q,y|x+=[*y..y+3]
3.times{q.map{|e|q|=[e.tr('LFRB','FRBL')]}}
w=->u{x.count{|t|u[t]!=G[t]}}
s=w[o]
(c=(0..rand(12)).map{q.sample}*''
z=o
c.chars{|m|z="=$'*:036\".?BOHKVGRWZ!$@*-0C69<4(E\\INQTMX!$'B-03<9*?6EHYLQPUZ!9'*-?360<$BSFKN[TWJ$'*!-0369<?BHKNEQTWZ!$'*6-039<?BEHKNTWZQ"[20*('FBLRUD'=~/#{m}/),20].bytes.map{|e|z[e/3-11].rotate e%3}}
t=w[z]
(c.chars{|e|$><<e<<'1 '};o=z;s=t)if s>t )until s<1}  The above ruby code is not yet golfed fully. There are still possibilities to improve the code further (but its already enough as a starter). It solves the cube layer by layer but uses no specific algorithm but instead performs random sequences of moves until the cube is solved. Due to the probabilistic nature it may sometimes take longer than 5 seconds to solve the cube and in rare cases take more than 1000 moves. Example output (for input 'RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU') is 757 moves: F1 R1 R1 F1 F1 F1 R1 R1 R1 L1 L1 L1 F1 D1 L1 L1 D1 D1 D1 D1 L1 B1 D1 B1 B1 B1 L1 L1 L1 F1 D1 F1 F1 F1 L1 D1 L1 L1 L1 B1 D1 B1 B1 B1 R1 D1 R1 R1 R1 L1 B1 D1 B1 B1 B1 L1 L1 L1 D1 D1 B1 D1 B1 B1 B1 B1 D1 B1 B1 B1 L1 D1 L1 L1 L1 D1 D1 D1 D1 D1 R1 D1 R1 R1 R1 R1 F1 D1 F1 F1 F1 R1 R1 R1 R1 D1 R1 R1 R1 F1 L1 D1 L1 L1 L1 F1 F1 F1 D1 D1 D1 D1 L1 D1 L1 L1 L1 F1 L1 D1 L1 L1 L1 F1 F1 F1 D1 D1 L1 D1 L1 L1 L1 D1 L1 D1 L1 L1 L1 L1 D1 L1 L1 L1 D1 R1 D1 D1 D1 R1 R1 R1 D1 D1 D1 B1 B1 B1 D1 B1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 F1 F1 F1 D1 F1 D1 D1 D1 B1 B1 B1 D1 B1 D1 R1 D1 D1 D1 R1 R1 R1 D1 D1 D1 B1 B1 B1 D1 B1 D1 R1 D1 D1 D1 R1 R1 R1 D1 B1 D1 D1 D1 B1 B1 B1 D1 D1 D1 L1 L1 L1 D1 L1 D1 B1 D1 D1 D1 B1 B1 B1 D1 D1 D1 L1 L1 L1 D1 L1 D1 D1 F1 D1 D1 D1 F1 F1 F1 D1 D1 D1 R1 R1 R1 D1 R1 D1 D1 D1 R1 R1 R1 D1 R1 D1 F1 D1 D1 D1 F1 F1 F1 D1 B1 D1 D1 D1 B1 B1 B1 D1 D1 D1 L1 L1 L1 D1 L1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 F1 D1 D1 D1 F1 F1 F1 D1 D1 D1 R1 R1 R1 D1 R1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 D1 D1 F1 F1 F1 D1 F1 D1 L1 D1 D1 D1 L1 L1 L1 D1 D1 D1 D1 D1 D1 R1 F1 D1 F1 F1 F1 D1 D1 D1 R1 R1 R1 D1 F1 L1 D1 L1 L1 L1 D1 D1 D1 F1 F1 F1 D1 B1 R1 D1 R1 R1 R1 D1 D1 D1 B1 B1 B1 D1 B1 R1 D1 R1 R1 R1 D1 D1 D1 B1 B1 B1 D1 D1 D1 D1 B1 R1 D1 R1 R1 R1 D1 D1 D1 B1 B1 B1 D1 D1 D1 D1 D1 D1 B1 B1 B1 D1 F1 D1 D1 D1 B1 D1 F1 F1 F1 D1 D1 D1 R1 R1 R1 D1 L1 D1 D1 D1 R1 D1 L1 L1 L1 D1 D1 D1 B1 D1 D1 D1 F1 F1 F1 D1 B1 B1 B1 D1 D1 D1 F1 D1 B1 B1 B1 D1 F1 D1 D1 D1 B1 D1 F1 F1 F1 D1 D1 D1 L1 D1 D1 D1 R1 R1 R1 D1 L1 L1 L1 D1 D1 D1 R1 D1 F1 R1 R1 R1 F1 F1 F1 R1 F1 R1 R1 R1 F1 F1 F1 R1 R1 R1 R1 D1 L1 D1 D1 D1 R1 D1 L1 L1 L1 D1 D1 D1 B1 B1 B1 D1 F1 D1 D1 D1 B1 D1 F1 F1 F1 D1 D1 D1 F1 R1 R1 R1 F1 F1 F1 R1 F1 R1 R1 R1 F1 F1 F1 R1 F1 D1 D1 D1 B1 B1 B1 D1 F1 F1 F1 D1 D1 D1 B1 D1 F1 R1 R1 R1 F1 F1 F1 R1 F1 R1 R1 R1 F1 F1 F1 R1 F1 F1 F1 D1 B1 D1 D1 D1 F1 D1 B1 B1 B1 D1 D1 D1 R1 D1 D1 D1 L1 L1 L1 D1 R1 R1 R1 D1 D1 D1 L1 D1 R1 R1 R1 D1 L1 D1 D1 D1 R1 D1 L1 L1 L1 D1 D1 D1 R1 D1 D1 D1 L1 L1 L1 D1 R1 R1 R1 D1 D1 D1 L1 D1 F1 F1 F1 D1 B1 D1 D1 D1 F1 D1 B1 B1 B1 D1 D1 D1 L1 L1 L1 D1 R1 D1 D1 D1 L1 D1 R1 R1 R1 D1 D1 D1  It is possible to reduce the move-count considerably if same moves are grouped together. Therefore, one can replace the output like (c.gsub(/(.)\1*/){j=$&.size%4;$><<$1<<j<<' 'if j>0};o=z;s=t)if s>t

• Nice, but sometimes it takes more than 20 sec on my computer, in one case it finished in 48.7 sec Commented Mar 19, 2013 at 10:38
• @aditsu Yes. But it also strongly depends on which ruby interpreter you use. On my machine it usually takes less than 5 seconds. Commented Mar 19, 2013 at 10:40
• I'm currently using ruby 1.9.3_p392, it often takes less than 5 seconds but I can't say "usually" Commented Mar 19, 2013 at 10:44
• Try this input: FU FR RU BR DB LD LU LB LF RD DF BU FRU BUR FDR DLB DFL LUB FUL DBR Commented Mar 19, 2013 at 10:46
• One request: could you consolidate sequences like U1 U1 U1 into a single U3`? Commented Mar 19, 2013 at 14:56