10th grade computer science, ap viewpoint school, calabasas … · 2009-11-19 · required to...
TRANSCRIPT
May 2004
Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Evan M. Gates
10th Grade Computer Science, APViewpoint School, CalabasasMr. Anderson
Abstract
Software & Hardware Implementation i of ivof Rubik’s Cube Solving Algorithms
1.0 Abstract
Objective: The goal was to write the software and create the hardware
required to autonomously solve a Rubik's cube.
Materials and Methods: The physical Rubik's cube solver was made
primarily out of Plexiglas. A stepper motor is mounted on each of the six
sides with a shaft that goes into the center of one face of the cube. In
this manner all faces of the cube can be turned. All of the required code
was written in C. An implementation of the Thistlethwaite algorithm was
written to solve the Rubik's cube. This algorithm uses an iterative deep-
ening search as well as pruning trees to search for moves to solve the
cube. It works through four nested subgroups of the cube, restricting
moves and solving certain aspects along the way. The state of the cube
was originally kept in a file after having a scrambling program scramble
it. The use of cameras has recently been implemented to read in the
state of the cube. A color recognition scheme was devised, discerning
the different colors by comparing rgb values. After a string of moves is
produced, either by the solver, the scrambler, or by manual input, it is
passed to a program which creates stepper motor commands. The face
turns of the cube are translated into turns of the stepper motors, and out-
put through the com port at a given pace.
Results: There was some trouble stopping the solver from jamming.
This was fixed by making all turns clockwise and slightly overshooting
the goal so that the cube would self correct if slightly misaligned. Creat-
ing consistent lighting for the color recognition to get consistent results
was difficult. Lights were added in an attempt to light each face consis-
tently. The solving algorithm solved the cube efficiently and executed
quickly.
Abstract
ii of iv Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Discussion: Although the goal was reached, the project can still be
improved upon. The main area that could use improvement is the color
recognition algorithm. The implementation of neural networks would
produce more accurate results. Neural networks could also be used to
determine the sampling areas as opposed to manually inputting where
the center of the cube is. Another possible extension would be the use
of a more efficient solving algorithm. The current algorithm is known as
the Thistlethwaite algorithm. Another popular algorithm is the Kociemba
algorithm. This algorithm solves the cube on average in ten less moves
than the Thistlethwaite algorithm.
Table of Contents
Software & Hardware Implementation iii of ivof Rubik’s Cube Solving Algorithms
1.0 Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i2.0 Literature Review . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.1 Permutation & Orientation . . . . . . . . . . . . . . . . . . . . . 12.2 Cube Notation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.1 Cube State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.2.2 Moves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.3 Computer Representation . . . . . . . . . . . . . . . . . . . . . 32.3.1 Facelet Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.3.2 Edge & Corner Representation . . . . . . . . . . . . . . . . . . . . . . 52.3.3 Coordinate Representation . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4 Group Theory & the Cube . . . . . . . . . . . . . . . . . . . . . 92.5 Cube Solving Algorithms . . . . . . . . . . . . . . . . . . . . . 10
2.5.1 Uninformed Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.5.2 Informed Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.5.3 Greedy Best-First Search . . . . . . . . . . . . . . . . . . . . . . . . . 112.5.4 Uniform Cost Best-First Search . . . . . . . . . . . . . . . . . . . . 122.5.5 A* Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.5.6 Iterative Deepening Search. . . . . . . . . . . . . . . . . . . . . . . . 122.5.7 Thistlethwaite Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . 122.5.8 Kociemba’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.0 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.1 Main Routines. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.1.1 CubeSolve.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.1.2 CubeMotor.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.1.3 CubeScramble.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.1.4 CubeMove.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.1.5 CubeView.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2 Batch Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.2.1 Scramble.bat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.2.2 Solve.bat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3 Robotic Cube Solver. . . . . . . . . . . . . . . . . . . . . . . . . 17
4.0 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.1 Cube Solving Code. . . . . . . . . . . . . . . . . . . . . . . . . . 194.2 Physical Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.3 Color Recognition . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Table of Contents
iv of iv Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
5.0 Discussion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215.1 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.1.1 Kociemba vs. Thistlethwaite . . . . . . . . . . . . . . . . . . . . . . .215.1.2 God’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215.1.3 Neural Networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
6.0 Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237.0 Appendix A - Solver Enclosure Drawings . . . . . . 258.0 Appendix B - Source Code . . . . . . . . . . . . . . . . . 29
8.1 CubeSolve.cpp. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298.2 CubeMotor.cpp. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388.3 ExecuteMotor.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 398.4 CubeScramble.cpp . . . . . . . . . . . . . . . . . . . . . . . . . 428.5 CubeMove.cpp. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448.6 CubeView.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488.7 Scramble.bat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.8 Solve.bat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568.9 GetState.bat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Literature Review
Software & Hardware Implementation 1 of 58of Rubik’s Cube Solving Algorithms
2.0 Literature Review
2.1 Permutation & OrientationWhen most people think of a Rubik's cube, they think of six sides, nine
squares per side, simple enough, and fifty-four little squares. Upon
closer inspection, it is apparent that not all the squares are separate, but
that the cube is actually made up of 3x3x3 or 27 "cubies". Looking
closer one more time, one would notice that there are three different
types of cubies. There are six center cubies, each with one color. These
are positioned on the end of axles, and will never move in relation to
each other; the color of a center, defines the color of a face. There are
twelve edge cubies, each with two colors. And there are eight corner
cubies, each with three colors. Each type of cubie can only move into a
spot of the like type. Thus edge cubies and corner cubies are not inter-
changeable. Another thing about the puzzle that most people do not
realize is that it is not strictly a permutation puzzle. Each cubie, as well
as being permuted, also has an attached orientation. This is to say, the
cubies can all be in their respective places, but the cube would not be
solved because the edge or corner pieces can have a flip or twist. (see
figure 1) This idea will be explored more in depth later.
FIGURE 1. Permutation vs. Orientation
Literature Review
2 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
2.2 Cube NotationBefore one can start working with the cube, there must be some form of
representation and instruction. The most common form of instruction is
the Singmaster notation, or a derivative thereof. The faces are labeled
Up, Down, Front, Back, Left, and Right. The order in which these faces
are labeled is important due to precedence, as will be explained later.
Up and Down are used as not to confuse Bottom and Back. A quarter
turn of a face is denoted by the first letter of the face followed by a super-
script. A superscript of 1, +, or nothing, means a clockwise quarter turn
of the face. A superscript of -1,-, or ', means a counter clockwise quarter
turn. And a superscript of 2 means a double turn; the direction doesn't
matter because the result will be the same either way. To determine
which way to turn a face, look directly at the face, and turn it clockwise or
counterclockwise.
2.2.1 Cube StateEach individual cubie is represented by lowercase italic letters which
correspond to the colors on it. For instance, the corner cubie that is
touching the Up, Front, and Right faces, in its solved state, is labeled ufr.
Now imagine that this cubie is still in the same place, but is rotated clock-
wise so that the Up color is now on the right face. Due to the prece-
dence of the faces, it would now be labeled fur. Edges are labeled in an
analogous way using only two letters.
2.2.2 MovesAny move on the cube can be represented using permutations and label-
ing the pieces as shown above. As an example, let's turn the Up face.
On a pristine cube, the up face is (ufr ufl ubl ubr) (uf ul ub ur), with the
four corners of the face first, and then the four edges. If the move U
were to be performed, the Up layer would be turned a quarter turn clock-
wise. The resulting representation for the Up layer would be (urb urf ulf
Literature Review
Software & Hardware Implementation 3 of 58of Rubik’s Cube Solving Algorithms
ulb) (ur uf ul ub). Therefore the move U can be represented by (ufr ufl
ubl ubr) (uf ul ub ur) => (urb urf ulf ulb) (ur uf ul ub).
A set of moves, or algorithm, can also be represented in this manner.
Let's take for instance, the algorithm R'U2RUR'URU2 which rotates the
UFL, UBL, and UBR corners clockwise. Just focusing on corners, the
Up layer initially looks like this (ufr ufl ubl ubr). Since the permutation of
the corners did not change, the same letters will be used in the same
places, but they will now be rotated as to represent the orientation
change. The Up layer is now represented by (ufr luf blu rub). So this
algorithm, when concentrating on only the corners, can be represented
at (ufr ufl ubl ubr) => (ufr luf blu rub).
2.3 Computer Representation
2.3.1 Facelet RepresentationThere are several different ways to implement a computer version of the
Rubik's cube. The simplest, is to represent the fifty-four different facelets
of the cube in a one dimensional array. The index of the array is a posi-
tion in the cube, and the number, or label, at this position, represents the
facelet, or color, in that position. In this representation, the cube is repre-
sented purely by permutations. An array is used to describe the permu-
tation. For instance, looking at just the Front face on a solved cube gives
(F1, F2, F3, F4, F5, F6, F7, F8, F9). If the move F is performed, then a
new permutation is given. This permutation is represented as (F7, F4,
F1, F8, F5, F2, F9, F6, F3). This means that F7 is now in the F1 spot, F4
is now in the F2 spot, and so on. (see figures 2 & 3). This same array
for the F permutation can be used when the cube is in any given state. If
F7 is taken to mean the facelet that is in F7, not strictly the F7 facelet,
then the permutation can be applied on any cube state.
Literature Review
4 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
FIGURE 2. Facelet Representation for a Pristine Cube
FIGURE 3. Facelet Representation after Move F is executed on a Pristine Cube
Any two permutations can be multiplied to form the product of the two.
For instance if the F permutation described above is used twice on a
solved cube, then the resulting permutation is (F9, F8, F7, F6, F5, F4,
F3, F2, F1). That is to say the facelet in F7 is moved to the F1 place.
This facelet is then moved to the F3 position, so in the resulting permuta-
tion, the F7 facelet has moved to the F3 position.
Literature Review
Software & Hardware Implementation 5 of 58of Rubik’s Cube Solving Algorithms
Now consider the inverse permutation. An inverse permutation undoes
whatever was just done. The inverse of the F permutation would be the
F' permutation: (F3, F6, F9, F2, F5, F8, F1, F4, F7). When a permuta-
tion is multiplied by its inverse, it results in the identity permutation; in
this case (F1, F2, F3, F4, F5, F6, F7, F8, F9). The solution to a scram-
bled cube simply put is the inverse of the current permutation as a prod-
uct of the predefined moves.
2.3.2 Edge & Corner RepresentationThe next way to represent the cube is by representing the twelve edges
and eight corner cubies. When working with the cubies instead of face-
lets, it is not possible to represent a move with a simple permutation.
This is due to the fact as mentioned before that cubies can be in their
home positions, but with the incorrect orientation. (see figure 1) As
such, the orientations of the cubies must be represented as well. To do
this, there must be a standard for determining the orientation of a piece.
This is where the roll of precedence comes into play. Place an X on
every facelet of the top and bottom, and on the two front and two back
facelets of the equatorial edges. These X’s will stay in the same position
in space no matter how the cube is twisted or turned. Now place a circle
on the corresponding facelets of the cube, such that in the solved state,
every circle is over an X. (See figure 4) When the circle of a cubie is
over an X, then that cubie is correctly oriented. If an edge cubie is incor-
rectly oriented, then it is said to have a flip of one. Since edges only
have two possible orientations, it is represented in binary, having the cor-
rect flip of zero, or the incorrect flip of one. Corner cubies are slightly
more complicated, having three possible orientations. If a corner cubie
has the correct orientation, it has a twist of zero. If the corner cubie is
twisted clockwise, it is said to have a twist of one. And if it is twisted
counterclockwise, it has a twist of two. These orientations can be
Literature Review
6 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
described using the Singmaster notation as described earlier, but are
much easier to follow in the described manner.
FIGURE 4. Orientation (Flips and Twists)
Metamagical Themas
In this sense, a move on the cube can be represented by a permutation
with attached orientations. For instance, looking at only the corners of
the Front face, the solved state is represented by (UFR.0, UFL.0, DFL.0,
DFR.0). When the move F is applied, the corners move to new posi-
tions, but their orientations change as well. The result of the move is
(UFL.1, DFL.2, DFR.1, UFR.2). Just as with the facelet permutations, if
this is understood to mean the cubie in the UFL position is moved to the
UFR position, then this can be used on any scrambled state. The new
orientation of the cubie that has been moved to the UFR position, is its
old orientation, plus one, modulo three. For instance, if the corner cubie
in the UFL position has an orientation of two, that is it is twisted counter
clockwise, after the F move it would have an orientation of zero because
one plus two modulo three is zero. The edges are represented in an
analogous form, using modulo two instead of three.
Moves can be multiplied on the cubie level just as with the facelet level,
except that the orientation must now be kept track of too. As an exam-
ple, let's find the product of the F and R moves, concentrating on the
Literature Review
Software & Hardware Implementation 7 of 58of Rubik’s Cube Solving Algorithms
UFL corner. (See figure 5) In the F move, the UFL corner is moved to
the UFR position and the orientation is increased by one. So after just
the F move, the result for the UFL.0 corner is UFR.1. If the R move is
performed on a pristine cube, the UFR corner is moved to the UBR cor-
ner and the orientation is increased by 1. So after just the R move, the
UFR.0 corner is now UBR.1. Now the combination of the moves is as
follows. After F the UFL corner is in the UFR position with an orientation
of one. Now move this corner to the UBR position, as done in the R
move, and add one to the orientation. Now the UFL corner is in the UBR
position with an orientation of two. This also works with edge cubies.
FIGURE 5. Product of F & R Moves
2.3.3 Coordinate RepresentationThe final of the three forms is the coordinate level. In the coordinate
level of representation, the orientations and the permutations of the
edges and corners are mapped to natural numbers.
There are eight corners, each with three possible orientations giving the
number 38-1 or 6560. This is not reached because only seven of the
corners can have any orientation, the third one is forced. The number of
possible corner orientations is then 37-1 or 2186. A natural order of the
Literature Review
8 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
corners must be established in order to determine the orientations. The
order used is URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB. The orienta-
tion is represented by a base three number, each digit representing the
orientation of a corner. If the move R is applied to a clean cube, the
result is (DFR.2, UFL.0, ULB.0, UBR.1, DRB.1, DLF.0, DBL.0, DRB.2).
The base three number would then be 20011002. The last two can be
omitted because it is forced. The orientation of all the corners in base
three must be divisible by three. Therefore the number is 2001100. This
number in decimal is 1494. Thus 1494 is the corner orientation coordi-
nate for a cube with the move R applied to it.
The orientation coordinate of the twelve edge cubies are mapped to a
number up to 211-1, or 2047. Once again this is 211 and not 212 because
the orientation of the last edge is forced.
The corner permutation coordinate is more complicated. It is repre-
sented by a number from 0 to 8!-1 or 40319. The natural order of the
corners comes in once again here, but must be thought of as an enumer-
ation with values that can be compared. Thus URF < UFL < ULB < UBR
< DFR < DLF < DBL < DRB. When the move R is applied, the result of
the permutation is (DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR). Now
the number of corners, to the left of any given corner with a greater value
than that corner determines the digit. For example, looking at the result
of the R move; there are no corners left of DFR, so it is left blank. There
is one corner, DFR, to the left of UFL. Looking at the order of the cor-
ners, DFR is greater than UFL, so the value of UFL is one. This contin-
ues and the resulting number is 1130114. Now to create the actual
number that this maps to, a system with variable base is used. So the
number for the corner permutation coordinate after the move R is 1*1! +
1*2! + 3*3! + 0*4! + 1*5! + 1*6! + 4*7! = 21021.
Literature Review
Software & Hardware Implementation 9 of 58of Rubik’s Cube Solving Algorithms
The permutation of the edges is done in a corresponding manner, with
the coordinate up to 12!-1 or 479001599.
Every cube therefore can be represented by four numbers representing
the corner orientation coordinate (0 to 37-1), the edge orientation coordi-
nate (0 to 211-1), the corner permutation coordinate (0 to 8!-1), and the
edge permutation coordinate (0 to 12!-1). The different possibilities are
then 37 * 211 * 8! * 12! = 86504006548979712000. But only half of these
combinations are actually possible because only even permutations can
exist. Therefore the total possible number of combinations is
43252003274489856000.
2.4 Group Theory & the CubeThe Rubik's cube is also a useful tool in the field of group theory. Fol-
lowing are a few basic rules/theories to go by. For any moves or algo-
rithms g and h the following are true.
gg-1 = g-1g = 1 (EQ 1)
(gh)-1 = h-1 g-1 (EQ 2)
Given g and h, ghg-1 is called the conjugate of h by g. This is a very
important idea in cubing, and will appear frequently when applying algo-
rithms. Following are some important properties.
(ghg-1)-1 = gh-1g-1 (EQ 3)
This is true because using rule two:
(ghg-1)-1 = (g-1)-1 h-1 g-1 and (g-1)-1 is g. (EQ 4)
gh1h2g-1 = gh1g-1 gh2g-1 (EQ 5)
Because the middle g-1 and g cancel out.
Literature Review
10 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Given the operations g and h, ghg-1h-1 is called the commutator of g and
h. Therefore the commutator of g and h, denoted by [g,h] = 1 if and only
if gh = hg. This is simple enough to prove. Assume that [g,h] = 1. Multi-
ply both sides by hg giving ghg-1h-1hg = hg. Now getting rid of inverses
that are adjacent, ghg-1g = hg. Once again get rid of adjacent inverses
the result is gh = hg.
Two operations are said to commute if gh = hg. Let G be the set of
pieces which are affected by the operation g. If for two operations g and
h, G intersect H is the empty set, then the two operations commute. For
instance, L affects only cubies on the left side, and R affects only cubies
on the right side, therefore LR = RL, and L and R commute. This is also
true for more complicated operations that only move certain pieces when
done, such as corner three cycles.
If G and H have a very small overlap, then g and h will almost commute.
That is that [g,h] will only affect a few pieces. Let's take for example g =
FRF' and h = L. The move L affects only the eight cubies on the Left face
(the center cubie is ignored). The sequence FRF' only affects one of the
eight cubies that are affected by L. Because of the small amount of
overlap, g and h will almost commute, and only a small amount of pieces
will be affected. In fact [g,h], or FRF'LFR'F'L', only affects three pieces; it
is a corner three cycle.
2.5 Cube Solving Algorithms
There are multiple techniques for solving the Rubik's cube; some are
appropriate for humans, others are better fit for computers. The most
common method for solving the cube is a layer by layer approach. The
first two layers can often be solved intuitively, but the last layer needs
more complex algorithms which will leave pieces that have already been
Literature Review
Software & Hardware Implementation 11 of 58of Rubik’s Cube Solving Algorithms
solved alone. When implementing computers, relatively short solutions
can be found which do not build off of prior visual steps as humans do.
When implementing a computer solver, there must be a way to search
for the next move. There are multiple types of tree searches to do this.
The root node of the tree is the initial state of the cube; there is a branch
corresponding to each possible move from that state.
2.5.1 Uninformed SearchAn uninformed search such as the breadth first or depth first search is
impractical due to the size of the tree, containing approximately 4.3 x
1019 nodes. Although the breadth first search is guaranteed to produce
an optimal solution, it can not be implemented due to the number of
states. A depth first search would most likely get stuck in an infinite
cycle. To stop this, a maximum depth could be set, but then there is no
guarantee that the solution would be found. Due to the time complexity
of this type of search, even if every node took only a nanosecond to visit,
the search would take over 5000 years.
2.5.2 Informed SearchesInformed searches choose which nodes to explore based on some eval-
uation which tries to select the best node. This is often called a best-first
search. Two versions of the best-first search evaluate this selection due
to distance incurred or the estimated distance remaining.
2.5.3 Greedy Best-First SearchThe greedy best-first search bases the next decision on the estimated
distance remaining to the solution. When calculating this distance, it is
important to never over estimate it. This estimate is called an admissible
heuristic. The greedy search is based on a depth first search.
Literature Review
12 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
2.5.4 Uniform Cost Best-First Search Uniform cost best-first searching sorts the elements in a queue by their
distance from the goal state. With the Rubik's cube, this would be the
number of moves, which produces a breadth first search. However if the
moves were weighted differently, then the uniform cost search would
return the solution with the minimum weight.
2.5.5 A* SearchA* searching uses both the greedy and uniform cost best-first searches.
The heuristic is set to the sum of the distance already traveled and the
estimated distance to the solution.
2.5.6 Iterative Deepening SearchIterative-Deepening A*, or IDA*, is simply put A* combined with iterative
deepening. By keeping track of the depth explored, the memory com-
plexity changes from O(bd) to O(bd), in that not all states must be stored
in memory.
2.5.7 Thistlethwaite AlgorithmMorwen B. Thistlethwaite created one of the early computer based algo-
rithms to solve the Rubik's cube. The algorithm worked through nested
subgroups of the cube. After performing a certain goal, the possible
moves were restricted, thus forming a subgroup. In step one the edges
would be correctly oriented. After correctly orienting the edges, only
double turns are allowed on the Left and Right faces. When only these
moves are used, the orientation of the edges remains the same. In the
second step of the algorithm, using only the given moves, the orientation
of the corners would be corrected. At the same time, the four edge
pieces from the equatorial slice are restored into that slice. At this time
the moves are further restricted, allowing only double turns on the Up
and Down face as well. In the fourth step, the Up and Down edges are
placed in their respective slices, the corners are placed in their respec-
Literature Review
Software & Hardware Implementation 13 of 58of Rubik’s Cube Solving Algorithms
tive tetrads, the parity of the edge and corner permutation is made even,
and the total twist of each tetrad is fixed. A tetrad is a set of four non-
adjacent corners. Now the moves are restricted again, to the point that
only double moves can be used on every face. In step four, the cube is
solved using these moves.
2.5.8 Kociemba’s AlgorithmHerbert Kociemba has created an algorithm that is closely related to
Thistlethwaite's. Whereas Thistlethwaite has four steps, and nested
subgroups, Kociemba uses only two steps. In the first step, he goes
directly to G2, correcting the orientation of all pieces, and getting the four
equatorial edges in their slice. In the second step, he solves the cube,
using moves from G2.
Literature Review
14 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Methods
Software & Hardware Implementation 15 of 58of Rubik’s Cube Solving Algorithms
3.0 Methods
The source code for the project was written in Microsoft Visual C++ 6.0.
It is broken up into five separate programs to keep them short and easy
to understand. The compilation of these five programs takes place with
the use of two batch files, one to scramble the cube, and one to solve it.
All code is included as Appendix A.
3.1 Main Routines
3.1.1 CubeSolve.exeCube solve is the heart of the project. It uses an implementation of the
Thistlethwaite algorithm as described in the literature review. This
allows it to solve random cubes with little code, little execution time, and
fairly efficiently. Whereas the Thistlethwaite algorithm uses lookup
tables for each of the four steps of the solution, this implementation cre-
ates two smaller pruning tables per step. This allows it to run fast with-
out creating tables each time.
3.1.2 CubeMotor.exeCube motor outputs a string of moves to the stepper motors in order to
turn the physical cube. It parses the string, passing the moves of the
separate faces to the corresponding motor. Along with the move com-
mands, a wait command must be issued as to make sure the motors turn
at the correct times.
3.1.3 CubeScramble.exeCube scramble outputs a string of random moves of given length. This
string is then passed to cube motor to scramble the physical cube. Cube
scramble is designed to take the number of moves, as well as a seed for
the random number generator. The number of moves defaults to fifty,
and the seed defaults to the time.
Methods
16 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
3.1.4 CubeMove.exeCube move performs a given string of moves on a virtual cube. The
resulting cube state is then returned. This is used with cube scramble, to
find the state of the cube after it is scrambled, and then pass it to cube
solve.
3.1.5 CubeView.exeCube view reads the state of the cube from two Ethernet cameras. The
cameras are placed looking at opposite corners of the cube. In this man-
ner almost all colors can be seen. The six that are blocked by the shafts
in the cube can be calculated because once two colors on a corner are
known the third can be figured out. A fixed pattern of sample points are
programmed and the point around which to center them is found manu-
ally and put in the program. The RGB values of these sample points are
compared to determine which of the six colors it is. Once determined,
the supposed color is painted over the sample point, and stored in a
table. The contents of this table are then output in the correct format to
be passed to Cube solve.
3.2 Batch Files
3.2.1 Scramble.batScramble.bat writes the output of cube scramble to a file called scram-
blemoves.txt. This file is then passed to both cube motor and cube
move. When passed to cube motor, the physical cube is scrambled
according to the random string of moves. When it is passed to cube
move, the state of the scrambled cube is returned, and written to the file
cubestate.txt.
Methods
Software & Hardware Implementation 17 of 58of Rubik’s Cube Solving Algorithms
3.2.2 Solve.batSolve.bat reads cubestate.txt into cube solve. It then writes the output of
cube solve to solvemoves.txt. This is then passed into cube motor, to
solve the physical cube. Cubestate.txt is set back to a solved cube.
3.3 Robotic Cube SolverThe physical cube solver is made primarily out of Plexiglas with Lexan
shafts attached both to the center pieces of the cube and stepper
motors. Controllers are attached to the back of the stepper motors and
daisy chained together. The motors are controlled by programs output to
the com port.
FIGURE 6. Robotic Cube Solver
Methods
18 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Results
Software & Hardware Implementation 19 of 58of Rubik’s Cube Solving Algorithms
4.0 Results
4.1 Cube Solving CodeThe solving algorithm is an implementation of the Thistlethwaite algo-
rithm. It solves in a maximum of 45 moves, but with an average of 30.
The algorithm could be optimized more by combining moves at the end
of one phase and the beginning of another. The code executes quickly
and solves the cube efficiently.
4.2 Physical SolverThe solver worked best at one move every 600 milliseconds. This is an
average of 18 seconds per solve. There was a problem with the solver
jamming, but this was fixed by always turning clockwise, and slightly
overshooting the goal position. By doing this, no matter what face is
turned, it will self correct instead of jamming.
4.3 Color RecognitionCreating consistent lighting conditions for color recognition proved to be
a challenge. Lights were attached to the stepper motors in an attempt to
light the faces equally. In the end the color recognition was fairly accu-
rate.
Results
20 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Discussion
Software & Hardware Implementation 21 of 58of Rubik’s Cube Solving Algorithms
5.0 Discussion
5.1 ImprovementsThis project has many possible improvements and extensions including
the algorithm implemented, the method of keeping track of the cube
state, and the method of scrambling the cube.
5.1.1 Kociemba vs. ThistlethwaiteAs mentioned in the literature review, algorithms that are more efficient
than the Thistlethwaite algorithm exist. Kociemba's algorithm solves the
cube in approximately half the moves of Thistlethwaite's algorithm. An
implementation of this algorithm, or a derivative thereof would greatly
increase the efficiency of the solver.
5.1.2 God’s AlgorithmAn interesting idea in the field of solving methodologies is the use of
"God's algorithm". This would be a lookup table, with each cube config-
uration as an index, and the information held therein as either 0, 1, or 2;
each move would take the cube either one step closer to solved, keep it
the same distance, or one step farther from solved. There are approxi-
mately 4.3 quintillion combinations. This number can be reduced by the
forty-eight symmetries of the cube. Taking this into account the size of
the table would be approximately 224,000 terabytes, or 224 petabytes.
5.1.3 Neural NetworksA possible extension of the use of cameras would be the implementation
of neural networks. Currently the accuracy of the program changes
depending on the amount of ambient light. Also the sample points are
fixed points relative to a center that must be input manually. With the
use of neural networks, distinguishing between colors in almost any
lighting, as well as distinguishing where one color ends and the other
begins, would be much more accurate.
Discussion
22 of 58 Software & Hardware Implementationof Rubik’s Cube Solving Algorithms
Bibliography
Software & Hardware Implementation 23 of 58of Rubik’s Cube Solving Algorithms
6.0 Bibliography
Bump, Daniel. "Mathematics of the Rubik's Cube." (n.d.).
<http://match.stanford.edu/rubik.pdf>.
Davis, Tom. "Group Theory via Rubik's Cube." (n.d.).
<http://www.geometer.org/rubik/group.pdf>.
Fowler, Joe. "Algorithmic Approaches to Solving the Rubik’s Cube."
<http://ouray.cudenver.edu/~jfowler/>.
Hofstadter, Douglas R. Metamagical Themas. New York City:
Basic Books, 1985.
Kociemba, Herbert. Cube Explorer.
<http://home.t-online.de/home/Kociemba/cube.htm>.
Scherphuis, Jaap. Jaap's Puzzle Page.
<http://www.geocities.com/jaapsch/puzzles/>.
Bibliography
24 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Appendix A - Solver Enclosure Drawings
Software & Hardware Implementation 25 of 58of Rubik’s Cube Solving Algorithms
7.0 Appendix A - Solver Enclosure Drawings
FIGURE 7. Solver Enclosure 3D Overview Drawing
Appendix A - Solver Enclosure Drawings
26 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
FIGURE 8. Solver Enclosure Sides and Miscellaneous Components Drawing
Eva
n G
ates
Eva
n G
ates
Rubik
s C
ube
Solv
er
Enclo
sure
E
1:2
1 O
F 2
RE
VF
ILE
DW
G N
O.
RE
VIS
ION
DE
SC
RIP
TIO
NE
CN
NO
.R
EV
.
SC
ALE
DA
TE
AP
PR
OV
ED
EN
GIN
EE
R
CH
EC
KE
D
DR
AW
N
SH
EE
T
DA
TE
BY
CH
K'D
AP
PD
.
2/24
/04
2/24
/04
13.5
00"
13.5
00"
18.0
00"
4.50
0"
9.00
0"
4.50
0"13.5
00"
18.0
00"
9.00
0"
13.5
00"
4.50
0"
18.0
00"
Upp
er &
Sid
e Fa
ces
(4 P
iece
s)Lo
wer
Fac
es(2
Pie
ces)
Bot
tom
(1 P
iece
)
18.0
00"
4.50
0"
9.00
0"9.
000"
R 0
.125
"
6.36
4"
1.85
0"
0.92
5"
1.85
0"
0.92
5"
R 0
.125
"
0.92
5"
1.85
0"
0.92
5"
1.85
0"
2.50
0"
NEM
A 2
3 to
17
Ada
pter
(1
0 Pi
eces
)
4.50
0"
1.85
0"1.
850"
1.22
0"
1.22
0"2.
500"
0.32
5"
0.32
5"
0.64
0"0.64
0"
R 0
.125
"R
0.0
63"
R 0
.750
"R
0.7
50"
13.5
00"
7.50
0"0.
750"
0.37
5"
0.50
0" Squ
are
Cyl
indr
ical
Shaf
t(1
0 Pi
eces
)
Appendix A - Solver Enclosure Drawings
Software & Hardware Implementation 27 of 58of Rubik’s Cube Solving Algorithms
FIGURE 9. Solver Enclosure Base Drawing
Eva
n G
ates
Eva
n G
ates
Rubik
s C
ube
Solv
er
Enclo
sure
A
1:2
2 O
F 2
RE
VF
ILE
DW
G N
O.
RE
VIS
ION
DE
SC
RIP
TIO
NE
CN
NO
.R
EV
.
SC
ALE
DA
TE
AP
PR
OV
ED
EN
GIN
EE
R
CH
EC
KE
D
DR
AW
N
SH
EE
T
DA
TE
BY
CH
K'D
AP
PD
.
2/12
/04
2/12
/04
36.0
00"
24.0
00"
Dis
play
Bas
e (1
Pie
ce)
4.50
0"
4.00
0"
0.50
0"
4.50
0"
4.00
0"
0.50
0"
CubeBase
Cam
era
Stan
dC
amer
a St
and
Not
e:C
amer
a St
and
Blo
ck6.
5" H
x 4
.5"
W x
4.0
" D
(2 P
iece
s)
18.0
00"
6.36
4"
10.6
37"
16.0
92"
2.64
7"
5.92
4"
10.6
37" 16
.092
"
5.92
4"
2.64
7"
59.0
0°
Appendix A - Solver Enclosure Drawings
28 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
Appendix B - Source Code
Software & Hardware Implementation 29 of 58of Rubik’s Cube Solving Algorithms
8.0 Appendix B - Source Code
8.1 CubeSolve.cpp/********************************************************************************* * cubesolve.cpp * * * * Purpose : to return a string of moves to solve a cube in the given state * *********************************************************************************/#include <iostream.h>#include <memory.h>#include <string>
typedef enum face {F, B, R, L, U, D};typedef enum piece{UF, DF, UB, DB, UR, DR, UL, DL, FR, FL, BR, BL, //edges
UFR, UBL, DFL, DBR, DLB, DRF, URB, ULF}; //corners
/********************************************************************************* * permutations which define face turns * *********************************************************************************/piece perm[] = {UF, FR, DF, FL, ULF, UFR, DRF, DFL, //F permutation
UB, BL, DB, BR, URB, UBL, DLB, DBR, //B permutationUR, BR, DR, FR, UFR, URB, DBR, DRF, //R permutationUL, FL, DL, BL, UBL, ULF, DFL, DLB, //L permutationUF, UL, UB, UR, UFR, ULF, UBL, URB, //U permutationDF, DR, DB, DL, DFL, DRF, DBR, DLB};//D permutation
char *bithash="TdXhQaRbEFIJUZfijeYV";
piece order[] = {UF, DF, UB, DB, UR, DR, UL, DL, FR, FL, BR, BL, UFR, UBL, DFL, DBR, DLB, DRF, URB, ULF};
int *tables[8]; //pruning tables, two per phaseint table_size[] = {1, 4096, 6561, 4096,
256, 1536, 13824, 576}; // length of pruning tablesint phase = 0;face moves[20]; //current phase solutionint move_amount[20];
char *piece_names[] = {"UF", "DF", "UB", "DB", "UR", "DR", "UL", "DL", "FR", "FL", "BR", "BL", "UFR", "UBL", "DFL", "DBR", "DLB", "DRF", "URB", "ULF"};
char face_names[] = {'F', 'B', 'R', 'L', 'U', 'D'};
piece pos[20]; //the position of all the piecespiece ori[20]; //the orientation of all the pieces
piece TEMP;#define SWAP(a, b) TEMP=a; a=b; b=TEMP;
Appendix B - Source Code
30 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * reset * * * * Purpose : to create a pristine cube * *********************************************************************************/void reset() {
int i;
for (i=0; i<20; i++) {pos[i] = (piece)i;ori[i] = (piece)0;
}}
/********************************************************************************* * cycle * * * * Purpose : to do a four cycle of pieces, used to do a face turn * *********************************************************************************/void cycle(piece *p, piece *start_pos) {
SWAP(p[*start_pos], p[*(start_pos + 1)]);SWAP(p[*start_pos], p[*(start_pos + 2)]);SWAP(p[*start_pos], p[*(start_pos + 3)]);
}
/********************************************************************************* * twist * * * * Purpose : to twist piece p a times * *********************************************************************************/void twist(piece p, int a) {
ori[p] = (piece)((ori[p] + a + 1) % ((p < UFR)? 2 : 3));}
Appendix B - Source Code
Software & Hardware Implementation 31 of 58of Rubik’s Cube Solving Algorithms
/********************************************************************************* * move * * * * Purpose : to do a clockwise turn on a given face f * *********************************************************************************/void move(face f){
piece *start_pos = &perm[8*f];int i;
cycle(pos, start_pos); //cycle edges according to the permutation tablecycle(ori, start_pos);
cycle(pos, start_pos + 4); //cycle corners according to the perm tablecycle(ori, start_pos + 4);
if (f < U) { //twist corners if RLFBfor (i=7; i>3; i--)
twist(*(start_pos + i), i & 1);}
if (f < R) { //flip edges if FBfor(i=3; i>=0; i--)
twist(*(start_pos + i), 0);}
}
Appendix B - Source Code
32 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * numtoperm * * * * Purpose : to change a number to a piece permutation * *********************************************************************************/void numtoperm(piece *p, int n, int o) {
int a, b;
p += o;p[3] = (piece)o;
for (a=2; a>=0; a--) {p[a] = (piece)(n % (4-a) + o);n /= 4-a;for (b=a+1; b<4; b++)
if(p[b] >= p[a])p[b] = (piece)(p[b] +1);
}}
/********************************************************************************* * permtonum * * * * Purpose : to change a piece to a number permutation * *********************************************************************************/int permtonum(piece *p) {
int n=0;int a, b;
for (a=0; a<4; a++) {n *= 4-a;for(b=a+1; b<4; b++)
if (p[b] < p[a])n++;
}return n;
}
Appendix B - Source Code
Software & Hardware Implementation 33 of 58of Rubik’s Cube Solving Algorithms
/********************************************************************************* * setposition * * * * Purpose : set position of the needed pieces for given table and index * *********************************************************************************/void setposition(int table, int index) {
int i, j, k;piece corn[] = {DLB, DRF, URB, ULF, DLB, DRF, ULF, URB,
DLB, URB, DRF, ULF, DLB, ULF, DRF, URB, //possible permutation of DLB, URB, ULF, DRF, DLB, ULF, URB, DRF}; //second tetrad
piece *corn_ptr = corn;
reset();switch(table) {
case 0:break;
case 1: //edge orientationfor (i=0; i<12; i++, index >>= 1)
ori[i] = (piece)(index & 1);break;
case 2: //corner orientationfor (i=12; i<20; i++, index /= 3)
ori[i] = (piece)(index % 3);break;
case 3: //middle edge choice (ud slice)for (i=0; i<12; i++, index >>= 1)
pos[i] = (piece)(8*index & 8);break;
case 4: //ud slice choice(fb slice)for (i=0; i<12; i++, index >>= 1)
pos[i] = (piece)(4*index & 4);case 5: //tetrad choice, parity, twist
corn_ptr += index%6 * 4;index /= 6;for (i=k=0, j=12; i<8; i++, index >>= 1)
pos[i+12] = (piece)(index & 1 ? corn_ptr[k++] : j++);break;
case 6: //slice permutationsnumtoperm(pos, index%24, 12);index /= 24;numtoperm(pos, index%24, 4);index /= 24;numtoperm(pos, index , 0);break;
case 7: //corner permutationsnumtoperm(pos, index/24, 8);numtoperm(pos, index%24, 16);break;
}}
Appendix B - Source Code
34 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * getposition * * * * Purpose : to get the current position of the cube in terms of a table index * *********************************************************************************/int getposition(int table) {
int i, j, k, l, n = 0;int corn[8], corn2[4];
switch(table) {case 0: break;case 1: //edge orientation
for (i=0; i<12; i++)//12 bits, set bit if edge is flippedn += ori[i] << i;
break;case 2: //corner orientation
for (i=19; i>11; i--)//8 base three digits, represents corner twistn = n*3 + ori[i];
case 3: // middle edge choice (ud slice)for (i=0; i<8; i++)
n += (pos[i] & 8)? (1 << i) : 0;break;
case 4: // ud slice choice (fb slice)for (i=0; i<8; i++)
n += (pos[i] & 4)? (1 << i) : 0;break;
case 5: // tetrad choice, twist and parityfor (i=j=k=0; i<8; i++)
if ((l = pos[i+12] - 12) & 4) {corn[l] = k++;n += 1<<i;
}else corn[j++] = l;for(i=0; i<4; i++)
corn2[i] = corn[4 + corn[i]];while(--i)
corn2[i] ^= corn2[0];n = n*6 + corn2[1]*2 -2;if (corn2[3] < corn2[2])
n++;break;
case 6: // two edge and one corner orbit, permutationn = permtonum(pos)*576 + permtonum(pos+4)*24 + permtonum(pos+12);break;
case 7:n = permtonum(pos + 8)*24 + permtonum(pos+16);break;
}return n;
}
Appendix B - Source Code
Software & Hardware Implementation 35 of 58of Rubik’s Cube Solving Algorithms
/********************************************************************************* * filltable * * * * Purpose : to fill the given pruning table * *********************************************************************************/void filltable(int table_num) {
int n=1;int i;int depth=1;int turn;int position;face side;int size = table_size[table_num];int *table = tables[table_num] = new int[size];
memset(table, 0, size);reset();table[getposition(table_num)] = 1;
while (n) {n=0;for(i=0; i<size; i++){
if(table[i] == depth) {setposition(table_num, i);for (side=F; side<D; side = (face)(side+1)) {
for(turn=1; turn<4; turn++) {move(side);position = getposition(table_num);
if ((turn==2 || side >= (table_num & 6)) && !table[position]) {table[position] = depth + 1;n++;
}}move(side);
}}
}depth++;
}}
Appendix B - Source Code
36 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * searchphase * * * * Purpose : to find the solution to the current phase * *********************************************************************************/bool searchphase(int moves_left, int moves_done, int last_move) {
int num_turn;int i;
if (tables[phase ][getposition(phase) ]-1 > moves_left || tables[phase+1][getposition(phase+1)]-1 > moves_left)
return false;
if(!moves_left)return true;
for (i=5; i>=0; i--) {if (i-last_move && (i-last_move+1 || i|1)) {
moves[moves_done] = (face)i;for(num_turn=1; num_turn<4; num_turn++) {
move((face)i);move_amount[moves_done] = num_turn;if((num_turn ==2 || i >= phase) &&
searchphase(moves_left-1, moves_done+1, i))return true;
}move((face)i);
}}return false;
}
void print(){int i;
for (i=0; i<20; i++)cout << piece_names[pos[i]] << " ";
cout << endl << endl;
for (i=0; i<20; i++)cout << ori[i] << " ";
cout << endl << endl;}
Appendix B - Source Code
Software & Hardware Implementation 37 of 58of Rubik’s Cube Solving Algorithms
void main(int argc, char *argv[]){
int i, j, f, k;int pc, mor;
for (i=0; i<20; i++) {pc = k = mor = 0;for (f=0; f<((i<12)?2:3); f++) {
j = strchr(face_names, argv[i+1][f]) - face_names;if (j>k) {
k = j;mor = f;
}pc += 1 << j;
}for (f=0; f<20; f++)
if(pc == bithash[f]-64)break;
pos[order[i]] = (piece)f;ori[order[i]] = (piece)(mor % ((i<12)? 2:3));
}
for(i=0; i<20; i++)cout << piece_names[pos[i]] << " ";
cout << endl << endl;for(i=0; i<20; i++)
cout << ori[i] << " ";cout << endl << endl;
for (j=0; j<8; j++)filltable(j);
for (phase=0; phase<8; phase+=2) {for(j=0; !searchphase(j, 0, 9); j++)
;for(i=0; i<j; i++)
cout << face_names[moves[i]] << move_amount[i];}
}
Appendix B - Source Code
38 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
8.2 CubeMotor.cpp/********************************************************************************* * cubemotor.cpp * * * * Purpose : return motor command string given move string for a Rubik's cube * *********************************************************************************/#include <iostream.h>#include <string>
#define is_face(i)(1 <= i && i <= 6)
int current_face = 0;int current_turn = 0;
/********************************************************************************* * write_move * * * * Purpose : to print a motor command given a face on the cube and a turn * *********************************************************************************/void write_move(){
printf ("/%d%sR\n", current_face, (current_turn == 270 ? "P304" : (current_turn == 180 ? "P204" : "P104")));
current_face = current_turn = 0;}
void main(int argc, char *argv[]){
char c, *icp;int t;char input_chars[] = "UFRDBLufrdbl123+-'";int trans_chars[] = {1,2,3,4,5,6, 1,2,3,4,5,6, 90,180,270,90,270,270};
while ((c = getchar()) > 0) {if (icp = strchr(input_chars, c)) {
t = trans_chars[icp - input_chars];if (is_face(t)) {
if (current_face && t != current_face)write_move();
current_face = t;current_turn += 90;
}else if ((current_turn = (current_turn + t-90) % 360) == 0)
current_face = 0;}
}if (current_face)
write_move();}
Appendix B - Source Code
Software & Hardware Implementation 39 of 58of Rubik’s Cube Solving Algorithms
8.3 ExecuteMotor.cpp/********************************************************************************* * executemotor.cpp * * * * Purpose : to print out a given set of motor commands in given intervals * *********************************************************************************/
#include <iostream.h>#include <time.h>#include <string>#include <conio.h>
using namespace std;
int current_time, start_time, total_time;int time_base = 650;int time_incr = 0;
void getline(char *str) {char c;
while ((c = getchar()) > 0 && c != '\n')*str++ = c;
*str++ = 0;}
void main(int argc, char *argv[]){
char str[50];int count = 0;bool jam = 0;
while (--argc) {if (**++argv == '-') {
switch (*++*argv) {case 't':
if (!argc-- || **++argv == '-') {cerr << "improper -t switch, requires a number";return;
}sscanf(*argv, "%d", &time_base);if (time_base < 1 || time_base > 2000) {
cerr << "time_base out of range";return;
}break;
Appendix B - Source Code
40 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
case 'i':if (!argc-- || **++argv == '-') {
cerr << "improper -i switch, requires a number";return;
}sscanf(*argv, "%d", &time_incr);if (time_base < 1 || time_incr > 2000) {
cerr << "time_incr out of range";return;
}break;
case 'h':cout << endl;cout << "executemotor [-t time_base] [-i increment] [-h]" << endl;cout << endl;cout << "time_base sets the time between steps in milliseconds"; cout << endl;
cout << "(1 < time_base < 2000, default = " << time_base << ")"; cout << endl;
cout << "increment sets the increment for each +90deg move in msec";cout << endl;
cout << "(1 < time_incr < 2000, default = " << time_incr << ")";cout << endl;return;
default:cerr << "unknown switch";return;
}}else {
cerr << "illegal command line input";return;
}}
Appendix B - Source Code
Software & Hardware Implementation 41 of 58of Rubik’s Cube Solving Algorithms
start_time = current_time = clock();
do {current_time += time_base;if (!jam) {
getline(str);if (str[0])
count++;}else
jam = 0;if (str[0]) {
current_time += (str[3] - '1') * time_incr;printf("%s\n", str);fprintf(stderr, "%3d: %s \n", count, str);while(clock() < current_time) {
if (_kbhit()) {_getch();fprintf(stderr, "Paused \n");do {
while (!_kbhit());
} while (_getch() != 's');jam = 1;current_time = clock();
}}
}} while(str[0]);
total_time = clock()- start_time;
fprintf(stderr, "\n %d Moves, %.3f Seconds\n", count, ((float)total_time)/1000.);}
Appendix B - Source Code
42 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
8.4 CubeScramble.cpp/********************************************************************************* * cubescramble.cpp * * * * Purpose : to return a random sequence of moves of a given length with a given * * seed. * *********************************************************************************/#include <iostream.h>#include <stdio.h>#include <cstdlib>#include <ctime>
char moves[18][3] = {"U1", "U2", "U3", "F1", "F2", "F3", "R1", "R2", "R3", "D1", "D2", "D3", "B1", "B2", "B3", "L1", "L2", "L3"};
char opposite_moves[18][3] = {"D1", "D2", "D3", "B1", "B2", "B3", "L1", "L2", "L3", "U1", "U2", "U3", "F1", "F2", "F3", "R1", "R2", "R3"};
void main(int argc, char *argv[]){
int num_moves = 50;int seed = time(NULL);int limit = 3;int index;char *move;char last_face = ' ';
while (--argc) {if (**++argv == '-') {
switch (*++*argv) {case 'n':
if (!argc-- || **++argv == '-') {cerr << "improper -n switch, requires a number";return;
}sscanf(*argv, "%d", &num_moves);if (num_moves < 1 || num_moves > 500) {
cerr << "num_moves out of range";return;
}break;
case 's':if (!argc-- || **++argv == '-') {
cerr << "improper -s switch, requires a number";return;
}sscanf(*argv, "%d", &seed);break;
Appendix B - Source Code
Software & Hardware Implementation 43 of 58of Rubik’s Cube Solving Algorithms
case 'l':if (!argc-- || **++argv == '-') {
cerr << "improper -l switch, requires a number";return;
}sscanf(*argv, "%d", &limit);if (limit < 1 || limit > 3) {
cerr << "limit out of range";return;
}break;
case 'h':cout << endl;cout << "cubescramble [-n num_moves] [-s rand_seed] [-l limit] [-h]";cout << endl;cout << " num_moves sets number of random moves" << endl;
cout << " (1 < num_moves < 500, default = 50)" << endl;cout << endl;cout << " rand_seed sets the random number seed" << endl;cout << " (0 < rand_seed < 65535, default = time)" << endl;cout << endl;cout << " limit sets the rotation limit (deg/90)" << endl;cout << " (0 < limit <= 3, default = 3)" << endl;cout << endl;return;
default:cerr << "unknown switch";return;
}}else {
cerr << "illegal command line input";return;
}}
srand(seed);
while (num_moves--) {do
move = moves[index = rand()%18];while(*move==last_face || *opposite_moves[index]==last_face || move[1]>limit+'0');last_face = *move;cout << move << " ";
}cout << endl;
}
Appendix B - Source Code
44 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
8.5 CubeMove.cpp/********************************************************************************* * cubemove.cpp * * * * Purpose : to return the state of the cube after performing the given set of * * moves on a solved cube * *********************************************************************************/
#include <iostream.h>#include <string>
typedef enum TurnAxis {U, F, R, D, B, L};
typedef enum Move {Ux1, Ux2, Ux3, Fx1, Fx2, Fx3, Rx1, Rx2, Rx3, Dx1, Dx2, Dx3, Bx1, Bx2, Bx3, Lx1, Lx2, Lx3};
struct MoveDef {TurnAxis Axis;int TwistNum;
} MoveTable[Lx3 - Ux1 + 1] = {{U, 3}, {U, 2}, {U, 1}, {F, 3}, {F, 2}, {F, 1}, {R, 3}, {R, 2}, {R, 1},{D, 3}, {D, 2}, {D, 1}, {B, 3}, {B, 2}, {B, 1}, {L, 3}, {L, 2}, {L, 1}
};
/********************************************************************************* * the definition of the 12 edge pieces consisting of two facelets each * * the definition of the 8 corner pieces consisting of three facelets each * *********************************************************************************/typedef enum Edge {UF, UR, UB, UL, DF, DR, DB, DL, FR, FL, BR, BL};typedef enum Corner {UFR, URB, UBL, ULF, DRF, DFL, DLB, DBR};
/********************************************************************************* * the definition of the 54 facelets * *********************************************************************************/typedef enum Face{U1, U2, U3, U4, U5, U6, U7, U8, U9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, R1, R2, R3, R4, R5, R6, R7, R8, R9, D1, D2, D3, D4, D5, D6, D7, D8, D9, B1, B2, B3, B4, B5, B6, B7, B8, B9, L1, L2, L3, L4, L5, L6, L7, L8, L9};
typedef Face Facelet[L9 - U1 + 1];
Appendix B - Source Code
Software & Hardware Implementation 45 of 58of Rubik’s Cube Solving Algorithms
/********************************************************************************* * the permutation of the facelets by face turns * *********************************************************************************/Facelet FaceletMove[L - U + 1] = {
{U3, U6, U9, U2, U5, U8, U1, U4, U7, L1, L2, L3, F4, F5, F6, F7, F8, F9, F1, F2, F3, R4, R5, R6, R7, R8, R9, D1, D2, D3, D4, D5, D6, D7, D8, D9, R1, R2, R3, B4, B5, B6, B7, B8, B9, B1, B2, B3, L4, L5, L6, L7, L8, L9}, // U {U1, U2, U3, U4, U5, U6, R1, R4, R7, F3, F6, F9, F2, F5, F8, F1, F4, F7, D3, R2, R3, D2, R5, R6, D1, R8, R9, L3, L6, L9, D4, D5, D6, D7, D8, D9, B1, B2, B3, B4, B5, B6, B7, B8, B9, L1, L2, U9, L4, L5, U8, L7, L8, U7}, // F {U1, U2, B7, U4, U5, B4, U7, U8, B1, F1, F2, U3, F4, F5, U6, F7, F8, U9, R3, R6, R9, R2, R5, R8, R1, R4, R7, D1, D2, F3, D4, D5, F6, D7, D8, F9, D9, B2, B3, D6, B5, B6, D3, B8, B9, L1, L2, L3, L4, L5, L6, L7, L8, L9}, // R {U1, U2, U3, U4, U5, U6, U7, U8, U9, F1, F2, F3, F4, F5, F6, R7, R8, R9, R1, R2, R3, R4, R5, R6, B7, B8, B9, D3, D6, D9, D2, D5, D8, D1, D4, D7, B1, B2, B3, B4, B5, B6, L7, L8, L9, L1, L2, L3, L4, L5, L6, F7, F8, F9}, // D {L7, L4, L1, U4, U5, U6, U7, U8, U9, F1, F2, F3, F4, F5, F6, F7, F8, F9, R1, R2, U1, R4, R5, U2, R7, R8, U3, D1, D2, D3, D4, D5, D6, R9, R6, R3, B3, B6, B9, B2, B5, B8, B1, B4, B7, D7, L2, L3, D8, L5, L6, D9, L8, L9}, // B
{F1, U2, U3, F4, U5, U6, F7, U8, U9, D1, F2, F3, D4, F5, F6, D7, F8, F9, R1, R2, R3, R4, R5, R6, R7, R8, R9, B9, D2, D3, B6, D5, D6, B3, D8, D9, B1, B2, U7, B4, B5, U4, B7, B8, U1, L3, L6, L9, L2, L5, L8, L1, L4, L7} // L};
/********************************************************************************* * the facelet pairs and triplets which make up the edges and corners * *********************************************************************************/
Face EdgeFacePairs[12][2] = {{U8, F2}, {U6, R2}, {U2, B2}, {U4, L2}, {D2, F8}, {D6, R8},{D8, B8}, {D4, L8}, {F6, R4}, {F4, L6}, {B4, R6}, {B6, L4}
};
Face CornerFaceTriplets[8][3] = {{U9, F3, R1}, {U3, R3, B1}, {U1, B3, L1}, {U7, L3, F1}, {D3, R7, F9}, {D1, F7, L9}, {D7, L7, B9}, {D9, B7, R9}
};
char Face2Char[] = "UUUUUUUUUFFFFFFFFFRRRRRRRRRDDDDDDDDDBBBBBBBBBLLLLLLLLL";
Appendix B - Source Code
46 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * reset_cube * * * * Purpose : creates a pristine cube * *********************************************************************************/void reset_cube(Facelet Cube){
int f;
for (f = U1; f <= L9; f++)Cube[f] = (Face) f;
}
/********************************************************************************* * rotate_face_ccw / move_cube * * * * Purpose : rotate a given face as defined by the permutation table on a * * given cube * *********************************************************************************/void rotate_face_ccw(Facelet Cube, TurnAxis Face){
Facelet TempCube;int f;
for (f = U1; f <= L9; f++)TempCube[f] = Cube[FaceletMove[Face][f]];
for (f = U1; f <= L9; f++)Cube[f] = TempCube[f];
}
void move_cube(Facelet Cube, Move m){
for (int i = 0; i < MoveTable[m].TwistNum; i++)rotate_face_ccw(Cube, MoveTable[m].Axis);
}
void cube_to_string(Facelet Cube, char *state_string){
int i, j;
for (i = 0; i < 12; i++, *state_string++ = ' ')for (j = 0; j < 2; j++)
*state_string++ = Face2Char[Cube[EdgeFacePairs[i][j]]];
for (i = 0; i < 8; i++, *state_string++ = ' ')for (j = 0; j < 3; j++)
*state_string++ = Face2Char[Cube[CornerFaceTriplets[i][j]]];
*state_string = 0;}
Appendix B - Source Code
Software & Hardware Implementation 47 of 58of Rubik’s Cube Solving Algorithms
void main(int argc, char *argv[]){
Facelet Cube;char cube_string[70];char input_chars[] = "UFRDBLufrdbl123+-'";int trans_chars[] = {0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,0,2,2};int f, r;char *icp;char c;
reset_cube(Cube);
while (cin >> c){ if (icp = strchr(input_chars, c)) {
f = trans_chars[icp - input_chars];cin >> c;if (c && (icp = strchr(input_chars, c))) {
r = trans_chars[icp - input_chars];}else
r = 0;move_cube(Cube, (Move) (f*3 + r));
}}
cube_to_string(Cube, cube_string);
cout << cube_string << endl;}
Appendix B - Source Code
48 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
8.6 CubeView.cpp/********************************************************************************* * cubeview.cpp * * * * Purpose : to read in the state of the cube from two ethernet cameras * *********************************************************************************/
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <magick/api.h>#include <iostream.h>
#define BIG_PIXEL_SIZE 6#define LT_CENTER_X 316 //335 #define LT_CENTER_Y 226 //229 #define RT_CENTER_X 336 //322 #define RT_CENTER_Y 234 //235
char face_names[8] = "UBFRLD!";
char facelets[6][8];
char corners[8][7] = {"UFRUFR", "URBURB", "UBLUBL", "ULFULF", "DRFDRF", "DFLDFL", "DLBDLB", "DBRDBR"
};
/********************************************************************************* * the facelets as perceived by the cameras that make up the edges and corners * *********************************************************************************/int edges_table[12][2][2] = {
{{4,2}, {5,4}}, //UF{{4,0}, {0,0}}, //UR{{4,6}, {1,6}}, //UB{{4,4}, {3,2}}, //UL{{2,0}, {5,0}}, //DF{{2,2}, {0,4}}, //DR{{2,4}, {1,4}}, //DB{{2,6}, {3,6}}, //DL{{5,6}, {0,6}}, //FR{{5,2}, {3,4}}, //FL{{1,4}, {0,2}}, //BR{{1,0}, {3,0}}, //BL
};
Appendix B - Source Code
Software & Hardware Implementation 49 of 58of Rubik’s Cube Solving Algorithms
int corners_table[8][3][2] = {{{4,1}, {5,5}, {0,7}}, //UFR{{4,7}, {0,1}, {1,5}}, //URB{{4,5}, {1,7}, {3,1}}, //UBL{{4,3}, {3,3}, {5,3}}, //ULF{{2,1}, {0,5}, {5,7}}, //DRF{{2,7}, {5,1}, {3,5}}, //DFL{{2,5}, {3,7}, {1,1}}, //DLB{{2,3}, {1,3}, {0,3}} //DBR
};
/********************************************************************************* * one facelet on six corners cannot be seen, this table designates these corners* *********************************************************************************/int missing_corners_table[6][3][2] = {
{{0,7}, {4,1}, {5,5}}, //RUF{{4,7}, {0,1}, {1,5}}, //URB{{1,7}, {3,1}, {4,5}}, //BLU{{5,7}, {2,1}, {0,5}}, //FDR{{2,7}, {5,1}, {3,5}}, //DFL{{3,7}, {1,1}, {2,5}}, //LBD
};
struct color_table_struct {char name[10];int r_avg;int g_avg;int b_avg;
} color_table[] = {{"White ", 255, 255, 255},{"Red ", 130, 60, 80},{"Orange", 240, 150, 150},{"Green ", 35, 65, 65},{"Blue ", 90, 70, 250},{"Yellow", 220, 250, 145},{"No Match", 0, 0, 0}
};
Appendix B - Source Code
50 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * calc_color * * * * Purpose : to determine a given color by comparing rgb values * *********************************************************************************/int calc_color(int r, int g, int b){
int color;
if ((r >= 240 && g >= 240 && b >= 240) || (r <= b && b <= g)) color = 0; /* white */else if (g <= b && b <= r) color = (r < 175) ? 1 : 2; /* red or orange */else if (b <= g && g <= r) color = 2; /* orange */else if (r <= g && g <= b) color = (b-g < 40) ? 3 : 4; /* green or blue */else if (g <= r && r <= b) color = 4; /* blue */else if (b <= r && r <= g) color = 5; /* yellow */else color = 6; /* none */
return(color);}
/********************************************************************************* * get_block * * * * Purpose : to determine the color of a given block of pixels in a given image * *********************************************************************************/int get_block(Image *image_ptr, int x, int y, int w, int h,
int *red_avg, int *green_avg, int *blue_avg){
PixelPacket*pixels;int red_sum = 0;int green_sum = 0;int blue_sum = 0;int color;
pixels = GetImagePixels (image_ptr, x-w/2, y-h/2, w, h); for (int i = 0; i < w*h; i++, pixels++) {
red_sum += pixels->red;green_sum += pixels->green;blue_sum += pixels->blue;
}color = calc_color(red_sum/(w*h), green_sum/(w*h), blue_sum/(w*h));
*red_avg = color_table[color].r_avg;*green_avg = color_table[color].g_avg;*blue_avg = color_table[color].b_avg;
return color;}
Appendix B - Source Code
Software & Hardware Implementation 51 of 58of Rubik’s Cube Solving Algorithms
/********************************************************************************* * draw_block * * * * Purpose : to paint the given color in a given block of pixels on a given image* *********************************************************************************/void draw_block(Image *image_ptr, int x, int y, int w, int h, int r, int g, int b){
PixelPacket*pixels;PixelPacketcolor;
color.red = r;color.green = g;color.blue = b;
pixels = SetImagePixels(image_ptr, x-w/2, y-h/2, w, h);for (int i = 0; i < w*h; i++, pixels++)
*pixels = color;SyncImagePixels(image_ptr);
}
/********************************************************************************* * match_corner * * * * Purpose : to determine the third (unseen) color on a given corner * *********************************************************************************/char match_corner(char kc1, char kc2){
for (int i = 0; i < 8; i++)for (int j = 0; j < 3; j ++)
if (kc1 == corners[i][j] && kc2 == corners[i][j+1])return (corners[i][j+2]);
return('!');}
/********************************************************************************* * finish_corners * * * * Purpose : to fill in the third (unseen) color on the six corners which need it* *********************************************************************************/void finish_corners(){
for (int i = 0; i < 6; i++)facelets[missing_corners_table[i][0][0]][missing_corners_table[i][0][1]] = match_corner(
facelets[missing_corners_table[i][1][0]][missing_corners_table[i][1][1]],facelets[missing_corners_table[i][2][0]][missing_corners_table[i][2][1]]);
}
Appendix B - Source Code
52 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
void output(){
int i, j;
for (i = 0; i < 12; i++) {for (j = 0; j < 2; j++)
cout << facelets[edges_table[i][j][0]][edges_table[i][j][1]];cout << " ";
}for (i = 0; i < 8; i++) {
for (j = 0; j < 3; j++)cout << facelets[corners_table[i][j][0]][corners_table[i][j][1]];
cout << " ";}
}
void main(int argc, char **argv){
ExceptionInfo left_exception, right_exception;Image *left_image_ptr, *right_image_ptr;ImageInfo *left_image_info, *right_image_info;
struct face_location {int x;int y;
};
/********************************************************************************* * the coordinates from which to sample color * *********************************************************************************/
face_location right_face_table[] = {{RT_CENTER_X - 69, RT_CENTER_Y - 29}, {RT_CENTER_X - 53, RT_CENTER_Y - 56},{RT_CENTER_X - 37, RT_CENTER_Y - 27}, {RT_CENTER_X - 19, RT_CENTER_Y + 2},{RT_CENTER_X - 37, RT_CENTER_Y + 33}, {RT_CENTER_X - 54, RT_CENTER_Y + 60},{RT_CENTER_X - 69, RT_CENTER_Y + 35},{RT_CENTER_X + 56, RT_CENTER_Y - 35}, {RT_CENTER_X + 72, RT_CENTER_Y - 11},{RT_CENTER_X + 42, RT_CENTER_Y - 12}, {RT_CENTER_X + 8, RT_CENTER_Y - 12},{RT_CENTER_X - 11, RT_CENTER_Y - 42}, {RT_CENTER_X - 26, RT_CENTER_Y - 69},{RT_CENTER_X + 5, RT_CENTER_Y - 68},{RT_CENTER_X + 2, RT_CENTER_Y + 77}, {RT_CENTER_X - 28, RT_CENTER_Y + 77},{RT_CENTER_X - 11, RT_CENTER_Y + 49}, {RT_CENTER_X + 8, RT_CENTER_Y + 18},{RT_CENTER_X + 41, RT_CENTER_Y + 20}, {RT_CENTER_X + 72, RT_CENTER_Y + 20},{RT_CENTER_X + 56, RT_CENTER_Y + 46}};
Appendix B - Source Code
Software & Hardware Implementation 53 of 58of Rubik’s Cube Solving Algorithms
face_location left_face_table[] = {{LT_CENTER_X - 67, LT_CENTER_Y - 32}, {LT_CENTER_X - 52, LT_CENTER_Y - 60},{LT_CENTER_X - 36, LT_CENTER_Y - 32}, {LT_CENTER_X - 19, LT_CENTER_Y - 1},{LT_CENTER_X - 36, LT_CENTER_Y + 29}, {LT_CENTER_X - 52, LT_CENTER_Y + 62},{LT_CENTER_X - 68, LT_CENTER_Y + 33},{LT_CENTER_X + 64, LT_CENTER_Y - 43}, {LT_CENTER_X + 78, LT_CENTER_Y - 18},{LT_CENTER_X + 43, LT_CENTER_Y - 17}, {LT_CENTER_X + 10, LT_CENTER_Y - 15},{LT_CENTER_X - 6, LT_CENTER_Y - 47}, {LT_CENTER_X - 24, LT_CENTER_Y - 75},{LT_CENTER_X + 8, LT_CENTER_Y - 76},{LT_CENTER_X + 7, LT_CENTER_Y + 74}, {LT_CENTER_X - 23, LT_CENTER_Y + 74},{LT_CENTER_X - 10, LT_CENTER_Y + 48}, {LT_CENTER_X + 8, LT_CENTER_Y + 18},{LT_CENTER_X + 45, LT_CENTER_Y + 17}, {LT_CENTER_X + 78, LT_CENTER_Y + 16},{LT_CENTER_X + 63, LT_CENTER_Y + 43}};
memset(facelets, '!', sizeof(facelets));
/********************************************************************************* * read in the images using ImageMagick * *********************************************************************************/
InitializeMagick(*argv);GetExceptionInfo(&left_exception);GetExceptionInfo(&right_exception);left_image_info = CloneImageInfo((ImageInfo *) NULL);right_image_info = CloneImageInfo((ImageInfo *) NULL);strcpy(left_image_info->filename , "lefteye.jpg");strcpy(right_image_info->filename, "righteye.jpg");
cout << "Reading Images" << endl;
left_image_ptr = ReadImage(left_image_info , &left_exception );right_image_ptr = ReadImage(right_image_info, &right_exception);
if (left_exception.severity != UndefinedException) CatchException(&left_exception); if (left_image_ptr == (Image *) NULL) exit(1);
if (right_exception.severity != UndefinedException) CatchException(&right_exception); if (right_image_ptr == (Image *) NULL) exit(1);
Appendix B - Source Code
54 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
/********************************************************************************* * read the colors from the sample locations, store them in an array, and paint * * the chosen color back on the sample area * *********************************************************************************/
int red, green, blue;int color;
for (int i = 0; i < 21; i++) {color = get_block( left_image_ptr , left_face_table[i].x , left_face_table[i].y ,
BIG_PIXEL_SIZE, BIG_PIXEL_SIZE, &red, &green, &blue);draw_block(left_image_ptr , left_face_table[i].x , left_face_table[i].y ,
BIG_PIXEL_SIZE, BIG_PIXEL_SIZE, red, green, blue);
facelets[i / 7][i % 7] = face_names[color];}cout << endl;
for (i = 0; i < 21; i++) {color = get_block( right_image_ptr, right_face_table[i].x, right_face_table[i].y ,
BIG_PIXEL_SIZE, BIG_PIXEL_SIZE, &red, &green, &blue);draw_block(right_image_ptr , right_face_table[i].x , right_face_table[i].y ,
BIG_PIXEL_SIZE, BIG_PIXEL_SIZE, red, green, blue);
facelets[(i+21) / 7][i % 7] = face_names[color];}
WriteImage(left_image_info , left_image_ptr );WriteImage(right_image_info, right_image_ptr);
finish_corners();
for (i = 0; i < 6; i++){for (int j = 0; j < 8; j++)
cout << facelets[i][j] << " ";cout << endl;
}cout << endl;
output();cout << endl;
}
Appendix B - Source Code
Software & Hardware Implementation 55 of 58of Rubik’s Cube Solving Algorithms
8.7 Scramble.bat@echo off
echo UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR > cubestate.txt
echo "Cube is being scrambled"
cubescramble %5 %6 %7 %8 > scramblemoves.txt
cubemove < scramblemoves.txt > cubestate2.txt
cubemotor < scramblemoves.txt > scramblemotor.txt:
executemotor %1 %2 %3 %4 < scramblemotor.txt > com5:
echo "Cube is scrambled"
Appendix B - Source Code
56 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms
8.8 Solve.bat@echo off
echo "Cube is being solved"
cubesolve < cubestate2.txt > solvemoves.txt
cubemotor < solvemoves.txt > solvemotor.txt
executemotor %1 %2 %3 %4 < solvemotor.txt > com5:
echo UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR > cubestate2.txt
echo "Cube is solved"
Appendix B - Source Code
Software & Hardware Implementation 57 of 58of Rubik’s Cube Solving Algorithms
8.9 GetState.batdel "SnapshotJPEG@Resolution=640x480"
wget "http://192.168.29.61/SnapshotJPEG?Resolution=640x480"
copy "SnapshotJPEG@Resolution=640x480" lefteye.jpg
del "SnapshotJPEG@Resolution=640x480"
wget "http://192.168.29.62/SnapshotJPEG?Resolution=640x480"
copy "SnapshotJPEG@Resolution=640x480" righteye.jpg
del "SnapshotJPEG@Resolution=640x480"
copy *.jpg cubeview
cubeview > cubestate.txt
Appendix B - Source Code
58 of 58 Software & Hardware Implementation of Rubik’s Cube Solving Algorithms