You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript递归生成数独终盘 函数中途停止无报错问题排查

问题根因

你的代码故障和JavaScript递归机制无关,是两处基础的语法使用和变量作用域错误导致回溯逻辑完全失效:

  • 第一处致命错误:你用Array.forEach遍历候选数字列表,但forEach本身不支持中途中断循环,回调函数里写的return true只会跳过当前遍历项,既不会终止整个遍历流程,也不会让forEach本身返回布尔值给外层判断。当递归走到死路需要回退换数时,代码根本不会正确执行回溯,走到走不通的节点就直接停了。
  • 第二处错误:row和col被定义为全局变量,递归调用下层fillGrid的时候,这两个变量的值会被下层循环覆盖,等递归回溯回到上层时,row/col已经不是当前层正在处理的单元格坐标,最后执行grid[row][col] = 0回溯重置的时候,会把之前正确填好的其他单元格清成0,直接打乱整个网格状态。
修复方案
  1. 把forEach遍历换成普通for...of循环,让循环内的return可以正确终止循环、向上层传递布尔返回值,让回溯逻辑正常生效。
  2. 把row、col改成fillGrid函数内部的局部变量,不要用全局声明,避免不同递归层级之间互相覆盖坐标值。
  3. 给fillGrid补全明确返回值:当所有候选数字都试完仍走不通时,返回false通知上层需要回溯换数。
  4. 冗余的宫格判断逻辑可以简化,不用写9个分支提取宫格内容,直接通过坐标计算宫格起始位置做冲突校验即可,减少出错概率。
修复后可直接运行的完整代码
// Fisher-Yates 数组洗牌工具
function shuffle(array) {
    let currentIndex = array.length, randomIndex;
    while (currentIndex != 0) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [array[currentIndex], array[randomIndex]] = [
            array[randomIndex], array[currentIndex]];
    }
    return array;
}

// 初始化9x9空网格
let grid = Array(9).fill().map(() => Array(9).fill(0));
const numberList = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// 检查网格是否填充完成
function checkGrid() {
    for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
            if (grid[i][j] === 0) return false;
        }
    }
    return true;
}

// 核心回溯填充函数
function fillGrid() {
    // 坐标改为函数内局部变量,避免递归层级互相污染
    let row, col;
    for (let i = 0; i < 81; i++) {
        row = Math.floor(i / 9);
        col = i % 9;
        if (grid[row][col] === 0) {
            shuffle(numberList);
            // 替换forEach为普通for循环,支持中断和返回值传递
            for (const v of numberList) {
                // 检查行重复
                if (grid[row].includes(v)) continue;
                // 检查列重复
                let colConflict = false;
                for (let r = 0; r < 9; r++) {
                    if (grid[r][col] === v) {
                        colConflict = true;
                        break;
                    }
                }
                if (colConflict) continue;

                // 定位当前所属3x3宫格,检查宫格重复
                const squareRowStart = Math.floor(row / 3) * 3;
                const squareColStart = Math.floor(col / 3) * 3;
                let squareConflict = false;
                for (let r = squareRowStart; r < squareRowStart + 3; r++) {
                    for (let c = squareColStart; c < squareColStart + 3; c++) {
                        if (grid[r][c] === v) {
                            squareConflict = true;
                            break;
                        }
                    }
                    if (squareConflict) break;
                }
                if (squareConflict) continue;

                // 数值合法,填入单元格
                grid[row][col] = v;
                if (checkGrid()) {
                    return true;
                }
                // 递归填充下一个单元格,返回true说明找到合法解,直接向上传递
                if (fillGrid()) {
                    return true;
                }
                // 递归返回false说明当前值走不通,重置单元格回溯
                grid[row][col] = 0;
            }
            // 所有候选值都试完仍无解,返回false通知上层回溯
            return false;
        }
    }
    return true;
}

// 生成数独终盘并打印
fillGrid();
grid.forEach(row => console.log(row));

内容的提问来源于stack exchange,提问作者jokeriino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:39:30