# There's an ant on my Rubik's Cube

A standard, solved, 3×3×3 Rubik's Cube has 6 differently colored faces, where each face is a 3×3 grid of squares of one color. The white face is opposite the yellow, the red opposite orange, the blue opposite green, and when white points upward, red is to the left of blue:

Imagine an ant sits on the center square of the white face, facing the red face. You can give him 3 commands:

• Forward (^) - take a step in the direction he's facing to the next grid square, stepping over an edge of the cube if necessary.
• Right (>) - rotate to the right (clockwise) by 90°, staying in the same grid square.
• Left (<) - rotate to the left (counter-clockwise) by 90°, staying in the same grid square.

Given an arbitrary list of commands, find the colors of the squares that the ant visits (not including the white starting square).

For example, the command sequence ^^>^^<^^^ has a path that looks like this:

The colors of the grid squares visited in order, not counting the starting square, are white red red green green green yellow, or just wrrgggy.

Write a program or function that takes in a string of the command characters <^> and prints or returns a string of the characters wyrobg (white, yellow, red orange, blue, green) that corresponds to the ant's path over the cube.

The shortest code in bytes wins. Tiebreaker is earlier answer.

## Notes

• The cube is in midair and the ant has effective pulvilli, so he can traverse the whole of the cube.
• The cube always remains in its solved state.
• A square's color is only recorded upon movement into the square, not rotation. The starting white square should not be recorded.
• A single optional trailing newline may be present in the input and/or output.

## Test Cases

input : output
[empty string] : [empty string]
^ : w
< : [empty string]
> : [empty string]
><><<<>> : [empty string]
>^ : w
<<^> : w
^<^<^<^< : wwww
^^ : wr
<^^ : wb
>><<<<^^ : wo
<^^^<^^^^<>^>^^>^ : wbbboooggyo
^^^^^^^^^^^^^^ : wrrryyyooowwwr
<<<^<^>^<^<^<^>^^^^<^>>>>>^^<^>^^<^>^>^>^>< : wwgrwgggoooobbbbyrby
^^>^^<^^^ : wrrgggy

• Mar 14, 2016 at 19:47
• @MartinBüttner Ants have six legs, cubes have six sides. <shrug> I dunno... Mar 15, 2016 at 1:05
• This is not a starter golfing challenge..... I'm losing my mind coming up with a coordinate system that is not hard coded.
– Matt
Mar 15, 2016 at 1:14
• @DigitalTrauma This challenge is screaming for a Hexagony answer :-) Mar 15, 2016 at 13:28
• I am so close with the worst PowerShell code you have ever seen.
– Matt
Mar 15, 2016 at 20:25

# Perl, 156143134128127125120119117113 109 bytes

Includes +1 for -p

Run with the control string on STDIN, e.g.

perl -p rubic.pl <<< "^^>^^<^^^"


rubic.pl:

@1=wryobg=~/./g;s##$n=w&$&;$y+=$x-=$y+=$x,@1[0,4,2,5,3,1]=@1while--$n%9;@{$n&&--$y%3}[3,0..2]=@1;$1[$n+9]#eg  ## Explanation Older version: @f=gboyrw=~/./g;s##$n=w&$&;$y+=$x-=$y+=$x,@f=@f[2,4,1,3,0,5]while--$n%9;@f=@f[0,$y=1,5,2..4]if$n&&$y--<0;$f[$n+8]#eg  The challenge of this question is to find a coordinate system that makes it easy to track the position and direction of the ant and to still easily get the face identity. The system I chose was to put standard (x,y) coordinates on the face the ant is on such that the ant is always facing in the negative y direction with the center of the face being (0,0). So: rotate right: (x',y') <- (-y, x) rotate left: (x',y') <- ( y, -x) alternatve: 3 right rotations Step forward: y' <- y-1  If y was already -1 the ant will leave the current face and step onto the next one. In the new coordinate system there x keeps its value, but y' becomes 1. This gives an easy coordinate system within a face. I also need something for the faces themselves. There I use an array consisting of The face to right of the ant g in the initial position The face to the left of of the ant b The face behind the ant o The face opposite to the ant y The face before the ant r The face the ant is on w  So the initial array is (g,b,o,y,r,w). Moving to the next face corresponds to rotating the last 4 elements, so moving from white to red makes this (g,b,w,o,y,r). Turning right is a permutation of the first 5 elements giving (o,r,b,y,g,w). Turning left is a simular permutation but can also be done by turning right 3 times, so applying this permutation 3 times. And not turning at all can also be done by applying the permutation 8 times. In fact turning right can also be done by applying the permutation 5 times. Knowing this the program is rather simple: @f=gboyrw=~/./g Set up the initial face orientation s## ... #eg Process each control string character {this is equivalent to s#.#...#eg because the empty regex repeats the last succesful regex)$n=w&$& Calculate n, the number of right rotations+1 modulo 9. This abuses a coincidence of the control characters: "<" & "w" = "4" -> 3 right rotations ">" & "w" = "6" -> 5 right rotations "^" & "w" = "V" = 0 but that is 9 mod 9 so leads to 8 right rtations$y+=$x-=$y+=$x, This is the same as ($x,$y)=(-$y,$x), so a right rotation of the face coordinates @f=@f[2,4,1,3,0,5] Right rotation of the face array while --$n%9                 Rotate right n-1 times. After this n=0
If this was a step then n was effectively 0.
So rotate right 8 times leaving n=-9

