day45扫雷

插件

// 使用闭包,解决$命名冲突问题

(function ($) {
/**
*
*/
function change() {

}
/**
 * 对外提供的接口
 * 
 * 必须传递 行 row,列 column,雷的个数 mine_num,显示画板的位置 obj 盒子的ID值
 */
$.fn.mineClearance = function (options) {
    // console.log(options);

    // var obj1 = {name:'张三',age:16};
    // var obj2 = {name:'李四',addr:'石家庄'}
    // 合并两个对象,如果有相同的属性,则使用后者替换前者
    // 所以前者适合做默认值,后者适合做参数传递
    // var obj3 = $.extend(obj1,obj2);
    // console.log(obj3);
    var settings = $.extend({
        // 默认列
        column: 10,
        // 默认行
        row: 10,
        // 默认雷个数
        mine_num: 20,
        // 默认画板ID
        obj: "#content",
        // 每一个div盒子,默认是空数组
        tiles: [],
        // 周边8个元素
        arr: [],
        // 判断游戏是否是第一点击,如果是第一次就初始化雷,true表示第一次点击
        flag: true
    }, options || {});
    // 生成画板
    buildTiles();
    /**
     * 生成画板
     */
    function buildTiles() {
        // 判断行和列是否合法
        if (settings.column <= 0 || settings.row <= 0) {
            alert('行和列必须大于 0 哦~');
            return;
        }
        // 判断雷
        if (settings.mine_num <= 0) {
            alert("没雷你玩啥?");
            return;
        }
        if (settings.mine_num >= (settings.column * settings.row)) {
            alert("全是雷");
            return;
        }
        // 到这里说明数据没啥问题
        // 获取画板的DOM对象
        var obj = $(settings.obj);
        // 设置画板的宽高
        // 每个盒子宽高是49,边框都是1,所以实际宽高为 51
        // 画板的宽度 = 列数 * 51
        // obj.style.width = 51 * settings.column + "px";
        // obj.style.height = 51 * settings.row + "px";
        obj.width(51 * settings.column);
        obj.height(51 * settings.row);

        // 对div添加索引,0,1,2,3,.....
        // 方便我们操作,我们能够根据点击的是谁,获取它和周边8个元素
        // 比如 3行4列,  我们点的是第6个,索引就是 5
        // 5 % 列数 = 1 
        // (5-1) / 列数 = 1
        var indexOfdiv = 0;
        // 根据行和列 生成div 并设置索引
        for (var i = 0; i < settings.row; i++) {
            for (var j = 0; j < settings.column; j++) {
                // 创建div标签
                // var tile = document.createElement("div");
                var tile = $('<div class="tile"></div>');


                // 设置class属性值为 tile
                // tile.className = 'tile';

                // 添加索引
                // tile.setAttribute('index',indexOfdiv);
                tile.attr('index', indexOfdiv);
                // 把div保存到 settings.tiles数组中,方便我们后续操作
                settings.tiles[indexOfdiv] = $(tile);
                indexOfdiv++;
                // 把div添加到 画板中
                // obj.appendChild(tile);
                obj.append(tile);
            }
        }
        //清空事件,避免叠加事件
        obj.unbind();
        // 绑定事件
        event();

    }

    /**
     * 对div绑定事件
     */
    function event() {
        // 获取画板对象
        var obj = $(settings.obj);
        // 对画板绑定事件,通过事件源,找到真正触发的这个小div即可

        // 移入
        obj.mouseover(function (e) {
            // 如果class属性值不是tile ,
            // 说明要么你移动到已经点击过的div
            // 要么你移动到边框上,就是画板了
            // 我们只对未点击过的div做移入事件
            if ($(e.target).attr('class') == 'tile') {
                $(e.target).attr('class','tile current') ;
                //添加音乐
                $('#move')[0].play();
            }
        });
        // 移出
        obj.mouseout(function (e) {
            // 如果class属性值不是tile ,
            // 说明要么你移动到已经点击过的div
            // 要么你移动到边框上,就是画板了
            // 我们只对未点击过的div做移入事件
            if ($(e.target).attr('class') == 'tile current') {
                $(e.target).attr('class','tile') ;
                //取消音乐
                $('#move')[0].pause();
            }
        });
        // 右键事件,添加小红旗
        obj.contextmenu(function (e) {
            // 当右键的时候,如果不是雷,不是已点击的,就可以添加红旗
            // 因为如果是boom雷的时候,说明游戏已经结束
            if ($(e.target).attr('class') != 'boom' && $(e.target).attr('class') != 'showed') {
                // e.target.className = 'tile';
                // console.log(e.target.className);
                // if(e.target.className.split(' ').length == 3){
                //     e.target.className = 'tile current'
                // }else{
                //     e.target.className = 'tile current tag'
                // }
                $(e.target).toggleClass('tag');
            }
            return false;
        });

        // 点击事件
        obj.click(function (e) {
            // alert(22);
            if ($(e.target).hasClass('tile')) {
                // 获取事件源索引
                // var index = e.target.index;
                var index = $(e.target).index();
                // console.log(index);
                // 判断点击的是否含有小红旗
                // class属性是否包含 tag
                // console.log(e.target.classList.contains('tag'));
                if ($(e.target).hasClass('tag')) {
                    alert("请先右键取消小红旗");
                    return;
                }
            }
            $('#click')[0].play();
            // 到这里 说明点击的不是小红旗
            // 初始化所有div , 生成雷,判断周边几个雷
            changeStyle($(e.target), index);
        });
    }
    /**
     * 生成雷,统计周围雷的个数等
     * 
     * 第一个参数 : 点击的元素
     * 第二个参数 : 该元素的index索引
     */
    function changeStyle(obj, num_index) {
        // 判断是否是第一次点击
        if (settings.flag) {
            // 是的话,生成雷等信息
            // 获取周围八个元素
            // store(num_index);
            // 生成雷,val 表示,1是雷,0不是雷
            setMineCraft();
            settings.flag = false;
        }
        /**
         * 初始化操作已完成
         */

        //  雷和周边雷个数 已完成,需判断点击之后,是否是雷,是否游戏结束(胜利和失败),不是雷就需要进行扩散显示
        // 不是就判断点击的是否是雷
        // 判断游戏是否结束 - 胜利, 失败  
        if (!obj.attr('val')) {
            // 设置为已点击状态
            // obj.className = 'showed';
            obj.attr('class', 'showed');
            // 显示周围几个雷
            // let value = obj.getAttribute('value');
            let value = obj.attr('value');
            obj.html(value) == 0 ? '' : value;
            // 扩散显示
            showAll(obj.index());
        }
        // 判断游戏是否结束,如果结束,显示所有div信息
        // 比如 是雷的 就替换成雷的图片,周围有几个雷 就显示几
        if (over(obj)) {
            // 进来说明游戏结束
            // 显示所有div信息
            show();
        }
    }
    /**
     * 游戏结束 重置div,所有信息都显示
     */
    function show() {
        // 思路 : 遍历所有div 判断val是1是0 是 设置class为 boom 是0 设置class为 showed
        for (var i = 0; i < settings.tiles.length; i++) {
            // settings.tiles[i].className = settings.tiles[i].getAttribute('val') == 1 ? 'boom' : 'showed';
            // console.log($(settings.tiles[i].addClass('val')));
            // $(settings.tiles[i]).addClass($(settings.tiles[i]).attr('val') ==1 ? 'boom' : 'showed') ;
            $(settings.tiles[i]).attr('class', $(settings.tiles[i]).attr('val') == 1 ? 'boom' : 'showed')

            // 如果不是雷 就要显示周边几个雷
            if ($(settings.tiles[i]).attr('class') != 'boom') {
                var value = $(settings.tiles[i]).attr('value');
                $(settings.tiles[i]).html(value) == 0 ? '' : value;
            }
        }
        // 取消事件
        $(settings.obj).unbind('click');
        
    }
    /**
     * 游戏结束判断
     * 
     * @param {点击的元素} obj 
     */
    function over(obj) {
        // true说明结束,false说明没有结束
        var flag = false;
        // 如何算游戏胜利 : 已点击的 + 雷的个数 = 总div个数
        // 获取已点击的元素
        var showed = $('.showed');
        // div总个数 减去 雷的个数,得到剩余div个数
        var num = settings.tiles.length - settings.mine_num;
        if (num == showed.length) {
            $('#victory')[0].play();
            alert("恭喜你获得成功~");
            flag = true;
            
            // 如何算失败 : 点到雷就失败  val == 1
        } else if (obj.attr('val') == 1) {
            $('#boom')[0].play();
            alert('被炸死,游戏结束!');
            $('#gameover')[0].play();
            flag = true;
        }
        // 没结束 就返回false,继续游戏
        return flag;
    }
    /**
     * 判断周围是否是雷,如果不是雷,就全部显示
     * 
     * 如果周围有雷,就不再进行遍历
     * 
     * @param {点击元素的索引} num 
     */
    function showAll(num) {
        // 判断 周围是否有雷
        // 如果有 终止
        // 如果没有,遍历周边元素的周边元素,依次判断
        // console.log($(settings.tiles[num]).attr('class') == 'showed'==$(settings.tiles[num]).attr('value'));

        if ($(settings.tiles[num]).attr('class') == 'showed' && $(settings.tiles[num]).attr('value') == 0) {
            // 获取周边8个(settings.arr)
            store(num);
            // 如果递归,会更改arr的值,所以保存为局部变量
            var arr2 = settings.arr;
            // 非showed 
            for (var i = 0; i < arr2.length; i++) {
                // 如果添加小红旗标识 就跳过该次循环
                // console.log($(arr2[i]).hasClass('tag'));
                if ($(arr2[i]).hasClass('tag')) {
                    continue;
                }
                if ($(arr2[i]).attr('class') != 'showed') {
                    // value == 0
                    // 判断周边8个是否有雷,没有就显示并递归

                    if ($(arr2[i]).attr('value') == 0) {
                        //  true     递归
                        // arr2[i].className = 'showed';
                        $(arr2[i]).attr('class', 'showed');
                        // console.log($(arr2[i]).index());
                        showAll($(arr2[i]).attr('value'));
                    } else {
                        //  false 设置为showed并显示value
                        // arr2[i].className = 'showed';

                        $(arr2[i]).attr('class', 'showed');
                        // arr2[i].innerHTML = arr2[i].getAttribute('value');
                        $(arr2[i]).html($(arr2[i]).attr('value'));
                    }
                }
            }

        }
    }
    /**
     * 生成雷,val 表示,1是雷,0不是雷
     */
    function setMineCraft() {
        // 雷的个数
        var num = settings.mine_num;
        // 遍历所有div 设置不是雷
        // for (var i = 0; i < settings.tiles.length; i++) {
        //     settings.tiles[i].setAttribute('val', 0);
        // }
        // 随机生成雷
        for (var i = 0; i < num; i++) {
            // 随机的雷的索引
            var index_Mine = Math.floor(Math.random() * settings.tiles.length);
            // 判断生成的索引 是否生产过雷
            // console.log(settings.tiles[index_Mine].getAttribute("val"));
            if (!$(settings.tiles[index_Mine]).attr("val")) {
                // 没有 就设置为 雷
                $(settings.tiles[index_Mine]).attr('val', 1);
            } else {
                // 如果生产过 就不搭理,但是 i要-1  否则 最终雷的个数就会少
                i--;
            }
        }
        // 设置value值,点击之后 显示周围有几个雷
        showValue();
    }
    /**
     * 设置value值,点击之后 显示周围有几个雷
     * 
     * 比如周围8个有一个类 就显示1 
     */
    function showValue() {
        // 1 对所有不是雷的元素 设置内容
        // 2 获取每个非雷元素的周边8个盒子
        // console.log(settings.tiles.length);
        for (var i = 0; i < settings.tiles.length; i++) {
            // 判断是否是雷,是就跳过
            if ($(settings.tiles[i]).attr('val') == 1) {
                continue;
            }
            // 如果不是雷,就获取周边8个元素,传递当前元素的索引 index
            store($(settings.tiles[i]).index());
            // console.log(settings.arr);
            // 3 遍历8个盒子,对雷的个数进行计数 arr
            var count = 0;
            for (var j = 0; j < settings.arr.length; j++) {
                if ($(settings.arr[j]).attr('val') == 1) {
                    count++;
                }
            }
            // 4 把计数结果 设置到 当前div的内容当中 
            // if (count != 0) {
            // settings.tiles[i].innerHTML = count;
            // settings.tiles[i].setAttribute('value', count);
            $(settings.tiles[i]).attr('value', count);
            // }
        }
    }
    /**
     *  获取周围八个元素
     * @param {点击的元素的索引} num 
     */
    function store(num) {
        /**
         * settings.tiles 转换为二维数组,方便查找周边八个元素
         */
        // var tiles_2d = [];
        // 当做 settings.tiles的下标
        // var indexs = 0;
        // 遍历settings.tiles 封装到二维数组中
        // for (var i = 0; i < settings.row; i++) {
        //     // 二维数组中 添加一个空的一维数组
        //     tiles_2d.push([]);
        //     for (var j = 0; j < settings.column; j++) {
        //         tiles_2d[i].push(settings.tiles[indexs]);
        //         indexs++;
        //     }
        // }
        // 根据点击的元素的索引 获取在二维数组中的下标
        // var j = num % settings.column;
        // var i = (num - j) / settings.column;
        // 对settings.arr 初始化
        settings.arr = [];
        var index = num;
        var c = settings.column;
        var r = settings.row;
        // 左上
        if (index % c > 0 && index - c >= 0) {
            settings.arr.push(settings.tiles[index - c - 1]);
        }
        // 正上
        if (index - c >= 0) {
            settings.arr.push(settings.tiles[index - c]);
        }
        // 右上
        if (index - c >= 0 && index % c < c - 1) {
            settings.arr.push(settings.tiles[index - c + 1]);
        }
        // 左边
        if (index % c > 0) {
            settings.arr.push(settings.tiles[index - 1]);
        }
        // 右边
        if (index % c < c - 1) {
            settings.arr.push(settings.tiles[index + 1]);
        }
        // 左下
        if (index % c > 0 && index + c < c * r) {
            settings.arr.push(settings.tiles[index + c - 1]);
        }
        // 正下
        if (index + c < c * r) {
            settings.arr.push(settings.tiles[index + c]);
        }
        // 右下
        if (index % c < c - 1 && index + c < c * r) {
            settings.arr.push(settings.tiles[index + c + 1]);
        }
        // console.log(settings.arr);
    }
}

})(jQuery);

