44
7
While idly twisting my Rubik's cube around, my son noticed that it kept going back to the solved state. I'm pretty sure he thought this was some sort of voodoo magic at first, but I explained that if you keep repeating the same sequence of moves, it will always return to its original state. Eventually.
Of course, being a kid, he had to try it out for himself and picked a "random" sequence he thought would be tricky. He lost track after ten repeats or so, and asked me how many times he would have to repeat it. Not knowing the sequence he was using, I told him I didn't know, but that we could write a program to find out.
This is where you come in. Of course, I could just whip something up, but he'd like to type it in himself. He isn't a very fast typist yet, though, so I need the shortest program possible.
Objective
Given a sequence of turns, output the fewest number of times it must be performed to return the cube to its original state. This is code golf, so least bytes wins. You can write a program or function, and all the other usual defaults apply.
Input
Input is a sequence of moves, taken as a string, list, or other format suitable for your language. Feel free to use a separator (or not) between moves if in string form.
There are six "basic" moves that must be taken into account, along with their inverses:
R - Turn the right face clockwise
L - Turn the left face clockwise
U - Turn the up (top) face clockwise
D - Turn the down (bottom) face clockwise
F - Turn the front face clockwise
B - Turn the back face clockwise
The inverses are represented by adding a prime mark '
after the letter. This indicates you turn that face counterclockwise, so F'
turns the front face counterclockwise, and F F'
would return it to the original state right away.
For the interested, this challenge is using a limited set of Singmaster Notation. Ruwix has some nice animations if you'd like to see it in action.
Output
Output is simply the minimum number of times the input sequence must be performed.
Examples
Input Output
FF' -> 1
R -> 4
RUR'U' -> 6
LLUUFFUURRUU -> 12
LUFFRDRBF -> 56
LF -> 105
UFFR'DBBRL' -> 120
FRBL -> 315
Here's a (quite naive) solver to compare your answers to, written in Java. It also accepts 2
for double moves (so the fourth case is equivalent to L2U2F2U2R2U2
).
import java.util.ArrayList;
import java.util.List;
public class CycleCounter{
public static void main(String[] args){
int[] cube = new int[54];
for(int i=0;i<54;i++)
cube[i] = i;
String test = args.length > 0 ? args[0] : "RUR'U'";
List<Rotation> steps = parse(test);
System.out.println(steps.toString());
int count = 0;
do{
for(Rotation step : steps)
cube = step.getRotated(cube);
count++;
}while(!isSorted(cube));
System.out.println("Cycle length for " + test + " is " + count);
}
static List<Rotation> parse(String in){
List<Rotation> steps = new ArrayList<Rotation>();
for(char c : in.toUpperCase().toCharArray())
switch(c){
case 'R':steps.add(Rotation.R);break;
case 'L':steps.add(Rotation.L);break;
case 'U':steps.add(Rotation.U);break;
case 'D':steps.add(Rotation.D);break;
case 'F':steps.add(Rotation.F);break;
case 'B':steps.add(Rotation.B);break;
case '\'':
steps.add(steps.get(steps.size()-1));
case '2':
steps.add(steps.get(steps.size()-1));
break;
}
return steps;
}
static boolean isSorted(int[] in){for(int i=0;i<in.length-1;i++)if(in[i]>in[i+1])return false;return true;}
enum Rotation{
R(new int[]{-1,-1,42,-1,-1,39,-1,-1,36, -1,-1,2,-1,-1,5,-1,-1,8, 20,23,26,19,-1,25,18,21,24, -1,-1,11,-1,-1,14,-1,-1,17, 35,-1,-1,32,-1,-1,29,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1}),
L(new int[]{9,-1,-1,12,-1,-1,15,-1,-1, 27,-1,-1,30,-1,-1,33,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 44,-1,-1,41,-1,-1,38,-1,-1, -1,-1,6,-1,-1,3,-1,-1,0, 47,50,53,46,-1,52,45,48,51}),
U(new int[]{2,5,8,1,-1,7,0,3,6, 45,46,47,-1,-1,-1,-1,-1,-1, 9,10,11,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 18,19,20,-1,-1,-1,-1,-1,-1, 36,37,38,-1,-1,-1,-1,-1,-1}),
D(new int[]{-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,24,25,26, -1,-1,-1,-1,-1,-1,42,43,44, 29,32,35,28,-1,34,27,30,33, -1,-1,-1,-1,-1,-1,51,52,53, -1,-1,-1,-1,-1,-1,15,16,17}),
F(new int[]{-1,-1,-1,-1,-1,-1,18,21,24, 11,14,17,10,-1,16,9,12,15, 29,-1,-1,28,-1,-1,27,-1,-1, 47,50,53,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,8,-1,-1,7,-1,-1,6}),
B(new int[]{51,48,45,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,0,-1,-1,1,-1,-1,2, -1,-1,-1,-1,-1,-1,26,23,20, 38,41,44,37,-1,43,36,39,42, 33,-1,-1,34,-1,-1,35,-1,-1});
private final int[] moves;
Rotation(int[] moves){
this.moves = moves;
}
public int[] getRotated(int[] cube){
int[] newCube = new int[54];
for(int i=0;i<54;i++)
if(moves[i]<0)
newCube[i] = cube[i];
else
newCube[moves[i]] = cube[i];
return newCube;
}
}
}
"clockwise" means "clockwise when you're facing it" I assume? – msh210 – 2016-02-03T20:49:06.590
@msh210 Correct. – Geobits – 2016-02-03T20:51:51.530
7On a point of pedantry, I think you should make it explicit that you want the smallest number which suffices. Otherwise I could just output the size of the group and cite Lagrange's theorem... – Peter Taylor – 2016-02-03T21:31:48.153
2@PeterTaylor Pedantry accepted. – Geobits – 2016-02-03T21:41:41.320
4I may offer a 500 point bounty for a solution in Shuffle. Not sure yet. – lirtosiast – 2016-02-03T22:32:02.307
Out of interest, what's the correct answer for
LFLF
? Although repeating the sequence 105 times returns you to the original state, so does repeating it 52.5 times... – Neil – 2016-02-04T11:30:50.453@Neil Assume it's integer output only. – Geobits – 2016-02-04T13:04:44.977
@ThomasKwa I don't think Shuffle is anywhere near Turing complete. I'm pretty sure this is impossible. – Martin Ender – 2016-02-05T09:05:27.233
So what's the longest a sequence of moves could take? Could that be calculated easily using abstract algebra? Perhaps that's a question for math.SE. – mbomb007 – 2019-04-05T14:12:55.747
@mbomb007 1260, based on group theory. Not an expert, but maybe reddit can help :)
– Geobits – 2019-04-05T18:09:33.670