我正在尝试使用回溯在JavaScript中编写一个Sudoku求解器,我做了一些研究,看到了类似的问题,但我的方法不同;它不起作用。
这是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);
}
没有if (n == 10) { // Code }
它做了预期的事。
有了它,浏览器停止响应,然后询问是否停止脚本。
在控制台中,我得到:
1,5,7
1,6,3
1,5,7
1,6,3
...
任何有关错误的线索?
这是个主意:
(I)在当前单元格中尝试“1”,如果它有效,则将其放入网格数组并继续下一个单元格,否则,尝试“2”并再次检查,然后“3”如果“2”是无效等...如果找到有效数字,将其放入网格并继续进入下一个单元格,如果没有有效数字(达到10),清除当前单元格的无效数字(如果有),请在前一个单元格在那里无效(不会导致解决方案),然后去那里(回溯)。
(II)重复(I)直到Sudoku被解决。
if (n == invalid[r][c][i]) b = false; break;
原意是:
if (n == invalid[r][c][i]) {b = false; break;}
答案 0 :(得分:0)
你有一个无限循环
for (var c = 0; c < 9; c++) {…}
退出循环的唯一方法是c >= 9
。通常,当c++
最终递增时,会发生这种情况。但是,当n == 10
时,您的逻辑将始终执行某种减量(--c
,c--
和c = 7
),以防止c
到达{{} 1}}。
因此,当引入9
代码分支时,n == 10
的递减在管理c
的for循环的每次迭代中发生一次,因为递减是c
或c = 7
它不会到达c = c - 2
并结束循环。
答案是不要改变循环内的值。重构代码以管理9
,r
和c
,就好像它们在for循环块中是不可变的一样。然后对块中的这些值执行计算,以查找执行业务逻辑所需的值。也许制作中间变量来存储中间值。
另一个重要的帮助是将逻辑的每个部分分解为函数。这样做可以帮助您抽象复杂性,以帮助您包围,因为它们是功能,它们可以是确定性的。意味着你输入的内容将产生可预测的输出。然后,只需要按顺序编写函数并想要执行业务逻辑。