css

{
margin: 0;
padding: 0;
}
body{
text-align: center;
font-size: 15px;
font-family: ‘楷体’;
}
#content{
/
border: 1px solid; /
/
width: 200px; /
margin: 0 auto;
}
/
重新加载 /
#refresh{
/
设置行内块,否则不能设置宽高 /
display: inline-block;
width: 100px;
height: 30px;
/
行高和高度一致,则内容垂直居中 /
line-height: 30px;
border: 1px solid gray;
/
圆角边 /
border-radius: 5px;
/
小手状 */
cursor: pointer;
color: white;
background-color: rgb(143,122,102);
}

/* 每一个div小格子 /
/
默认 */
#content div{
width: 48px;
height: 49px;
border: 1px solid black;
text-align: center;
font-size: 20px;
line-height: 49px;
cursor: pointer;
float: left;
}
.tile{
background: url(…/img/ba.png);
}

/* 已点击 */
.showed{

background: rgb(195,206,228);
/* background-color: red; */

}
/* 雷 /
.boom{
background: rgb(195,206,228) url(…/img/Minesmall.png);
}
/
移入 */
.current{

background: url(../img/baq.png);

}
/* 小红旗 /
.tag{
/
第一个是前景,第二个是背景 */
background: url(…/img/hq.png),url(…/img/ba.png);
}

布局

Document 初级 中级 高级 自定义
行: 列: 雷:
开始游戏 重新加载游戏

选择难度并点击确定,开始游戏
右键可以标记小红旗哦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值