... if $n If a step...$y--             ... decrease y ...
&&$y--<0 ... but if y was already negative ... @f=@f[0,$y=1,5,2..4]            ... change face and set y to 1

$f[$n+8]                        return the last element (current face)
if this was a step, otherwise empty


So for that last statement rotations lead to the empty string and steps forward lead to the current face. Therefore $_ gets replaced by the faces visited on each step. • If I understand what's going on here, that @1 bit is an amazing abuse of what looks like a horrific language feature. Mar 23, 2016 at 14:38 • @NotthatCharles Yes, it's exactly as evil as it looks. In serious perl programs the first thing you do is turn off that feature using use strict. Thanks for the modulo 3 by the way. Mar 23, 2016 at 16:04 # Brachylog, 287 bytes :1:2222:"w":"y":["r":"b":"o":"g"]{h""|[L:I:N:A:B:[C:D:E:F]]hhM("^",(NhI,CwX,EY,B:D:A:FZ;AwX,BY,[C:D:E:F]Z),NhJ,(I1,2313O;I2,(Nh2,N$($(O;Nh1,2222O;Nbh1,3223O;3322O);3322N,2332O;3223N,2233O;2233N,3132O;2332N,3231O);IJ,AX,BY,(M"<",[C:D:E:F]$(Z,N$(O;M">",[C:D:E:F]$)Z,N$)O)),Lb:J:O:X:Y:Z:1&}  Expects a string containing the moves as Input, and no Output, e.g. brachylog_main("^^>^^<^^^",_). will write wrrgggy to STDOUT. ### Explanation § There are 3 types of tiles we can be on: centers (noted 1), edges (2) and corners (3) § When we are on a tile, we can denote adjacent tiles in order: front, left, back, right § Similarly, we can denote the adjacent colors depending on the current one of the face § § We start on the center (1) of face white ("w"). The adjacent tiles are 4 edges (2222) § The adjacent colors of white are red, blue, orange and green ("r":"b":"o":"g") § Yellow is opposite of white ("y") § We pass those initial conditions in an array, with the sequence of moves as first § element, as input to subpredicate 1 :1:2222:"w":"y":["r":"b":"o":"g"]{...} § SUB-PREDICATE 1 h"" § If the sequence of moves is empty, terminate the recursion | § Else... § Here are the variables' names of the input (which correspond to what's described in § the first few paragraphs) [L:I:N:A:B:[C:D:E:F]] § If the move is "^"... hhM("^", § The only way we change from one face to another is if the tile we end up on is of the § same type as the tile we started from (NhI, § If this is the case CwX, § Then write the color of the face we're facing, this face will now be the § current color EY, § The third color in the list is now the opposite color B:D:A:FZ § The opposite color is now the one we face, the color behind us (the third § in the list) is the one we were on, and the other 2 don't change § If the tiles are not the same type, then we don't change color ; AwX, § Write the current color, this will remain the color BY, § Opposite color stays the same [C:D:E:F]Z), § Other colors stay in the same order since we moved forward NhJ, § The new tile type is the one we were facing (I1,2313O; § If we were on the center, then the adjacent tiles are 2313 I2, § Else if we were on an edge (Nh2,N$($(O; § then if we were facing an edge (changed face), then the new types § of tiles are a double circular permutation of the previous types Nh1,2222O; § Else if we were facing a center, then the new tiles are 2222 Nbh1,3223O; § Else (corners) if the tile to our left is the center, then 3223 3322O) § Else 3322 ; § Else if we were on a corner 3322N,2332O; § then one of those 4 possibilities applies 3223N,2233O; 2233N,3132O; 2332N,3231O) § Else if the move is NOT "^" ; IJ,AX,BY, § We stay on the same type of tile, same color, same opposite color (M"<", § if the move is "turn left" [C:D:E:F]$(Z, § Then we circular permute the adjacent colors to the left
N$(O § we also circular permute the adjacent tiles to the left ;M">", § Else if the move is "turn right" [C:D:E:F]$)Z, § Then we do the same but with right circular permutations
N$)O) ), Lb:J:O:X:Y:Z:1& § Recursively call sub-predicate 1 with the new input, and the next move  ### Equivalent SWI-Prolog code If you don't want to bother with Brachylog's compiler, you can run this solution in SWI-Prolog using the following code (this is what gets generated by Brachylog's compiler): :- style_check(-singleton). :- use_module(library(clpfd)). brachylog_main(Input,Output) :- 1=1, brachylog_subpred_1([Input,1,2222,"w","y",["r","b","o","g"]],V0). brachylog_subpred_1(Input,Output) :- 1=1, brachylog_head(Input, ""). brachylog_subpred_1(Input,Output) :- 1=1, [L,I,N,A,B,[C,D,E,F]] = Input, brachylog_head([L,I,N,A,B,[C,D,E,F]], V0), brachylog_head(V0, M), ( 1=1, "^" = M, ( 1=1, brachylog_head(N, I), brachylog_write(C, X), Y = E, Z = [B,D,A,F] ; 1=1, brachylog_write(A, X), Y = B, Z = [C,D,E,F] ), brachylog_head(N, J), ( 1=1, I = 1, O = 2313 ; 1=1, I = 2, ( 1=1, brachylog_head(N, 2), brachylog_math_circular_permutation_left(N, V1), brachylog_math_circular_permutation_left(V1, O) ; 1=1, brachylog_head(N, 1), O = 2222 ; 1=1, brachylog_behead(N, V2), brachylog_head(V2, 1), O = 3223 ; 1=1, O = 3322 ) ; 1=1, N = 3322, O = 2332 ; 1=1, N = 3223, O = 2233 ; 1=1, N = 2233, O = 3132 ; 1=1, N = 2332, O = 3231 ) ; 1=1, J = I, X = A, Y = B, ( 1=1, "<" = M, brachylog_math_circular_permutation_left([C,D,E,F], Z), brachylog_math_circular_permutation_left(N, O) ; 1=1, ">" = M, brachylog_math_circular_permutation_right([C,D,E,F], Z), brachylog_math_circular_permutation_right(N, O) ) ), brachylog_behead(L, V3), brachylog_call_predicate([V3,J,O,X,Y,Z,1], V4). brachylog_behead(X,Y) :- string(X),!, sub_string(X, 1, _, 0, Y) ; number(X),!, number_codes(X,[_|T]), catch(number_codes(Y,T),_,Y=[]) ; atom(X),!, atom_codes(X,[_|T]), atom_codes(Y,T) ; X = [_|Y]. brachylog_math_circular_permutation_left(X,Y) :- string(X),!, string_codes(X,C), C = [H|T], append(T,[H],D), string_codes(Y,D) ; number(X),!, number_codes(X,C), C = [H|T], append(T,[H],D), number_codes(Y,D) ; atom(X),!, atom_codes(X,C), C = [H|T], append(T,[H],D), atom_codes(Y,D) ; X = [H|T],!, append(T,[H],Y). brachylog_math_circular_permutation_right(X,Y) :- string(X),!, string_codes(X,C), append(T,[H],C), D = [H|T], string_codes(Y,D) ; number(X),!, number_codes(X,C), append(T,[H],C), D = [H|T], number_codes(Y,D) ; atom(X),!, atom_codes(X,C), append(T,[H],C), D = [H|T], atom_codes(Y,D) ; append(T,[H],X), Y = [H|T]. brachylog_call_predicate(X,Y) :- reverse(X,R), R = [N|RArgs], number(N), reverse(RArgs, Args), ( N = 0,!, Name = brachylog_main ; atom_concat(brachylog_subpred_,N,Name) ), ( Args = [UniqueArg],!, call(Name,UniqueArg,Y) ; call(Name,Args,Y) ). brachylog_write(X,Y) :- X = [List,Format], is_list(List), string(Format),!, format(Format,List), flush_output, Y = List ; write(X), flush_output, Y = X. brachylog_head(X,Y) :- string(X),!, sub_string(X, 0, 1, _, Y) ; number(X),!, number_codes(X,[A|_]), number_codes(Y,[A]) ; atom(X),!, atom_codes(X,[A|_]), atom_codes(Y,[A]) ; X = [Y|_].  # PowerShell, 882 bytes Usage Save the code in a script and call it like this from the command line. Assuming working directory is the current directory. .\WalkingAntcg.ps1 "^^>^^<^^^"  Code $o=[char[]]"grbowy";[int]$c=4;[int]$global:x=1;[int]$global:y=1;[int]$f=1;[int]$n=5;$u={$c=$args[0];$1="341504251435240503210123".Substring($c*4,4);$2=$1*2-match".$($args[1]).";$3=$Matches[0];"$3";"012345"-replace([char[]]"$1$c"-join"|")} function t{param($o,$x,$y)if($o){switch($y){0{switch($x){0{$x=2}1{$y=1;$x=2}2{$y=2}}}1{switch($x){0{$y=0;$x=1}2{$y=2;$x=1}}}2{switch($x){0{$x=0;$y=0}1{$x=0;$y=1}2{$x=0}}}}}else{switch($y){0{switch($x){0{$y=2}1{$x=0;$y=1}2{$x=0}}}1{switch($x){0{$y=2;$x=1}2{$y=0;$x=1}}}2{switch($x){0{$x=2}1{$x=2;$y=1}2{$y=0;$x=2}}}}}$global:x=$x;$global:y=$y} ([char[]]$args[0]|%{switch($_){'^'{$global:y++;if($global:y-eq3){$global:y=0;$c="$f";$f="$n";$z=&$u $c$f;$f,$n="$($z[0][1])","$($z[1])"}$o[$c]}
"<"{$z=&$u $c$f;$f,$n="$($z[0][0])","$($z[1])";t 0 $global:x$global:y}
">"{$z=&$u $c$f;$f,$n="$($z[0][2])","$($z[1])";t 1 $global:x$global:y}}})-join""


