基于JavaScript实现简单扫雷游戏


Posted in Javascript onJanuary 02, 2021

对于10年前的人来说,扫雷肯定是家喻户晓,由于当时的科技并不是很发达,大家对于电脑游戏的了解,可能都是从扫雷开始的,今天就交大家一种用js原生代码写一个简单的扫雷游戏,话不多说,直接上干货:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style>
  *{
   margin: 0;
   padding: 0;
  }
  li{
   list-style: none;
  }
  .box{
   border: 1px solid #666;
   position: fixed;
   width: 300px;
   height: 350px;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
   margin: auto;
  }
  .btn-group{
   display: flex;
   height: 50px;
   line-height: 50px;
   text-align: center;
   justify-content: space-evenly;
   font-size: 12px;
  }
  .row{
   height: 30px;
   line-height: 30px;
   text-align: center;
   display: flex;
  }
  .col{
   flex-shrink: 0;
   /* flex-shrink 是否允许缩小 */
   flex-grow: 0;
   /* flex-grow 是否允许放大 */
   width: 30px;
   height: 30px;
   border: 1px solid #666;
   background-color: #ccc;
   box-sizing: border-box;
  }
 </style>
</head>
<body>
 <div class="box">
  <div class="qipan">
  </div>
  <div class="btn-group">
   <div class="btn-item">
    <span class="item-name">时间</span>
    <span class="item-value passTime">000</span>
   </div>
   <div class="btn-item">
    <span class="item-name">剩余雷数</span>
    <span class="item-value leftLei">10</span>
   </div>
   <div class="btn-item">
    <select class="level">
     <option value="1">初级</option>
     <option value="2">中级</option>
     <option value="3">高级</option>
    </select>
   </div>
   <div class="btn-item">
    <span class="start">开始</span>
    <span class="restart">重开</span>
   </div>
  </div>
 </div>
 <script>
  function $(s,t){
   if(t == 'l'){
    return document.querySelectorAll(s)
   }else{
    return document.querySelector(s)
   }
  }
  var qipan = $('.qipan'),
    box = $('.box'),
    level = $('.level'),
    leftLei = $('.leftLei'),
    start = $('.start'),
    restart = $('.restart'),
    passTime = $('.passTime')
    ;
  var row = 10,// 行数
    col = 10,// 列数
    leiNum = 10,// 雷数
    restNum = 10,//剩余的雷数
    flag = false,// 格子是否可以被点击
    time,//计时器的名字
    count = 0,// 计时的秒数
    leiList = [],// 用来存放地雷坐标的数组
    sum = col*row,// 棋盘所有格子的总数
    openGz = 0,// 已经点开的格子的数量
    color = ['rgba(0,0,255,.6)','rgba(0,255,0,.6)','red','blue','yellow','pink','auqa','black']
    ;
  window.oncontextmenu = function(e){
   e.preventDefault();
   if(!flag){
    alert('请先点开始!');
    return;
   }
   if(e.target.isOpen){
    alert('这个格子已经翻过了,换个格子标记');
    return
   }
   if(e.target.localName == 'li'){
    if(e.target.isMark){
     e.target.isMark = false;
     e.target.innerHTML = '';
     restNum++;
    }else{
     e.target.isMark = true;
     e.target.innerHTML = '▲';
     e.target.style.color = 'red';
     restNum--;
    }
    leftLei.innerHTML = restNum
   }
  }
  start.onclick = function(){//点击开始游戏
   flag = true;// 棋盘可以被点击
   if(time>0){// 判断开始键是否已经被点过,防止重复点击
    alert('游戏已经开始了,不要再点开始了')
    return
   }
   countTime()//开始计时
  }
  restart.onclick = function(){//点击开始游戏
   flag = false;// flag置为false,棋盘格子变成不可点击状态
   createQp();// 画棋盘
  }
  box.onclick = function(e){//点击棋盘的格子
   var t = e.target;
   if(t.localName == 'li'){// 只有当点击的格子是li的时候才会继续往下判断
    if(!flag){// 如果当前不允许点击,提示先点开始
     alert('请先点开始!')
     return
    }
    var x = t.dataset.x - 0 ,y = t.dataset.y - 0;
    // console.log(x,y);
    if(t.isOpen){
     alert('这个格子已经翻过了,换个格子翻');
     return
    }
    if(t.isMark){
     alert('这个格子已经标记了,换个格子翻');
     return
    }
    if(isInArray(x,y,leiList) != -1 ){
     flag = false;
     clearInterval(time);
     count = 0;
     passTime.innerHTML = count;
     boom();
     alert('你输了')
    }else{
     testLei(x,y);
     if(leiNum == sum - openGz){
      flag = false;
      boom();
      clearInterval(time);
      alert('你赢了');
     }
    }
   }
  }
  level.onchange = function(){
   var v = this.value;//获取改变后的level
   if(v == 1){//改变棋盘规格及雷的数量
    row = 10;
    col = 10;
    leiNum = 10;
   }else if(v == 2){
    row = 16;
    col = 16;
    leiNum = 40;
   }else if(v == 3){
    row = 16;
    col = 30;
    leiNum = 99;
   }
   createQp();// 重新画棋盘
  };
  function createQp(){// 创建棋盘
   var str = '';
   for(var i = 0;i<row;i++){// 行数
    str += '<ul class="row">'
    for(var j = 0;j<col;j++){// 列数
     str+='<li class="col" data-x="'+i+'" data-y="'+j+'"></li>'
    }
    str += '</ul>'
   }
   box.style.width = col * 30 +'px';//修改box的宽度
   box.style.height = row * 30 + 50 +'px';// 修改box的高度
   leftLei.innerHTML = leiNum;// 修改剩余雷数
   qipan.innerHTML = str;// 将拼接的棋盘内容添加到棋盘中
   count = 0;// 计时重置为0
   sum = row*col;// 重置格子的总数
   openGz = 0;// 重置已经点开的格子的数量
   passTime.innerHTML = count; // 时间设置为count
   restNum = leiNum;//重置剩余的雷的数量
   leftLei.innerHTML = restNum;
   clearInterval(time);// 清除定时器
   time = 0;// 定时器变量的值置为 0 
   createLei();
  }
  function countTime(){// 开始计时
   time = setInterval(function(){
    count++;
    passTime.innerHTML = count;
   },1000)
  }
  function createLei(){// 创建地雷
   leiList = [];// 把地雷的坐标先清空
   for(var i = 0;i<leiNum;i++){
    var x = parseInt(Math.random()*row),//
     y = parseInt(Math.random()*col);//
     if(isInArray(x,y,leiList) == -1){// 如果 x,y组成的坐标[x,y] 不在leiList里
      leiList.push([x,y])// 把 [x,y] push进 leiList里
     }else{// x,y组成的坐标 [x,y] 已经在 leiList里了
      i-- // 重新取一次随机坐标
     }
   }
  }
  // arr = [[0,0],[1,1],[2,2],...]
  function isInArray(x,y,arr){// 判断 x,y 组成的坐标 [x,y] 在不在数组 arr 里
   for(var i = 0;i<arr.length;i++){// 遍历arr的每一个元素
    if(x == arr[i][0] && y == arr[i][1]){// 将 x与arr[i]的第0个元素对比,将 y 与 arr[i]的第1个元素对比,如果能对上,说明 [x,y] 已经存在于 arr 里,
     return i;// 返回[x,y] 在 arr中的索引
    }
   }
   if(i == arr.length){// 当 循环遍历一遍也没在arr中找到与 [x,y] 相同的坐标时,说明 [x,y] 不在arr 里
    return -1;// 返回 -1;
   }
  }
  function boom(){// boom
   var ul = $('.row','l');//获取棋盘里所有的行
   for(var i = 0;i<leiList.length;i++){
    var li = ul[leiList[i][0]].querySelectorAll('li')[leiList[i][1]];//通过索引去获取行里具体的li
    li.style.background = 'red'
   }
  }
  function testLei(x,y){
   var num = 0; // 声明一个num用来累计雷的数量
   for(var i = 0;i<leiList.length;i++){// 遍历所有的雷的坐标
    if(Math.abs(x - leiList[i][0]) <2 && Math.abs(y - leiList[i][1])<2){// 找到在当前点击的格子周围八个格子里的雷
     num++;
    }
   }
   var ul = $('.row','l');
   var li = ul[x].querySelectorAll('li')[y];// 通过索引获取当前被点击的格子
   li.innerHTML = num;// 把格子的内容换成雷的数量
   li.isOpen = true;// 给当前格子加一个属性 isOpen,表示当前格子已经被点开了
   openGz++;
   li.style.background = '#fff';
   if(num>0){
    li.style.color = color[num-1];// 把代表雷的数量的数字换一个颜色
   }
   if(num == 0){// 如果当前格子周围没有雷
    li.innerHTML = '';// 
    for(var a = x-1;a<=x+1;a++){// 
     for(var b = y-1;b<=y+1;b++){// 遍历当前格子周围八个格子
      var ul = $('ul','l');
      if(a>= 0 && a<row && b>=0 && b<col){// 保证要遍历的格子坐标在棋盘之内
       var dom = ul[a].querySelectorAll('li')[b];// 通过坐标获取到具体的 li
       if(!dom.isOpen && !dom.isMark){// 判断当前的li格子是否已经被点开了,如果还没有被点开,递归查询该格子周围有几颗雷
        testLei(a,b)
       }
      }
     }
    }
   }
  }
  createQp();
 </script>
