Fullmoonbaka 发表于 2021-7-28 17:36

【扫雷游戏】使用 javascript 编写的扫雷游戏

本帖最后由 Fullmoonbaka 于 2021-7-28 21:31 编辑

如题所示,
本人使用javascript实现了一个扫雷游戏,基本涵盖了windows7扫雷的所有基本功能


游戏程序主要技术点:
1.【生成炸弹】
在第一次点击地板的时候,需要确保点击的地方不是炸弹(防止第一次点击就输),因此炸弹生成在第一次点击之后。
在第一次点击时先获取到点击落点周围9格的id,
在所有地板id的列表中排除这些id,
然后在剩下的id中随机抽取一定量的地板id生成炸弹
2.【揭开地板】(个人觉得是扫雷的核心规则)
在揭开地板时先判断是否为炸弹,为炸弹就直接判输
如果不为炸弹,获取落点地板周围9格的地板id逐个判断是否为炸弹,
如果有炸弹就将落点地板标上炸弹数且就此结束
如果没有炸弹就递归遍历落点地板周围一圈8个地板重复执行此操作
(此操作会形成一揭一大片的情况,当周围的8个地板都没有炸弹时一直往外扩散遍历,直至检测到炸弹以后将地板填入数字后停止。)
这一步要注意将地板的状态及时更新成揭开状态,不然会无限递归导致卡死
3.【双击地板】
双击地板操作需要双击已经揭开、带有数字并且附近插有旗子的地板才有效。
当落点周围8格有雷且插上旗子数等于雷的数量的时候,会自动揭开其他格子。(据我多年扫雷经验,此规则应该和win7版扫雷的左键+右键功能一致)
如果插旗错误(对应的旗子没有插在雷上而是插在安全格子上)会直接失败,如果插旗每个都插在雷上,会自动揭开周围8格其他所有未揭开且未插旗的格子。
本操作规则遵守揭开地板规则,遇到空地板时候会递归揭开周围的格子。

