资讯专栏INFORMATION COLUMN

扫雷小程序的js实现

crelaber / 1302人阅读

摘要:初学,写了一个扫雷程序练练手扫雷规则及功能扫雷想必大家都不陌生,就是上点击排雷的小游戏,它的主要规则有左键点击显示当前格子是否为雷,如果为雷的话,啦,如果不是雷的话,这个格子会显示周围八个格子内的雷数量。

初学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

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-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= 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

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

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]=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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88664.html

相关文章

  • 扫雷游戏(C语言实现

    摘要:写在前面我们已经写过了三子棋小游戏肯定没玩过瘾,我们再写个扫雷小游戏吧目录写在前面认识游戏游戏规则游戏框架游戏实现效果展示全部代码文件文件文件认识游戏相信大家对扫雷都不陌生每台电脑必备的小游戏游戏规则就是在规定的时间将 ...

    Coding01 评论0 收藏0
  • 扫雷(C语言版)

    摘要:展示雷盘和初始化雷盘不一样,展示雷盘只需要用即可,并不需要将都展示出来,只是为了我们更好的计算扫雷的位置周围的雷的数量。 目录 1、需求分析 2、程序架构 3、代码实现(分函数呈现) (1)主函数代码实现 分析: 异常处理: (2)游戏主函数实现 分析: (3)初始化函数的实现 分析: (4...

    EscapedDog 评论0 收藏0
  • [译]JavaScript中不可变性(Immutability)

    摘要:整个这个雷区面板都是由的和组成的,最后由的方法对其进行不可变化处理剩下的主要逻辑部分就是扫雷了,传入扫雷游戏对象一个不可变结构做为第一个参数,以及要扫的那个雷区块对象,最后返回新的扫雷游戏实例。 不可变性(Immutability)是函数式编程的核心原则,在面向对象编程里也有大量应用。在这篇文章里,我会给大家秀一下到底什么是不可变性(Immutability)、她为什么还这么屌、以及在...

    clasnake 评论0 收藏0

发表评论

0条评论

crelaber

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<