User:Tisane/Rubik's cube program
Appearance
This program still doesn't work completely yet; see User:Tisane/Rubik's cube saga. |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
<?php
$myHistory=new history; // Global function
$solvedCube=new cube; // Global function
// Each face has 9 squares, arranged like this:
// 1 2 3
// 4 5 6
// 7 8 9
class square {
private $color;
// Return the color of this square
public function displayColor() {
return $this->color;
}
// Set the color of this square
public function setColor($inputcolor) {
$this->color=$inputcolor;
}
}
// Each cube has 6 faces, arranged like this:
// Face 1: Top
// Face 2: Front
// Face 3: Right side
// Face 4: Back
// Face 5: Left side
// Face 6: Bottom
class face {
// Create 9 new squares
function __construct() {
for ($squareCount=1; $squareCount<=9; $squareCount++) {
$this->thisSquare[$squareCount]=new square;
}
}
// Return the color of a square on this face
public function displaySquare($whichSquare) {
return $this->thisSquare[$whichSquare]->displayColor();
}
// Set the color of a square on this face
public function setSquare($whichSquare,$whatValue) {
$this->thisSquare[$whichSquare]->setColor($whatValue);
return;
}
}
class cube {
private $thisMove;
function __construct() {
for ($faceCount=1; $faceCount<=6; $faceCount++) {
$this->thisFace[$faceCount]=new face;
}
}
// Return the move associated with this cube
public function displayMove()
{
return $this->thisMove;
}
public function setMove($whichMove){
$this->thisMove=$whichMove;
}
// Return the color of a square on this cube
public function displaySquare($whichFace,$whichSquare) {
return $this->thisFace[$whichFace]->displaySquare($whichSquare);
}
// Set the color of a square on this cube
public function setSquare($whichFace,$whichSquare,$whatValue) {
$this->thisFace[$whichFace]->setSquare($whichSquare,$whatValue);
}
// Make this cube equal to another
public function duplicateCube($whichCube) {
for ($faceCount=1; $faceCount<=6; $faceCount++) {
for ($squareCount=1; $squareCount<=9; $squareCount++) {
$this->setSquare($faceCount,$squareCount,$whichCube->displaySquare($faceCount,$squareCount));
}
}
}
// See if this cube is identical to another
public function compareCube(cube $whichCube) {
for ($faceCount=1; $faceCount<=6; $faceCount++) {
for ($squareCount=1; $squareCount<=9; $squareCount++) {
if ($this->displaySquare($faceCount,$squareCount)!=$whichCube->displaySquare($faceCount,$squareCount))
return false; // They are different
}
}
return true; // They are the same
}
// Rotate a row to the right
public function rotateRight($whichRow) // $whichRow ranges from 1 to 3
{
$escrow=new cube;
$escrow->duplicateCube($this);
if ($whichRow!=2) { // If it's not the middle row
// Let's do the top or bottom of the cube
// As this face turns, each square ends up in a different place. For instance, the 7 moves to where the 1 is.
// $sub means substitute
for ($squareCount=1; $squareCount<=9; $squareCount++) {
switch ($squareCount) {
case 1:
$sub=7;
break;
case 2:
$sub=4;
break;
case 3:
$sub=1;
break;
case 4:
$sub=8;
break;
case 5:
$sub=5;
break;
case 6:
$sub=2;
break;
case 7:
$sub=9;
break;
case 8:
$sub=6;
break;
case 9:
$sub=3;
break;
}
switch ($whichRow) {
case 1:
$whichFaceToRotate=1; // The top
break;
case 3:
$whichFaceToRotate=6; // The bottom
break;
}
$escrow->setSquare($whichFaceToRotate,$squareCount,$this->displaySquare($whichFaceToRotate,$sub));
}
}
// Now the four faces (faces 2 through 5)
for ($faceCount=2; $faceCount<=5; $faceCount++) {
for ($squareCount=$whichRow*3-2; $squareCount<=$whichRow*3; $squareCount++) // Each row has three squares
{
$fromFace=$faceCount+1; // Get color data from the face to the right
if ($fromFace==6) { // If we've circled all the way around, go back to face 2
$fromFace=2;
}
$escrow->setSquare($faceCount,$squareCount,$this->displaySquare($fromFace,$squareCount));
}
}
$this->duplicateCube($escrow);
}
// Rotate a column down
public function rotateDown($whichColumn) // $whichColumn ranges from 1 to 3
{
$escrow=new cube;
$escrow->duplicateCube($this);
if ($whichColumn!=2) { // If it's not the middle row
// Let's do the left and right sides of the cube
for ($squareCount=1; $squareCount<=9; $squareCount++) {
switch ($squareCount) {
case 1:
$sub=7;
break;
case 2:
$sub=4;
break;
case 3:
$sub=1;
break;
case 4:
$sub=8;
break;
case 5:
$sub=5;
break;
case 6:
$sub=2;
break;
case 7:
$sub=9;
break;
case 8:
$sub=6;
break;
case 9:
$sub=3;
break;
}
switch ($whichColumn) {
case 1:
$whichFaceToRotate=5; // The left face
break;
case 3:
$whichFaceToRotate=3; // The right face
break;
}
$escrow->setSquare($whichFaceToRotate,$squareCount,$this->displaySquare($whichFaceToRotate,$sub));
}
}
// Now the four faces (faces 1, 4, 6, and 2 - i.e., top, back, bottom, and front
$toFace=array(1 => 1,4,6,2);
$fromFace=array(1 => 4,6,2,1);
for ($faceCount=1; $faceCount<=4; $faceCount++) {
$substituteColumn=$whichColumn;
for ($squareCount=$substituteColumn; $squareCount<=$substituteColumn+6; $squareCount+=3){
$fromSquare=$squareCount;
$toSquare=$squareCount;
if ($toFace[$faceCount]==4){
if ($whichColumn==1)
$toSquare+=2;
if ($whichColumn==3)
$toSquare-=2;
}
if ($toFace[$faceCount]==1 || $toFace[$faceCount]==4)
$fromSquare=10-$toSquare;
$escrow->setSquare($toFace[$faceCount],$toSquare,$this->displaySquare($fromFace[$faceCount],$fromSquare));
}
}
// for ($faceCount=1; $faceCount<=4; $faceCount++) {
// Every face but face 4 uses these instructions.
// if ($toFace[$faceCount]!=4) {
// We need to reverse these so they show up in the proper places.
//if ($whichColumn==1)
// $substituteColumn=3;
//if ($whichColumn==3)
// $substituteColumn=1;
// $substituteColumn=$whichColumn;
// for ($squareCount=$substituteColumn; $squareCount<=$substituteColumn+6; $squareCount+=3) {
// if ($toFace[$faceCount]==1)
// $substituteSquare=10-$squareCount;
// $escrow->setSquare($toFace[$faceCount],$squareCount,$this->displaySquare($fromFace[$faceCount],$substituteSquare));
// }
// }
// else {
// Face 4 uses these special instructions
// $substituteColumn=$whichColumn;
// for ($squareCount=$substituteColumn; $squareCount<=$substituteColumn+6; $squareCount+=3) {
// We need to reverse these so they show up in the proper places.
// $substituteSquare=$squareCount;
// $substituteSquare=10-$squareCount;
// Square 1 is a special case.
// }
// $escrow->setSquare($toFace[$faceCount],$squareCount,$this->displaySquare($fromFace[$faceCount],$substituteSquare));
// }
// }
$this->duplicateCube($escrow);
}
public function showMeTheCube() {
print '<table><tr>';
for ($faceCount=1; $faceCount<=6; $faceCount++) {
// print 'Face ';
// print $faceCount;
// print '<br />';
for ($squareCount=1; $squareCount<=9; $squareCount++) {
print '<td width="30">';
echo $this->displaySquare($faceCount,$squareCount);
print '</td>';
// if ($squareCount%3==0)
// print '<br />';
}
}
print '</table>';
//print '<br />';
// for ($faceCount=1; $faceCount<=6; $faceCount++) {
// print 'Face'.$faceCount;
// }
}
// Make this cube perfectly solved
public function createDefaultCube() {
for ($faceCount=1; $faceCount<=6; $faceCount++) {
// Each color is associated with a letter. E.g., W is White.
for ($squareCount=1; $squareCount<=9; $squareCount++) {
switch ($faceCount) {
case 1:
$color='W';
break;
case 2:
$color='O';
break;
case 3:
$color='G';
break;
case 4:
$color='R';
break;
case 5:
$color='B';
break;
case 6:
$color='Y';
break;
}
// Add square numbers
$this->setSquare($faceCount,$squareCount,$color.$squareCount);
}
}
return;
}
public function solveCube(){
global $solvedCube;
global $myHistory;
$solvedCube->createDefaultCube();
//$solvedIt=$this->compareCube($solvedCube);
//if ($solvedIt==false)
$this->anotherMove();
$myHistory->showMeTheHistory();
}
public function manipulateCube($whichMove){
switch ($whichMove){
case 1:
$this->rotateRight(1);
break;
case 2:
$this->rotateRight(2);
break;
case 3:
$this->rotateRight(3);
break;
case 4:
$this->rotateDown(1);
break;
case 5:
$this->rotateDown(2);
break;
case 6:
$this->rotateDown(3);
break;
}
}
public function anotherMove(){
global $myHistory;
global $solvedCube;
$solvedIt=$this->compareCube($solvedCube); // Have we solved it?
// $this->showMeTheCube();
if ($solvedIt==true){
return true; // We're done! Now let's get out of this recursion.
}
else
{
if ($myHistory->isItInTheHistory($this)==true)
return false; // We've been here before
for ($count=1; $count<=6 && $solvedIt==false; $count++){
$this->manipulateCube($count); // Manipulate the cube
$this->showMeTheCube();
$myHistory->storeThisCube($this,$count); // Store the current cube and move info
$solvedIt=$this->anotherMove(); // Now try manipulating the cube a different way
if ($solvedIt==false)
$myHistory->eraseThisCube(); // Go back
}
if ($solvedIt==true)
return true; // Again, let's GTFO
else
return false; // We'll have to retrace our steps
}
}
}
class history{
private $historyNumber=0;
private $highestWeHaveBeen=0;
public function storeThisCube($whichCube,$whichMove)
{
$this->historyNumber++;
if ($this->historyNumber>$this->highestWeHaveBeen)
{
$this->historyCube[$this->historyNumber]=new cube;
$this->highestWeHaveBeen++;
}
$this->historyCube[$this->historyNumber]->duplicateCube($whichCube);
$this->historyCube[$this->historyNumber]->setMove($whichMove);
}
public function eraseThisCube()
{
$this->historyNumber--;
}
public function isItInTheHistory($whichCube){
for ($count=1; $count<$this->historyNumber; $count++){ // Notice the operator is <, not <=
if ($this->historyCube[$count]->compareCube($whichCube)==true){
return true;
}
}
return false;
}
public function showMeTheHistory(){
for ($count=1; $count<=$this->historyNumber; $count++){
echo $this->historyCube[$count]->displayMove();
}
}
}
// Main program
$myCube= new cube();
$myCube->createDefaultCube();
//$myCube->showMeTheCube();
$myCube->rotateDown(1);
// $myCube->rotateRight(1);
// $myCube->rotateRight(1);
//$myCube->showMeTheCube();
//$myCube->rotateDown(1);
//$myCube->showMeTheCube();
$myCube->solveCube();
?>
</body>
</html>