Less golfed code with explanation

# Recorded order of cube colours and their indexes
# Green=0,Red=1,Blue=2,Orange=3,White=4,Yellow=5
$o=[char[]]"grbowy" [int]$c=4   # Ant is currently on this colour
[int]$global:x=1 # X coordinate on this face [int]$global:y=1   # Y coordinate on this face
[int]$f=1 # Colour that the Ant is facing [int]$n=5   # Colour beyond that the ant is facing.
# If the ant moves of this cube to the next this value becomes the one he is facing.
# It is also the only colour not neighboring this current colour.

# Anonymous function that will return the colour facing left and right
$u = { # Cube relationships relative to position. Groups of 4 colours that are important given the order... # Green=0-3,Red=4-7,Blue=8-11,Orange=12-15,White=16-19,Yellow=20-23 # Get the colours surrounding the current colour we are on and the surrounding ones # String version: "owrygwbyrwoybwgygrbogrbo"$c=$args[0] # "341504251435240501230123"$1="341504251435240503210123".Substring($c*4,4) # double the string so that we can get the characters before and after the facing colour reliably # Assign the output to surpress a boolean.$2 is not used. Shorter than a cast
$2=$1*2-match".$($args[1]).";$3=$Matches[0]
# Return two values. First is the colours to the left,current and right as a string.
# Second is the colour beyond the one we are facing. If we were to move forward two blocks
# we would end up on this colour
"$3";"012345"-replace([char[]]"$1$c"-join"|") } # function that will transpose the ants position based on right/left rotation. # Using current x and y determines what the tranposed values are and return them. function t{ param($o,$x,$y)
# X = $1; Y =$2
# Left 0 Right 1
if($o){ # Right Transpose # All values are hard coded to rotate to their new positions switch($y){
0{switch($x){0{$x=2}1{$y=1;$x=2}2{$y=2}}} # 1,1 is in the center and nothing changes 1{switch($x){0{$y=0;$x=1}2{$y=2;$x=1}}}
2{switch($x){0{$x=0;$y=0}1{$x=0;$y=1}2{$x=0}}}
}
}else{
# Left Transpose
# All values are hard coded to rotate to their new positions
switch($y){ 0{switch($x){0{$y=2}1{$x=0;$y=1}2{$x=0}}}
# 1,1 is in the center and nothing changes
1{switch($x){0{$y=2;$x=1}2{$y=0;$x=1}}} 2{switch($x){0{$x=2}1{$x=2;$y=1}2{$y=0;$x=2}}} } } # Update global variables with the ones from this function$global:x=$x$global:y=$y } # Process each character passed by standard input ([char[]]$args[0]|%{
switch($_){ # Moving Forward '^'{$global:y++
if($global:y-eq3){ # We have walked of the colour onto the next one. Update coordinates to the next colour$global:y=0
$c="$f"
$f="$n"
# Get the new neighboring colour indexes
$z=&$u $c$f
$f,$n="$($z[0][1])","$($z[1])"
}
# Output the colour we have just moved to.
$o[$c]
}
# Turn Left
"<"{$z=&$u $c$f;$f,$n="$($z[0][0])","$($z[1])"
# Transpose the ants location by passing current location to the transposition function.
t 0 $global:x$global:y
}
# Turn Right
">"{$z=&$u $c$f;$f,$n="$($z[0][2])","$($z[1])"
# Transpose the ants location by passing current location to the transposition function.
t 1 $global:x$global:y
}
}
}) -join ""
# Line above converts the output to a single string.


