基于JavaScript实现简单扫雷游戏

时间:2022-07-05 04:54:52

对于10年前的人来说,扫雷肯定是家喻户晓,由于当时的科技并不是很发达,大家对于电脑游戏的了解,可能都是从扫雷开始的,今天就交大家一种用js原生代码写一个简单的扫雷游戏,话不多说,直接上干货:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style>
  *{
   margin: 0;
   padding: 0;
  }
  li{
   list-style: none;
  }
  .box{
   border: 1px solid #666;
   position: fixed;
   width: 300px;
   height: 350px;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
   margin: auto;
  }
  .btn-group{
   display: flex;
   height: 50px;
   line-height: 50px;
   text-align: center;
   justify-content: space-evenly;
   font-size: 12px;
  }
  .row{
   height: 30px;
   line-height: 30px;
   text-align: center;
   display: flex;
  }
  .col{
   flex-shrink: 0;
   /* flex-shrink 是否允许缩小 */
   flex-grow: 0;
   /* flex-grow 是否允许放大 */
   width: 30px;
   height: 30px;
   border: 1px solid #666;
   background-color: #ccc;
   box-sizing: border-box;
  }
 </style>
</head>
<body>
 <div class="box">
  <div class="qipan">
  </div>
  <div class="btn-group">
   <div class="btn-item">
    <span class="item-name">时间</span>
    <span class="item-value passTime">000</span>
   </div>
   <div class="btn-item">
    <span class="item-name">剩余雷数</span>
    <span class="item-value leftLei">10</span>
   </div>
   <div class="btn-item">
    <select class="level">
     <option value="1">初级</option>
     <option value="2">中级</option>
     <option value="3">高级</option>
    </select>
   </div>
   <div class="btn-item">
    <span class="start">开始</span>
    <span class="restart">重开</span>
   </div>
  </div>
 </div>
 <script>
  function $(s,t){
   if(t == 'l'){
    return document.querySelectorAll(s)
   }else{
    return document.querySelector(s)
   }
  }
  var qipan = $('.qipan'),
    box = $('.box'),
    level = $('.level'),
    leftLei = $('.leftLei'),
    start = $('.start'),
    restart = $('.restart'),
    passTime = $('.passTime')
    ;
  var row = 10,// 行数
    col = 10,// 列数
    leiNum = 10,// 雷数
    restNum = 10,//剩余的雷数
    flag = false,// 格子是否可以被点击
    time,//计时器的名字
    count = 0,// 计时的秒数
    leiList = [],// 用来存放地雷坐标的数组
    sum = col*row,// 棋盘所有格子的总数
    openGz = 0,// 已经点开的格子的数量
    color = ['rgba(0,0,255,.6)','rgba(0,255,0,.6)','red','blue','yellow','pink','auqa','black']
    ;
  window.oncontextmenu = function(e){
   e.preventDefault();
   if(!flag){
    alert('请先点开始!');
    return;
   }
   if(e.target.isOpen){
    alert('这个格子已经翻过了,换个格子标记');
    return
   }
   if(e.target.localName == 'li'){
    if(e.target.isMark){
     e.target.isMark = false;
     e.target.innerHTML = '';
     restNum++;
    }else{
     e.target.isMark = true;
     e.target.innerHTML = '▲';
     e.target.style.color = 'red';
     restNum--;
    }
    leftLei.innerHTML = restNum
   }
  }
  start.onclick = function(){//点击开始游戏
   flag = true;// 棋盘可以被点击
   if(time>0){// 判断开始键是否已经被点过,防止重复点击
    alert('游戏已经开始了,不要再点开始了')
    return
   }
   countTime()//开始计时
  }
  restart.onclick = function(){//点击开始游戏
   flag = false;// flag置为false,棋盘格子变成不可点击状态
   createQp();// 画棋盘
  }
  box.onclick = function(e){//点击棋盘的格子
   var t = e.target;
   if(t.localName == 'li'){// 只有当点击的格子是li的时候才会继续往下判断
    if(!flag){// 如果当前不允许点击,提示先点开始
     alert('请先点开始!')
     return
    }
    var x = t.dataset.x - 0 ,y = t.dataset.y - 0;
    // console.log(x,y);
    if(t.isOpen){
     alert('这个格子已经翻过了,换个格子翻');
     return
    }
    if(t.isMark){
     alert('这个格子已经标记了,换个格子翻');
     return
    }
    if(isInArray(x,y,leiList) != -1 ){
     flag = false;
     clearInterval(time);
     count = 0;
     passTime.innerHTML = count;
     boom();
     alert('你输了')
    }else{
     testLei(x,y);
     if(leiNum == sum - openGz){
      flag = false;
      boom();
      clearInterval(time);
      alert('你赢了');
     }
    }
   }
  }
  level.onchange = function(){
   var v = this.value;//获取改变后的level
   if(v == 1){//改变棋盘规格及雷的数量
    row = 10;
    col = 10;
    leiNum = 10;
   }else if(v == 2){
    row = 16;
    col = 16;
    leiNum = 40;
   }else if(v == 3){
    row = 16;
    col = 30;
    leiNum = 99;
   }
   createQp();// 重新画棋盘
  };
  function createQp(){// 创建棋盘
   var str = '';
   for(var i = 0;i<row;i++){// 行数
    str += '<ul class="row">'
    for(var j = 0;j<col;j++){// 列数
     str+='<li class="col" data-x="'+i+'" data-y="'+j+'"></li>'
    }
    str += '</ul>'
   }
   box.style.width = col * 30 +'px';//修改box的宽度
   box.style.height = row * 30 + 50 +'px';// 修改box的高度
   leftLei.innerHTML = leiNum;// 修改剩余雷数
   qipan.innerHTML = str;// 将拼接的棋盘内容添加到棋盘中
   count = 0;// 计时重置为0
   sum = row*col;// 重置格子的总数
   openGz = 0;// 重置已经点开的格子的数量
   passTime.innerHTML = count; // 时间设置为count
   restNum = leiNum;//重置剩余的雷的数量
   leftLei.innerHTML = restNum;
   clearInterval(time);// 清除定时器
   time = 0;// 定时器变量的值置为 0
   createLei();
  }
  function countTime(){// 开始计时
   time = setInterval(function(){
    count++;
    passTime.innerHTML = count;
   },1000)
  }
  function createLei(){// 创建地雷
   leiList = [];// 把地雷的坐标先清空
   for(var i = 0;i<leiNum;i++){
    var x = parseInt(Math.random()*row),//
     y = parseInt(Math.random()*col);//
     if(isInArray(x,y,leiList) == -1){// 如果 x,y组成的坐标[x,y] 不在leiList里
      leiList.push([x,y])// 把 [x,y] push进 leiList里
     }else{// x,y组成的坐标 [x,y] 已经在 leiList里了
      i-- // 重新取一次随机坐标
     }
   }
  }
  // arr = [[0,0],[1,1],[2,2],...]
  function isInArray(x,y,arr){// 判断 x,y 组成的坐标 [x,y] 在不在数组 arr 里
   for(var i = 0;i<arr.length;i++){// 遍历arr的每一个元素
    if(x == arr[i][0] && y == arr[i][1]){// 将 x与arr[i]的第0个元素对比,将 y 与 arr[i]的第1个元素对比,如果能对上,说明 [x,y] 已经存在于 arr 里,
     return i;// 返回[x,y] 在 arr中的索引
    }
   }
   if(i == arr.length){// 当 循环遍历一遍也没在arr中找到与 [x,y] 相同的坐标时,说明 [x,y] 不在arr 里
    return -1;// 返回 -1;
   }
  }
  function boom(){// boom
   var ul = $('.row','l');//获取棋盘里所有的行
   for(var i = 0;i<leiList.length;i++){
    var li = ul[leiList[i][0]].querySelectorAll('li')[leiList[i][1]];//通过索引去获取行里具体的li
    li.style.background = 'red'
   }
  }
  function testLei(x,y){
   var num = 0; // 声明一个num用来累计雷的数量
   for(var i = 0;i<leiList.length;i++){// 遍历所有的雷的坐标
    if(Math.abs(x - leiList[i][0]) <2 && Math.abs(y - leiList[i][1])<2){// 找到在当前点击的格子周围八个格子里的雷
     num++;
    }
   }
   var ul = $('.row','l');
   var li = ul[x].querySelectorAll('li')[y];// 通过索引获取当前被点击的格子
   li.innerHTML = num;// 把格子的内容换成雷的数量
   li.isOpen = true;// 给当前格子加一个属性 isOpen,表示当前格子已经被点开了
   openGz++;
   li.style.background = '#fff';
   if(num>0){
    li.style.color = color[num-1];// 把代表雷的数量的数字换一个颜色
   }
   if(num == 0){// 如果当前格子周围没有雷
    li.innerHTML = '';//
    for(var a = x-1;a<=x+1;a++){//
     for(var b = y-1;b<=y+1;b++){// 遍历当前格子周围八个格子
      var ul = $('ul','l');
      if(a>= 0 && a<row && b>=0 && b<col){// 保证要遍历的格子坐标在棋盘之内
       var dom = ul[a].querySelectorAll('li')[b];// 通过坐标获取到具体的 li
       if(!dom.isOpen && !dom.isMark){// 判断当前的li格子是否已经被点开了,如果还没有被点开,递归查询该格子周围有几颗雷
        testLei(a,b)
       }
      }
     }
    }
   }
  }
  createQp();
 </script>
</body>
</html>

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

原文链接:https://blog.csdn.net/weixin_48156531/article/details/111951871