開心消消樂遊戲算法基礎版

消消樂遊戲算法

咱們常常看到各種的消除遊戲,最近玩了兩把消消樂,有想着來理解下其中的規則,市場上主流的是地圖型的,幾乎是無盡模式,各類消除特效,各類各樣的過關方式,玩起來仍是不錯的,就是遇到比較難的關卡,要多試幾回,運氣很是好的時候就過了,否則卡死。 三消涉及到簡單的算法以下所示,我會根據這個搭建一個簡單的消除遊戲:git

  • 隨機生成地圖的算法
  • 遍歷地圖三個或三個以上連着的能夠進行消除
  • 除去元素,上面的元素補下來
  • 涉及道具

因爲篇幅關係,本章只會講解生成地圖的算法,後面我會附上寫好的demo,但願你們能有收穫。github

一.隨機生成地圖的算法

首先遊戲界面有各類各樣的地圖,須要知足如下幾個條件:算法

  • 隨機生成一張地圖,可是不能有三個或三個以上在橫向和縱向一樣。
  • 用戶在移動一步就能造成三個橫向或者縱向可消除

1.1 先隨機生成一個二維的數組

// 生成一個地圖 9 * 9
function productMap(n) {
  const randomMap = []
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      const value = parseInt(Math.random() * 5)
      if (!randomMap[i]) {
        randomMap[i] = []
      }
      randomMap[i].push(value)
    }
  }
  return randomMap
}
productMap(9)
複製代碼

上面的代碼能夠獲得一個隨機的 9*9 的二維數組 當咱們生成一個二維數組後,會發現裏面大機率會出現3個或3個以上在橫向或者縱向連續且同樣的值,這種數組是不知足消消樂的準則之一。數組

1.2 加入不能生成在橫衆方向連續3個或3個以上同樣的值

1.3 最終代碼

//  x方向判斷有沒有連續兩個同色
 if (x > 1 && judgeSameColor(randomMap[y], value)) {
    value = getExceptRandom(value)
}
 //  y方向判斷有沒有連續兩個同色
  if (
    y > 1 &&
    judgeSameColor(getTwoArrColumnByIndex(randomMap, y), value)
  ) {
    value = getExceptRandom(value)
  }
  
  // 判斷是否連續2個同色
function judgeSameColor(arr, value) {
  return arr.find(
    (item, index) =>
      arr[index - 1] && item === value && arr[index - 1] === value
  )
}
// 獲取二維數組某一列的值
function getTwoArrColumnByIndex(arr, n) {
  return arr.map(item => item[n])
}
複製代碼

1.3 判斷生成的二維數組是不是死地圖

死地圖條件:用戶戶移動相鄰的一步,不能造成3個或3個以上連續的 【注意】:若是是死地圖就須要從新生成地圖bash

咱們能夠對相鄰移動一步的狀況進行窮舉以下:dom

  • 第一種:

注意 x 的位置,由於第二排有兩個同樣的連在一塊兒,移動一步就能消除的狀況有不少種方式,左右兩邊各有3種狀況,找到一個這種,就不是死圖了。 ui

  • 第二種:

第二種和第一種相似,只是放到了垂直方向 spa

  • 第三種:

根據上面這些窮舉的狀況,咱們就能夠來寫判斷是不是死圖的代碼了。code

//判斷是不是死圖
function judgeCanRemoveByOneStep(map) {
  const resultStep = []
  let len = map.length
  for (let y = 0; y < len; y++) {
    for (let x = 0; x < len; x++) {
      const currentValue = map[y][x]
      // 考慮橫軸方向
      if (x + 1 < len) {
        // 第一種狀況
        if (map[y][x] === map[y][x + 1]) {
          if (x - 2 >= 0) {
            if (map[y][x - 2] === currentValue) {
              resultStep.push({ y, x })
              resultStep.push({ y, x: x + 1 })
              resultStep.push({ y, x: x - 2 })
              return resultStep
            }
          }
          if (x - 1 >= 0 && y - 1 >= 0 && map[y - 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y - 1, x: x - 1 })
            return resultStep
          }
          if (x + 2 < len && y - 1 > 0 && map[y - 1][x + 2] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y - 1, x: x + 2 })
            return resultStep
          }
          if (x + 3 < len && map[y][x + 3] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y, x: x + 3 })
            return resultStep
          }
          if (x + 2 < len && y + 1 < len && map[y + 1][x + 2] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y + 1, x: x + 2 })
            return resultStep

          }
          if (x - 1 > 0 && y + 1 < len && map[y + 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
        }
        if (x - 1 >= 0 && map[y][x] === map[y + 1][x - 1]) {
          if (y + 1 <= len && x + 1 < len && map[y + 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x: x + 1 })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
          if (y + 2 < len && map[y + 2][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 2, x })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
        }
        if (x + 2 < len && map[y][x] === map[y][x + 2]) {
          if (x + 1 < len && map[y + 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y, x: x + 2 })
            resultStep.push({ y: y + 1, x: x + 1 })
            return resultStep
          }
        }
      }
      // 縱向
      if (y + 1 < len) {
        if (map[y + 1][x] === currentValue) {
          if (y - 2 >= 0 && map[y - 2][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y - 2, x })
            return resultStep
          }
          if (x + 1 < len && y - 1 > 0 && map[y - 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y - 1, x })
            resultStep.push({ y: y - 1, x: x + 1 })
            return resultStep
          }
          if (x + 1 < len && y + 2 < len && map[y + 2][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 2, x: x + 1 })
            return resultStep
          }
          if (y + 3 < len && map[y + 3][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 3, x: x })
            return resultStep
          }
          if (x - 1 >= 0 && y + 2 < len && map[y + 2][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 2, x: x - 1 })
            return resultStep
          }
          if (x - 1 >= 0 && y - 1 >= 0 && map[y - 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y - 1, x: x - 1 })
            return resultStep
          }
        }
      }
    }
  }
}

