原生js实现自定义难度的扫雷游戏


Posted in Javascript onJanuary 22, 2021

本文实例为大家分享了js实现扫雷游戏的具体代码,供大家参考,具体内容如下

游戏功能:

1、有四个难度
2、可以自定难度

1、html相关代码

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>扫雷</title>
 <script src="js/mine.js"></script>
 <link rel="stylesheet" href="./css/mine.css" >
</head>
<!-- 
需求分析:
 1.游戏的区域:
  9*9的区域
 2.方格可以打开与标记
  左键打开,显示数字,为周围格子的地雷数,右键标记
 3.地雷
  地雷随机分布
 4.踩到地雷时,游戏结束
  所有的地雷显示出来
 5.连锁开大空方格
 6.剩余地雷数与计时器
 7.游戏胜利条件
  所有的方格除了地雷都被打开了,则游戏胜利
 一个方格所包含的信息:
  坐标 x y
  是否是一个地雷
  周围的地雷数 = 9
  二维数组中存储的是周围的地雷数
 -->
 
<body>
 <div class="level">
 <button type="button" name="button" class="choice-level">自定义</button>
 <button type="button" name="button" class="choice-level">初级</button>
 <button type="button" name="button" class="choice-level">中级</button>
 <button type="button" name="button" class="choice-level">高级</button>
 <button type="button" name="button" class="choice-level">魔鬼级</button>
 <button type="button" name="button" class="restart">重新开始</button>
 </div>
 <div class="gameBox"></div>
 <div class="info">
 <p>剩余雷数:
  <span class="residue"></span>
 </p>
 <p>
  TIME:
  <span class="tick"></span>S
 </p>
 
 </div>
</body>
 
 
</html>

2、css样式

*{
 margin: 0;
 padding: 0;
}
.gameBox{
 margin-top: 30px;
}
body{
 font-size: 0;
}
ul{
 list-style: none;
 text-align: center;
 overflow: hidden;
}
.col{
 display: inline-block;
 width: 22px;
 height: 22px;
 line-height: 22px;
 background-color: rgba(32, 226, 255, 0.4);
 border: 1px solid rgb(129, 129, 129);
 font-size: 16px;
 margin: 1.5px;
 vertical-align: top;
 position: relative;
}
.col:hover{
 background-color: #0af;
}
.col span{
 cursor: default;
}
.hide{
 display: none;
}
.boom{
 background: url("../img/boom.svg") no-repeat 2.5px 2px;
 background-size: 18px 18px;
}
.num-1{
 color: rgb(8, 153, 235);
}
.num-2{
 color: rgb(255, 45, 178);
}
.num-3{
 color:#16a085;
}
.num-4{
 color: #8e44ad;
}
.num-5{
 color: rgb(255, 167, 45);
}
.num-6{
 color: rgb(8, 126, 176);
}
.num-7{
 color: #e67e22;
}
.num-8{
 color: #c0392b;
}
.img-flag{
 width: 18px;
 height: 18px;
 position: absolute;
 top: 3px;
 left: 3px;
}
.level{
 margin-top: 30px;
 font-size: 20px;
 text-align: center;
}
.level button{
 padding: 5px 8px;
 background-color: rgb(67, 183, 189);
 border: none;
 outline: none;
 border-radius: 3px;
 cursor: pointer;
 color: #fff;
}
.level button:hover{
 background-color: rgb(23, 132, 138);
}
.info{
 margin-top: 30px;
 font-size: 16px;
 text-align: center;
}
.info p{
 display: inline-block;
 width: 130px;
 margin: 0 auto;
}
.info p span{
 color: rgb(67, 183, 189);
}

3、js代码

