js的数独游戏(dfs)

const col = {}; //缓存列

const box = {}; //缓存块

//以上三个缓存用来排除,并且持续维护,每个里面有至多9个栈

//初始化一个拷贝二维数组

const cb = new Array(N).fill(0).map(© => new Array(N).fill(D));

//初始化字符串1-9的枚举

const emnu = new Array(N).fill(0).map((c, i) => i + 1 + “”);

//封装一个根据坐标转化成第k块的函数

const getk = (i, j) => (((i / 3) | 0) * 3 + j / 3) | 0;

//fx函数用来获取拷贝二维数组或者单元格的排除数组

const fx = (i, j) => {

//如果本来九宫格有数字就用它,没有则说明是需要填的

if (cb[i][j][0] !== D) return cb[i][j];

//过滤得到单元格可能出现的数字

return emnu.filter((item) => filter(i, j, item));

};

//用于判断一个数字是否在缓存中,不在就返回true

const filter = (i, j, item) => {

//k就是计算得到的第k块

let k = getk(i, j);

if ((row[i] || []).indexOf(item) > -1) return false;

if ((col[j] || []).indexOf(item) > -1) return false;

if ((box[k] || []).indexOf(item) > -1) return false;

return true;

}

//添加一个数字到缓存

const add = (i, j, cur) => {

let k = getk(i, j);

row[i] ? row[i].push(cur) : (row[i] = [cur]);

col[j] ? col[j].push(cur) : (col[j] = [cur]);

box[k] ? box[k].push(cur) : (box[k] = [cur]);

};

//如果这个数字不能用,不好意思只能弹出,不能影响接下来的判断

const pop = (i, j) => {

let k = getk(i, j);

row[i].pop();

col[j].pop();

box[k].pop();

};

//以上都是函数和初始化

//下面开始才是运行流程

//先便利原二维数组,得到缓存row、col、box、cb,如果是’.‘就给个[’.']

let start = 0; //start优化开始跳过最开始的一串原始数字

let first = true; //用来判断是否经历过空单元格

for (let i = 0; i < N; i++) {

for (let j = 0; j < N; j++) {

let cur = board[i][j];

if (first) start = i * N + j;

if (cur !== D) {

if (!filter(i, j, cur)) return(‘不是有效数独’)

add(i, j, cur)

cb[i][j] = [cur];

} else {

first = false;

cb[i][j] = [D];

}

}

}

//深度递归函数,以index序号0-80为递归依据

//每个单元格根据fx函数拿到nums数组

const dfs = (index) => {

//根据序号拿到坐标值

let [x, y] = [(index / N) | 0, index % N | 0];

const nums = fx(x, y);

//nums返回的数组可能长度为0、1、或者多个,要么来源于初始,要么来源于cb

//如果是0说明已经没有选择了(题目中表示一定有唯一解,所以可以忽略)

//如果是1说明只能选择这个

//进入循环

for (let i = 0; i < nums.length; i++) {

//将这个数字加入缓存排除

add(x, y, nums[i]);

board[x][y] = nums[i];

//如果只有一个数字,到了终点,说明结束了

if (index === N * N - 1 && nums.length === 1) {

success = true;

return true;

}

//如果之后的递归都返回true

if (dfs(index + 1)) return true;

//如果不满足递归正确的条件,则说明现在为止的数字都是不对的

//恢复board的区域并弹出缓存

board[x][y] = cb[x][y][0];

pop(x, y);

}

return false;

};

dfs(start);

if (!success) return ‘对不起,解不出来~~~’

return board;

};

const ax=[

[“5”, “.”, “.”, “.”, “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”],

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值