javascript实现扫雷游戏

html代码:

        <div id="mine">
            <div class="level">
                <button type="button">初级</button>
                <button type="button">中级</button>
                <button type="button">高级</button>
                <button type="button">重新开始</button>
            </div>
            <div class="gameBox"></div>
            <div class="info">
                剩余雷数:<span class="mineNum"></span>
            </div>
        </div>        

css代码:

 1 #mine {
 2     margin: 50px auto;
 3 }
 4 .level {
 5     text-align: center;
 6     margin-bottom: 10px;
 7 }
 8 .level button {
 9     padding: 5px 15px;
10     background-color: cornflowerblue;
11     border: none;
12     color: #fff;
13     border-radius: 3px;
14     outline: none;
15     cursor: pointer;
16 }
17 .level button.active {
18     background-color: #00abff;
19 }
20 .info {
21     margin-top: 10px;
22     text-align: center;
23 }
24 table {
25     border-spacing: 1px;
26     background: #929196;
27     margin: 0 auto;
28 }
29 td {
30     padding: 0;
31     width: 20px;
32     height: 20px;
33     background: #ccc;
34     border: 2px solid;
35     border-color: #fff #a1a1a1 #a1a1a1 #fff;
36     
37     text-align: center;
38     line-height: 20px;
39     font-weight: bold;
40 }
41 td.zero {
42     border-color: #D9D9D9;
43     background: #D9D9D9;
44 }
45 td.one {
46     border-color: #D9D9D9;
47     background: #D9D9D9;
48     color: #0332fe;
49 }
50 td.two {
51     border-color: #D9D9D9;
52     background: #D9D9D9;
53     color: #019f02;
54 }
55 td.three {
56     border-color: #D9D9D9;
57     background: #D9D9D9;
58     color: #ff2600;
59 }
60 td.four {
61     border-color: #D9D9D9;
62     background: #D9D9D9;
63     color: #93208f;
64 }
65 td.five {
66     border-color: #D9D9D9;
67     background: #D9D9D9;
68     color: #019f02;
69 }
70 td.six {
71     border-color: #D9D9D9;
72     background: #D9D9D9;
73     color: #ff3fff;
74 }
75 td.seven {
76     border-color: #D9D9D9;
77     background: #D9D9D9;
78     color: #3fffbf;
79 }
80 td.eight {
81     border-color: #D9D9D9;
82     background: #D9D9D9;
83     color: #22ee0f;
84 }
85 .mine {
86     background: #d9d9d9 url(./mine.png) no-repeat center;
87     background-size: cover;
88 }
89 .flag {
90     background: #ccc url(./flag.png) no-repeat center;
91     background-size: cover;
92 }

