vue: 做一个数独游戏

练习使用VUE制作一个数独游戏:判断方法比较简单,没有使用算法,只是单纯的判断数字是否重复出现,功能简单,游戏开始后可以选择看提示,提示出现时间5秒,倒计时结束后,可正常答题,有提交功能(校验)判断是否填完或者时候填写准确

下面是效果图

 

 

 

 

<template >
    <div class="main" >
        <div style="margin-top: 2vh;" >
            <el-button v-if="!showThree"
                       type="primary"
                       class="button-class"
                       @click="generateShuDu()"
            >
                开始游戏
            </el-button>
            <el-button v-if="showThree"
                       type="primary"
                       class="button-class"
                       @click="showTip()"
            >
                答案<span v-if="isTip" >{{ count }}s</span>
            </el-button>
            <el-button v-if="showThree"
                       type="primary"
                       class="button-class"
                       @click="checkShudu()"
            >
                提交
            </el-button>
        </div>
        <div v-if="showThree"
             class="foot"
             style="margin-top: 5vh;"
        >
            <div v-if="!isTip" class="sudoku_area" >
                <div v-for="(row, index) of rowList"
                     :key="index"
                     class="sudoku_row"
                >
                    <div v-for="(value, cellIndex) of row"
                         :key="cellIndex"
                         class="sudoku_cell"
                    >
                        <el-input v-model="inputValue"
                                  style="height:6vh"
                                  :value="value"
                                  maxlength="1"
                                  :disabled="isOkNew(index, cellIndex)"
                                  onkeyup="value=value.replace(/^\.+|[^\d.]/g,'')"
                                  @change="changeValue(index, cellIndex)"
                        />
                    </div>
                </div>
            </div>
            <div v-else class="sudoku_area" >
                <div v-for="(row, index) of rightList"
                     :key="index"
                     class="sudoku_row"
                >
                    <div v-for="(value, cellIndex) of row"
                         :key="cellIndex"
                         class="sudoku_cell"
                    >
                        <el-input v-model="inputValue"
                                  style="height:6vh;color: black;"
                                  :value="value"
                                  :disabled="isOkNew(index, cellIndex)"
                                  readonly
                        />
                    </div>
                </div>
            </div>
            <div v-if="showThree" class="sudoku_area1" >
                <div v-for="index of 9"
                     :key="index"
                     class="three-div"
                />
            </div>
        </div>
        <div v-if="!showThree" class="foot" >
            <div class="tip-class" >
                <p >数独(Sudoku)是源自18世纪瑞士的一种数学游戏。</p>
                <p > 是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。</p>
                <p > 数独盘面是个九宫,每一宫又分为九个小格。</p>
                <p >在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。</p>
                <p > 使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。</p>
            </div>
        </div>
    </div>
</template>

 JS代码:

