生成任意空格的数独,但是由于其确定解的条件是17个提示数以上,我们指定提示数为20到35之间
算法思路
依次使用dfs进行填空,将所有不合法的数字去除后随机选择
使用变化的概率值来确定是否该空需要被填充,概率值为需要的提示数个数除以剩余的格子
这样可以保证一定可以填充到该数目的提示数且有一定的随机性
当提示数填充完毕后即结束
结果
[
[0, 0, 0, 9, 5, 0, 1, 0, 0],
[0, 7, 8, 0, 6, 0, 0, 0, 4],
[0, 0, 0, 0, 0, 0, 0, 5, 0],
[0, 0, 7, 0, 9, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 5],
[0, 5, 0, 6, 0, 0, 0, 7, 0],
[0, 0, 9, 0, 0, 4, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 5, 0, 0]
]
使用之前的算法求解
2,3,4,9,5,7,1,6,8
5,7,8,1,6,2,3,9,4
1,9,6,3,4,8,7,5,2
3,4,7,2,9,5,6,8,1
9,8,5,4,1,6,2,3,7
6,1,2,7,8,3,9,4,5
8,5,1,6,2,9,4,7,3
7,2,9,5,3,4,8,1,6
4,6,3,8,7,1,5,2,9
const {cloneDeep, random} = require('lodash')
// 填充数字,或者对象的拷贝
function getM(n = 9, val = 0) {
return Array(n).fill().map(
() => Array(n).fill().map(
() => cloneDeep(val)
)
)
}
// 向m中的x,y位置放入合法数字
function setNum(m, x, y) {
let s = new Set(Array(9).fill().map((_, k) => k + 1))
for (let i = 0; i < 9; i++) {
s.delete(m[i][y])
s.delete(m[x][i])
}
// 去除九宫格中的重复数
let stx = Math.floor(x / 3) * 3// 左上角x
let sty = Math.floor(y / 3) * 3// 左上角y
for (let i = 0; i < 3; i++)
for (let j = 0; j < 3; j++) {
let nx = stx + i
let ny = sty + j
s.delete(m[nx][ny])
}
let list = [...s]
let index = random(0, list.length - 1)
m[x][y] = list[index]
console.log('set', x, y, m[x][y])
}
// 向m中的x,y 位置填充数据,可以填充的数字个数为num
function dfs(m, x, y, num) {
console.log('dfs', x, y)
if (num === 0 || x > 8) {
return
}
// 该格子放数字的概率
let blank = 81 - (x * 9 + y)
let p = num / blank
console.log(p, num, blank, x, y)
if (Math.random() <= p) {
// 放入数字
setNum(m, x, y)
num--
}
if (y === 8)
x++, y = 0
else y++
dfs(m, x, y, num)
}
function fill(n) {
let m = getM(9)
dfs(m, 0, 0, n)
return m
}
function toStr(m) {
let rows = m.map(x => x.join(','))
return rows.join('n')
}
function main() {
let n = random(20, 35)
let m = fill(n)
// console.log(m)
console.log(toStr(m))
}
// for (let i = 0; i < 10; i++) {
// console.log(random(1, 9))
// }
main()
来源:oschina
链接:https://my.oschina.net/ahaoboy/blog/4296471