js 数独生成算法

原文链接: js 数独生成算法

上一篇: 表驱动编程

下一篇: webstorm ts学习环境

生成任意空格的数独,但是由于其确定解的条件是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()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值