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; }
发表评论 取消回复