数独解题器

140 阅读2分钟

说明

用数字1-9填满一个99的矩阵,要求每行和每列有这9个数字构成,矩阵还包含方块(33)的矩阵,他们同样需要分别用这9个数字填满。谜题在开始的时候给出已填了部分的矩阵,如图所示

image.png

例子

使用下面代码进行测试

const sudokuGrid = [
  [5, 3, 0, 0, 7, 0, 0, 0, 0],
  [6, 0, 0, 1, 9, 5, 0, 0, 0],
  [0, 9, 8, 0, 0, 0, 0, 6, 0],
  [8, 0, 0, 0, 6, 0, 0, 0, 3],
  [4, 0, 0, 8, 0, 3, 0, 0, 1],
  [7, 0, 0, 0, 2, 0, 0, 0, 6],
  [0, 6, 0, 0, 0, 0, 2, 8, 0],
  [0, 0, 0, 4, 1, 9, 0, 0, 5],
  [0, 0, 0, 0, 8, 0, 0, 7, 9],
];

思路

  1. 在空白(0)的位置使用尝试填入1-9中的每个数字
  2. 如果当前填入的数字符合条件,则尝试填写下一个位置(递归)。如果有一数字填在了不正确的位置,则会将此位置标记为空(0)
  3. 如果当前填入数字不符合条件,尝试下一个数字

代码

function sudokuSolver(matrix) {
  if (solveSudoku(matrix)) {
    return matrix;
  }
  return "数独错误";
}
function solveSudoku(matrix) {
  // 从[0][0]开始,如果位置为空(0)则尝试在此位置填入数字
  let row = 0;
  let col = 0;
  let isBlank = false;
  for (row = 0; row < matrix.length; row++) {
    for (col = 0; col < matrix.length; col++) {
      if (matrix[row][col] === 0) {
        isBlank = true;
        break;
      }
    }
    if (isBlank) {
      break;
    }
  }
  if (!isBlank) {
    return true;
  }
  // 当前位置为空[row][col],尝试填入1-9的数字
  for (let num = 1; num <= 9; num++) {
    // 判断当前数字是否安全
    if (isSafe(row, col, matrix, num)) {
      // 当前数字安全,则递归调用此方法,看下一个位置是否能填入安全的数字
      matrix[row][col] = num;
      if (solveSudoku(matrix)) {
        return true;
      }
      // 如果下一个位置不能填入安全的数字,则证明当前数字有误,重置当前的位置为空(0)
      matrix[row][col] = 0;
    }
  }
  // 这时没有数字是安全的
  return false;
}
// 判断当前数字是否安全
function isSafe(row, col, matrix, num) {
  if (
    !usedInRow(row, matrix, num) &&
    !usedInCol(col, matrix, num) &&
    !usedInBox(row, col, matrix, num)
  ) {
    return true;
  }
  return false;
}
// 使用的数字是否已经在当前行了
function usedInRow(row, matrix, num) {
  return matrix[row].includes(num);
}
// 使用的数字是否已经在当前列了
function usedInCol(col, matrix, num) {
  return matrix.map((row) => row[col]).includes(num);
}
// 使用数字收已经在当前box(3*3)
function usedInBox(row, col, matrix, num) {
  const rowIndex = Math.floor(row / 3);
  const colIndex = Math.floor(col / 3);
  return matrix
    .slice(rowIndex*3, 3)
    .map((row) => row.slice(colIndex*3, 3))
    .flat()
    .includes(num);
}

const sudokuGrid = [  [5, 3, 0, 0, 7, 0, 0, 0, 0],
  [6, 0, 0, 1, 9, 5, 0, 0, 0],
  [0, 9, 8, 0, 0, 0, 0, 6, 0],
  [8, 0, 0, 0, 6, 0, 0, 0, 3],
  [4, 0, 0, 8, 0, 3, 0, 0, 1],
  [7, 0, 0, 0, 2, 0, 0, 0, 6],
  [0, 6, 0, 0, 0, 0, 2, 8, 0],
  [0, 0, 0, 4, 1, 9, 0, 0, 5],
  [0, 0, 0, 0, 8, 0, 0, 7, 9],
];

console.log(sudokuSolver(sudokuGrid));