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

你可能感兴趣的:(web,js扫雷,洗牌算法,广搜算法)