You may have noticed that in the comments of the previous post, I declared that we could actually represent the STATE of a Rubik's Cube with the same data structure that we store the TRANSFORMATIONS of a Rubik's Cube with.

Here is briefly how that works, and this should be the most difficult bit to figure out in this initial series!

First, note that (as tested below) a solved cube's position, acting as a transformation, is actually an identity on the cube. By identity, I essentially mean that it does nothing (like add 0 or multiplying by 1!). That thought may help guide you while I explain the rest of this.

The position transformations are a bit easier to explain that the orientation bits. We'll start with those.

Given:

• An existing Rubik's Cube
• A transformation on that Rubik's Cube

Let's say that the cubeState we're passing in has an EdgePosition array of:

``````[| 1; 0; 2; 3; 4; 5; 6; 7 |] // all solved edges, except for 2 swapped
``````

and that t (the transformation to be made on cubeState) has an EdgePosition array of:

`````` [| 2; 1; 0; 3; 4; 5; 6; 7 |]
``````

This begs the question "What should be the edge position (some integer 0-11) at position 0?!"

[I honestly cannot figure out a way to say this in English. Please read the following line of code. Help?]

``````cubeState.EdgePositions.[t.EdgePositions.[0]]
``````

The permutations of corners follow an exactly similar pattern.

Orientations work in a similar fashion, but:

• We must grab the ORIENTATION rather than the position of the above scenarios.
• We must reduce (via modulus) the number of twists down of each operation.
``````let Execute (cubeState: CubeState, t : CubeState) : CubeState =
{
EdgePositions =
[|
cubeState.EdgePositions.[t.EdgePositions.[0]]
cubeState.EdgePositions.[t.EdgePositions.[1]]
cubeState.EdgePositions.[t.EdgePositions.[2]]
cubeState.EdgePositions.[t.EdgePositions.[3]]
cubeState.EdgePositions.[t.EdgePositions.[4]]
cubeState.EdgePositions.[t.EdgePositions.[5]]
cubeState.EdgePositions.[t.EdgePositions.[6]]
cubeState.EdgePositions.[t.EdgePositions.[7]]
cubeState.EdgePositions.[t.EdgePositions.[8]]
cubeState.EdgePositions.[t.EdgePositions.[9]]
cubeState.EdgePositions.[t.EdgePositions.[10]]
cubeState.EdgePositions.[t.EdgePositions.[11]]
|]

EdgeFlips =
[|
cubeState.EdgeFlips.[t.EdgePositions.[0]] + t.EdgeFlips.[0]
cubeState.EdgeFlips.[t.EdgePositions.[1]] + t.EdgeFlips.[1]
cubeState.EdgeFlips.[t.EdgePositions.[2]] + t.EdgeFlips.[2]
cubeState.EdgeFlips.[t.EdgePositions.[3]] + t.EdgeFlips.[3]
cubeState.EdgeFlips.[t.EdgePositions.[4]] + t.EdgeFlips.[4]
cubeState.EdgeFlips.[t.EdgePositions.[5]] + t.EdgeFlips.[5]
cubeState.EdgeFlips.[t.EdgePositions.[6]] + t.EdgeFlips.[6]
cubeState.EdgeFlips.[t.EdgePositions.[7]] + t.EdgeFlips.[7]
cubeState.EdgeFlips.[t.EdgePositions.[8]] + t.EdgeFlips.[8]
cubeState.EdgeFlips.[t.EdgePositions.[9]] + t.EdgeFlips.[9]
cubeState.EdgeFlips.[t.EdgePositions.[10]] + t.EdgeFlips.[10]
cubeState.EdgeFlips.[t.EdgePositions.[11]] + t.EdgeFlips.[11]
|] |> Array.map (fun z -> (z%2))

CornerPositions =
[|
cubeState.CornerPositions.[t.CornerPositions.[0]]
cubeState.CornerPositions.[t.CornerPositions.[1]]
cubeState.CornerPositions.[t.CornerPositions.[2]]
cubeState.CornerPositions.[t.CornerPositions.[3]]
cubeState.CornerPositions.[t.CornerPositions.[4]]
cubeState.CornerPositions.[t.CornerPositions.[5]]
cubeState.CornerPositions.[t.CornerPositions.[6]]
cubeState.CornerPositions.[t.CornerPositions.[7]]
|]

CornerTwists =
[|
cubeState.CornerTwists.[t.EdgePositions.[0]] + t.CornerTwists.[0]
cubeState.CornerTwists.[t.EdgePositions.[1]] + t.CornerTwists.[1]
cubeState.CornerTwists.[t.EdgePositions.[2]] + t.CornerTwists.[2]
cubeState.CornerTwists.[t.EdgePositions.[3]] + t.CornerTwists.[3]
cubeState.CornerTwists.[t.EdgePositions.[4]] + t.CornerTwists.[4]
cubeState.CornerTwists.[t.EdgePositions.[5]] + t.CornerTwists.[5]
cubeState.CornerTwists.[t.EdgePositions.[6]] + t.CornerTwists.[6]
cubeState.CornerTwists.[t.EdgePositions.[7]] + t.CornerTwists.[7]
|] |> Array.map (fun z -> (z%3))

}
``````

Relevant Tests:

``````[<Fact>]
let ``Solved cube performed on self is solved`` () =
solvedCube
|> Execute solvedCube
|> should equal solvedCube

// by definition!
``````