複製代碼

上面的代碼窮舉了如下狀況,這個算法執行速度仍是很快的,這個算法還記錄了當前步驟,能夠給用戶提示。cdn

總結

咱們能夠看下完整的代碼,而後本身能夠複製下面這段代碼運行下,若是有問題,歡迎指出。完整代碼以下:

// 生成一個地圖 9 * 9
function productMap(n) {
  const randomMap = []
  for (let y = 0; y < n; y++) {
    for (let x = 0; x < n; x++) {
      let value = parseInt(Math.random() * 5 + 1)
      if (!randomMap[y]) {
        randomMap[y] = []
      }
      //  x方向判斷有沒有連續兩個同色
      if (x > 1 && judgeSameColor(randomMap[y], value)) {
        value = getExceptRandom(value)
      }
      if (
        y > 1 &&
        judgeSameColor(getTwoArrColumnByIndex(randomMap, y), value)
      ) {
        value = getExceptRandom(value)
      }
      randomMap[y].push(value)
    }
  }
  return randomMap
}

function getExceptRandom(exceptNum) {
  let value = parseInt(Math.random() * 5 + 1)
  while (value === exceptNum) {
    value = parseInt(Math.random() * 5 + 1)
  }
  return value
}

/**
 * 獲取二維數組某一列的值
 * @param {Array} arr
 * @param {number} n
 */
function getTwoArrColumnByIndex(arr, n) {
  return arr.map(item => item[n])
}
// 判斷是否連續幾個同色
function judgeSameColor(arr, value) {
  return arr.find(
    (item, index) =>
      arr[index - 1] && item === value && arr[index - 1] === value
  )
}

//判斷是不是死圖
function judgeCanRemoveByOneStep(map) {
  const resultStep = []
  let len = map.length
  for (let y = 0; y < len; y++) {
    for (let x = 0; x < len; x++) {
      const currentValue = map[y][x]
      // 考慮橫軸方向
      if (x + 1 < len) {
        // 第一種狀況
        if (map[y][x] === map[y][x + 1]) {
          if (x - 2 >= 0) {
            if (map[y][x - 2] === currentValue) {
              resultStep.push({ y, x })
              resultStep.push({ y, x: x + 1 })
              resultStep.push({ y, x: x - 2 })
              return resultStep
            }
          }
          if (x - 1 >= 0 && y - 1 >= 0 && map[y - 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y - 1, x: x - 1 })
            return resultStep
          }
          if (x + 2 < len && y - 1 > 0 && map[y - 1][x + 2] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y - 1, x: x + 2 })
            return resultStep
          }
          if (x + 3 < len && map[y][x + 3] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y, x: x + 3 })
            return resultStep
          }
          if (x + 2 < len && y + 1 < len && map[y + 1][x + 2] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y + 1, x: x + 2 })
            return resultStep

          }
          if (x - 1 > 0 && y + 1 < len && map[y + 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y, x: x + 1 })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
        }
        if (x - 1 >= 0 && map[y][x] === map[y + 1][x - 1]) {
          if (y + 1 <= len && x + 1 < len && map[y + 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x: x + 1 })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
          if (y + 2 < len && map[y + 2][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 2, x })
            resultStep.push({ y: y + 1, x: x - 1 })
            return resultStep
          }
        }
        if (x + 2 < len && map[y][x] === map[y][x + 2]) {
          if (x + 1 < len && map[y + 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y, x: x + 2 })
            resultStep.push({ y: y + 1, x: x + 1 })
            return resultStep
          }
        }
      }
      // 縱向
      if (y + 1 < len) {
        if (map[y + 1][x] === currentValue) {
          if (y - 2 >= 0 && map[y - 2][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y - 2, x })
            return resultStep
          }
          if (x + 1 < len && y - 1 > 0 && map[y - 1][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y - 1, x })
            resultStep.push({ y: y - 1, x: x + 1 })
            return resultStep
          }
          if (x + 1 < len && y + 2 < len && map[y + 2][x + 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 2, x: x + 1 })
            return resultStep
          }
          if (y + 3 < len && map[y + 3][x] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 3, x: x })
            return resultStep
          }
          if (x - 1 >= 0 && y + 2 < len && map[y + 2][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y + 2, x: x - 1 })
            return resultStep
          }
          if (x - 1 >= 0 && y - 1 >= 0 && map[y - 1][x - 1] === currentValue) {
            resultStep.push({ y, x })
            resultStep.push({ y: y + 1, x })
            resultStep.push({ y: y - 1, x: x - 1 })
            return resultStep
          }
        }
      }
    }
  }
}

function getRandomMap(n) {
  let map = productMap(n)
  if (!judgeCanRemoveByOneStep(map)) {
    map = productMap(n)
  }
  console.log(map)
}
getRandomMap(9)

複製代碼

如下是隨機產生的地圖

生成地圖的方法我大概就將我理解的講完了,後續有時間會具體分析其餘的進行講解,但願能給你們帶來收穫,如下是個人項目源碼,後續會逐漸完善這個項目。謝謝觀看。

相關文章
相關標籤/搜索