js实现扫雷小程序的示例代码

初学javascript,写了一个扫雷程序练练手!

扫雷规则及功能

扫雷想必大家都不陌生,就是windows上点击排雷的小游戏,它的主要规则有

1.左键点击显示当前格子是否为雷,如果为雷的话,GameOver啦,如果不是雷的话,这个格子会显示周围八个格子内的雷数量。
2.鼠标右键标记,标记可能的雷,标记了之后取消需要再次右键点击该格子,左键无效果。
3.鼠标中键(滚轮)按下后,快捷扫雷(如果周围雷数和未被标记且未被翻开的格子相等,会将这些格子一并翻开)

主要功能基本完全复刻了windows7扫雷的功能

扫雷github地址:扫雷github地址

扫雷算法

1.首先我定义了一个构造函数,里面是一系列的属性:

  var mineCraft = function(num1,num2,mine_num,obj,type){
    this.num1 = num1;            //整个扫雷的行数
    this.num2 = num2;            //整个扫雷的列数
    this.mine_num = mine_num;        //雷的个数
    this.tiles = [];             //数组里面存放的是每个小格子
    this.obj = obj;             //扫雷放置的对象
    this.flag = true;
    this.arr = [];
    this.arr_2 = [];
    this.time_dsq = null;
    this.time_dc ='';
    this.time_arr = [[],[],[]];       //时间统计信息
    this.details = [[],[],[]];       // 游戏统计详情
    this.type = type;           //游戏类型:初级/中级/高级/自定义
    this.buildTiles();           //创建游戏函数
  };

2.在页面上创建扫雷的界面 函数buildTiles

    buildTiles:function(){
      this.obj.style.width = 51*this.num1+'px'; //在传进来的对象上画整体格子,每个小格子51px大小,总大小就为个数*单个大小
      this.obj.style.height = 51*this.num2+'px';
      var indexOfdiv = 0;
      for(var i = 0;i<this.num2;i++){
        for(var j = 0;j<this.num1;j++){
          var tile = document.createElement('div');
          tile.className = 'tile';     //定义小格子class
          tile.index = indexOfdiv;     //为每个小格子添加索引
          this.tiles[indexOfdiv] = tile;  //将小格子存入数组中
          indexOfdiv++;
          this.obj.appendChild(tile);    //将小格子插入到整个扫雷界面中
        }
      }
      this.obj.oncontextmenu = function(){  //取消浏览器的默认右键菜单事件
        return false;
      }
      this.event();            //点击事件
    },

3.绑事件函数:

    event : function(){
      var _this = this;
      this.obj.onmouseover = function(e){    //鼠标悬停事件---
        if(e.target.className == 'tile'){
          e.target.className = 'tile current';
        }
      }
      this.obj.onmouseout = function(e){    //鼠标移出事件--
        if(e.target.className == 'tile current'){
          e.target.className = 'tile';
        }
      }
      this.obj.onmousedown = function(e){    //鼠标按下事件
        var index = e.target.index;
        if(e.button == 1){          //e.button属性 左键0/中键1/右键2
          event.preventDefault();    //取消默认
        }
        _this.changeStyle(e.button,e.target,index);
      }
      this.obj.onmouseup = function(e){   //鼠标弹起事件
        if(e.button == 1){
          _this.changeStyle(3,e.target);
        }
      }
    },

4.点击调用的函数:

    changeStyle:function(num1,obj,num_index){
      if(num1 == 0){         //是左键的话
        if(this.flag){       //this.flag 是之前定义的用于判断是否为第一次点击
          this.store(num_index);     //store函数,存放被点击的格子周围的8个格子
          this.setMineCraft(this.mine_num,this.arr,num_index); //如果是第一次点击 即调用布雷函数 更改flag状态
          this.flag = false;
          this.detail_statistics(0,false);   //开始信息统计函数
        }
        if(obj.className != 'tile'&&obj.className !='tile current'){//如果不是第一次点击,被点击的格子不是未点击状态,无效
          return false;
        }
        if(obj.getAttribute('val') == 0){  //如果不是雷。改为翻开状态
          obj.className = "showed";
          obj.innerHTML = obj.getAttribute('value') == 0?'':obj.getAttribute('value');          //显示周围雷数
          this.showAll(obj.index);   //递归函数判断周围格子的情况,就是扫雷游戏上一点开会出现一片的那种
        }
        if(this.over(obj)){       //判断游戏是否结束
          this.last();
        }
      }
      if(num1 == 2){            //右键标记事件
        if(obj.className == 'biaoji'){
          obj.className = 'tile';
        }else if(obj.className !='biaoji'&&obj.className != 'showed'){
          obj.className = 'biaoji';
        }
      }
      if(num1 == 1){           // 中键事件
        if(obj.className =="showed"){
          this.show_zj1(obj.index);
        }
      }
      if(num1 == 3){          //鼠标弹起事件

        if (obj.className == "showed") {
          var flag1 = this.show_zj2(obj.index,0);
        }else{
          this.show_zj2(obj.index,1)
          return false;
        }

        if(flag1&&this.over()){     //弹起判断是否结束
          this.last();
        }
      }
    },

