1,前言
8x8的棋盘,放8个棋子。
各自不能在同一直线上。(水平方向,对角线方向)
在线游玩:https://www.novelgames.com/zh/queens/
2,JS实现
let size = 8
let count = 0
loopTo([], 0)
function loopTo(arr, v) {
if (arr.length === size) {
console.log(++count + "[" + arr.toLocaleString() + "]")
loopBack(arr)
} else if (canPut(arr, v)) {
arr.push(v)
loopTo(arr, 0)
} else if (v < size - 1) {
loopTo(arr, v + 1)
} else {
setTimeout(() => {
loopBack(arr)
}, 1)
}
}
function loopBack(arr) {
let v = arr.pop()
while (v !== undefined && v >= size - 1) {
v = arr.pop()
}
if (v === undefined) {
console.log("无解")
} else {
loopTo(arr, v + 1)
}
}
function canPut(arr, v) {
for (let m = 0; m <= arr.length - 1; m++) {
if (arr[m] === v) {
return false
} else if (arr.length - m === v - arr[m]) {
return false
} else if (arr.length - m === arr[m] - v) {
return false
}
}
return true
}
效果:算到92,然后再无其他解。
3,细节实现
验证结果的有效性
比较结果的长度。
两层遍历,比较棋子与之前的所有棋子位置是否符合。
function checkResult(arr) {
if (arr.length !== size) {
return false
}
for (let i = 1; i < size; i++) {
for (let j = 0; j < i; j++) {
if (arr[i] === arr[j]) {
return false
} else if (Math.abs(i - j) === Math.abs(arr[i] - arr[j])) {
return false
}
}
}
return true
}
验证是否可以加入数组
位置符合就true,不符合false。
function canPut(arr, v) {
for (let m = 0; m <= arr.length - 1; m++) {
if (arr[m] === v) {
return false
} else if (Math.abs(arr.length - m) === Math.abs(v - arr[m])) {
return false
}
}
return true
}
回退
如果到了最大值还不满足,就会回退。
没元素说明无解。
栈顶元素大小到了最大值,继续回退。
否则就加一,重新尝试。
扫描二维码关注公众号,回复:
13759851 查看本文章
function loopBack(arr) {
if (arr.length === 0) {
console.log("无解")
return
}
let v = arr.pop()
if (v >= size - 1) {
loopBack(arr)
} else {
loopTo(arr, v + 1)
}
}
主循环
加定时器是为了避免堆栈溢出。。。
(奇怪的用途增加了!)
如果长度足够,就说明已经放满了。
输出,然后回退。
如果能入,就入。然后继续。
如果不能入,判断值,太大了就回退,不大就加一。
function loopTo(arr, v) {
setTimeout(() => {
if (arr.length === size) {
console.log(++count + "[" + arr.toLocaleString() + "]" + checkResult(arr))
loopBack(arr)
} else if (canPut(arr, v)) {
arr.push(v)
loopTo(arr, 0)
} else if (v < size - 1) {
loopTo(arr, v + 1)
} else {
loopBack(arr)
}
}, 1)
}
番外:更多皇后
九皇后。