Simulate a Rubik's cube

A Rubik's cube has 6 colors: red, orange, yellow, white, blue, and green. Red and orange, yellow and white, and blue and green faces are on opposite sides.

Net of a solved Rubik's cube looks like this:

 Y
BRGO
W


And the tiles look like this:

      Y Y Y
Y Y Y
Y Y Y
B B B R R R G G G O O O
B B B R R R G G G O O O
B B B R R R G G G O O O
W W W
W W W
W W W


Challenge

Given rotations, reversed rotations, or double rotations output what a solved cube will transform to, as ASCII art or as an image (whitespaces aren't necessary, may or may not exist, trailing whitespaces are allowed.).

Input will be rotation (and optional modifier). Rotation notation goes like: U(p), L(eft), F(ront), R(ight), B(ack), D(own); 2 (double), ' or i (inverse).

All normal rotations will be 90° clockwise, inverse ones will be counterclockwise.

Explanation about clockwiseness: Imagine the cube as you're looking at the red face, and the yellow face is at the top. Then rotate the cube so that the face that the program will rotate will face you. This is the way clockwiseness will work. (Except back face, you will rotate the cube horizontally in that case.)

Input

Input will be a list of moves.

Output

An ASCII art that represents the cube or an image of the net of the cube.

Examples

Input: (empty)

Output:

      Y Y Y
Y Y Y
Y Y Y
B B B R R R G G G O O O
B B B R R R G G G O O O
B B B R R R G G G O O O
W W W
W W W
W W W


Input: U (up)

Output:

      Y Y Y
Y Y Y
Y Y Y
R R R G G G O O O B B B
B B B R R R G G G O O O
B B B R R R G G G O O O
W W W
W W W
W W W


Input: U' or Ui (inverse up)

Output:

      Y Y Y
Y Y Y
Y Y Y
O O O B B B R R R G G G
B B B R R R G G G O O O
B B B R R R G G G O O O
W W W
W W W
W W W


Input: U2 (double up)

Output:

      Y Y Y
Y Y Y
Y Y Y
G G G O O O B B B R R R
B B B R R R G G G O O O
B B B R R R G G G O O O
W W W
W W W
W W W


Input: L' (inversed left)

Output:

      R Y Y
R Y Y
R Y Y
B B B W R R G G G O O Y
B B B W R R G G G O O Y
B B B W R R G G G O O Y
O W W
O W W
O W W


Input: R (right)

Output:

      Y Y R
Y Y R
Y Y R
B B B R R W G G G Y O O
B B B R R W G G G Y O O
B B B R R W G G G Y O O
W W O
W W O
W W O


Input: U2 L' D (double up, inverse left, down)

Output:

      O Y Y
R Y Y
R Y Y
G B B W O O B B B R R Y
G B B W R R G G G O O Y
O O Y G B B W R R G G G
R O O
W W W
W W W


Rules

• No loopholes allowed.
• This is , so shortest code in bytes solving the problem wins.
• – betseg Sep 6 '16 at 18:42
• May we choose to choose to re-orient the cube (for example, having White U, Orange F, and Green R)? – primo Sep 7 '16 at 12:07
• Yes, of course, as long as they're separate and recognizable. – betseg Sep 7 '16 at 12:09
• Do we need to support S, E, M, x, y, z, u/Uw, d/Dw, r/Rw, l/Lw, f/Fw, b/Bw moves as well? Or only the default: U, D, R, L, F, B and their counterclockwise variant with apostrophe (')? Off-topic: I always wonder with Rubik's Cube related questions, are you also a Twisty Puzzles collector? – Kevin Cruijssen Sep 7 '16 at 12:27
• @KevinCruijssen Dang, that's a lot of puzzles. – mbomb007 Sep 7 '16 at 20:08

Ruby, 370 339 305 bytes

Latest edit: a few bytes saved by rearrangement of the plotting formulas and removal of unnecessary brackets. A massive saving by rewriting the generation of the cube - I never knew Ruby had a builtin for Cartesian Products!

->s{q=[-66,0,71].product [-87,0,89],[-79,0,82]
s.map{|c|m="LDBRUF".index c[0];e=m/3*2-1
c.sub(/[i']/,"33").chars{q.map{|j|j[m%=3]*e>0&&(j[m-2],j[m-1]=j[m-1]*e,-j[m-2]*e)}}}
t=[" "*12]*9*$/ q.map{|r|a,b,c=r.map{|i|i<=>0} 3.times{|i|r[i]!=0&&t[56+[a*3-a*c-d=b*13,a-d*3+d*c,3-d-c*3+c*a][i]]=r[i].abs.chr}} t}  Anonymous function. Accepts an array of strings, each representing one face turn (a single string with spaces between each face turn is an additional 6 bytes.) Returns a 9x12 rectangular string. Brief explanation This is closely based on a concept from my answer to this question, which in turn was based on a similar concept by Jan Dvorak. The first line generates a 27 element array, representing the 27 cubies. Each cubie is represented by a 3 dimensional vector in which the sign represents its current position and the magnitude of each coordinate represents the ascii code for the colour of the sticker. Example move: for R, for each cubie check if the x coordinate is >0 and if so rotate 90 degrees by swapping the y and z coordinates and swapping the sign of one of them. Take a 9x12 array of spaces and plot the cube into it. For each cubie and axis we check if the sticker exists (coordinate in that axis nonzero), and work out where it is to go. Then we take the coordinate and perform .abs.chr to change the number into the required character and plot it. Ungolfed in test program (per 339 byte edit) f=->s{ q=(0..26).map{|i| #Build an array of 27 cubies [[-66,0,71][i%3], #x coordinate B.G [-87,0,89][i/3%3], #y coordinate Y.W [-79,0,82][i/9]] #z coordinate O.R } s.map{|c| #For each move in the input array m="LDBRUF".index(c[0]);e=m/3*2-1 #m=face to move. e=-1 for LDB, +1 for RUF. c.sub(/[i']/,"33").chars{ #Substitute "i" and "'" for "33" so chars in string = clockwise 1/4 turns required. For each char... q.map{|j|j[m%=3]*e>0&& #...and each cubie, m%3 tells the relevant axis. if coordinate*e>1 rotate the cubie 1/4 turn. (j[m-2],j[m-1]=j[m-1]*e,-j[m-2]*e)} #Swap other two axes and change sign of one. e performs sign change if necessary for LDB. } } t=[" "*12]*9*$/                           #Make an array of 9 strings of 12 spaces, then make a single string by joining them with newlines
q.map{|r|                                 #For each cubie
a,b,c=r.map{|i|i<=>0}                   #make a normalised (-1,0,1) copy of each coordinate.
d=b*13                                  #13 chars per line, d will be useful for plotting to the correct line of the output.
3.times{|i|                             #For each of the 3 coordinates of the cubie
r[i]!=0&&                             #if zero, sticker doesn't exist (edges and centres have <3 stickers.) If not zero plot the sticker.
t[[56-d+a*3-a*c,                      #Calculate position on plot for x (L/R faces),
56-d*3+d*c+a,                      #Calculate position on plot for y (D/U faces),
59-d-c*3+c*a][i]]=                 #Calculate position on plot for z (B/F faces). Select the correct axis.
r[i].abs.chr                          #Convert the coordinate to a character and assign to the correct space on the output plot.
}
}
t}                                          #Return the output string.

puts f[gets.chomp.split]


Output

Checkerboard
U2 D2 F2 B2 L2 R2
YWY
WYW
YWY
BGBRORGBGORO
GBGOROBGBROR
BGBRORGBGORO
WYW
YWY
WYW

6-spot
U D' R L' F B' U D'
RRR
RYR
RRR
WWWGGGYYYBBB
WBWGRGYGYBOB
WWWGGGYYYBBB
OOO
OWO
OOO

Testcase
U2 L' D
OYY
RYY
RYY
GBBWOOBBBRRY
GBBWRRGGGOOY
OOYGBBWRRGGG
ROO
WWW
WWW


Javascript (ES5), 1615 bytes

function m(a){b=[];b[0]=a[6];b[2]=a[0];b[8]=a[2];b[6]=a[8];b[1]=a[3];b[5]=a[1];b[7]=a[5];b[3]=a[7];b[4]=a[4];return b}function q(a,b){c=[];c[0]=b[0];c[1]=b[1];c[2]=a[2];c[3]=b[3];c[4]=b[4];c[5]=a[5];c[6]=b[6];c[7]=b[7];c[8]=a[8];return c}function r(a){var b=[];b[0]=m(a[0]);b[1]=q(a[2],a[1]);b[4]=q(a[1],a[4]);b[3]=q(a[4],a[3]);b[2]=q(a[3],a[2]);b[5]=a[5];return b}function x(a){var b=[];b[0]=m(a[0]);b[1]=a[2];b[2]=a[3];b[3]=a[4];b[4]=a[1];b[5]=m(m(m(a[5])));return b}function y(a){var b=[];b[0]=a[4];b[1]=m(a[1]);b[2]=a[0];b[3]=m(m(m(a[3])));b[4]=a[5];b[5]=a[2];return b}function s(a){a=a.replace(/F2/,"F F");a=a.replace(/R2/,"R R");a=a.replace(/U2/,"U U");a=a.replace(/D2/,"D D");a=a.replace(/B2/,"B B");a=a.replace(/L2/,"L L");a=a.replace(/F'/,"F F F");a=a.replace(/R'/,"R R R");a=a.replace(/U'/,"U U U");a=a.replace(/D'/,"D D D");a=a.replace(/B'/,"B B B");a=a.replace(/L'/,"L L L");a=a.replace(/F/,"y y y R y");a=a.replace(/L/,"y y R y y");a=a.replace(/U/,"x y R y y y x x x");a=a.replace(/B/,"y R y y y");a=a.replace(/D/,"x y y y R y x x x");a=a.split(" ");for(b=["RRRRRRRRR".split(""),"WWWWWWWWW".split(""),"GGGGGGGGG".split(""),"YYYYYYYYY".split(""),"BBBBBBBBB".split(""),"OOOOOOOOO".split("")],c=0;c<a.length;++c)"x"==a[c]?b=x(b):"y"==a[c]?b=y(b):"R"==a[c]&&(b=r(b));return p(b)}function p(a){for(var b="",c=0;3>c;++c)b+="\n   "+a[1][3*c+0]+a[1][3*c+1]+a[1][3*c+2];for(c=0;3>c;++c)b+="\n"+a[5][3*c+0]+a[5][3*c+1]+a[5][3*c+2]+a[2][3*c+0]+a[2][3*c+1]+a[2][3*c+2]+a[0][3*c+0]+a[0][3*c+1]+a[0][3*c+2]+a[4][3*c+0]+a[4][3*c+1]+a[4][3*c+2];for(c=0;3>c;++c)b+="\n   "+a[3][3*c+0]+a[3][3*c+1]+a[3][3*c+2];return b}


Ungolfed:

function m(fac){ //Turn a face
//0 1 2
//3 4 5
//6 7 8

var fac2=[];
fac2[0]=fac[6];
fac2[2]=fac[0];
fac2[8]=fac[2];
fac2[6]=fac[8];

fac2[1]=fac[3];
fac2[5]=fac[1];
fac2[7]=fac[5];
fac2[3]=fac[7];

fac2[4]=fac[4];

return fac2;
}

function q(face1,face3){ //Swap right third of two faces
var face2=[];
face2[0]=face3[0];
face2[1]=face3[1];
face2[2]=face1[2];
face2[3]=face3[3];
face2[4]=face3[4];
face2[5]=face1[5];
face2[6]=face3[6];
face2[7]=face3[7];
face2[8]=face1[8];
return face2;
}

function r(state){ //Apply a R move
var state2=[];
state2[0]=m(state[0]);
//Swap right set of Front, Up, Back, Down (2,1,4,3);

state2[1]=q(state[2],state[1]);
state2[4]=q(state[1],state[4]);
state2[3]=q(state[4],state[3]);
state2[2]=q(state[3],state[2]);
state2[5]=state[5];
return state2;
}

function x(staten){ //Apply a x move
var state2=[];
state2[0]=m(staten[0]);
state2[1]=staten[2];
state2[2]=staten[3];
state2[3]=staten[4];
state2[4]=staten[1];
state2[5]=m(m(m(staten[5])));
return state2;
}

function y(state){ //Apply a y move
var state2=[];
state2[0]=state[4];
state2[1]=m(state[1]);
state2[2]=state[0];
state2[3]=m(m(m(state[3])));
state2[4]=state[5];
state2[5]=state[2];
return state2;
}

function s(algo){ //Solve a cube, representing every move with x, y and R
algo=algo.replace(/F2/,"F F");
algo=algo.replace(/R2/,"R R");
algo=algo.replace(/U2/,"U U");
algo=algo.replace(/D2/,"D D");
algo=algo.replace(/B2/,"B B");
algo=algo.replace(/L2/,"L L");

algo=algo.replace(/F'/,"F F F");
algo=algo.replace(/R'/,"R R R");
algo=algo.replace(/U'/,"U U U");
algo=algo.replace(/D'/,"D D D");
algo=algo.replace(/B'/,"B B B");
algo=algo.replace(/L'/,"L L L");

algo=algo.replace(/F/,"y y y R y");
algo=algo.replace(/L/,"y y R y y");
algo=algo.replace(/U/,"x y R y y y x x x");
algo=algo.replace(/B/,"y R y y y");
algo=algo.replace(/D/,"x y y y R y x x x");

algo=algo.split(" ");

var cstate=[["R","R","R","R","R","R","R","R","R"],["W","W","W","W","W","W","W","W","W"],["G","G","G","G","G","G","G","G","G"],["Y","Y","Y","Y","Y","Y","Y","Y","Y"],["B","B","B","B","B","B","B","B","B"],["O","O","O","O","O","O","O","O","O"]];

for(var i=0;i<algo.length;++i){
if(algo[i]=="x"){
cstate=x(cstate);
}else if(algo[i]=="y"){
cstate=y(cstate);
}else if(algo[i]=="R"){
cstate=r(cstate);
}
}

return p(cstate);
}

function p(cstate){ //Print
var out="";
var leftspace="\n   ";
for(var i=0;i<3;++i){
out+=leftspace+cstate[1][3*i+0]+cstate[1][3*i+1]+cstate[1][3*i+2]
}
for(var i=0;i<3;++i){
out+="\n"+cstate[5][3*i+0]+cstate[5][3*i+1]+cstate[5][3*i+2]+cstate[2][3*i+0]+cstate[2][3*i+1]+cstate[2][3*i+2]+cstate[0][3*i+0]+cstate[0][3*i+1]+cstate[0][3*i+2]+cstate[4][3*i+0]+cstate[4][3*i+1]+cstate[4][3*i+2]
}
for(var i=0;i<3;++i){
out+=leftspace+cstate[3][3*i+0]+cstate[3][3*i+1]+cstate[3][3*i+2]
}
return out;
}


This was a very difficult challenge.

Explanation

Take the example call s("R U' F").

The program can only execute x, y and R moves.

U' is equal to U U U, so replace that.

F is equal to y y y R y, so replace that.

R U' F' is therefore equal to R U U U y y y R y, which the program can run.

cstate is defined with a solved cube. A cube is represented by an array containing 6 arrays containing the 9 stickers. The first array is for R, second for U, third for F, D, B, last array is for L. When an y needs to be executed, the program swaps the four arrays of the front, left, back and right face. For an x, it swaps front, down, back and top. Every rotation also rotates the other faces, that were not swapped. A R move rotates the right face and swaps the right part of the front, up, back, down face.

This could be modified to be able to solve problems with all types of moves, by defining them with x, y and R.

• I'm working on stealing your concept of only 3 moves to make my own shorter ;) Great Idea – Aaron Sep 7 '16 at 19:44
• So R U' F2 gets converted to R U' F F first, then R U U U F F, then R x y R y y y x x x x y R y y y x x x x y R y y y x x x y y y R y y y y R y which it then executes? Weird.. but very original. +1 :) How did you came up with this idea? – Kevin Cruijssen Sep 7 '16 at 20:00
• My code converts U' into U U U too, but xes and ys are really good. I want to steal this too :p – betseg Sep 7 '16 at 20:03
• @KevinCruijssen Rotations are much easier to program than move affecting one layer only. I first tried this concept with a program for simulating NxN cubes, and now implemented an easier version here. It first removes any ' and 2, and then replaces all moves. – Paul Schmitz Sep 8 '16 at 11:48
• Well done but still golfable. I'm trying to port it to ES6 – edc65 Dec 25 '16 at 21:35

C, 1715170916861336 1328 bytes

25 bytes saved thanks to @KevinCruijssen!

No answers so far, so I decided to put my own solution.

#define m(a,b,c,d)t[c][d]=r[a][b];
#define n(a)m(a,0,a,2)m(a,1,a,5)m(a,2,a,8)m(a,3,a,1)m(a,5,a,7)m(a,6,a,0)m(a,7,a,3)m(a,8,a,6)
#define y memcpy
typedef char R[6][9];R t;F(R r){y(t,r,54);n(0)m(4,6,1,0)m(4,7,1,3)m(4,8,1,6)m(1,0,5,0)m(1,3,5,1)m(1,6,5,2)m(5,0,3,2)m(5,1,3,5)m(5,2,3,8)m(3,2,4,6)m(3,5,4,7)m(3,8,4,8)y(r,t,54);}B(R r){y(t,r,54);n(2)m(1,2,4,0)m(1,5,4,1)m(1,8,4,2)m(3,0,5,6)m(3,3,5,7)m(3,6,5,8)m(4,0,3,6)m(4,1,3,3)m(4,2,3,0)m(5,6,1,8)m(5,7,1,5)m(5,8,1,2)y(r,t,54);}L(R r){y(t,r,54);n(3)m(0,0,5,0)m(0,3,5,3)m(0,6,5,6)m(2,2,4,6)m(2,5,4,3)m(2,8,4,0)m(4,0,0,0)m(4,3,0,3)m(4,6,0,6)m(5,0,2,8)m(5,3,2,5)m(5,6,2,2)y(r,t,54);}E(R r){y(t,r,54);n(1)m(0,2,4,2)m(0,5,4,5)m(0,8,4,8)m(5,2,0,2)m(5,5,0,5)m(5,8,0,8)m(4,2,2,6)m(4,5,2,3)m(4,8,2,0)m(2,0,5,8)m(2,3,5,5)m(2,6,5,2)y(r,t,54);}U(R r){y(t,r,54);n(4)m(0,0,3,0)m(0,1,3,1)m(0,2,3,2)m(1,0,0,0)m(1,1,0,1)m(1,2,0,2)m(2,0,1,0)m(2,1,1,1)m(2,2,1,2)m(3,0,2,0)m(3,1,2,1)m(3,2,2,2)y(r,t,54);}D(R r){y(t,r,54);n(5)m(0,6,1,6)m(0,7,1,7)m(0,8,1,8)m(1,6,2,6)m(1,7,2,7)m(1,8,2,8)m(2,6,3,6)m(2,7,3,7)m(2,8,3,8)m(3,6,0,6)m(3,7,0,7)m(3,8,0,8)y(r,t,54);}a,b,c,d,e,o,p,l;f(char*z,R s){char c[6]="RGOBYW";for(;b<7;b++)for(a=0;a<10;)s[b][a++]=c[b];for(l=strlen(z);l-->0;){d=*z++;if(d-32){e=*z++;if(*z++-32)*z++;o=e-50?e-39?1:3:2;for(p=0;p++<o;)d-70?d-66?d-76?d-82?d-85?D(s):U(s):E(s):L(s):B(s):F(s);}}}


Try it online!

Ungolfed old version:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>

typedef char Tile;
typedef Tile Face[10];
typedef Face Rubik[7];

void main_loop(Rubik);
void rubik_init(Rubik);
void rubik_print(Rubik);
void rotate(Rubik, char, char);
void print_tile(Rubik, int, int);

void F(Rubik);
void B(Rubik);
void L(Rubik);
void R(Rubik);
void U(Rubik);
void D(Rubik);

#define move(a, b, c, d) \
temp[c][d] = rubik[a][b]

#define move_f(a) \
move(a, 1, a, 3); \
move(a, 2, a, 6); \
move(a, 3, a, 9); \
move(a, 4, a, 2); \
move(a, 6, a, 8); \
move(a, 7, a, 1); \
move(a, 8, a, 4); \
move(a, 9, a, 7)

void F(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(1);
move(5, 7, 2, 1);
move(5, 8, 2, 4);
move(5, 9, 2, 7);
move(2, 1, 6, 1);
move(2, 4, 6, 2);
move(2, 7, 6, 3);
move(6, 1, 4, 3);
move(6, 2, 4, 6);
move(6, 3, 4, 9);
move(4, 3, 5, 7);
move(4, 6, 5, 8);
move(4, 9, 5, 9);
memcpy(rubik, temp, sizeof(Rubik));
}

void B(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(3);
move(2, 3, 5, 1);
move(2, 6, 5, 2);
move(2, 9, 5, 3);
move(4, 1, 6, 7);
move(4, 4, 6, 8);
move(4, 7, 6, 9);
move(5, 1, 4, 7);
move(5, 2, 4, 4);
move(5, 3, 4, 1);
move(6, 7, 2, 9);
move(6, 8, 2, 6);
move(6, 9, 2, 3);
memcpy(rubik, temp, sizeof(Rubik));
}

void L(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(4);
move(1, 1, 6, 1);
move(1, 4, 6, 4);
move(1, 7, 6, 7);
move(3, 3, 5, 7);
move(3, 6, 5, 4);
move(3, 9, 5, 1);
move(5, 1, 1, 1);
move(5, 4, 1, 4);
move(5, 7, 1, 7);
move(6, 1, 3, 9);
move(6, 4, 3, 6);
move(6, 7, 3, 3);
memcpy(rubik, temp, sizeof(Rubik));
}

void R(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(2);
move(1, 3, 5, 3);
move(1, 6, 5, 6);
move(1, 9, 5, 9);
move(6, 3, 1, 3);
move(6, 6, 1, 6);
move(6, 9, 1, 9);
move(5, 3, 3, 7);
move(5, 6, 3, 4);
move(5, 9, 3, 1);
move(3, 1, 6, 9);
move(3, 4, 6, 6);
move(3, 7, 6, 3);
memcpy(rubik, temp, sizeof(Rubik));
}

void U(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(5);
move(1, 1, 4, 1);
move(1, 2, 4, 2);
move(1, 3, 4, 3);
move(2, 1, 1, 1);
move(2, 2, 1, 2);
move(2, 3, 1, 3);
move(3, 1, 2, 1);
move(3, 2, 2, 2);
move(3, 3, 2, 3);
move(4, 1, 3, 1);
move(4, 2, 3, 2);
move(4, 3, 3, 3);
memcpy(rubik, temp, sizeof(Rubik));
}

void D(Rubik rubik) {
Rubik temp;
memcpy(temp, rubik, sizeof(Rubik));
move_f(6);
move(1, 7, 2, 7);
move(1, 8, 2, 8);
move(1, 9, 2, 9);
move(2, 7, 3, 7);
move(2, 8, 3, 8);
move(2, 9, 3, 9);
move(3, 7, 4, 7);
move(3, 8, 4, 8);
move(3, 9, 4, 9);
move(4, 7, 1, 7);
move(4, 8, 1, 8);
move(4, 9, 1, 9);
memcpy(rubik, temp, sizeof(Rubik));
}

int main(int argc, char *argv[]) {
Rubik rubik;
rubik_init(rubik);
main_loop(rubik);
return 0;
}

void main_loop(Rubik rubik) {
char a, b;
for (;;) {
a=toupper(getchar());
if (a == 'Q') break;
if (a != 10) {
b=toupper(getchar());
if (b != 10) getchar();
rotate(rubik, a, b);
}
rubik_print(rubik);
}
}

void rubik_init(Rubik rubik) {
int i,n;
char c[7] = " RGOBYW";

for (n=1; n<=7; n++)
for (i=1; i<=10; i++)
rubik[n][i] = c[n];
}

void rotate(Rubik rubik, char a, char b){
int i = b == '2' ? 2 : b == '\'' || b == toupper('i') ? 3 : 1;
int j;
for (j=0; j<i; j++)
if (a == 'F') F(rubik);
else if (a == 'B') B(rubik);
else if (a == 'L') L(rubik);
else if (a == 'R') R(rubik);
else if (a == 'U') U(rubik);
else if (a == 'D') D(rubik);
else;
}

void rubik_print(Rubik rubik) {
int i,j,k;

for (i=1; i<=9; i++)
if (i%3==0) {
print_tile(rubik,5,i);
printf("\n");
}
else if (i%3==1) {
printf("    ");
print_tile(rubik,5,i);
}
else
print_tile(rubik,5,i);

printf("\n");

for (k=1; k<=3; k++) {
for (i=3; i<=6; i++) {
for (j=k*3-2; j<=k*3; j++)
print_tile(rubik, i%4+1, j);
printf(" ");
}
printf("\n");
}

printf("\n");

for (i=1; i<=9; i++)
if (i%3==0) {
print_tile(rubik, 6, i);
printf("\n");
}
else if (i%3==1) {
printf("    ");
print_tile(rubik, 6, i);
}
else
print_tile(rubik, 6, i);

}

void print_tile(Rubik rubik, int a, int b) {
switch (rubik[a][b]) {
case 'R':
printf("R");
break;
case 'O':
printf("O");
break;
case 'B':
printf("B");
break;
case 'G':
printf("G");
break;
case 'Y':
printf("Y");
break;
case 'W':
printf("W");
break;
default:
exit(1);
}
}

• I'm no C-programmer, so correct me if I'm wrong, but I believe you can golf some of your for-loops: for(b=1;b<8;b++)for(a=1;a<11;a++)r[b][a]=c[b]; to for(b=1;b<8;)for(a=1;a<11;)r[b][a++]=c[b++]; and for(i=1;i<=9;i++) to for(i=0;++i<=9;), and some of the other for-loops as well. Also, the else if can be changed to just if when you check if(d==66)B(r);if(d==76)L(r);... And, unless i can be negative, you can change if(i%3==0) to if(i%3<1) two times. And I'm sure it can be golfed some more. Nice to see an answer on your own challenge, though. :) – Kevin Cruijssen Sep 7 '16 at 14:58
• I tried golfing the loops down, but it didn't work, so I decided not to touch them. I'm outside and can't try them now. But you're right about ifs and i though, I'll edited them once I go home. Thanks! – betseg Sep 7 '16 at 15:12
• @KevinCruijssen removing elses bork the program, golfing loops bork the program, the thing with i works. Thanks anyway. – betseg Sep 7 '16 at 18:42
• Hmm, why does the else if changing to if fail? :S In each of the else ifs you compare d==##, so I'm confused why it doesn't. Again, I don't program C, so maybe I'm missing something obvious that C can't do, but still.. Ah well, glad I could help with the modulo <1 instead of ==0 – Kevin Cruijssen Sep 7 '16 at 19:54
• 979 bytes – ceilingcat Oct 13 '19 at 4:59

Python 3,  610 563 533  526 bytes

-7 bytes thanks to my colleague rhsmits (really nice d,*c form & removal of redundant parentheses)

This is a full program.

import re
d,*c=[f*9for f in' YBRGOW']
r=lambda f:[f[int(v)]for v in'630741852']
U=lambda c:[r(c[0])]+[c[j%4+1][:3]+c[j][3:]for j in(1,2,3,4)]+[c[5]]
y=lambda c:[r(c[0])]+c[2:5]+[c[1],r(r(r(c[5])))]
z=lambda c:[c[2],r(r(r(c[1]))),c[5],r(c[3]),c[0][::-1],c[4][::-1]]
exec("c="+"(c);c=".join("".join("zzzUz U zzUzz yyyzUzzzy zUzzz yzUzzzyyy".split()[ord(t)%11%7]*(ord(n or'a')%6)for t,n in re.findall("([B-U])(['2i]?)",input())))+"(c)")
k=' '.join
for q in[d,c[0]],c[1:5],[d,c[5]]:
for w in 0,3,6:print(k(k(f[w:w+3])for f in q))


Superflip and all tests are available at ideone or Try it online!

The program:

• creates the six faces YBRGOW of stickers.
• creates a function, r, which only rotates the stickers on a face, clockwise a quarter-turn
• creates a function, U, which rotates the U face clockwise a quarter-turn by applying r and rotating the stickers on the top-band of LFRB clockwise a quarter-turn
• creates a function, y, which performs r on the U and D faces and slices LFRB
- this performs a rotation of the whole cube in the y axis (which runs through U and D)
- the rotation is clockwise if looking from above
• creates a function z, which performs a rotation of the whole cube in the z axis clockwise a quarter turn looking at R (the axis runs through R and L) - this time because the way the faces are oriented in our net (same as given in the OP) we have to flip the B and U faces over (they switch from the horizontal to vertical parts of the net and vice-versa)
• Performs a regex on the input, input(), (the moves to be performed) matching a character from BUDLRF (actually B-U) possibly followed by a character 'i2
• Performs a mapping from the 'i2 to the number of clockwise turns (the ordinals of these mod 6 does the job, with a dummy a to yield 1 when none is present)
• Performs a lookup to map each of these single clockwise turn instructions to a setup of calls to y and z, a quarter-turn of U (which will now be the face instructed), and then the calls to inverse the sequence of the setup performed. Taking the ordinal of the face character modulo by 11 then by 7 maps B:0 U:1 D:2 L:3 F:4 R:5, allowing a simple indexing into a string of the function name sequences split by spaces.
• executes the string to actually perform the manoeuvre
• creates a dummy face d to shorten the printing
• prints the result by stepping through the rows in the net and the faces in the row (including a dummy face to the left of each of U and D

Here is the superflip:

D:\Python Scripts>python rubiksAscii.py
U R2 F B R B2 R U2 L B2 R U' D' R2 F R' L B2 U2 F2
Y O Y
B Y G
Y R Y
B Y B R Y R G Y G O Y O
O B R B R G R G O G O B
B W B R W R G W G O W O
W R W
B W G
W O W


Python 760 750 649 Bytes

shamelessly stole the idea of using only 3 rotations from @Paul Schmitz :D

new version:

from numpy import*
c=kron([[32,89,32,32],[66,82,71,79],[32,87,32,32]],ones([3,3])).astype(int)
def x():t=copy(c);c[:3,3:6],c[3:6,3:6],c[6:,3:6],c[3:6,9:],c[3:6,:3],c[3:6,6:9]=t[3:6,3:6],t[6:,3:6],rot90(t[3:6,9:],2),rot90(t[:3,3:6],2),rot90(t[3:6,:3]),rot90(t[3:6,6:9],3)
def y():c[3:6],c[:3,3:6],c[6:,3:6]=roll(c[3:6],3,1),rot90(c[:3,3:6]),rot90(c[6:,3:6],3)
def F():c[2:7,2:7]=rot90(c[2:7,2:7],3)
s=raw_input()
for p in"':i,Fi:FFF,F2:FF,Bi:BBB,B2:BB,Ri:RRR,R2:RR,Li:LLL,L2:LL,Ui:UUU,U2:UU,Di:DDD,D2:DD,B:xxFxx,R:yyyFy,L:yFyyy,U:xxxFx,D:xFxxx".split(','):s=s.replace(*p.split(':'))
for S in s:eval(S+'()')
for r in c:print(''.join(chr(x)for x in r))


I mostly just did lots of numpy list slicing and used its built in rotate and roll functions. Input is handled by calling the functions directly with eval()

from numpy import*
l=[0];c=kron([[32,89,32,32],[66,82,71,79],[32,87,32,32]],ones([3,3])).astype(int)
def i():l[0]();l[0]()
def d():l[0]()
def U():c[:3,3:6]=rot90(c[:3,3:6],3);c[3]=roll(c[3],9);l[0]=U
def D():c[6:,3:6]=rot90(c[6:,3:6],3);c[5]=roll(c[5],3);l[0]=D
def F():c[2:7,2:7]=rot90(c[2:7,2:7],3);l[0]=F
def B():c[3:6,9:]=rot90(c[3:6,9:],3);t=copy(c);c[:,:9],c[1:-1,1:8]=rot90(t[:,:9]),t[1:-1,1:8];l[0]=B
def R():c[3:6,6:9]=rot90(c[3:6,6:9],3);t=copy(c);c[:6,5],c[3:6,9],c[6:,5]=t[3:,5],t[2::-1,5],t[5:2:-1,9];l[0]=R
def L():c[3:6,:3]=rot90(c[3:6,:3],3);t=copy(c);c[3:,3],c[3:6,-1],c[:3,3]=t[:6,3],t[:5:-1,3],t[5:2:-1,-1];l[0]=L
for s in raw_input().replace("'",'i').replace('2','d').replace(' ',''):eval(s+'()')
for r in c:print(''.join(chr(x)for x in r))


ungolfed..

import numpy as np
last = [0] #store last move to repeat for inverse or double
#list is shorter syntax than global var

cube = np.array([
[' ',' ',' ','Y','Y','Y',' ',' ',' ',' ',' ',' '],
[' ',' ',' ','Y','Y','Y',' ',' ',' ',' ',' ',' '],
[' ',' ',' ','Y','Y','Y',' ',' ',' ',' ',' ',' '],
['B','B','B','R','R','R','G','G','G','O','O','O'],
['B','B','B','R','R','R','G','G','G','O','O','O'],
['B','B','B','R','R','R','G','G','G','O','O','O'],
[' ',' ',' ','W','W','W',' ',' ',' ',' ',' ',' '],
[' ',' ',' ','W','W','W',' ',' ',' ',' ',' ',' '],
[' ',' ',' ','W','W','W',' ',' ',' ',' ',' ',' ']
]) #ascii ascii codes in golfed version

def i(): #triple move (inverse)
last[0]()
last[0]()

def d(): #double move
last[0]()

def U(): #clockwise upface (yellow)
cube[:3,3:6] = np.rot90(cube[:3,3:6],3)
cube[3] = np.roll(cube[3],9)
last[0] = U

def D(): #clockwise downface (white)
cube[6:,3:6] = np.rot90(cube[6:,3:6],3)
cube[5] = np.roll(cube[5],3)
last[0] = D

def F(): #clockwise frontface (red)
cube[2:7,2:7] = np.rot90(cube[2:7,2:7],3)
last[0] = F

def B(): #clockwise backface (orange)
cube[3:6,9:] = np.rot90(cube[3:6,9:],3)
tempCube = np.copy(cube)
cube[:,:9],cube[1:-1,1:8] = np.rot90(tempCube[:,:9]),tempCube[1:-1,1:8]
last[0] = B

def R(): #clockwise rightface (green)
cube[3:6,6:9] = np.rot90(cube[3:6,6:9],3)
tempCube = np.copy(cube)
cube[:6,5],cube[3:6,9],cube[6:,5] = tempCube[3:,5],tempCube[2::-1,5],tempCube[5:2:-1,9]
last[0] = R

def L(): #clockwise leftface (blue)
cube[3:6,:3] = np.rot90(cube[3:6,:3],3)
tempCube = np.copy(cube)
cube[3:,3],cube[3:6,-1],cube[:3,3] = tempCube[:6,3],tempCube[:5:-1,3],tempCube[5:2:-1,-1]
last[0] = L

for character in raw_input('type a move sequence: ').replace("'",'i').replace('2','d').replace(' ',''):
eval(character+'()')

print("-"*12)

for row in cube:
print(''.join(character for character in row)) #uses ascii codes in golfed version


test input:

>>> runfile('C:~/rubiks cube.py', wdir='C:~/python/golf')
U2 L' D
OYY
RYY
RYY
GBBWOOBBBRRY
GBBWRRGGGOOY
OOYGBBWRRGGG
ROO
WWW
WWW


Comments or suggestions are greatly appreciated :)

• of using only 3 rotations wrong. The program converts any sequence into a sequence with more moves. If you input F F F F, it uses more than 3 rotations, as it converts to y y y R y y y y R y y y y R y y y y R y. It uses three types of rotations. – Paul Schmitz Sep 8 '16 at 11:51
• @PaulSchmitz three types is what I meant.... conversions are listed in the string in the seventh line – Aaron Sep 8 '16 at 14:02

C, 839 bytes

#include <stdio.h>
#define b(c) c,c+1,c+2,c+15,c+28,c+27,c+26,c+13
char a[]="   YYY      \n   YYY      \n   YYY      \nBBBRRRGGGOOO\nBBBRRRGGGOOO\nBBBRRRGGGOOO\n   WWW      \n   WWW      \n   WWW      \n",k;int d[][8]={b(3),b(39),b(42),b(45),b(48),b(81)},e[][12]={50,49,48,47,46,45,44,43,42,41,40,39,3,16,29,42,55,68,81,94,107,76,63,50,29,30,31,45,58,71,83,82,81,67,54,41,109,96,83,70,57,44,31,18,5,48,61,74,39,52,65,107,108,109,73,60,47,5,4,3,65,66,67,68,69,70,71,72,73,74,75,76},i,*j,r,p,q,s;f(int*g,int h){i=h<0?-1:1;for(j=g;j!=g+h;j+=i){k=a[j[3*h]];for(r=3;r--;)a[j[r*h+h]]=a[j[r*h]];a[*j]=k;}}l(int g,int m){f(d[g+m]-m,m?-2:2);f(e[g+m]-m,m?-3:3);}void n(char*o){while(*o){*o-'U'||(p=0);*o-'L'||(p=1);*o-'F'||(p=2);*o-'R'||(p=3);*o-'B'||(p=4);*o-'D'||(p=5);s=*++o=='\''||*o=='i';q=*o=='2';(s||q)&&o++;l(p,s);q&&l(p,0);}printf("%s",a);}


As this is not a full program (function with input from a string argument and output to the console), you need to call it like this:

int main() {
//  n("U2D2R2L2F2B2");    //checker cube
n("UDiRL'FBiUD'");    //spotted cube
}


Use only one call at a time as the function uses and modifies global variables.

Ungolfed:

#include <stdio.h>

char cube[] = "   YYY      \n"
"   YYY      \n"
"   YYY      \n"
"BBBRRRGGGOOO\n"
"BBBRRRGGGOOO\n"
"BBBRRRGGGOOO\n"
"   WWW      \n"
"   WWW      \n"
"   WWW      \n";

#define faceMove(offset) offset,offset+1,offset+2,offset+15,offset+28,offset+27,offset+26,offset+13
int faceMoves[6][8] = {
faceMove(3),    //Up
faceMove(39),   //Left
faceMove(42),   //Front
faceMove(45),   //Right
faceMove(48),   //Back
faceMove(81)    //Down
}, lineMoves[6][12] = {
50,49,48,47,46,45,44,43,42,41,40,39,    //Up
3,16,29,42,55,68,81,94,107,76,63,50,    //Left
29,30,31,45,58,71,83,82,81,67,54,41,    //Front
109,96,83,70,57,44,31,18,5,48,61,74,    //Right
39,52,65,107,108,109,73,60,47,5,4,3,    //Back
65,66,67,68,69,70,71,72,73,74,75,76 //Down
};

int rotate(int*move,int rotation){
int sign=rotation<0?-1:1;
for(int*submove=move;submove!=move+rotation;submove+=sign){
char takeout=cube[submove[3*rotation]];
for(int j=3;j--;)cube[submove[j*rotation+rotation]]=cube[submove[j*rotation]];
cube[*submove]=takeout;
}
}

int move(int move,int inverted){
rotate(faceMoves[move+inverted]-inverted,inverted?-2:2);
rotate(lineMoves[move+inverted]-inverted,inverted?-3:3);
}

void performMoves(char*instructions){
while(*instructions){
int moveIndex;
*instructions-'U'||(moveIndex=0);
*instructions-'L'||(moveIndex=1);
*instructions-'F'||(moveIndex=2);
*instructions-'R'||(moveIndex=3);
*instructions-'B'||(moveIndex=4);
*instructions-'D'||(moveIndex=5);
int inverted=*++instructions=='\''||*instructions=='i', twice=*instructions=='2';
(inverted||twice)&&instructions++;
move(moveIndex,inverted);
twice&&move(moveIndex,0);
}
printf("%s",cube);
}

int main() {
//  performMoves("U2D2R2L2F2B2");    //checker cube
performMoves("UDiRL'FBiUD'");    //spotted cube
}


As you can see, the main idea is to use a fully data-driven approach: The different rotations are expressed as lists of indices that have to be permuted. The permutation code can thus be very short and generic.

• Welcome to PPCG! Nice first post! – Rɪᴋᴇʀ Dec 28 '16 at 3:18
• You can do the following to save more bytes: f(h,g)int*g;{ -2, l(g,m){ -8, n(char*o){ -5, printf("%s",a) to puts(a) -7, also you can replace char constants with their ASCII decimal representation -1 each – Khaled.K Apr 30 '17 at 10:18
• 572 bytes – ceilingcat Oct 8 '19 at 10:11

Cubically, 2 bytes

¶■


Try it online!

Explanation:

¶   read a line from stdin, evaluate
■  print the cube to stdout


If extraneous output is allowed, this is an alternative. 1 byte:

¶


Try it online!

Cubically automatically dumps its memory cube to STDERR when the program ends. However, it also prints the notepad beforehand.

• I don't know whether to applaud or boo you. +1 – Jo King Jan 23 '18 at 2:54
• @JoKing Both. Just like when Cubically pwns other cube challenges. 1 2 3 – MD XF Jan 23 '18 at 3:08

JavaScript (ES6), 820

A porting of the buggy answer by @Paul Schmitz. It's still not completely golfed, but it has the added value that it works.

The main problem in the original answer is that a single function Q is not enough for all the movements involved in a rotation. I had to add 2 other functions O and N. All of them are just called in the right rotation function R.

(a,M=a=>[a[6],a[3],a[0],a[7],a[4],a[1],a[8],a[5],a[2]],Q=(a,b)=>[b[0],b[1],a[2],b[3],b[4],a[5],b[6],b[7],a[8]],N=(a,b)=>[b[0],b[1],a[6],b[3],b[4],a[3],b[6],b[7],a[0]],O=(a,b)=>[b[8],a[1],a[2],b[5],a[4],a[5],b[2],a[7],a[8]],R=a=>[M(a[0]),Q(a[2],a[1]),Q(a[3],a[2]),N(a[4],a[3]),O(a[4],a[1]),a[5]],X=a=>[M(a[0]),a[2],a[3],M(M(a[4])),M(M(a[1])),M(M(M(a[5])))],Y=a=>[a[4],M(a[1]),a[0],M(M(M(a[3]))),a[5],a[2]],F=c=>Array(9).fill(c[0]),r='replace',b=[FG,FY,FR,FW,FO,FB],J=(p,l)=>p.join[r](/.../g,l))=>(a[r](/(.)2/g,"$1$1")[r](/(.)['i]/g,"$1$1$1")[r](/F/g,"yyyRy")[r](/L/g,"yyRyy")[r](/B/g,"yRyyy")[r](/U/g,"xyRyyyxxx")[r](/D/g,"xyyyRyxxx")[r](/\w/g,c=>b=(c<'a'?R:c<'y'?X:Y)(b)),o=J(b[1],$&),J(b[5],(c,p)=>o+=
+c+b[2].join.substr(p,3)+b[0].join.substr(p,3)+b[4].join.substr(p,3)),o+J(b[3],
$&))  More readable maybe ( a, // local variables as default parameters r='replace', F=c=>Array(9).fill(c[0]), // function to fill a 3x3 square b=[FG,FY,FR,FW,FO,FB], // cube status // aux functions to perform basic moves M=a=>[a[6],a[3],a[0],a[7],a[4],a[1],a[8],a[5],a[2]], Q=(a,b)=>[b[0],b[1],a[2],b[3],b[4],a[5],b[6],b[7],a[8]], N=(a,b)=>[b[0],b[1],a[6],b[3],b[4],a[3],b[6],b[7],a[0]], O=(a,b)=>[b[8],a[1],a[2],b[5],a[4],a[5],b[2],a[7],a[8]], // R : right side rotation R=a=>[M(a[0]),Q(a[2],a[1]),Q(a[3],a[2]),N(a[4],a[3]),O(a[4],a[1]),a[5]], // X,Y: to put other sides in place of right side X=a=>[M(a[0]),a[2],a[3],M(M(a[4])),M(M(a[1])),M(M(M(a[5])))], Y=a=>[a[4],M(a[1]),a[0],M(M(M(a[3]))),a[5],a[2]], // aux function for output J=(p,l)=>p.join[r](/.../g,l), ) => ( // convert common moves to basic moves a[r](/(.)2/g,"$1$1")[r](/(.)['i]/g,"$1$1$1")[r](/F/g,"yyyRy")[r](/L/g,"yyRyy")[r](/B/g,"yRyyy")[r](/U/g,"xyRyyyxxx")[r](/D/g,"xyyyRyxxx")
// then execute each
[r](/\w/g,c=>b=c<'a'?R(b):c<'y'?X(b):Y(b)),
// built output in o
o=J(b[1],'\n   $&'), J(b[5],(c,p)=>o+='\n'+c+b[2].join.substr(p,3)+b[0].join.substr(p,3)+b[4].join.substr(p,3)), o+J(b[3],'\n$&') // returned output
)


S=
(a,M=a=>[a[6],a[3],a[0],a[7],a[4],a[1],a[8],a[5],a[2]],Q=(a,b)=>[b[0],b[1],a[2],b[3],b[4],a[5],b[6],b[7],a[8]],N=(a,b)=>[b[0],b[1],a[6],b[3],b[4],a[3],b[6],b[7],a[0]],O=(a,b)=>[b[8],a[1],a[2],b[5],a[4],a[5],b[2],a[7],a[8]],R=a=>[M(a[0]),Q(a[2],a[1]),Q(a[3],a[2]),N(a[4],a[3]),O(a[4],a[1]),a[5]],X=a=>[M(a[0]),a[2],a[3],M(M(a[4])),M(M(a[1])),M(M(M(a[5])))],Y=a=>[a[4],M(a[1]),a[0],M(M(M(a[3]))),a[5],a[2]],F=c=>Array(9).fill(c[0]),r='replace',b=[FG,FY,FR,FW,FO,FB],J=(p,l)=>p.join[r](/.../g,l))=>(a[r](/(.)2/g,"$1$1")[r](/(.)['i]/g,"$1$1$1")[r](/F/g,"yyyRy")[r](/L/g,"yyRyy")[r](/B/g,"yRyyy")[r](/U/g,"xyRyyyxxx")[r](/D/g,"xyyyRyxxx")[r](/\w/g,c=>b=(c<'a'?R:c<'y'?X:Y)(b)),o=J(b[1],$&),J(b[5],(c,p)=>o+=
+c+b[2].join.substr(p,3)+b[0].join.substr(p,3)+b[4].join.substr(p,3)),o+J(b[3],
\$&))

function update() { O.textContent=S(I.value) }

update()
<input id=I value='U2 Li D' oninput='update()'><pre id=O></pre>

• I get update() is not defined in my console while running the snippet – user41805 Dec 27 '16 at 11:44
• @KritixiLithos you have probably a sintax error, for not having a ES6 compliant browser. I tested it with Firefox, what browser are you using? – edc65 Dec 27 '16 at 11:46
• I'm using Chrome – user41805 Dec 27 '16 at 11:49
• @KritixiLithos my fault, there was an unnecessary comma. Fixed – edc65 Dec 27 '16 at 11:55