5.布雷:我之前的布雷是在页面加载在buildTiles()的时候布雷的,但是这样会导致有可能你电机的第一个格子就是雷(游戏性不强),后来修改到第一次点击完成之后布雷(确保第一下点的不是雷),避开直接炸死的现象.所以把调用放在后面的event后触发的changeStyle函数中

    setMineCraft:function(num,arr_first,num_first){ //雷的个数、最开始被点击的格子周围的八个、被点击的那个格子
      var arr_index = [];
      for(var i = 0;i<arr_first.length;i++){
        arr_index.push(arr_first[i].index);
      }
      var length = this.tiles.length;
      for (var i = 0; i < length; i++) {
        this.tiles[i].setAttribute("val", 0);
      }
      for (var i = 0; i < num; i++) {
        var index_Mine = Math.floor(Math.random() * this.tiles.length);
        if(index_Mine == num_first||arr_index.lastIndexOf(index_Mine)>-1){//如果是属于第一次点击的周围的直接跳过在该位置布雷
          num++;
          continue;
        }

        if (this.tiles[index_Mine].getAttribute("val") == 0) {
          this.tiles[index_Mine].setAttribute("val", 1);
        }else {
          num++;
        }
      }
      this.showValue();
      this.event()
    },

6.存储周围格子的函数:

    store : function(num) {  //传入格子的index.
      var tiles_2d = [];
      var indexs = 0;
      for(var i = 0;i<this.num2;i++){
        tiles_2d.push([]);
        for(var j = 0;j<this.num1;j++){
          tiles_2d[i].push(this.tiles[indexs]);
          indexs++;
        }
      }
      var j = num % this.num1;
      var i = (num - j) / this.num1;
      this.arr = [];
        //左上
      if (i - 1 >= 0 && j - 1 >= 0) {
        this.arr.push(tiles_2d[i - 1][j - 1]);
      }
        //正上
      if (i - 1 >= 0) {
        this.arr.push(tiles_2d[i - 1][j]);
      }
        //右上
      if (i - 1 >= 0 && j + 1 <= this.num1-1) {
        this.arr.push(tiles_2d[i - 1][j + 1]);
      }
        //左边
      if (j - 1 >= 0) {
        this.arr.push(tiles_2d[i][j - 1]);
      }
        //右边
      if (j + 1 <= this.num1-1) {
        this.arr.push(tiles_2d[i][j + 1]);
      }
        //左下
      if (i + 1 <= this.num2-1 && j - 1 >= 0) {
        this.arr.push(tiles_2d[i + 1][j - 1]);
      }
        //正下
      if (i + 1 <= this.num2-1) {
        this.arr.push(tiles_2d[i + 1][j]);
      }
        //右下
      if (i + 1 <= this.num2-1 && j + 1 <= this.num1-1) {
        this.arr.push(tiles_2d[i + 1][j + 1]);
      }
    },

7.showAll函数:作用是如果该格子周围没有雷,自动翻开周围8个格子,然后再判断周围八个格子的周围8隔格子是否有雷,利用了递归的方法

    showAll:function(num){
      if (this.tiles[num].className == "showed" && this.tiles[num].getAttribute("value") == 0){
        this.store(this.tiles[num].index);
        var arr2 = new Array();
        arr2 = this.arr;
        for (var i = 0; i < arr2.length; i++) {
          if (arr2[i].className != "showed"&&arr2[i].className !='biaoji') {
            if (arr2[i].getAttribute("value") == 0) {
              arr2[i].className = "showed";
              this.showAll(arr2[i].index);
            } else {
              arr2[i].className = "showed";
              arr2[i].innerHTML = arr2[i].getAttribute("value");
            }
          }
        }
      }
    },

