class Sudoku
{
public $data = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
];
public $sudoku_map = [];
public $stacks = [];
public $resolved = false;
public $data_map = [];
public $orders = [];
public $current_order = 0;
public $steep_count = 0;
public $max_count = 100000;
public function getRandData()
{
try {
for ($i = 0; $i < 9; $i++) {
for ($j = 0; $j < 9; $j++) {
$this->data[$i][$j] = 0;
}
}
$num = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for ($i = 0; $i < 9; $i++) {
$index = random_int(0, count($num) - 1);
$k = random_int(0, 8);
$this->data[$i][$k] = $num[$index];
unset($num[$index]);
$num = array_values($num);
}
$this->data = Common::rotateArr(random_int(1, 4), $this->data);
foreach ($this->data as $key => $item) {
$this->data[$key] = array_values($item);
}
$this->data = Common::horizontalMirrorArr(random_int(0, 1), $this->data);
$this->data = Common::verticalMirrorArr(random_int(0, 1), $this->data);
$this->init();
foreach ($this->sudoku_map as $key => $item) {
$this->sudoku_map[$key] = array_values($item);
}
$this->sudoku_map = array_values(Common::rotateArr(random_int(1, 4), $this->sudoku_map));
foreach ($this->sudoku_map as $key => $item) {
$this->sudoku_map[$key] = array_values($item);
}
$this->sudoku_map = Common::horizontalMirrorArr(random_int(0, 1), $this->sudoku_map);
$this->sudoku_map = Common::verticalMirrorArr(random_int(0, 1), $this->sudoku_map);
} catch (\Exception $e) {
}
return $this->sudoku_map;
}
public function init()
{
$this->sudoku_map = $this->data;
$this->stacks = [];
$this->resolved = false;
$this->data_map = [];
$this->orders = [];
$this->current_order = 0;
$this->steep_count = 0;
for ($i = 0; $i < 9; $i++) {
for ($j = 0; $j < 9; $j++) {
$node = $this->sudoku_map[$i][$j];
if ($node === 0) {
$this->testMayFill($i, $j);
}
}
}
$data = [];
foreach ($this->data_map as $key => $value) {
$data[] = [
'x' => explode('-', $key)[0],
'y' => explode('-', $key)[1],
'value' => $value
];
}
$this->orders = $data;
$this->start();
}
public function start()
{
$this->stacks[] = $this->getFirstPoint();
while ($this->resolved === false) {
$this->steep_count++;
if ($this->steep_count > $this->max_count) {
$this->resolved = true;
return;
}
$c_stack = $this->stacks[count($this->stacks) - 1];
if ($c_stack['x'] === -1 && $c_stack['y'] === -1) {
$this->resolved = true;
return;
}
$valid = $this->testRules($c_stack);
if ($valid) {
$this->sudoku_map[$c_stack['x']][$c_stack['y']] = $c_stack['value'];
$this->stacks[] = $this->getNextPoint();
} else {
$this->rollback();
}
usleep(100);
}
}
public function rollback()
{
$current_stack = array_pop($this->stacks);
$this->sudoku_map[$current_stack['x']][$current_stack['y']] = 0;
$cOrder = $this->orders[$this->current_order];
if ($current_stack['value'] === $cOrder['value'][count($cOrder['value']) - 1]) {
$this->current_order--;
$this->rollback();
} else {
$order_index = array_search($current_stack['value'], $cOrder['value']);
$current_stack['value'] = $cOrder['value'][$order_index + 1];
$this->stacks[] = $current_stack;
}
}
public function getNextPoint()
{
$ret = [
'x' => -1,
'y' => -1,
'value' => 1
];
$this->current_order++;
$next_value = isset($this->orders[$this->current_order]) ? $this->orders[$this->current_order] : '';
if (!$next_value) {
$this->resolved = true;
return $ret;
}
$ret['x'] = $next_value['x'];
$ret['y'] = $next_value['y'];
$ret['value'] = $next_value['value'][0];
return $ret;
}
public function testRules($stack)
{
$x = $stack['x'];
$y = $stack['y'];
$val = $stack['value'];
$ret = true;
for ($i = 0; $i < 9; $i++) {
$node = $this->sudoku_map[$i][$y];
if ($node === $val) {
return false;
}
}
for ($j = 0; $j < 9; $j++) {
$node = $this->sudoku_map[$x][$j];
if ($node === $val) {
return false;
}
}
$startX = floor($x / 3) * 3;
$startY = floor($y / 3) * 3;
for ($i = $startX; $i < $startX + 3; $i++) {
for ($j = $startY; $j < $startY + 3; $j++) {
$node = $this->sudoku_map[$i][$j];
if ($node === $val) {
return false;
}
}
}
return $ret;
}
public function getFirstPoint()
{
$ret = [
'x' => $this->orders[0]['x'],
'y' => $this->orders[0]['y'],
'value' => $this->orders[0]['value'][0]
];
return $ret;
}
public function testMayFill($x, $y)
{
$may_fill_number = [1, 2, 3, 4, 5, 6, 7, 8, 9];
shuffle($may_fill_number);
for ($i = 0; $i < 9; $i++) {
$node = $this->sudoku_map[$i][$y];
if (in_array($node, $may_fill_number)) {
unset($may_fill_number[array_search($node, $may_fill_number)]);
$may_fill_number = array_values($may_fill_number);
}
}
for ($i = 0; $i < 9; $i++) {
$node = $this->sudoku_map[$x][$i];
if (in_array($node, $may_fill_number)) {
unset($may_fill_number[array_search($node, $may_fill_number)]);
$may_fill_number = array_values($may_fill_number);
}
}
$startX = floor($x / 3) * 3;
$startY = floor($y / 3) * 3;
for ($i = $startX; $i < $startX + 3; $i++) {
for ($j = $startY; $j < $startY + 3; $j++) {
$node = $this->sudoku_map[$i][$j];
if (in_array($node, $may_fill_number)) {
unset($may_fill_number[array_search($node, $may_fill_number)]);
$may_fill_number = array_values($may_fill_number);
}
}
}
$this->data_map[$x . '-' . $y] = $may_fill_number;
}
}
旋转数组
public static function rotateArr($count, $data)
{
for ($i = 0; $i < $count; $i++) {
$actual_data = [];
for ($j = 0; $j < count($data); $j++) {
for ($k = count($data[$j]) - 1; $k >= 0; $k--) {
if (!isset($actual_data[$k])) {
$actual_data[$k] = [];
}
$actual_data[$k][count($data[$j]) - 1 - $j] = $data[$j][$k];
}
}
$data = $actual_data;
}
foreach ($data as $key => $item) {
ksort($item);
$data[$key] = $item;
}
ksort($data);
return $data;
}
镜像数组
public static function verticalMirrorArr($count, $data) {
$actual_data = $data;
for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j <= count($data) / 2; $j ++) {
$actual_data[$j] = $data[count($data) - 1 - $j];
$actual_data[count($data) - 1 - $j] = $data[$j];
}
$data = $actual_data;
}
return $actual_data;
}
public static function horizontalMirrorArr($count, $data) {
$data = self::rotateArr(3, $data);
$data = self::verticalMirrorArr(1, $data);
$data = self::rotateArr(1, $data);
foreach ($data as $key => $item) {
$data[$key] = array_values($item);
}
return $data;
}

发表评论 取消回复