初学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函数中