js小遊戲---掃雷

前言

掃雷小遊戲已推入gitHub點擊此處試玩
歡迎各位體驗,菜雞的練手小項目,輕噴。
同樣可在留言處或在線諮詢提出您寶貴的意見,祝您玩得愉快

介紹

掃雷小遊戲通過洗牌算法進行隨機佈雷,通過用戶點擊對旁邊區域進行搜索判斷,達到空白的展開效果
目前遊戲中有9*915*1520*20三張地圖,後期會加入更多。雷數可自己調節或隨機生成


難點詳解

  1. 洗牌算法:
    洗牌算法可實現集合的隨機排序,且各排序機率等同,因此正好可以實現隨機佈雷的效果
    參考於:實現洗牌算法
function shuffle() {
  for(let i = grids.length-1; i >0 ; i--) {
    let randomIndex = Math.floor(Math.random()*(grids.length-1))
    let temp = grids[i]
    grids[i] = grids[randomIndex]
    grids[randomIndex] = temp
  }
}
  1. 渲染地圖
    渲染地圖前首先要把數組分割,在計算機中二維數組正好可以對應上平面中的x軸,y軸所以可把數組分割爲二維數組
function sliceArray(minColumns) {
  let reasonable = grids.length % minColumns == 0 ? true:false
  let newColumns = minColumns
  columns = minColumns
  do {
    if(reasonable) {
      lines = grids.length/columns
      //console.log(grids.length + '  '+ columns + '  ' + lines)
      break
    } else {
      newColumns++
      console.log('分行失敗,已調整列數爲' + newColumns)
      reasonable = grids.length % newColumns == 0 ? true:false
    }
    columns = newColumns
  } while (newColumns< 10 + columns)
  
  if(lines == 0){
    console.log('棋盤創建失敗,請選擇合理的棋格數')
  } else {
    for (let i = 0; i < lines; i++) {
      arr.push(grids.slice(i*lines,i*lines+lines))
    }
    arr.forEach((element, index) => {
      element.forEach((ele, inde) =>{
        ele.x = index
        ele.y = inde
      })
    })
  }
  fillNumber(arr, lines, columns) //此處填充數字
  for(let i = 0; i < lines; i++){
    for(let j = 0; j < columns; j++) {
      div = document.createElement('div')
      div.index = arr[i][j].id
      div.value = arr[i][j].number
      div.dirx = arr[i][j].x
      div.diry = arr[i][j].y
      div.state = arr[i][j].state
      div.className = 'grid'
      main.appendChild(div)
    }
  }
  main.style.width = 25*lines +2*(lines-1) +'px'
  main.style.gridTemplateColumns = 'repeat(' + lines + ', 25px)'
}
  1. 填充數字
    通過對每個元素進行遍歷,然後判斷其8個方向,如果是雷則方格數字+1
function fillNumber(arr, lines, columns) {
  let dir = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]
  for(let i = 0; i < lines; i++){
    for(let j = 0; j < columns; j++) {
      for(let k = 0; k < 8; k++) {
        if(i + dir[k][0] < 0 || i+dir[k][0] >= lines || j + dir[k][1] < 0 || j + dir[k][1] >= columns){
          continue
        }
        if(arr[i+dir[k][0]][j+dir[k][1]].sweep == true && arr[i][j].number != 9) {
          arr[i][j].number += 1
        }
      }
    }
  }
}
  1. 對方格添加點擊事件
    通過事件委託方式添加點擊事件
function addClickEvent() {
  main.addEventListener('click', (e) => {
    switch(e.target.value) {
      case 0: scanGrid(e.target); break
      case 1: changeState(e.target); addColor(e.target, 'rgb(80, 228, 159)', '#aaa'); break
      case 2: changeState(e.target); addColor(e.target, 'rgb(230, 199, 112)', '#aaa'); break
      case 3: changeState(e.target); addColor(e.target, 'rgb(239, 243, 30)', '#aaa'); break
      case 4: 
      case 5: 
      case 6: 
      case 7: 
      case 8: changeState(e.target); addColor(e.target, 'rgb(255, 115, 48)', '#aaa'); break
      case 9: addColor(e.target, 'rgb(240, 78, 49)' , '#fbb', '?'); gameOver(); break
    }
    if(count == gridss - sweeps) {
      console.log('你獲勝了')
      mark.style.display = 'block'
    }
  })
  main.addEventListener('contextmenu', (e) =>{
    if(e.path.length == 9){
      if (e.target.textContent == '?') {
        addColor(e.target, '' , '', '')
      } else {
        addColor(e.target, '' , '', '?')
      }
    }
    e.preventDefault()
  })
}
  1. 掃描
    通過廣搜算法進行掃描如果,點擊到0把所有0和其邊緣方格展開提高用戶體驗
    PS:廣搜算法解析
function scanGrid(base) {
  let dir = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]
  let scanArr = new Array()
  arr[base.dirx][base.diry].state = true
  count++
  scanArr.push(arr[base.dirx][base.diry])
  while (scanArr.length != 0){
    let element = scanArr.pop()
    //console.log(scanArr.length)
    divArr[element.x][element.y].style.backgroundColor = '#ccc'
    for(let k = 0; k < 8; k++) {
      if(element.x + dir[k][0] < 0 || element.x + dir[k][0] >= lines || element.y + dir[k][1] < 0 || element.y + dir[k][1] >= columns){  
        continue
      }
      if(arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number == 0) {
        scanArr.push(arr[element.x+dir[k][0]][element.y+dir[k][1]])
        arr[element.x+dir[k][0]][element.y+dir[k][1]].state = true
        count++
      } else if (arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number != 9) {
        let a = arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number
        let a_x = element.x+dir[k][0]
        let a_y = element.y+dir[k][1]
        arr[a_x][a_y].state = true
        count++
        switch(a) {
          case 1: addColor(divArr[a_x][a_y], 'rgb(80, 228, 159)', '#aaa'); break
          case 2: addColor(divArr[a_x][a_y], 'rgb(230, 199, 112)', '#aaa'); break
          case 3: addColor(divArr[a_x][a_y], 'rgb(239, 243, 30)', '#aaa'); break
          case 4: 
          case 5: 
          case 6: 
          case 7: 
          case 8: addColor(divArr[a_x][a_y], 'rgb(255, 115, 48)', '#aaa'); break
        }
      }
    }
  }
}
  1. 遊戲失敗
    把地圖中所有雷顯示出來並且在1s後彈出遮罩層
function gameOver() {
  divs.forEach(element => {
    if(element.value == 9){
      addColor(element, 'rgb(240, 78, 49)' , '#fbb', '?')
    }
  });
  setTimeout(() => {
    mark.style.display = 'block'
  }, 1000);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章