php生成数独和判断数独是否是合理的数独,并给出解决方案:
php
<?php
namespace numbers;
require "SudokuGenerator.php";
class SudokuSolve
{
/**
* 解数独
* @param String[][] $board
* @return NULL
*/
public function solveSudoku(&$board)
{
if (count($board) != 9 || count($board[0]) != 9) return false;
//初始化
$rows = $columns = $blocks = [];
$nums = array_flip(range(1, 9));
for ($i = 0; $i < 9; $i++) {
$rows[$i] = $nums;
$columns[$i] = $nums;
$blocks[$i] = $nums;
}
//收集需要填数的位置
$empty = [];
for ($i = 0; $i < 9; $i++) {
for ($j = 0; $j < 9; $j++) {
if ($board[$i][$j] != '.') {
$num = $board[$i][$j];
$b = intval($i / 3) * 3 + intval($j / 3);
unset($rows[$i][$num], $columns[$j][$num], $blocks[$b][$num]);
} else {
$empty[] = [$i, $j];
}
}
}
return $this->backtrack($board, $empty, $rows, $columns, $blocks);
}
private function backtrack(&$board, $empty, $rows, $columns, $blocks, $index = 0)
{
if ($index == count($empty)) {
return true;
}
[$i, $j] = $empty[$index];
$b = intval($i / 3) * 3 + intval($j / 3);
$nums = array_intersect(array_keys($rows[$i]), array_keys($columns[$j]), array_keys($blocks[$b]));
foreach ($nums as $num) {
unset($rows[$i][$num], $columns[$j][$num], $blocks[$b][$num]);
$board[$i][$j] = (int)$num;
if ($this->backtrack($board, $empty, $rows, $columns, $blocks, $index + 1))
return true;
$rows[$i][$num] = $num;
$columns[$j][$num] = $num;
$blocks[$b][$num] = $num;
}
return false;
}
// 对前端传来的数独结果进行检测
public function isValidSudoku($board)
{
$rows = array_fill(0, 9, array_fill(0, 9, false));
$columns = array_fill(0, 9, array_fill(0, 9, false));
$subBoxes = array_fill(0, 3, array_fill(0, 3, array_fill(0, 9, false)));
foreach ($board as $i => $row) {
foreach ($row as $j => $c) {
if ($c !== 0) {
$index = ord($c) - ord('1');
if ($rows[$i][$index] || $columns[$j][$index] || $subBoxes[$i / 3][$j / 3][$index]) {
return false;
}
$rows[$i][$index] = true;
$columns[$j][$index] = true;
$subBoxes[$i / 3][$j / 3][$index] = true;
}
}
}
return true;
}
}
$solution = new SudokuSolve();
$board =
// [["5", "3", 0, 0, "7", 0, 0, 0, 0], ["6", 0, 0, "1", "9", "5", 0, 0, 0], [0, "9", "8", 0, 0, 0, 0, "6", 0], ["8", 0, 0, 0, "6", 0, 0, 0, "3"], ["4", 0, 0, "8", 0, "3", 0, 0, "1"], ["7", 0, 0, 0, "2", 0, 0, 0, "6"], [0, "6", 0, 0, 0, 0, "2", "8", 0], [0, 0, 0, "4", "1", "9", 0, 0, "5"], [0, 0, 0, 0, "8", 0, 0, "7", "9"]];
// $board = [[4, 7, 0, 3, 9, 1, 5, 6, 2], [0, 0, 0, 0, 5, 6, 4, 1, 7], [6, 1, 0, 4, 7, 2, 9, 8, 3], [0, 0, 6, 2, 0, 3, 1, 7, 0], [8, 2, 1, 7, 6, 0, 0, 9, 4], [3, 5, 7, 1, 4, 9, 0, 2, 0], [1, 9, 4, 5, 2, 0, 6, 3, 8], [7, 8, 0, 6, 1, 4, 2, 0, 9], [0, 6, 2, 9, 0, 0, 0, 4, 1]];
$sudokuGenerator = new SudokuGenerator();
$sudoku = $sudokuGenerator->generateSudoku();
$board = $sudokuGenerator->removeNumbers(60); // 难度级别,可以调整,越大越难
var_dump(json_encode($board, 320));
$isValidSudoku = $solution->isValidSudoku($board);
if (!$isValidSudoku) {
echo '数独不合法!';
die();
}
echo '数独合法!解答如下:';
$solution->solveSudoku($board);
// 数独结果
var_dump(json_encode($board, 320));