8.show_zj函数:主要是中键按钮的作用中键点击后的函数,这里的show_zj1是鼠标键按下后的显示效果,
show_zj2函数就是

    show_zj1:function(num){
      this.store(this.tiles[num].index);
      for (var i = 0; i < this.arr.length; i++) {
        if (this.arr[i].className == "tile") {
          this.arr_2.push(this.arr[i]);
          this.arr[i].className = "showed";
          // this.arr[i].className = "test";
        }
      }
    },
    show_zj2:function(num,zt){

      var count = 0;
      this.store(this.tiles[num].index);      

      for(var i = 0,len = this.arr_2.length;i<len;i++){
        this.arr_2[i].className = 'tile';     //按下效果恢复原状
      }

      this.arr_2.length = 0;
      for(var i = 0;i<this.arr.length;i++){
        this.arr[i].className == 'biaoji'&&count++;
      }
      if(zt == 1){
        return false;
      }
      var numofmines = this.tiles[num].getAttribute("value");
      if(numofmines == count){               //如果周围雷数和周围被标记数相等就翻开周围的格子
          var arr = new Array(this.arr.length);
          for(var i = 0;i<this.arr.length;i++){
            arr[i] = this.arr[i];
          }
          for (var i = 0,length = arr.length; i < length; i++) {
            if (arr[i].className == "tile" && arr[i].getAttribute("val") != 1) {//如果周围格子无雷则继续。
              arr[i].className = "showed";
              arr[i].innerHTML = arr[i].getAttribute("value") == 0?"":arr[i].getAttribute("value");
              this.showAll(arr[i].index);
            } else if (arr[i].className == "tile" && arr[i].getAttribute("val") == 1) {  //如果周围格子有雷,游戏结束
              this.over(arr[i]);
              this.last();
              return false;
            }
          }
      }
      return true;
    },

9.结束判断:

    over:function(obj){
      var flag = false;
      var showed = document.getElementsByClassName('showed');
      var num = this.tiles.length - this.mine_num;
      if(showed.length == num){           //如果被排出来的格子数等于总格子数-雷数,这游戏成功结束
        this.detail_statistics(1,true);      //游戏统计 ,true代表胜,false,代表失败
        alert('恭喜你获得成功');
        flag = true;
      }else if(obj&&obj.getAttribute('val') == 1){   //如果被点击的是雷,则炸死
        this.detail_statistics(1,false);
        alert('被炸死!');
        flag = true;

      }
      return flag;
    },

10.结束后的显示函数:

    last:function(){
      var len = this.tiles.length;
      for(var i = 0;i<len;i++){
        this.tiles[i].className = this.tiles[i].getAttribute('val') == 1?'boom':'showed';
        if(this.tiles[i].className != 'boom'){  //
          this.tiles[i].innerHTML = this.tiles[i].getAttribute('value') == 0?'':this.tiles[i].getAttribute('value');
        }
      }
      this.obj.onclick = null;
      this.obj.oncontextmenu = null;
    },