window.onload = function() {
 var row = 4;
 var col = 4;
 var num = 1;
 // 判断踩雷之后不能胜利
 var gg = false;
 // 生成地图
 function mineMap(r, c, num) {
 // 定义行
 var map = [];
 //给行数,生成二维数组
 for (var i = 0; i < r; i++) {
  map[i] = new Array()
 }
 // 赋值
 for (var i = 0; i < map.length; i++) {
  for (var j = 0; j < c; j++) {
  // //周围的地雷数
  map[i][j] = 0;
  }
 }
 var plus = function(array, x, y) {
  if (x >= 0 && x < r && y >= 0 && y < c) {
  if (array[x][y] !== 9) {
   array[x][y]++
  }
  }
 }
 for (var i = 0; i < num; i++) {
  var x = Math.floor(Math.random() * r)
  var y = Math.floor(Math.random() * c)
  if (map[x][y] != 9) {
  map[x][y] = 9
   //上下6个 +1
  for (var j = -1; j < 2; j++) {
   //上三个
   plus(map, x - 1, y + j)
   //下三个
   plus(map, x + 1, y + j)
  }
  //左右2个 +1
  plus(map, x, y - 1)
  plus(map, x, y + 1)
  } else {
  //重新随机
  num++
  }
 }
 return map;
 }
 //先通过x轴数量写入ul,再讲过y轴的属性写入li
 function writeHtml(map) {
 // 获取盒子
 var gameBox = document.querySelector(".gameBox");
 // 声明空字符串,存放生成的ul、li
 var gridHTML = "";
 for (var i = 0; i < map.length; i++) {
  gridHTML += '<ul class = "row" data-x="' + i + '">';
  //生成li
  for (var j = 0; j < map[0].length; j++) {
  var m = map[i][j]
  if (m == 0) {
   m = "";
  }
  gridHTML += "<li class='col' data-y=" + j + ">" +
   "<span class='hide num-" + m + "'>" + m + "</span>" +
   "<img src='img/flag.svg' class='img-flag hide'>" +
   "</li>"
  }
  gridHTML += '</ul>'
  gameBox.innerHTML = gridHTML;
 }
 }
 
 //给方格绑定事件, 点开数字 地雷 右键标记
 function show() {
 // 获取行ul
 var rows = document.querySelectorAll(".row");
 // 遍历所有ul
 for (var i = 0; i < rows.length; i++) {
  var element = rows[i];
  // 添加点击事件
  element.onclick = function(event) {
   // 当前点击元素
   var el = event.target;
   // 判断是否为li
   if (el.nodeName != "LI") {
   return;
   }
   //todo 判断是否被打开以及标记了
   if (el.style.background == "white" || !el.children[1].classList.contains("hide")) {
   return;
   }
   // 获取span标签内容
   var mineNum = el.children[0].innerHTML;
   if (mineNum !== "9" && el.style.background !== "white") {
   // 空白连锁打开
   if (mineNum == "") {
    var x = parseInt(el.parentNode.dataset.x);
    var y = parseInt(el.dataset.y);
    showNoMine(x, y);
   }
   // li背景变白色;span显示
   el.style.background = "white";
   el.children[0].style.display = "inline";
   // 判断打开数量
   clearMineNum++;
   // 胜利函数
   judgeVictory()
 
   } else if (mineNum == "9") {
   // 清除胜利计时器
   clearInterval(stopTime);
   // li添加类名
   el.classList.add("boom");
   alert("你真菜!")
   gg = true;
   // 显示所有地雷,获取所有li
   var all = document.querySelectorAll(".col");
   // 放置所有的地雷
   var ff = [];
   var allnum = 0;
   // 遍历所有li
   for (var i = 0; i < all.length; i++) {
    if (all[i].children[0].innerHTML == "9") {
    // 雷赋值给数组
    ff[allnum] = all[i];
    allnum++;
    }
   }
   // 设置一个计时器一个一个打开雷
   allnum = 0;
   var stop = setInterval(function() {
    ff[allnum].classList.add("boom")
    allnum++;
    // 判断结束条件
    if (allnum == ff.length) {
    // 清除计时器
    clearInterval(stop);
    }
   }, 30)
 
   }
  }
  // 右键标记地雷
  element.oncontextmenu = function(event) {
  // 阻止右键菜单
  event.preventDefault();
  // 获取当前点击节点
  var el = event.target;
  // 判断是否是
  if (el.parentNode.nodeName == "LI") {
   el = el.parentNode;
  }
  if (el.nodeName != "LI") {
   return;
  }
  // 获取img
  var classList = el.children[1].classList;
  // 剩余雷数
  var residue = document.querySelector(".residue");
  var mineNum = parseInt(residue.innerHTML);
  // 如果没有旗子,没有被点开,可以插旗子
  if (classList.contains("hide") && el.style.background != "white") {
   // 移除隐藏
   classList.remove("hide");
   // 获取雷数
   mineNum--;
  } else if (el.style.background != "white") {
   classList.add("hide");
   // 判断雷数
   if (mineNum < num) {
   mineNum++;
   }
  }
  // 剩余雷数
  residue.innerHTML = mineNum;
  }
 }
 }
 
 function judgeVictory() {
 //游戏胜利
 if (clearMineNum === (row * col - num)) {
  //做一个小动画
  var all = document.querySelectorAll(".col");
  var allNum = 0;
  var stop = setInterval(function() {
  var r = Math.floor(Math.random() * 256)
  var g = Math.floor(Math.random() * 256)
  var b = Math.floor(Math.random() * 256)
  all[allNum].style.background = "rgba(" + r + "," + g + "," + b + ",0.6)";
  //将旗子和span都隐藏
  all[allNum].children[0].style.display = "none"
  all[allNum].children[1].style.display = "none"
  allNum++
  if (allNum === all.length) {
   clearInterval(stop)
   if (!gg) {
   alert("大吉大利,今晚吃鸡")
   init(row, col, num)
   }
  }
  }, 20)
 }
 }
 //自动打开空格
 function showNoMine(x, y) {
 for (var i = -1; i <= 1; i++) {
  if (x + i >= 0 && x + i < row) {
  // 获取当前行
  var rowElement = document.querySelectorAll(".row")[x + i];
  for (var j = -1; j <= 1; j++) {
   if (y + j >= 0 && y + j < col) {
   //获取当前单元格
   var el = rowElement.children[y + j]
    //自动打开必须是未打开的方格
   if (el.style.background != "white") {
    el.style.background = "white"
    el.children[0].style.display = "inline"
    //打开方格数量+1
    clearMineNum++
    //判断游戏是否胜利
    judgeVictory(clearMineNum)
 
    if (el.children[0].innerText === "") {
    showNoMine(x + i, y + j)
    }
   }
   }
  }
  }
  // if (x + i >= 0 && x + i < row) {
  // // 获取当前行
  // var rowElement = document.querySelectorAll(".row")[x + i];
  // for (var j = -1; j <= 1; j++ && y + j < col) {
  //  // 获取当前单元格
  //  var el = rowElement.children[y + j];
  //  if (el.style.background !== "white") {
  //  el.style.background = "white";
  //  el.children[0].style.display = "inline";
  //  // 打开放格数量加1
  //  clearMineNum++;
  //  // 判断游戏是否胜利
  //  judgeVictory(clearMineNum);
  //  // 判断打开周围的放格周围是否为空
  //  if (el.children[0].innerHTML === "") {
  //   showNoMine(x + i, y + j)
  //  }
  //  }
  // }
  // }
 }
 
 }
 //初始化方法
 var stopTime;
 
 function init(row, col, num) {
 //数据初始化
 clearMineNum = 0
 gg = false;
 //清除原来的地图,生成新的地图
 var box = document.querySelector(".gameBox")
 box.innerHTML = "";
 var map = mineMap(row, col, num);
 // 新建地图
 writeHtml(map);
 show()
  //将雷数写入html中
 var residue = document.querySelector(".residue")
 residue.innerHTML = num
  // 获取计时
 var tick = document.querySelector(".tick");
 var i = 0;
 // 初始化
 tick.innerHTML = i;
 // 清除计时
 clearInterval(stopTime);
 // 时间计时器
 stopTime = setInterval(function() {
  tick.innerHTML = ++i
 }, 1000)
 }
 // 重置
 var restart = document.querySelector(".restart");
 restart.onclick = function(event) {
  //阻止冒泡
  event.stopPropagation()
  init(row, col, num)
 }
 // 自定义
 var level = document.querySelector(".level")
 level.onclick = function(event) {
 var el = event.target;
 switch (el.innerHTML) {
  case "初级":
  row = 9;
  col = 9;
  num = 10;
  init(row, col, num)
  break;
  case "中级":
  row = 16;
  col = 16;
  num = 40;
  init(row, col, num)
  break;
  case "高级":
  row = 16;
  col = 30;
  num = 479;
  init(row, col, num)
  break;
  case "魔鬼级":
  row = 40;
  col = 50;
  num = 300;
  init(row, col, num)
  break;
  case "自定义":
  row = prompt("请输入列数!");
  col = prompt("请输入行数!");
  num = prompt("请输入你想要的雷数,(请慎重选择)");
  init(row, col, num);
  break;
  default:
  row = 9;
  col = 9;
  num = 10;
  init(row, col, num)
  break;
 }
 }
 init(row, col, num)
}

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

