数独谜题测试

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]],
));