php生成和解决数独

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));
相关推荐
茉莉玫瑰花茶3 分钟前
GO [ 并发 · 调度器 ]
开发语言·后端·golang
zhangzeyuaaa3 分钟前
深入理解 Ruby 可变对象与不可变对象的原理、坑点与最佳实践
开发语言·后端·ruby
新鲜势力呀38 分钟前
PHP 实战:第三方接口经常超时怎么办?从API调用优化到服务稳定性完整方案
开发语言·php
艾莉丝努力练剑42 分钟前
【AI大模型接入SDK】ChatSDK:CMake构建静态库完整实现
java·开发语言·网络·c++·人工智能·学习·sdk
haerapi44 分钟前
仓库拣货路线不只靠最短边:S 形启发式的反例记录
android·开发语言·javascript
时间的拾荒人1 小时前
Qt 显示类控件详解:从 QLabel 到 QCalendarWidget 的实战指南
开发语言·qt·面试
.道阻且长.1 小时前
C++11 :右值引用的作用,引用折叠和完美转发
java·开发语言·c++
code2cat1 小时前
Java进阶篇之StampedLock:先读取,再校验,必要时退回读锁
java·开发语言
阿里嘎多学长1 小时前
2026-09-30 GitHub 热点项目精选
开发语言·程序员·github·代码托管