<?php
$colors = array(
1 => 'R',
2 => 'O',
4 => 'Y',
8 => 'G',
16 => 'B',
32 => 'P',
false => 'X',
);
$used_towers = array_fill(0, 6, 0);
$cube = array(
array(1,3,4,5,2,0),
array(2,5,1,4,1,3), // note 'special' base at (2, 1) here
array(0,1,3,2,5,4),
array(5,4,0,3,0,2), // note 'special' base at (2, 3) here
array(4,2,5,0,3,1),
array(3,0,2,1,4,5),
);
$solution = array_fill(0, 6, array_fill(0, 6, false));
function solve_color($color) {
global $solution, $used_towers, $colors, $cube;
$orig = $solution;
$failed = array( );
$i = 0;
$j = -1;
while ($i <= 5) {
// if we already have a piece in this space (via pre-reqs)
// just skip it
if (in_array($color, $orig[$i])) {
$i++;
$j = -1;
continue;
}
if ( ! isset($failed[$i])) {
$failed[$i] = array( );
}
do {
$j++;
$size = $cube[$i][$j];
// we've already tried this one, try the next space
} while (in_array($size, $failed[$i]) && (5 > $j));
// try putting a piece in the ith row in the last + 1 col
if (test_color(($i * 6) + $j, $solution, $used_towers, $color, $size) && ! in_array($size, $failed[$i])) {
$solution[$i][$j] = $color;
$used_towers[$size] |= $color;
$i++;
$j = -1;
continue;
}
// something failed, go back a row and try a new piece
if (5 <= $j) {
// backtrack until we find a row that didn't already have a piece in it
do {
$i--;
} while (in_array($color, $orig[$i]));
// find out what piece was used here
foreach ($solution[$i] as $j => $col) {
if ($color == $col) {
$size = $cube[$i][$j];
$failed[$i][] = $size;
$used_towers[$size] ^= $color;
}
}
$solution[$i] = $orig[$i];
$j = -1;
continue;
}
}
return $solution;
}
function solve_color_by_pieces($color, $solution, $used_towers, $continue_colors = false, $top = false) {
global $colors, $cube;
$orig = $solution;
$sols = array( );
while (32 >= $color) {
$size = 0;
while (6 >= count(filter_color($used_towers, $color)) && (5 >= $size)) {
if ($color & $used_towers[$size]) {
$size++;
continue;
}
// find ALL possible solutions for this size
for ($pos = 0; $pos < 36; ++$pos) {
if ($size != $cube[floor($pos / 6)][$pos % 6]) {
continue;
}
if ( ! test_color($pos, $solution, $used_towers, $color, $size)) {
continue;
}
// add to this solution path and continue...
$solution[floor($pos / 6)][$pos % 6] = $color;
$used_towers[$size] |= $color;
$return = ((6 > count(filter_color($used_towers, $color))) ? solve_color_by_pieces($color, $solution, $used_towers, $continue_colors) : array('SOLUTION' => $solution));
if ($return) {
$sols[] = $return;
}
// remove this solution and continue searching this level
$solution[floor($pos / 6)][$pos % 6] = false;
$used_towers[$size] ^= $color;
}
break;
}
if ($top) {
unset($sols);
$sols = array( );
}
if ($continue_colors) {
$color << 1;
}
else {
break;
}
}
return $sols;
}
// solve for yellow given the initial piece constraint
$color = 4;
$solution[1][2] = $color;
$size = $cube[1][2];
$used_towers[$size] |= $color;
echo solve_color_by_pieces($color, $solution, $used_towers);
// helper functions
function test_color($pos, $solution, $used_towers, $color, $size) {
if (36 <= $pos) {
return false;
}
// check if piece exists in solution at this location
if (false !== $solution[floor($pos / 6)][$pos % 6]) {
return false;
}
// check if tower of this size and color has already been used
if ($color & $used_towers[$size]) {
return false;
}
// check if tower has already been used in row or column:
for ($i = 0; $i < 6; ++$i) {
if ($color == $solution[floor($pos / 6)][$i]) {
return false;
}
if ($color == $solution[$i][$pos % 6]) {
return false;
}
}
// special conditions for the two special towers
if (array(1, 2) == (array(floor($pos / 6), $pos % 6)) && (4 != $color)) {
return false;
}
if (array(3, 2) == (array(floor($pos / 6), $pos % 6)) && (2 != $color)) {
return false;
}
return true;
}
function filter_color($used, $color) {
foreach ($used as & $row) {
$row = (bool) ($color & $row);
}
unset($row);
return array_filter($used);
}
function find_sols($sols, $color) {
foreach ($sols as $key => $sol) {
if ('SOLUTION' === $key) {
foreach ($sol as $i => $row) {
foreach ($row as $j => $piece) {
if ($color == $piece) {
echo '$solution['.$i.']['.$j.'] = ';
}
}
}
echo "<br>\n";
}
elseif (is_array($sol)) {
find_sols($sol, $color);
}
}
}