# Roll a painted cube

There is a 1x1x1 cube placed on a infinite grid of 1x1 squares. The cube is painted on every side, so it leaves a mark on the grid when it moves. The sides of the cube are colored 6 distinct colors, re-presentable with any 6 distinct values. A 7th value represents a blank space.

The cube can roll around the grid. Every step it rotates precisely 90 degrees around one edge that touches the ground. Then the side facing down will leave a mark in that spot.

Given the path of the cube, output the pattern it leaves on the grid.

You may assume every spot is hit at most once. 0 bonus points if you use proper paint mixing rules in this case, but this is not necessary.

## Test Cases

Path:        Pattern

EEE          YMBG

ESE          YM
RB

SEN          YY
RM

NNNN         Y
R
B
C
Y


## IO

You can use any 4 distinct values to represent the directions, except complete or partial functions.

Output as a 2d array, a string, or a image. Any 6 values can be used to represent the colors of the cube sides. Extra respect for those who output as a image though.

You may leave extra blank spaces around the edges.

• May we assume no point in the grid will be hit more than once? If not, how are we supposed to treat that case? Feb 8 at 15:09
• @CommandMaster you may assume every spot will be hit 1 or 0 times Feb 8 at 15:34
• "0 bonus points if you use proper paint mixing rules in this case" - in which case? That sentence doesn't seem connected with any 'case' to make sense. Feb 10 at 20:47

# Vyxal, 28 bytes

6ɾ£⟑½4ʁ=⁺…*9+⟑¥Ṗi£;¥h;1pṅ2ø∧


Try it Online!

Expects a list of numbers 0, 2, 4, 6 for NESW respectively. Outputs a string with numbers 1 to 6 for each of the colors.

It represents cube rotations as permutations of sides of the cube. The lexicographically 9th permutation represents rotating 90 degrees around the vertical axis and the lexicographically 325th permutation represents rotating 90 degrees around the vertical axis and then rolling west.

Rolling in direction $$\n\$$ can be represented as rotating $$\90(n/2+1)\$$ degrees around the vertical axis, rolling west and then rotating rotating $$\90(3-n/2)\$$ degrees around the vertical axis. This corresponds to sequences of three 9th permutations and one 325th permutation.

6ɾ£                     # save [1,2,3,4,5,6] to the register
⟑                    # map input:
½                   #   halve
4ʁ                 #   push [0,1,2,3]
=                #   equals?
⁺…*             #   times 316
9+           #   plus 9
#     Now we have a list with three nines and one 325
⟑          #   for each:
¥         #      push register
Ṗi       #      index into permutations
£      #      save register
;     #   end for
¥h   #   first item of register
;  # end map


Now we have the sequence of bottom side colors after rolling the cube along the path.

1p       # prepend 1
ṅ      # join by nothing
2     # push 2
ø∧   # canvas draw


# JavaScript (ES6), 154 bytes

-7 thanks to @l4m2

Expects a list of directions in $$\0..3\$$ for NWSE and returns a matrix filled with $$\-3..3\$$ for MRB.YCG.

A rather naive implementation.

a=>a.map(d=>m[[A,B,C]=[[-B,A,C],[A,C,-B],[B,-A,C],[A,-C,B]][d],y+=--d%2][x+=~-d%2]=B,m=(b=[...a+0,C=3]).map(_=>b.map(_=>0)),m[x=y=a.length][x]=B=1,A=2)&&m


Try it online!

### How?

The sides of the cube are arranged in such a way that the sum of two opposite faces is always $$\0\$$, which is similar to how 6-sided dice are designed (except the sum is $$\7\$$ in that case).

We only need to keep track of $$\3\$$ orthogonal faces $$\A\$$, $$\B\$$, $$\C\$$. By convention, we define $$\B\$$ as the face currently touching (and painting) the ground.

When rotating the cube, the value of a 'hidden' face is given by $$\-X\$$ where $$\X\$$ is the value of its 'visible' counterpart.