Javascript 相关文章推荐
jquery之Document元素选择器篇
Aug 14 Javascript
js location.replace与location.reload的区别
Sep 08 Javascript
idTabs基于JQuery的根据URL参数选择Tab插件
Apr 11 Javascript
浅析javascript的间隔调用和延时调用
Nov 12 Javascript
判断JS对象是否拥有某属性的方法推荐
May 12 Javascript
jQuery1.9+中删除了live以后的替代方法
Jun 17 Javascript
原生js实现返回顶部缓冲效果
Jan 18 Javascript
js 将input框中的输入自动转化成半角大写(税号输入框)
Feb 16 Javascript
Bootstrap输入框组件使用详解
Jun 09 Javascript
vue.js中引入vuex储存接口数据及调用的详细流程
Dec 14 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
Jan 22 Javascript
layui table 复选框跳页后再回来保持原来选中的状态示例
Oct 26 Javascript
Element-ui upload上传文件限制的解决方法
Jan 22 #Javascript
js canvas实现五子棋小游戏
Jan 22 #Javascript
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
Jan 22 #Vue.js
element-ui 弹窗组件封装的步骤
Jan 22 #Javascript
动态实现element ui的el-table某列数据不同样式的示例
Jan 22 #Javascript
原生js实现放大镜组件
Jan 22 #Javascript
Vue仿Bibibili首页的问题
Jan 21 #Vue.js
You might like
php json_encode()函数返回json数据实例代码
2014/10/10 PHP
laravel 实现划分admin和home 模块分组
2019/10/15 PHP
Yii框架小部件(Widgets)用法实例详解
2020/05/15 PHP
过虑特殊字符输入的js代码
2010/08/05 Javascript
jQuery getJSON()+.ashx 实现分页(改进版)
2013/03/28 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
2013/07/17 Javascript
javascript 3d 逐侦产品展示(核心精简)
2014/03/26 Javascript
js实现兼容IE和FF的上下层的移动
2015/05/04 Javascript
基于Javascript实现返回顶部按钮
2016/02/29 Javascript
jQuery实现摸拟alert提示框
2016/05/22 Javascript
jQuery双向列表选择器DIV模拟版
2016/11/01 Javascript
微信小程序 欢迎界面开发的实例详解
2016/11/30 Javascript
AngularJS ng-repeat指令及Ajax的应用实例分析
2017/07/06 Javascript
基于node.js express mvc轻量级框架实践
2017/09/14 Javascript
微信小程序简单实现form表单获取输入数据功能示例
2017/11/30 Javascript
Ionic学习日记实现验证码倒计时
2018/02/08 Javascript
Angular 数据请求的实现方法
2018/05/07 Javascript
Node.js命令行/批处理中如何更改Linux用户密码浅析
2018/07/22 Javascript
vue解决使用webpack打包后keep-alive不生效的方法
2018/09/01 Javascript
详解vue挂载到dom上会发生什么
2019/01/20 Javascript
vue 引用自定义ttf、otf、在线字体的方法
2019/05/09 Javascript
关于Python元祖,列表,字典,集合的比较
2017/01/06 Python
详解PyTorch批训练及优化器比较
2018/04/28 Python
Python设计模式之状态模式原理与用法详解
2019/01/15 Python
Django 框架模型操作入门教程
2019/11/05 Python
Python time库基本使用方法分析
2019/12/13 Python
python随机生成大小写字母数字混合密码(仅20行代码)
2020/02/01 Python
Keras模型转成tensorflow的.pb操作
2020/07/06 Python
英语专业毕业生自荐信
2013/10/28 职场文书
商业活动邀请函
2014/02/04 职场文书
十周年庆典策划方案
2014/06/03 职场文书
学雷锋标语
2014/06/25 职场文书
艺术学院毕业生自荐信
2014/07/05 职场文书
武侯祠导游词
2015/02/04 职场文书
党员个人总结范文
2015/02/14 职场文书
图神经网络GNN算法
2022/05/11 Python