当前位置: 首页 > 知识库问答 >
问题:

javascript中的数独求解器回溯

郑帅
2023-03-14

我试图使用回溯在JavaScript中创建一个数独求解器,我做了一些研究,看到了类似的问题,但我的方法不同;而且没用。

var grid = [ // Empty grid to test the solver
            [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]
           ];
var invalid = [ // Here go additional invalid numbers
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
               [[],[],[],[],[],[],[],[],[]],
              ];

function sudokuSolver() { // The solver function
    for (var r = 0; r < 9; r++) { // For each row
        for (var c = 0; c < 9; c++) { // For each column
            for (var n = 1; n < 11; n++) { // For each number + 10
                if (n == 10) { // If no solutions were found for the current cell, backtrack.
                    if (c == 0) { // If at left-most position
                        var x = grid[--r][8]; // Assign the number in the previous cell to "x". Decremented "r" because the previous cell is in the previous row, and the number in it should be changed
                        invalid[r+1][0] = []; // Reset invalid numbers for current cell
                        invalid[r][8].push(x); // Mark "x" as invalid in the previous cell
                        c = 7; // The number in the previous cell should be changed, the previous cell is in column 8, the loop increments each time the code block is executed, so c here should hold 8 - 1 = 7
                    } else { // Same goal here
                        var x = grid[r][--c]; 
                        invalid[r][c+1] = [];
                        invalid[r][c].push(x);
                        c--;
                    }
                    break;
                } else if (isValid(r, c, n)) {
                    grid[r][c] = n; // If n is valid, put it
                    console.log(r + ',' + c + ',' + n);
                    break; // And break the loop (it won't reach n = 10)
                }
            }
        }
    }

    // Print the solution
    for (var r = 0; r < 9; r++) {
        for (var c = 0; c < 9; c++) {
            document.getElementById('sudoku').getElementsByTagName('tr')[r].getElementsByTagName('td')[c].innerHTML = grid[r][c];
        }
    }
}

function isValid(r,c,n) {
    var a;
    var b = true;
    var col = '';
    for (var i = 0; i < 9; i++) {
        col += grid[i][c];
    }
    var sec = '';
    for (var lr = 3 * Math.floor(r / 3); lr < 3 * Math.floor(r / 3) + 3; lr++) {
        for (var lc = 3 * Math.floor(c / 3); lc < 3 * Math.floor(c / 3) + 3; lc++) {
            sec += grid[lr][lc];
        }
    }
    a = (grid[r].toString().indexOf(n) == -1 && col.indexOf(n) == -1 && sec.indexOf(n) == -1);
    for (var i = 0; i < invalid[r][c].length; i++) {
        if (n == invalid[r][c][i]) b = false; break;
    }
    return (a && b);
}

使用它,浏览器停止响应,然后询问是否停止脚本。

控制台中,我得到:1,5,7 1,6,3 1,5,7 1,6,3...

有什么问题的线索吗?

if (n == invalid[r][c][i]) b = false; break;
if (n == invalid[r][c][i]) {b = false; break;}

共有1个答案

卓麒
2023-03-14

你有一个无限循环

for (var c = 0; c < 9; c++) {…}

退出循环的唯一方法是使c>=9。通常,当C++最终使其递增时,就会发生这种情况。但是,当n==10时,逻辑将始终执行某种递减(--C--C=7),以防止C达到9

因此,当引入n==10代码分支时,c的递减对于管理c的for循环的每一次迭代都会发生一次,因为递减是c=7c=C-2,它不会到达9并结束循环。

答案是不要改变循环内的值。重构代码以管理RCN,就好像它们在for循环块中是不可变的一样。然后对块中的这些值执行计算,以找到执行业务逻辑所需的值。也许是制造中间变量来存储中间值。

另一个很大的帮助是将逻辑的每个部分分解成函数。这样做可以帮助您抽象复杂度,这样可以帮助您集中精力,而且由于它们是函数,它们可以是确定性的。意味着您所投入的内容将产生可预测的输出。然后,这只是一个问题,组成的功能,在顺序和希望执行业务逻辑。

 类似资料:
  • 由于缺乏信息,我在这里锁定了最后一个问题,现在我将尝试进一步解释,以消除混淆。 好的,先离开,获取一些关于我正在做什么的背景信息<我开始了一个制作数独游戏的个人项目,学习面向对象编程、数组列表、算法、模型/控制/设计层,并扩展我的编程知识<我在制作这个游戏方面已经走了很长的路,它即将完成,但我遇到了一个需要帮助解决的小问题。 当我生成3个数独,一个简单,一个中等和一个困难时,我遇到了问题。 简单和

  • 我正在用Java构建一个数独求解器,我正在使用回溯算法。有一个堆栈溢出错误,我怀疑在我的代码中有无限递归。我知道我提供的信息很少,但我太难了,不知道该怎么做。 网格是一个9乘9的数组,表示每个数独平方,它保存一个名为“value”的自定义类型,该类型简单地包含一个整数和一个布尔值,“IsOriginal”指示该值是给定的还是可更改的。 “moveon”是一个全局变量,它的值在“checkall”中

  • 问题内容: 我创建了一个Sudoku Backtracking解算器,并且效果很好,但是现在我想给出一个错误,如果该数独无法解决,因为它是无效的,例如如果给出了这个数独: http://img5.imageshack.us/img5/2241/sudokugq.jpg 如果无法解决,我该怎么办才能使我的解决方法出错?我总是以零结束或陷入循环。 问题答案: 当然,当您触及代码时,您刚刚尝试了平方中的

  • 我正在做一个小的个人数独游戏,并试图扩展它。 到目前为止,我使用递归回溯方法使“Solve”部分正常工作,每当它设法解决递归时,就会返回true。 现在我正在尝试构建一个独特的解决方案板生成器,我在网上找到了很多关于如何实现它的信息。 然而,我在第一步很挣扎,这是我的布尔递归回溯算法变成一个递归算法,它保留了一个可能解决方案的计数。这对于检查我生成的板是否是唯一的至关重要。 更重要的是,我意识到我

  • 我已经在这里寻求帮助,但没有人回答,这真的很令人沮丧,我试图写一个代码,解决递归函数中的数独(回溯),下面是代码: 它不是真正的代码(只是因为UI现在不重要)。所以我在这里所做的是,每次它改变任何单元格时,都打印板子。当它试图解决一个错误时,我看到了一个错误,当它到达第2行col:6单元格(在索引its[1][5])时,它跳过了数字1(这是真正的答案),因为它没有尝试一个,它不能解决数独的其余部分

  • 我正在为迷宫[30][30]编写查找路径解决方案,我在路径查找函数中使用了回溯;以下是伪代码: 找到起始点然后运行该点的函数 将房间标记为已参观 终止条件1:如果,在路径上标记,然后返回true 递归部分:搜索8个邻居:西部、西北部、北部、东北部、东部、东南部、南部、西南部。检查房间是否可访问,然后调用find_path函数,如果返回true,则在find path上标记 终止条件2:返回fals