练习使用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>