export default {
  name: 'Sudoku',
  data() {
    return {
      rowList: [], // 数独二维数组
      rowListNew: [], // 题目数组
      rightList: [], // 正确的数独数组
      inputValue: '', // input数值
      isTip: false, // 是否展示提示
      count: 5, // 倒计时
      showThree: false

    }
  },
  methods: {
    // 初始化数独
    generateArr() {
      const arr = []
      for (let i = 0; i < 9; i++) {
        arr[i] = []
        for (let j = 0; j < 9; j++) {
          arr[i][j] = 0
        }
      }
      return arr
    },
    // 生成1-9的随机整数
    generateRandom() {
      return Math.floor(Math.random() * 9 + 1)
    },
    // 生成数独
    generateShuDu() {
      this.showThree = true
      const arr = this.generateArr()
      for (let i = 0; i < 9; i++) {
        let time = 0
        for (let j = 0; j < 9; j++) {
          arr[i][j] = time === 9 ? 0 : this.generateRandom()
          if (arr[i][j] === 0) { // 不是第一列,则倒退一列
            if (j > 0) {
              j -= 2
              continue
            } else { // 是第一列,则倒退到上一行的最后一列
              i--
              j = 8
              continue
            }
          }
          if (this.isCorret(arr, i, j)) {
            time = 0// 初始化time,为下一次填充做准备
          } else {
            time++// 次数增加1
            j--// 继续填充当前格
          }
        }
      }
      this.rightList = JSON.parse(JSON.stringify(arr))
      // 随机删除部分数独内容
      this.delSomeList(arr)
    },
    // 是否满足行、列和3X3区域不重复的要求
    isCorret(arr, row, col) {
      return (this.checkRow(arr, row) && this.checkLine(arr, col) && this.checkNine(arr, row, col))
    },
    // 检测行是否符合标准
    checkRow(arr, row) {
      for (let j = 0; j < 8; j++) {
        if (arr[row][j] === 0) {
          continue
        }
        for (let k = j + 1; k < 9; k++) {
          if (arr[row][j] === arr[row][k]) {
            return false
          }
        }
      }
      return true
    },
    // 检测列是否符合标准
    checkLine(arr, col) {
      for (let j = 0; j < 8; j++) {
        if (arr[j][col] === 0) {
          continue
        }
        for (let k = j + 1; k < 9; k++) {
          if (arr[j][col] === arr[k][col]) {
            return false
          }
        }
      }
      return true
    },
    // 检测3X3是否符合标准
    checkNine(arr, row, col) {
      // 获得左上角的坐标
      const j = Math.floor(row / 3) * 3
      const k = Math.floor(col / 3) * 3
      // 循环比较
      for (let i = 0; i < 8; i++) {
        if (arr[j + Math.floor(i / 3)][k + i % 3] === 0) {
          continue
        }
        for (let m = i + 1; m < 9; m++) {
          if (arr[j + Math.floor(i / 3)][k + Math.round(i % 3)] === arr[j + Math.floor(m / 3)][k + Math.round(m % 3)]) {
            return false
          }
        }
      }
      return true
    },
    // 随机删除部分数独内容
    delSomeList(arr) {
      for (let a = 0; a < 50; a++) {
        const i = Math.floor(Math.random() * 9)
        const j = Math.floor(Math.random() * 9)
        arr[i][j] = ''
      }
      this.rowList = JSON.parse(JSON.stringify(arr))
      this.rowListNew = JSON.parse(JSON.stringify(arr))
    },
    // 是否为题目
    isOkNew(index, cellIndex) {
      if (this.rowListNew[index][cellIndex] === '') {
        return false
      }
      return true
    },
    // 填写数独
    changeValue(index, cellIndex) {
      this.inputValue === '' ? this.rowList[index][cellIndex] = '' : this.rowList[index][cellIndex] = parseInt(this.inputValue)
    },
    // 提交数独
    checkShudu() {
      const answer = this.rowList
      for (let i = 0; i < answer.length; i++) {
        for (let j = 0; j < answer[i].length; j++) {
          if (answer[i][j] === '') {
            this.$message({
              message: '数独未填完',
              type: 'error'
            })
            return
          }
        }
      }
      if (answer.toString() === this.rightList.toString()) {
        this.showThree = false
        this.$message({
          message: '答案正确',
          type: 'success'
        })
      } else {
        this.$message({
          message: '答案错误',
          type: 'error'
        })
      }
    },
    // 提示
    showTip() {
      this.isTip = true
      this.countDown()
    },
    // 倒计时
    countDown() {
      // 有定时器 -> 清除定时器(避免重复设置)
      if (window.timer) {
        clearInterval(window.timer)
      }
      // 设置定时器
      window.timer = setInterval(() => {
        if (this.count > 0) {
          this.count--
          if (this.count === 0) {
            // 倒计时到0时发送请求 并清除定时器
            this.isTip = false
            this.count = 5
            clearInterval(window.timer)
          }
        }
      }, 1000)
    }
  }
}

 样式

<style scoped >
.main {
width: 100%;
height: 80%;
position: relative;
display: flex;
flex-direction: column;

}
.sudoku_area {
border: 2px solid black;
display: flex;
justify-content:center;
margin-top: 6vh;
position: absolute;
overflow: hidden;
margin: auto;
z-index: 5;
opacity: 0.8;
}

.button-class {
  width: 15vh;
  height: 5vh;
  font-size: 2vh;
}

.tip-class {
  height: 30vh;
  border: 1px solid #a5aeb3;
  font-size: 2vh;
  text-align: initial;
  width: 120vh;
  padding: 0 3vh;
  margin-top: 5vh;
}

.sudoku_area1 {
  width: 55.5vh;
  margin-top: 6vh;
  position: absolute;
  overflow: hidden;
  margin: auto;
  z-index: 4;
}
.sudoku_cell {
width: 6.1vh;
}
::v-deep .el-input__inner {
  text-align: center;
  color: rgba(0, 19, 39, 0.96) !important;
}



.foot {
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  cursor: pointer;
}

.three-div {
  width: 18vh;
  height: 17.7vh;
  border: 2px solid #5a83a7;
  float: left;
}
</style>

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值