This website requires JavaScript.
原创

无聊一写之旋转矩形算法篇

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
    }
  })
)

  • 😃
  • 😂
  • 😅
  • 😉
  • 😌
  • 😔
  • 😓
  • 😘
  • 😡
  • 😭
  • 😱
  • 😳
  • 😵
  • 🌚
  • 👍
  • 👎
  • 💪
  • 🌹
  • 💊
  • 🇨🇳
  • 🇺🇸