原创
like 3
无聊一写之旋转矩形算法篇
2020.12.17 12:53
3 人喜欢
764 次阅读
0 条评论
/**
*
* @param {Number} maxFillNum 最大填充数
* @param {Boolean} isSizeEqual 矩形大小是否相同,若相同则当正方形处理,如不相同则按计算出最大填充数最合适的矩形大小
* @param { height: Number, width: Number } sizeObj 矩形大小参数,如不传,则自动计算生成
*/
function rotatingRectangular({
maxFillNum = 100,
isSizeEqual = true,
sizeObj = {}
}) {
let width = 1 // 矩形列数
let height = 1 // 矩形行数
if (sizeObj.height && sizeObj.width) {
width = sizeObj.width
height = sizeObj.height
} else {
while (true) {
if (width * height >= maxFillNum) {
break
}
width++
height++
}
// 计算出最佳的矩形大小
if (!isSizeEqual) {
const suitable = {
w: 0,
h: 0,
v: width * width
}
for (let i = 0; i < width; i++) {
const w = width - i
for (let index = 0; index < width; index++) {
const h = width + i
const result = w * h
if (result >= maxFillNum && result < suitable.v) {
suitable.w = w
suitable.h = h
suitable.v = result
}
}
}
width = suitable.w
height = suitable.h
}
}
// 生成矩形盒子先,使用null填充
const rectangle = new Array(height)
// fill api复制的内容是引用类型的值,是浅拷贝,会出事,需要特殊处理下 转字符串再map转回去即可
.fill(JSON.stringify(new Array(width).fill(null)))
.map(e => JSON.parse(e))
/**
*
* @param {Array} cPosition 当前位置 y,x
* @param {Number} direction 方向,0 = 上, 1 = 下, 2 = 左, 3 = 右
* @param {Number} cNum 当前的数值,一直往前填充
* @description 旋转递归的方向是,右-下-左-上,以此类推至结束递归条件
*/
function rotat(cPosition, direction, cNum) {
let [y, x] = cPosition
if (direction === '右') {
const source = rectangle[y] // 横向,当前行
const notFillSize = source.filter(v => v === null).length
for (let i = 0; i < notFillSize; i++) {
source[x + i] = ++cNum
if (cNum === maxFillNum || cNum === height * width) return
}
x += notFillSize - 1
rotat([y + 1, x], '下', cNum)
} else if (direction === '下') {
let end = 0
// 因为是上/下的原因,需要跳数组形式进行操作,就不用notFillSize形式了,直接循环+判断配合end即可
for (let i = 0; i < height - y; i++) {
if (rectangle[y + i][x] === null) {
rectangle[y + i][x] = ++cNum
end++
}
if (cNum === maxFillNum || cNum === height * width) return
}
y += end - 1
rotat([y, x - 1], '左', cNum)
} else if (direction === '左') {
const source = rectangle[y] // 横向,当前行
const notFillSize = source.filter(v => v === null).length
for (let i = 0; i < notFillSize; i++) {
source[x - i] = ++cNum
if (cNum === maxFillNum || cNum === height * width) return
}
x -= notFillSize - 1
rotat([y + 1, x], '上', cNum)
} else if (direction === '上') {
let end = y
for (let i = y; i > 0; i--) {
if (rectangle[i - 1][x] === null) {
rectangle[i - 1][x] = ++cNum
end--
if (cNum === maxFillNum || cNum === height * width) return
}
}
y = end - 1
rotat([y, x + 1], '右', cNum)
}
}
rotat([0, 0], '右', 0)
return rectangle
}
console.log(
rotatingRectangular({
maxFillNum: 96,
isSizeEqual: false
})
)
console.log(
rotatingRectangular({
maxFillNum: 96,
isSizeEqual: true
})
)
console.log(
rotatingRectangular({
maxFillNum: 96,
isSizeEqual: true,
sizeObj: {
width: 7,
height: 9
}
})
)