Using a lot of single letter variables used to records the ant current state (colour,position and orientation). The ant is always facing up. When a rotate instruction is read the cube is transposed in that direction. Hardcoded transposition matrices used to determine new position based on current position.

Code satisfies all examples in question.

• This can be golfed more but it works now so I need to try and remove some of the repetition now.
– Matt
Mar 16, 2016 at 12:28

# Tcl/Tk, 422 bytes

rename split S
array se {} [S wyywroorgbbg {}]
proc R a {foreach x [lassign $a y] {lappend b$x}
lappend b $y} proc < {V H} {set ::H$V
set ::V [lreverse [R $H]]} proc > {V H} [string map {V H H V} [info b <]] proc ^ {V H} { lassign$V x
lassign [set ::V [R $V]] y set ::H [string map "$x $y$::($x)$::($y)"$::H]
puts -nonewline $y} set V [S wwrrryyyooow {}] set H [S wwgggyyybbbw {}] foreach p [S {*}$argv {}] {$p$V $H}  Alas, I can't get it any smaller. Non-obfuscated version: array set opposites [split wyywroorgbbg {}] proc lrotate xs { foreach x [lassign$xs y] {
lappend ys $x } lappend ys$y
}

proc < {V H} {
set ::H $V set ::V [lreverse [lrotate$H]]
}