### Commented

a =>                 // a[] = input array
a.map(d =>           // for each direction d in a[]:
m[                 //
[A, B, C] = [    //   apply the cube rotation ...
[-B,  A,  C],  //     0: North
[ A,  C, -B],  //     1: West
[ B, -A,  C],  //     2: South
[ A, -C,  B]   //     3: East
][d],            //   ... according to d
y += --d % 2     //   add dy to y
][x += ~-d % 2]    //   add dx to x
= B,               //   set m[y][x] = B
//   initialization:
m = (              //     set up a square matrix m[]
b = [ ...a + 0,  //     using an array b[] twice as large as a[]
C = 3 ]    //     with an additional (dummy) element
)                  //
.map(_ =>          //     fill all cells ...
b.map(_ => 0)    //     ... with 0's
),                 //
m[                 //     initialize (x, y) to the center square
x = y = a.length //
][x] = B = 1,      //     and set this square to 1 (yellow)
) && m               // end of map(); return m[]

• ...a, ...a => ...a+0 if all elements in a has length 1
– l4m2
Feb 9 at 11:42
• Also use -1..-3 instead of 4..6
– l4m2
Feb 9 at 11:44

# 05AB1E, 39 38 bytes

6LIĆv¤ˆā•R∊j% uWQöñ•4ô₂S£y;δè‡<è}2¯IΛ


Uses 0,2,4,6 for N,E,S,W respectively, and uses 1,2,3,4,5,6 for the colors B,R,M,C,G,Y of the challenge description respectively.

Explanation:

General explanation:

1. 6LIĆv¤ˆā•R∊j% uWQöñ•4ô₂S£y;δè‡<è} is to generate the output values in the correct order based on the 'rolling' cube.
2. 2¯IΛ is to output it in the correct output-format.

For step 1, I start with a list [1,2,3,4,5,6] as this starting position:

1     U
2345  FRBL
6     D


(The diagram next to it indicates Up; Front; Right; Back; Left; and Down respectively.)

For the four directions, the following changes take place:

Direction Cube 'roll' change Changes pattern Actual changes
North 123456263154 xx.x.x 12462614
Eeast 123456521463 x.x.xx 13565163
South 123456413652 xx.x.x 12464162
West 123456326415 x.x.xx 13563615

These are basically the changes I do in my code as well with a transliterate on 123456, after which I use this to index into the current state of the cube.

For step 2: I use the Canvas builtin Λ (see this 05AB1E tip of mine for an in-depth explanation of the Canvas builtin) to draw the characters from step 1 in the directions of the given input.

Code explanation:

6L                   # Push list [1,2,3,4,5,6]
I                  # Push the input-list
Ć                 # Enclose; append its own head (to have an extra iteration)
v                # Pop and for-each y over these input-directions:
¤               #  Push the last item of the list (without popping)
ˆ              #  Pop and add this last digit to the global array
ā               #  Push a list in the range [1,length] (without popping the list);
#  a.k.a. push list [1,2,3,4,5,6] again
•R∊j% uWQöñ•   #  Push compressed integer 124613562614516341623615
4ô            #  Split it into parts of size 4: [1246,1356,2614,5163,4162,3615]
₂S£         #  Split it into parts [2,6]: [[1246,1356],[2614,5163,4162,3615]]
y        #  Push the current direction y
;       #  Halve it
δ      #  Map over each inner list with halve the direction as argument:
è     #   Modular 0-based index halve the direction into the inner list
    #  Pop and push both integers to the stack
‡   #  Transliterate the digits of the first to the second in list
#  [1,2,3,4,5,6]
<  #  Decrease each by 1 to a 0-based index
è #  Index it into the current list
}2                # After the loop: Push 2
¯               # Push the global array
I              # Push the input-list
Λ             # Use the Canvas builtin with these three options,
# and output immediately afterwards implicitly


