数独谜题测试
Sudoku puzzle test
正在尝试编写一个脚本来检查数独谜题是否已正确解决。我尝试使用 2 个周期和测试方法检查每个值,如果测试 return 为真,则将值替换为“0”,但脚本不会替换所有值,我不明白为什么。您能解释一下为什么脚本会替换某些值,而其他值不会吗?
const doneOrNot = (sudoku) => {
const copiedSudoku = JSON.parse(JSON.stringify(sudoku));
console.log(copiedSudoku);
const testNums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const num in copiedSudoku) {
for (const newnum in copiedSudoku[num]) {
const regexp = RegExp(`${testNums[newnum]}`);
if (regexp.test(copiedSudoku[num])) {
copiedSudoku[num][newnum] = 0;
}
}
}
return copiedSudoku;
};
console.log(doneOrNot(
[[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]],
));
but script does not replace all the values and I don't understand why.
发生这种情况是因为您的代码在当前行中查找列号作为值,但该值可能已更改为 0,因此没有匹配项,并且当前值不会被替换0.
在您的示例中,这发生在第一行,此时内部循环处于第 3 次迭代。然后newnum
等于2,此时当前数独行copiedSudoku[num]
看起来像这样:
[0, 0, 4, 6, 7, 8, 9, 1, 2]
如你所见,内循环的前两次迭代放置了一个零,但现在 testNums[newnum]
是 3,并且该数字已经被删除,因此 test
方法调用将 return false,所以4没有被清除。
问题
对该算法的主要评论是,应该没有必要 修改 给定数独中的任何内容。该算法应该查找并计算。
创建一个正则表达式只是为了找到一个数字是大材小用。为此,您可以使用 include
数组方法。
.test
RegExp 方法需要一个字符串作为参数,但您向它传递了一个数组。这意味着数组被转换为 comma-separated 字符串,因此它仍然可以工作,但当然不建议这样做。
在 数组 上使用 for..in
循环不是好的做法。如果您对数组中的值感兴趣,请使用 for..of
循环。
正如您的函数名称暗示的布尔值return,它不应该return 数独,而是用 true 或 false 表示成功。
Read-only解决方案
如前所述,应该不需要放置零。这无助于实现您的目标。
const hasAllDigits = arr =>
arr.reduce((acc, digit) => acc | (1 << digit), 0) == 0x3FE;
const doneOrNot = (sudoku) => {
for (let i = 0; i < 9; i+=3) {
for (let j = 0; j < 3; j++) {
let k = i + j;
// Check k-th row
if (!hasAllDigits(sudoku[k])) return false;
// Check k-th column
if (!hasAllDigits(sudoku.map(row => row[k]))) return false;
// Check k-th 3x3 box
if (!hasAllDigits(sudoku.slice(j*3, j*3+3)
.flatMap(row => row.slice(i, i + 3)))) return false;
}
}
return true;
};
console.log(doneOrNot(
[[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]],
));
正在尝试编写一个脚本来检查数独谜题是否已正确解决。我尝试使用 2 个周期和测试方法检查每个值,如果测试 return 为真,则将值替换为“0”,但脚本不会替换所有值,我不明白为什么。您能解释一下为什么脚本会替换某些值,而其他值不会吗?
const doneOrNot = (sudoku) => {
const copiedSudoku = JSON.parse(JSON.stringify(sudoku));
console.log(copiedSudoku);
const testNums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const num in copiedSudoku) {
for (const newnum in copiedSudoku[num]) {
const regexp = RegExp(`${testNums[newnum]}`);
if (regexp.test(copiedSudoku[num])) {
copiedSudoku[num][newnum] = 0;
}
}
}
return copiedSudoku;
};
console.log(doneOrNot(
[[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]],
));
but script does not replace all the values and I don't understand why.
发生这种情况是因为您的代码在当前行中查找列号作为值,但该值可能已更改为 0,因此没有匹配项,并且当前值不会被替换0.
在您的示例中,这发生在第一行,此时内部循环处于第 3 次迭代。然后newnum
等于2,此时当前数独行copiedSudoku[num]
看起来像这样:
[0, 0, 4, 6, 7, 8, 9, 1, 2]
如你所见,内循环的前两次迭代放置了一个零,但现在 testNums[newnum]
是 3,并且该数字已经被删除,因此 test
方法调用将 return false,所以4没有被清除。
问题
对该算法的主要评论是,应该没有必要 修改 给定数独中的任何内容。该算法应该查找并计算。
创建一个正则表达式只是为了找到一个数字是大材小用。为此,您可以使用
include
数组方法。.test
RegExp 方法需要一个字符串作为参数,但您向它传递了一个数组。这意味着数组被转换为 comma-separated 字符串,因此它仍然可以工作,但当然不建议这样做。在 数组 上使用
for..in
循环不是好的做法。如果您对数组中的值感兴趣,请使用for..of
循环。正如您的函数名称暗示的布尔值return,它不应该return 数独,而是用 true 或 false 表示成功。
Read-only解决方案
如前所述,应该不需要放置零。这无助于实现您的目标。
const hasAllDigits = arr =>
arr.reduce((acc, digit) => acc | (1 << digit), 0) == 0x3FE;
const doneOrNot = (sudoku) => {
for (let i = 0; i < 9; i+=3) {
for (let j = 0; j < 3; j++) {
let k = i + j;
// Check k-th row
if (!hasAllDigits(sudoku[k])) return false;
// Check k-th column
if (!hasAllDigits(sudoku.map(row => row[k]))) return false;
// Check k-th 3x3 box
if (!hasAllDigits(sudoku.slice(j*3, j*3+3)
.flatMap(row => row.slice(i, i + 3)))) return false;
}
}
return true;
};
console.log(doneOrNot(
[[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]],
));