proc > {V H} {
set ::H [lreverse [lrotate $V]] set ::V$H
}

proc ^ {V H} {
lassign $V x lassign [set ::V [lrotate$V]] y
set ::H [string map [list $x$y $::opposites($x) $::opposites($y)] $::H] puts -nonewline$y
}

set V [split wwrrryyyooow {}]
set H [split wwgggyyybbbw {}]
foreach p [split {*}$argv {}] {$p $V$H}
puts {}


It works by maintaining a list of horizontal and vertical cell colors. ^ < and > are all commands that properly permute the lists. The current cell is the first in each list.

# Ruby, 132

m=?w
g="bgoyr"
x=z=1
gets.bytes{|c|(m,g[2,3]=g[4],m+g[2,2]if(x+=1)%3<1
\$><<m)if 93<c.upto(64){x,z,g=2-z,x,g[4]+g[2]+g[0]+g[3]+g[1]}}


This position system is sadly very similar to other answers out there. x and z track your position on the current face with +x being the direction of travel. Forward is always x+=1, and the bounds of each face are divisible by 3 (we don't care the number, just its modulus with 3).

m is the current face (this saves some bytes)

g is arranged [left, right, behind, opposite, front] so that we don't need to change g[0..1] on ^

< is done simply by doing > three times.

# Java, 619605534517 485 bytes

Well, here goes nothing...

At least it beat powershell!

-14 bytes thanks to @KevinCruijssen

And over 6 years later, -71 bytes (wow!) thanks to @ceilingcat . Try It Online!

And less than a year after that, @ceilingcat saved another 17 bytes. Try It Online!

OK @ceilingcat saved another 32 bytes, marking this as community wiki so they can make further edits. Try It Online!

String t(String f){int h[]={0,0,1},p[]={0,2,0},n[],i,s,r;String o="";for(int c:f.toCharArray()){r=r(p);n=h;if(c==94){for(s=i=3;i-->0;)if(h[i]==p[i]&p[i]!=0){s=i;n[1]=r<1?-1:r>4?1:n[1];i=2-r;if(i*i==1)n[0]=i;if(++i*i==1)n[2]=-i;i=0;}for(int a:n)p[++i]+=a;if(s<3)h[s]=0;o+="wgrboy".toCharArray()[r(p)];}i=r==3|r==5?2:r>0&r<3?1:0;r=h[s=r>-1&r<2?2:r>2&r<5?1:0];c-=61;if(c*c==1){h[s]=r==0?h[i]*c:0;h[i]=-r*c;}}return o;}int r(int[]p){return-1>p[0]?1:p[0]>1?3:p[1]>1?0:p[1]<-1?5:p[2]>1?2:4;}


## Explanation:

Unlike some of the other answers, which used used a 2-d coordinate system, I used a 3-d system to keep track of where the ant was.

The direction was also kept in a 3-d fashion to facilitate switching sides and movement.

Each face had one of the coordinates, x, y, or z, be set to 2 (or -2 for the opposite face) to signify which face it was.

Switching faces was accomplished by checking if the ant was about to go off (position and heading have a value that is same, but not 0), make sure it would "fall off" diagonally onto the next, and change the heading to be non-diagonal. This was surprisingly easy.

Turning was more difficult. Making sure it would always go the same direction required an extra if-else statement inside the check for each character, costing me many bytes. In addition, the "up" and "right" axes had to be hard-coded in for each side.

## Original ungolfed code

(Unchanged from previous edits for clarity in method)

private static String[] sides="w,g,r,b,o,y".split(",");
public static String traverse(String commands)
{
int[] pos = {0,2,0};
int i;
int saved;
String out = "";
for(char command:commands.toCharArray())
{
if(command=='^')
{
saved=3;
for(i=0;i<3;i++)
{
{
saved=determineSide(pos);
saved=i;
break;
}
}
i=0;
{
pos[i++]+=c;
}
out+=sides[determineSide(pos)];
}
if(command=='>')
{
if(saved==0)
{
}
else
{
}
}
if(command=='<')
{
if(saved==0)
{
}
else
{
}
}
}
return out;
}
public static int determineSide(int[] pos)
{
return pos[0]==2?3:pos[0]==-2?1:pos[1]==2?0:pos[1]==-2?5:pos[2]==2?2:4;
}
public static int[] getPlane(int side)
{
int[] out=new int[2];
out[0]=side==0|side==1?2:side==3|side==4?1:0;
out[1]=side==3|side==5?2:side==1|side==2?1:0;
//side==0?{2,0}:side==1?{2,1}:side==2?{0,1}:side==3?{1,2}:side==4?{1,0}:{0,2};
return out;
}

• That hurts.... I vow to try and out golf this now! :)
– Matt
Apr 2, 2016 at 20:31
• I know this was posted over a year ago, but there are some small things to golf: d[]={"w","g","r","b","o","y"} -> "w,g,r,b,o,y".split(",") (-1 byte); 2x '^' -> 94 (-2 bytes); 3x ==0 -> <1 (-3 bytes); 2x ==1 -> <2 (-2 bytes); etc for ==2, ==3, ==4, ==5. Aug 18, 2017 at 8:15
• @KevinCruijssen Thank you for the tips!
– Blue
Aug 19, 2017 at 11:22
• @ceilingcat oh wow thanks!! have no idea how you found this but this is a good golf, clever uses of assignments as expressions
– Blue
Nov 18, 2022 at 14:44