javascript代码:

  1 function Mine(tr, td, mineNum) {
  2     this.tr = tr; //行数
  3     this.td = td; //列数
  4     this.mineNum = mineNum; //雷的数量
  5 
  6     this.squares = []; //存储所有方块的信息,他是一个二维数组,按行列的顺序摆放,存储都使用行列形式
  7     this.tds = []; //存储所有单元格的DOM(二维数组)
  8     this.surplusMine = mineNum; //剩余雷的数量
  9     this.allRight = false; //右击标的小红旗是否全是雷,用来判断用户是否游戏成功
 10 
 11     this.parent = document.querySelector('.gameBox');
 12 
 13
 14 }
 15 
 16 //生成n格不重复的数字
 17 Mine.prototype.randomNum = function() {
 18     var square = new Array(this.tr * this.td), //先生成一个空数组,长度为格子的总数
 19         len = square.length;
 20     for (var i = 0; i < square.length; i++) {
 21         square[i] = i;
 22     }
 23     square.sort(function() {
 24         return 0.5 - Math.random()
 25     });
 26     return square.slice(0, this.mineNum);
 27 }
 28 Mine.prototype.init = function() {
 29     var rn = this.randomNum(); //雷在格子里的位置
 30     var n = 0; //用来找到格子对应的索引
 31     for (var i = 0; i < this.tr; i++) {
 32         this.squares[i] = [];
 33         for (var j = 0; j < this.td; j++) {
 34             // this.squares[i][j] = ;
 35 
 36             //取一个方块在数组里的数据要使用行和列的形式去取,
 37             //找方块周围的方块的时候要使用坐标的形式去取,
 38             //行和列的形式跟坐标的形式 x,y 是刚好相反的
 39 
 40             if (rn.indexOf(++n) != -1) {
 41                 //如果这个条件成立,说明现在循环到的这个索引在雷的数组中找到了,那就表示这个索引对应的是个雷
 42                 this.squares[i][j] = {
 43                     type: 'mine',
 44                     x: j,
 45                     y: i
 46                 };
 47             } else {
 48                 this.squares[i][j] = {
 49                     type: 'number',
 50                     x: j,
 51                     y: i,
 52                     value: 0
 53                 };
 54             }
 55         }
 56     }
 57 
 58 
 59     this.updateNum();
 60     this.createDom();
 61 
 62     this.parent.oncontextmenu = function() {
 63         return false;
 64     }
 65 
 66     //剩余雷数
 67     this.mineNumDom = document.querySelector('.mineNum');
 68     this.mineNumDom.innerHTML = this.surplusMine;
 69 
 70 };
 71 
 72 //创建表格
 73 Mine.prototype.createDom = function() {
 74     var self = this;
 75     var table = document.createElement('table');
 76 
 77     for (var i = 0; i < this.tr; i++) { //
 78         var domTr = document.createElement('tr');
 79         this.tds[i] = [];
 80 
 81         for (var j = 0; j < this.td; j++) { //
 82             var domTd = document.createElement('td');
 83 
 84             domTd.pos = [i, j]; //把格子对应的行和列存到格子身上,为了下面通过这个值去数组里取到对应的数据
 85             domTd.onmousedown = function() {
 86                 self.play(event, this); //self 指的是实例对象, this指的是点击的那个td
 87             };
 88 
 89             this.tds[i][j] = domTd; //这里是把所有创建的td都添加到数组中
 90 
 91             // if (this.squares[i][j].type == 'mine') {
 92             //     domTd.className = 'mine';
 93             // }
 94             // if (this.squares[i][j].type == 'number') {
 95             //     domTd.innerHTML = this.squares[i][j].value;
 96             // }
 97 
 98 
 99             domTr.appendChild(domTd);
100         }
101         table.appendChild(domTr);
102     }
103     this.parent.innerHTML = '';
104     this.parent.appendChild(table);
105 };
106 
107 //找某个方格周围的8个方格
108 Mine.prototype.getAround = function(square) {
109     var x = square.x;
110     var y = square.y;
111     var result = []; //把找到的格子的坐标返回出去--二维数组
112 
113 
114     //通过坐标去循环九宫格
115     for (var i = x - 1; i <= x + 1; i++) {
116         for (var j = y - 1; j <= y + 1; j++) {
117             if (
118                 i < 0 || //格子超出了左边的范围
119                 j < 0 || //格子超出了上边的范围
120                 i > this.td - 1 || //格子超出了右边的范围
121                 j > this.tr - 1 || //格子超出了下边的范围
122                 (i == x && j == y) || //当前循环到的格子是自己
123                 this.squares[j][i].type == 'mine' //周围的格子是个雷
124             ) {
125                 continue;
126             }
127 
128             result.push([j, i]); //要以行和列
129         }
130     }
131     return result;
132 };
133 
134 //更新所有的数字
135 Mine.prototype.updateNum = function() {
136     for (var i = 0; i < this.tr; i++) {
137         for (var j = 0; j < this.td; j++) {
138             //只更新的是雷周围的数字
139             if (this.squares[i][j].type == 'number') {
140                 continue;
141             }
142 
143             var num = this.getAround(this.squares[i][j]); //获取到每一个雷周围的数字
144 
145             for (var k = 0; k < num.length; k++) {
146                 this.squares[num[k][0]][num[k][1]].value += 1;
147             }
148         }
149     }
150 }
151 
152 
153 Mine.prototype.play = function(ev, obj) {
154     var self = this;
155     if (ev.which == 1 && obj.className != 'flag') { //后面的条件是为了限制用户标完小红旗后就不能够被左键点击
156 
157         var curSquare = this.squares[obj.pos[0]][obj.pos[1]];
158         var cl = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']
159         if (curSquare.type == 'number') {
160             //用户点到的是数字
161 
162             obj.innerHTML = curSquare.value;
163             obj.className = cl[curSquare.value];
164
165             if (curSquare.value == 0) {
166                 /*
167                     用户点到了数字0
168                      1/显示自己
169                      2/找周围
170                         1/显示四周(如果周围的值不为0, 那就显示到这里,不需要再找了
171                         2/如果值为0
172                             1/显示自己
173                             2/找四周(如果四周的值不为0,那就显示到这里,不需要再找了)
174                 */
175                 obj.innerHTML = ''; //如果数字为0的话,不显示
176                 function getAllZero(square) {
177                     var around = self.getAround(square); //找到了周围的n个格子
178 
179                     for (var i = 0; i < around.length; i++) {
180                         var x = around[i][0]; //
181                         var y = around[i][1]; //
182 
183                         self.tds[x][y].className = cl[self.squares[x][y].value];
184 
185                         if (self.squares[x][y].value == 0) {
186                             //如果以某个格子为中心找到的格子值为0,那就需要接着调用函数
187                             if (!self.tds[x][y].check) {
188                                 //给对应的td函数一个属性,这条属性用于决定这个格子有没有被找过
189                                 //如果找过的话,他的值就为true,下一次就不会再找了
190                                 self.tds[x][y].check = true;
191                                 getAllZero(self.squares[x][y]);
192                             }
193                         } else {
194                             //如果以某个格子为中心找到的四周格子的值不为0, 那就把人家的数字显示出来
195                             self.tds[x][y].innerHTML = self.squares[x][y].value;
196                         }
197                     }
198                 }
199                 getAllZero(curSquare);
200             }
201         } else {
202             this.gameOver(obj);
203         }
204     }
205     //用户点击 的 是右键
206     if (ev.which == 3) {
207         //如果右击的是一个数字,就不能点击
208         if (obj.className && obj.className != 'flag') {
209             return;
210         }
211         obj.className = obj.className == 'flag' ? '' : 'flag'; //切换class
212 
213         if (this.squares[obj.pos[0]][obj.pos[1]].type == 'mine') {
214             this.allRight = true;
215         } else {
216             this.allRight = false;
217         }
218         if (obj.className == 'flag') {
219             this.mineNumDom.innerHTML = --this.surplusMine;
220         } else {
221             this.mineNumDom.innerHTML = ++this.surplusMine;
222         }
223         if (this.surplusMine == 0) {
224             //剩余的雷的数量为0 ,表示用户已经标完小红旗了,这时候要判断游戏是成功还是结束
225             if (this.allRight) {
226                 alert('恭喜你,游戏通过');
227             } else {
228                 alert('恭喜你,游戏失败');
229                 this.gameOver();
230             }
231         }
232 
233     }
234 };
235 
236 //游戏失败函数
237 Mine.prototype.gameOver = function(clickTd) {
238     /*
239         1\显示所有的雷
240         2/取消所有格子的点击事件
241         3/给点中的那个雷标上一个杠
242     */
243     for (var i = 0; i < this.tr; i++) {
244         for (var j = 0; j < this.td; j++) {
245             if (this.squares[i][j].type == 'mine') {
246                 this.tds[i][j].className = 'mine';
247             }
248 
249             this.tds[i][j].onmousedown = null;
250         }
251     }
252 
253     if (clickTd) {
254         clickTd.style.backgroundColor = '#f00';
255     }
256 
257 
258 }
259 
260 //添加的是上面button的功能
261 var btns = document.querySelectorAll('.level button');
262 var mine = null;
263 var ln = 0;
264 var arr = [
265     [9, 9, 10],
266     [16, 16, 40],
267     [28, 28, 90]
268 ];
269 
270 for(let i =0; i < btns.length-1; i ++) {
271     btns[i].onclick = function() {
272         btns[ln].className = '';
273         this.className = 'active';
274         
275         mine = new Mine(...arr[i]);
276         mine.init();
277         ln = i;
278     }
279 }
280 btns[0].onclick();   //初始化一下
281 btns[3].onclick = function () {
282     mine.init();
283 }
284 // var mine = new Mine(28, 28, 99);
285 
286 // mine.init();

猜你喜欢

转载自www.cnblogs.com/hjysunshine/p/12284480.html