想要运行的可以看这个 https://www.52pojie.cn/thread-1484299-1-1.html
本人编程时间尚短、技术力有限,本文章有错误望大佬一一指正。


      class sweep{
            constructor(item) {
                this.item = document.querySelector(item)
                this.bombNum = 99   // 炸弹数量(默认)
                this.allBlock = []// 全部地块DOM列表
                this.blockList = [] // 无炸弹地块列表
                this.bombList = []// 有炸弹地块列表
                this.showList = []// 揭开地块的列表
                this.blockObj = []// 地块对象
                this.flagList = new Set()   // 旗子列表
                this.begin = false// 开始
                this.timer = null   // 计时器

                this.init()
            }

            // 启动器
            init () {
                this.conTextMenu()
                this.createFloor()
                this.clickBlock()
            }

            // 生成地形
            createFloor () {
                let frg = document.createDocumentFragment()
                for(let j = 0; j < 450; j++){
                  let div = document.createElement('div')
                  this.blockList.push(j)
                  this.blockObj.push({
                        id: j,
                        x: j%30,
                        y: parseInt(j/30)
                  })
                  div.dataset.id = j
                  div.className = 'block'
                  this.allBlock.push(div)
                  frg.appendChild(div)
                }
                this.item.appendChild(frg)
            }

            // 生成炸弹
            createBomb (arr) {
                this.bombNum = parseInt(document.querySelector('#num').value)
                arr.forEach((item) => {
                  this.blockList.splice(this.blockList.indexOf(item), 1)
                })
                for(let i = 0; i < this.bombNum; i++){
                  this.bombList.push(this.blockList.splice(parseInt(Math.random() * this.blockList.length), 1))
                }
                arr.forEach((item) => {
                  this.blockList.push(item)
                })
            }

            // 点击事件
            clickBlock () {
                // 单击
                this.item.addEventListener('click', (e) => {
                  e = e || window.event
                  let target = e.target || e.srcElement
                  if(!this.begin){
                        this.begin = true
                        this.setTime()
                        let arr = this.getBlock(target.dataset.id - 0)
                        arr.push(target.dataset.id - 0)
                        this.createBomb(arr)
                  }
                  if(target.className === 'block'){
                        this.show(target)
                        if(!this.blockList.some((item) => {return this.allBlock.className !== 'show'})){
                            this.victory()
                            return
                        }
                  }
                })

                // 选中事件
                this.item.addEventListener('selectstart', (e) => {
                  e = e || window.event
                  e.preventDefault()
                })

                // 双击事件
                this.item.addEventListener('dblclick', (e) => {
                  e = e || window.event
                  let target = e.target || e.srcElement
                  if(target.className === 'show'){
                        let num = target.dataset.id - 0
                        let arr = this.getBlock(num)
                        if(arr.some((item) => { return this.bombList.indexOf(item) !== -1 && this.allBlock.className !== 'bomb' })){
                            if(target.innerText - 0 && arr.filter((item) => { return this.allBlock.className === 'bomb'}).length === target.innerText - 0){
                              this.fail()
                            }
                        } else {
                            arr.forEach((item) => {
                              if(this.allBlock.className === 'block'){
                                    this.show(this.allBlock)
                              }
                            })
                            if(this.showList.length === this.blockList.length) {
                              this.victory()
                            }
                        }
                  }
                })
            }

            // 判断方块四周
            show (item) {
                let sum = 0
                let num = parseInt(item.dataset.id)
                if(this.bombList.some((i) => { return i === parseInt(item.dataset.id) })){
                  this.fail()
                } else {
                  this.showList.push(parseInt(item.dataset.id))
                  let arr = this.getBlock(num)
                  arr.forEach((one) => {
                        if(this.bombList.some((i) => {return i === one})){
                            sum ++
                        }
                  })
                  item.className = 'show'
                  if(sum){
                        item.innerText = sum
                  } else {    // 追加 show
                        arr.forEach((num) => {
                            if(this.allBlock.className === 'block'){
                              this.show(this.allBlock)
                            }
                        })
                  }
                }
            }

            // 获取到四周的方块
            getBlock(num) {
                let arr = []
                if(num === 0){
                  arr =
                } else if (num === 29){
                  arr =
                } else if (num === 420){
                  arr =
                } else if (num === 449){
                  arr =
                } else if (num < 29){
                  arr =
                } else if (num > 420){
                  arr =
                } else if (num % 30 === 0){
                  arr =
                } else if (num % 30 === 29){
                  arr =
                } else {
                  arr =
                }
                return arr
            }

            // 计时器
            setTime(){
                let t = document.getElementById('time')
                let s = t.innerText - 0
                this.timer = setInterval(() => {
                  s ++
                  t.innerText = s
                }, 1000)
            }

            // 失败
            fail (){
                let bool = confirm('踩到雷,失败了!')
                if(bool){
                  window.location.reload()
                }
            }

            // 成功
            victory (){
                alert('成功了!成功了!带成功!')
                clearInterval(this.timer)
                alert('你的生命减少了 ' + document.querySelector('#time').innerText + ' 秒')
            }

            // 右键事件
            conTextMenu () {
                this.item.addEventListener('contextmenu', (e) => {
                  e = e || window.event
                  let target = e.target || e.srcElement
                  try {e.preventDefault()} catch (err) {e.returnValue = false}
                  if(target.className === 'block'){
                        target.className = 'bomb'
                        this.flagList.add(parseInt(target.dataset.id))
                  } else if (target.className === 'bomb'){
                        target.className = 'block'
                        this.flagList.delete(parseInt(target.dataset.id))
                  }
                  if(this.flagList.size === this.bombNum) {
                        let flagAllBomb = this.bombList.every(item => {
                            return this.flagList.has(item)
                        })
                        if(flagAllBomb) {
                            this.victory()
                        }
                  }
                })
            }
      }

      let first = new sweep('#box')

Fullmoonbaka 发表于 2021-7-28 21:28

luliucheng 发表于 2021-7-28 21:14
这怎么运行呀?贴到Html里没有用呀?

还需要dom结构和css样式呢,https://www.52pojie.cn/thread-1484299-1-1.html 看这个

Fullmoonbaka 发表于 2021-7-28 18:38

976431852qwe 发表于 2021-7-28 18:19
大佬好强,我想问一下你大概学了多久啊?我想知道学多久可以达到这种程度
我学了快一年,全心全力的学的话,三个月足以。这个是我好久之前写的,今天想起来就分享到论坛上

blindcat 发表于 2021-7-28 18:22

挺厉害的,学习下

xhy13721357088 发表于 2021-7-28 18:31

大佬就是强,拜服了

rescal 发表于 2021-7-28 19:25

大佬牛啊

Sunshine0804 发表于 2021-7-28 19:43

66666666666666666666666666666666666

baiqpl0123 发表于 2021-7-28 19:46

扫雷有什么方法吗{:1_896:}

Brillant 发表于 2021-7-28 19:55

学习一下

ytlk0535 发表于 2021-7-28 20:21

计算这个雷的数量是比较费脑的

bqcar168 发表于 2021-7-28 20:30

可以边工作边玩游戏
页: [1] 2
查看完整版本: 【扫雷游戏】使用 javascript 编写的扫雷游戏