解数独
let board = [
["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"]
]
const startTime = Date.now()
const lastPoint = getLastPointIndex()
// 校验
function verify (row, col, val) {
// 校验横竖轴
for (let i = 0; i < 9; i++) {
if (board[i][col] === val || board[row][i] === val) {
return false
}
}
// 校验3*3
const rect9RowIndex = row / 3 | 0
const rect9ColIndex = col / 3 | 0
for (let i= 0; i < 3; i++) {
for (let r= 0; r < 3; r++) {
const currntVal = board[rect9RowIndex * 3 + i][rect9ColIndex * 3 + r]
if (currntVal === val) return false
}
}
return true
}
// 主运行函数
function solveSudoku (current) {
// console.log('curr:', current)
let i = current / 9 | 0
let r = current % 9
if (current === lastPoint + 1) {
console.log('time:', Date.now() - startTime)
// console.log('board:', board)
return true
}
if (board[i][r] !== '.') return solveSudoku(current + 1)
for (let item = 1; item < 10; item++) {
if (verify(i, r, item + '')) {
board[i][r] = item + ''
if (solveSudoku(current + 1)) return true
board[i][r] = '.'
}
}
}
// 获取最后一个点的下标
function getLastPointIndex () {
const boardArr = board.flat()
const last = boardArr.lastIndexOf('.')
console.log('last:', last)
return last
}
solveSudoku(0)
生成九宫格的思路
- 先在上面的1、5、9(3*3)框内填写1-9的随机数
- 再使用回溯法填写其他的空格
// 生成9*9宫格题目
const totalArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
let board = []
for (let i = 0; i < 9; i ++) {
board.push([])
for (let r = 0; r < 9; r++) {
board[i].push('.')
}
}
// 校验
function verify (row, col, val) {
// 校验横竖轴
for (let i = 0; i < 9; i++) {
if (board[i][col] === val || board[row][i] === val) {
return false
}
}
// 校验3*3宫格
const rect9RowIndex = row / 3 | 0
const rect9ColIndex = col / 3 | 0
for (let i= 0; i < 3; i++) {
for (let r= 0; r < 3; r++) {
const currntVal = board[rect9RowIndex * 3 + i][rect9ColIndex * 3 + r]
if (currntVal === val) return false
}
}
return true
}
// 先设置三个3*3数独值
function firstSetValue (rowIndex, colIndex) {
const rect9RowIndex = rowIndex / 3 | 0
const rect9ColIndex = colIndex / 3 | 0
const totalArr = shuffle(['1', '2', '3', '4', '5', '6', '7', '8', '9'])
for (let i= 0; i < 3; i++) {
for (let r= 0; r < 3; r++) {
board[rect9RowIndex * 3 + i][rect9ColIndex * 3 + r] = totalArr.pop()
}
}
}
// 洗牌法打乱一个数组
function shuffle (array) {
var m = array.length,
t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
// 主程序
function main (current) {
let i = current / 9 | 0
let r = current % 9
if (current === 81) {
console.log('time:', Date.now() - startTime)
console.log('board:', board)
return true
}
if (board[i][r] !== '.') return main(current + 1)
for (let item = 1; item < 10; item++) {
if (verify(i, r, item + '')) {
board[i][r] = item + ''
if (main(current + 1)) return true
board[i][r] = '.'
}
}
}
// 先在上面的1、5、9(3*3)框内填写1-9的随机数
[0, 3, 6].forEach(item => {
firstSetValue(item, item)
})
const startTime = Date.now()
main(0)