11 统计信息:还是比较全的和windows7扫雷版的判断项目是一样的,使用的是每次结束游戏后将数据存入localStorage中,

    //已玩游戏,已胜游戏,胜率,最多连胜,最多连败,当前连局;
    detail_statistics:function(num,zt){
      var time_pay = 1;
      var _this = this;
      if(num == 0){
        this.time_dsq = setInterval(function(){
          $('#time_need').text(time_pay);
          _this.time_dc =time_pay;
          time_pay++;
         },1000);

      }
      else if(num == 1){
        clearInterval(this.time_dsq);
        if(this.type == 4){return false;}
        if(localStorage.details == undefined){
          localStorage.details = JSON.stringify([[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]]); //这里存放的就是上面注释中的六项数据
        }
        if(JSON.parse(localStorage.details) instanceof Array){
          this.details = JSON.parse(localStorage.details);
        }
        this.details[this.type][0] += 1;
        if(zt == false){
          if(this.details[this.type][5]>=0){
            this.details[this.type][5] = -1;
          }else{
            this.details[this.type][5] -= 1;
          }
          if(this.details[this.type][5]<this.details[this.type][4]){
            this.details[this.type][4] = this.details[this.type][5];
          }
          this.details[this.type][2] = this.toPercent(this.details[this.type][2]/this.details[this.type][0]);
          localStorage.details = JSON.stringify(this.details);
          return false;
        }

        if(this.details[this.type][5]>=0){
          this.details[this.type][5] += 1;
        }else{
          this.details[this.type][5] = 1;
        }
        if(this.details[this.type][5]>this.details[this.type][3]){
          this.details[this.type][3] = this.details[this.type][5];
        }
        this.details[this.type][3] += 1;
        this.details[this.type][2] = this.toPercent(this.details[this.type][4]/this.details[this.type][0]);
        localStorage.details = JSON.stringify(this.details);

        var time1 = new Date();
        var time_str = time1.getFullYear()+'/'+time1.getMonth()+'/'+time1.getDate()+' '+time1.getHours()+':'+time1.getMinutes();
        if(localStorage.time == undefined){
          localStorage.time = JSON.stringify([[],[],[]]);
        }
        if(JSON.parse(localStorage.time) instanceof Array){
          this.time_arr = JSON.parse(localStorage.time);
        }

        this.time_arr[this.type].push([this.time_dc,time_str]);
        this.time_arr[this.type].sort(function(a,b){
          return a[0]-b[0];
        });
        if(this.time_arr[this.type].length>5){
          this.time_arr[this.type].pop();
        }
        localStorage.time = JSON.stringify(this.time_arr);

      }
    },

扫雷的主要部分就是这些了,还有一些小功能包括没写来,要看完整的可以看gitHub

之前看书学习总觉得学了就忘,感觉懂了公式却不知道怎么用,写完扫雷小程序觉得收获了很多

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

(0)

