返回

JS实现数独游戏的奥秘

前端

数独,一种风靡全球的谜题游戏,考验着智力和推理能力。而今,随着技术的进步,我们可以在JS的数字王国中体验数独的魅力。本文将带领你踏上JS解数独之旅,揭开它背后的神奇算法。

算法的精髓

数独的解题过程本质上是一个约束满足问题(CSP)。CSP将问题建模为一组变量和一系列约束,变量可以取特定值,约束限制变量的取值范围。在数独中,变量是空格,约束是数字1-9。

回溯搜索算法

解决CSP的经典算法之一是回溯搜索。它以深度优先的方式遍历可能的解决方案空间,尝试为每个变量分配一个值。如果分配成功,算法继续递归地解决子问题。如果分配失败,算法回溯到前一步并尝试另一个值。

实现JS解数独

步骤1:创建数独网格

我们首先创建一个9x9的二维数组来表示数独网格。每个单元格的初始值为空字符串(""),表示空格。

const grid = new Array(9).fill("").map(() => new Array(9).fill(""));

步骤2:加载数独谜题

下一步是加载数独谜题,它可以是一个预定义的谜题或用户输入。我们将使用一个二位数组来表示谜题,其中已知值用数字填充,空格用空字符串表示。

const puzzle = [
  ["5", "3", "", "", "7", "", "", "", ""],
  ["6", "", "", "1", "9", "5", "", "", ""],
  ["", "9", "8", "", "", "", "", "6", ""],
  ["8", "", "", "", "6", "", "", "", "3"],
  ["4", "", "", "8", "", "3", "", "", "1"],
  ["7", "", "", "", "2", "", "", "", "6"],
  ["", "6", "", "", "", "", "2", "8", ""],
  ["", "", "", "4", "1", "9", "", "", "5"],
  ["", "", "", "", "8", "", "", "7", "9"],
];

步骤3:填充已知值

我们遍历数独谜题,将已知值填充到JS网格中。

for (let i = 0; i < 9; i++) {
  for (let j = 0; j < 9; j++) {
    if (puzzle[i][j] !== "") {
      grid[i][j] = parseInt(puzzle[i][j]);
    }
  }
}

步骤4:使用回溯算法解决谜题

function solveSudoku(grid) {
  // 找到第一个空格
  let row, col;
  for (row = 0; row < 9; row++) {
    for (col = 0; col < 9; col++) {
      if (grid[row][col] === "") {
        break;
      }
    }
    if (row < 9) break;
  }

  // 如果没有空格,则数独已解决
  if (row === 9) return true;

  // 尝试所有可能的数字
  for (let value = 1; value <= 9; value++) {
    // 如果数字合法,则填充并尝试解决子问题
    if (isValid(grid, row, col, value)) {
      grid[row][col] = value;
      if (solveSudoku(grid)) return true;
      grid[row][col] = ""; // 回溯
    }
  }

  return false; // 无法解决
}

步骤5:验证数字是否合法

function isValid(grid, row, col, value) {
  // 检查行
  for (let i = 0; i < 9; i++) {
    if (grid[row][i] === value) return false;
  }

  // 检查列
  for (let i = 0; i < 9; i++) {
    if (grid[i][col] === value) return false;
  }

  // 检查3x3方块
  const blockRow = Math.floor(row / 3) * 3;
  const blockCol = Math.floor(col / 3) * 3;
  for (let i = blockRow; i < blockRow + 3; i++) {
    for (let j = blockCol; j < blockCol + 3; j++) {
      if (grid[i][j] === value) return false;
    }
  }

  return true;
}

步骤6:打印解题结果

if (solveSudoku(grid)) {
  console.table(grid);
} else {
  console.log("数独无法解决");
}

总结

通过将数独问题建模为约束满足问题并应用回溯搜索算法,我们成功实现了JS中的数独解题程序。这项技术不仅体现了编程的艺术,还展示了解决复杂问题的算法之美。

享受JS数独之旅,用你的智慧破解每一个谜题!