See this 05AB1E tip of mine (section How to compress large integers?) to understand why •R∊j% uWQöñ• is 124613562614516341623615.

# Python NumPy, 165 bytes

def f(p):
for c in p:s=s[2*c];_,j,k,l=c;y+=j+k-3;x+=(k+l)%4-1;o[y,x]=s[argmin(s):][1:4]
return o
from numpy import*


Attempt This Online!

Takes a list of lists as input S=[2,3,1,0],N=[3,2,0,1],W=[2,0,3,1],E=[1,3,0,2] and returns an NxNx3 array of RGB values.

### How?

Represents cube orientations (and 90 degree rotations) as permutations of its four long diagonals.

Each diagonal connects two opposite corners of the cube:

   3----------2
/|\        /|
/ | \      / |
0----------1  |
|  |   \   |  |
|  1----\--|--0
| /      \ | /
|/        \|/
2----------3


This wireframe shows the outline of a cube and one of the diagonals (diagonal 3). All eight corners are labelled by the diagonal (0,1,2,3) they belong to.

As the rotations we are interested in are fully characterised by the permutation they induce on the corners and as they preserve oppositeness of corners it may look like a good idea to encode such rotations as permutations of the four diagonals. And it is.

Now, we can see that the (orthogonal) orientations of the cube map 1:1 to permutations of 0,1,2,3.

Let us against normal convention write permutation abcd

as

ba
cd


and think of corners of the bottom face like in the picture (in the picture a,b,c,d = 0,1,2,3)

Now for example rolling the cube repeatedly over the (bottom) back edge will map:

10  ->  32  ->  01  ->  23  ->  10
23      10      32      01      32


(Always the bottom face is shown.)

For the (bottom) right edge it would be

 10  ->  02  ->  23  ->  31  ->  10
23      31      10      02      23


Note that every orientation maps to a unique permutation and, conversely, each permutation actually represents an orientation (not in the examples but over all possible orientations)

Further note that by singling out a "null" orientation O_n 0123 each orientation o doubles as a rotation r, viz. the r that takes O_n to o. Also, te effect of two consecutive rotations is the product of the corresponding permutations.

Finally, note the identity of the bottom face and therefore the colour applied is easily read off the permutation representation of the orientation: the total of 24 orientations / permutations splits into six groups of four which differ by quarter turns:

10  ~~  03  ~~  32  ~~  21
23      12      01      30


In practical terms, we can given an orientation; find the position of zero and then read ccw. This yields one of the six permutations of 1,2,3; a different one depending on which of the six faces of the cube is facing down.

# Charcoal, 47 bytes

≔YMCRGBηＦＳ«✳ι§η⁰≔⭆§⪪”)⊟Z➙.κ⊗φαμ”⁶⌕RULι§ηＩκη»§η⁰


Try it online! Link is to verbose version of code. Uses ULDR instead of NWSE. Explanation:

≔YMCRGBη


ＦＳ«


Loop over the path.

✳ι§η⁰


Draw the square just being exited.

≔⭆§⪪”)⊟Z➙.κ⊗φαμ”⁶⌕RULι§ηＩκη


Permute the colours according to the direction.

»§η⁰


Draw the final square.

# Python3, 580 bytes:

m=['abcd','afce','fbed']
E=enumerate
def f(d):
v,s,c,x,y,U,P=[[m]],0,0,0,0,0,0
v=m
for i in d:
X,Y={'N':(-1,0),'S':(1,0),'E':(0,1),'W':(0,-1)}[i]
if(0,0)!=(U,P)and((not U and X)or(not P and Y)):[(s,c)]=[(j,a.index(m[s][c]))for j,a in E(m)if m[s][c]in a and j!=s]
U,P=X,Y
c+=[-1,1][::[1,-1][s%2]][::[-1,1][i in['N','W']]][i in['E','N']];x+=X;y+=Y
c%=4
if y==len(v):y=len(v);v=[I+['']for I in v]
if y<0:y=0;v=[['']+I for I in v]
if x==len(v):x=len(v);v=v+[[''for _ in v]]
if x<0:x=0;v=[[''for _ in v]]+v
v[x][y]=m[s][c]
return v