</body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
动态加载script文件的两种方法
Aug 15 Javascript
基于jquery的simpleValidate简易验证插件
Jan 31 Javascript
JS比较2个日期间隔的示例代码
Apr 15 Javascript
原生JS绑定滑轮滚动事件兼容常见浏览器
Jun 30 Javascript
JavaScript中document.forms[0]与getElementByName区别
Jan 21 Javascript
easyUI combobox实现联动效果
Jan 17 Javascript
详解Angular.js指令中scope类型的几种特殊情况
Feb 21 Javascript
JS实现动态添加DOM节点和事件的方法示例
Apr 28 Javascript
vue2.0项目中使用Ueditor富文本编辑器示例代码
Aug 14 Javascript
vue 微信授权登录解决方案
Apr 10 Javascript
小程序多图列表实现性能优化的方法步骤
May 28 Javascript
JS高级程序设计之class继承重点详解
Jul 07 Javascript
JS+CSS实现过渡特效
Jan 02 #Javascript
jQuery实现全选按钮
Jan 01 #jQuery
vue实现登录功能
Dec 31 #Vue.js
vue 实现图片懒加载功能
Dec 31 #Vue.js
vue 动态创建组件的两种方法
Dec 31 #Vue.js
Vue 修改网站图标的方法
Dec 31 #Vue.js
利用 JavaScript 实现并发控制的示例代码
Dec 31 #Javascript
You might like
PHP4在Windows2000下的安装
2006/10/09 PHP
PHP获取当前文件的父目录方法汇总
2016/07/21 PHP
PHP基于SPL实现的迭代器模式示例
2018/04/22 PHP
laravel5.2表单验证,并显示错误信息的实例
2019/09/29 PHP
php设计模式之代理模式分析【星际争霸游戏案例】
2020/03/23 PHP
javascript 获取HTML DOM父、子、临近节点
2014/06/16 Javascript
Javascript 构造函数详解
2014/10/22 Javascript
原生javascript实现图片按钮切换
2015/01/12 Javascript
JS实现控制表格单元格垂直对齐的方法
2015/03/30 Javascript
localResizeIMG先压缩后使用ajax无刷新上传(移动端)
2015/08/11 Javascript
使用jquery实现鼠标滑过弹出更多相关信息层附源码下载
2015/11/23 Javascript
五种js判断是否为整数类型方式
2015/12/03 Javascript
js实现下拉列表选中某个值的方法(3种方法)
2015/12/17 Javascript
基于React.js实现原生js拖拽效果引发的思考
2016/03/30 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
2016/09/14 Javascript
jQuery事件用法详解
2016/10/06 Javascript
jQuery中页面返回顶部的方法总结
2016/12/30 Javascript
JavaScript基本类型值-Number类型
2017/02/24 Javascript
vue将对象新增的属性添加到检测序列的方法
2018/02/24 Javascript
vue.js中$set与数组更新方法
2018/03/08 Javascript
轻量级JS Cookie插件js-cookie的使用方法
2018/03/22 Javascript
JavaScript中arguments和this对象用法分析
2018/08/08 Javascript
vue项目上传Github预览的实现示例
2018/11/06 Javascript
零基础之Node.js搭建API服务器的详解
2019/03/08 Javascript
微信小程序位置授权处理方法
2019/06/13 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
python实现比较两段文本不同之处的方法
2015/05/30 Python
PyQt5每天必学之带有标签的复选框
2018/04/19 Python
python for 循环获取index索引的方法
2019/02/01 Python
django搭建项目配置环境和创建表过程详解
2019/07/22 Python
什么时候需要进行强制类型转换
2016/09/03 面试题
大学军训感言400字
2014/03/11 职场文书
初二数学教学反思
2016/02/17 职场文书
导游词之泰山玉皇顶
2019/12/23 职场文书
opencv深入浅出了解机器学习和深度学习
2022/03/17 Python
Javascript的promise,async和await的区别详解
2022/03/24 Javascript