相关推荐

  • js实现扫雷小程序的示例代码

    初学javascript,写了一个扫雷程序练练手! 扫雷规则及功能 扫雷想必大家都不陌生,就是windows上点击排雷的小游戏,它的主要规则有 1.左键点击显示当前格子是否为雷,如果为雷的话,GameOver啦,如果不是雷的话,这个格子会显示周围八个格子内的雷数量. 2.鼠标右键标记,标记可能的雷,标记了之后取消需要再次右键点击该格子,左键无效果. 3.鼠标中键(滚轮)按下后,快捷扫雷(如果周围雷数和未被标记且未被翻开的格子相等,会将这些格子一并翻开) 主要功能基本完全复刻了windows7扫雷

  • C#模拟实现抽奖小程序的示例代码

    目录 1.抽奖主界面 2.操作步骤 2.1 抽奖界面 2.2 抽奖结果导出 3.源码 3.1 数据库连接 3.2 抽奖程序 1.抽奖主界面 2.操作步骤 S键开始: 0.1.2.3.4.5键分别对应6次奖项: 分别是 特等奖.一等奖.二等奖.三等奖.四等奖.五等奖 9键是加抽奖: 空格退出抽奖结果界面: P键关闭气泡效果. 2.1 抽奖界面 2.2 抽奖结果导出 *************特等奖奖获得者:(抽奖时间:2021/12/30 22:41:22)*************** 工号:1

  • C语言实现扫雷小游戏的示例代码

    目录 一.扫雷 1.演示效果 2.完整代码 二.代码解析 1.初始化雷盘 2.打印雷盘 3.布置雷 4.排雷 5.游戏函数主体 6.菜单函数 7.头文件.宏定义及主函数 一.扫雷 扫雷小游戏主要是利用字符数组.循环语句和函数实现. 设计思路:雷盘大小为9*9,但是为了后续能更好的统计出雷的个数在定义数组的时候定义大小为11*11,先定义两个字符数组,一个用来记录雷的位置,另一个用来展现给玩家,初始化雷盘,将两个字符数组分别全部赋值为字符0和字符*,打印棋盘,随机设置雷所在位置,根据玩家输入的坐标

  • 基于Python制作天眼查小程序的示例代码

    目录 界面搭建 整体布局 界面美化 天眼查爬虫 获取信息 代码编写 结果展示 今天我们一起来制作一个天眼查GUI程序,开宗明义,我们先来看下最终的效果 这次的GUI程序,我们使用的框架是PyQt5,该框架拥有比tkinter更为丰富的内置组件,在界面美化方面,貌似也更胜一筹! 从上图也可以看出,我们的目标还是蛮远大的,最终我们希望可以完成一个工具集合,把我们日常当中常用的功能都集成的该GUI程序中,比如天眼查公司信息,知乎用户知识图谱,B视频弹幕抓取等等. 好了,今天我们先完成天眼查的功能吧~

  • C语言实现经典扫雷小游戏的示例代码

    目录 一.游戏简介 二.游戏实现 1.初始化棋盘 2.打印棋盘 3.布置雷 4.排查雷 三.源文件 1.game.h 2.game.c 3.Test.c 一.游戏简介 游戏初始界面有两个选择,选项“1”为开始游戏,选项“0”为退出游戏:选择开始游戏之后将会打印出9*9的棋盘,此时系统已经为游戏设置了10个雷,输入坐标之后将会打印出此坐标周围八个位置有几个雷,如果踩到了雷,那么游戏结束,打印出所有雷的位置. 二.游戏实现 1.初始化棋盘 void InitBoard(char board[ROWS

  • vue实现微信公众号h5跳转小程序的示例代码第1/3页

    目录 项目概述 涉及知识点 实现 实现容器 computed 实现分页 项目概述 实现类似图中红色框框选中可以左右滑动的组件,点击可以跳转到对应的小程序页面. 涉及知识点 computed 实现分页 开放标签 wx-open-launch-weapp 使用 实现 实现容器 首先我们来实现两行可以左右滑动的容器. 这边为了省事,我是选择了 vue-awesome-swiper@2.6.7: npm i vue-awesome-swiper@2.6.7 -S main.js 引入 import Vu

  • 用C语言实现扫雷小程序

    本文实例为大家分享了C语言实现扫雷小程序的具体代码,供大家参考,具体内容如下 扫雷程序的编写需要有清晰的思路,所以我们先要清楚扫雷的实现有几个功能模块让我们编写,再用主函数将功能结合在一起: //菜单函数//初始化数组函数//布雷函数//统计周围雷的个数//打印玩家棋盘//打印设计者棋盘//扫雷函数//避免第一次被雷炸死的函数//展开函数//判断玩家棋盘剩余未知区域的个数 根据这几点可以写出如下的头文件: #ifndef __GAME_H__ #define __GAME__H__ #inclu

  • C语言编写扫雷小程序

    本文实例为大家分享了C语言实现扫雷小程序的具体代码,供大家参考,具体内容如下 首先创建一个项目,建立一个头文件game.h,两个源文件game.c和test.c game.h代码片: #ifndef  __GAME_H__ #define  __GAME_H__ #include<stdio.h> #include<stdlib.h> #include<string.h> #define ROWS 10//行数 #define COLS 10//列数 #define M

  • 京东优选小程序的实现代码示例

    写在前面 过年有大把的时光,为何一直宅在家里不出家门看着电脑,这究竟是道德的沦丧还是人性的泯灭...这一切都还得从一只蝙蝠说起... 咳咳,好了不皮了,言归正传.微信推出的小程序可谓是轻量又强大,所以最近我也开始了小程序的学习,学了挺多也看了很多文档,但总觉得自己没学到什么,感觉很迷茫.正所谓实践出真知,所以我选择了从高仿别人的小程序开始,选来选去最后选择了京东优选这个小程序(绝对不是因为它的界面清爽!). 开发工具 微信开发者工具 VS Code 效果速览 废话不多说,咱先来搞一波图片看看,点

  • 基于JS实现接粽子小游戏的示例代码

    目录 游戏设计 游戏实现 添加粽子元素 粽子掉落 难度选择 开始游戏 总结 端午节马上就到了,听说你们公司没发粽子大礼包?没关系,这里用 JS 实现了一个简单的接粽子小游戏,能接到多少粽子,完全看你手速,不用担心端午没粽子了. 游戏设计 在游戏屏幕内,会随机的从顶部掉落粽子,通过鼠标移动到粽子上并点击,成功接住粽子,得到积分.在设置面板中,可以设置游戏难度,分为简单.很难.超级难三种等级,不同等级的积分也是不同的,玩家可根据自己的手速进行设置.游戏结束后,可看到自己的成绩.实现出来的效果如下(可

随机推荐