Try it online!

# HTML + Javascript graphical output, 269 254 bytes

Building on Arnaulds answer, this draws the colored fields to a <svg>.

-15 bytes by switching from <canvas> to <svg>.

Directions are entered as 0..3 for NWSE. Colors are mapped from 1..6 as

1: hsl(60,90%,50%)  = #f2f20d
2: hsl(120,90%,50%) = #0df20d
3: hsl(180,90%,50%) = #0df2f2
4: hsl(240,90%,50%) = #0d0df2
5: hsl(300,90%,50%) = #f20df2
6: hsl(360,90%,50%) = #f20d0d


w=a=>{A=1,B=2,C=3,x=y=a.length,c=<svg viewBox=${[0,0,3*x,3*y]}>;(f=()=>(c+=<rect x=${x} y=${y} width=1 height=1 fill=hsl(${B*60},90%,50%) />))();for(d of a){[A,B,C]=[[7-B,A,C],[A,C,7-B],[B,7-A,C],[A,7-C,B]][d],y+=--d%2,x+=~-d%2,f()}document.write(c)}

w([3,2,3])

# Ruby, 126 124 122 119 bytes

2 bytes saved by changing colours from ABCEFG to 123456, 2 bytes saved by deleting [] from [1,2,3], 3 bytes saved by changing directions from 0,1,2,3 to -2,-1,0,1.

->n{a=($/+?.*w=n.size*4)*w a[q=w*w/2]=?2 c=1,2,3 n.map{|i|c[j=i&1,2]=c[j+1]*s=i|1,-c[j]*s a[q+=s+j*w*s]="#{c%7}"} a}  Try it online! Takes an array of numbers -2,-1,0,1 corresponding to W,N,E,S or equivalently x-=1,z-=1, x+=1,z+=1. Outputs the path of the cube traced on a string of w*w periods, where w is four times the length of the input. The cube is represented as a vector c=[x,y,z] starting at [1,2,3] which rolls in the xz plane. The colour is determined by the current y coordinate. If the cube is rotated 180 degrees, the y coordinate becomes negative, so the possible values are -3,-2,-1,1,2,3 with opposite faces adding to zero. To display, the number is taken mod 7 and this is converted to a character, so the possible displayed colours are 1,2,3,4,5,6 with opposite faces adding to 7. The vector is rotated by 90 degrees by swapping two coordinates and changing the sign of one of them, similar to Arnauld's answer, but where he uses an array, I use the formula c[j,2]=c[j+1]*s,-c[j]*s where c[j,2] is a block of 2 array elements starting at j=0 or 1 and s is the sign of the rotation, +1 or -1. s is also the sign of the direction of movement and is calculated as i|1. s equals -1 for -2|1 and -1|1, and 1 for 0|1 and 1|1. j is calculated as i&1 and equals 0 for even numbers -2 and 0 (travel in x direction) and 1 for odd numbers -1 and 1 (travel in z direction.) Commented code ->n{a=($/+?.*w=n.size*4)*w            #make a string of w*w periods separated in lines by /n
a[q=w*w/2]=?2                         #set q to the centre of the field (padding by the /n characters ensures w*w/2 is central horizontally as well as vertically)
c=1,2,3                               #put a 2 at position q. Set up a vector c for colours x,y,z
n.map{|i|                             #iterate through array of directions. j=1 for vertical, 0 for horizontal. s=1 for increase, -1 for decrease
c[j=i&1,2]=c[j+1]*s=i|1,-c[j]*s       #in accordance with value of j, swap c&c or c&c and change the sign of one in accordance with s
a[q+=s+j*w*s]="#{c%7}"}            #modify the value of q by s (horizontal) or (1+w)s (vertical) and save colour%7 at a[q]
a}                                    #return the final string a.
`