uniapp-数独游戏

介绍

数独(すうどく,Sūdoku),是源自18世纪瑞士的一种数学游戏,流传到美国,再由日本发扬光大。

  1. 玩家需要填入剩下的数字,使得已经填写的数字应当满足:每行、每列、每个线较粗的方框(或称:宫)内同样的数字不能够出现两次。
  2. 当填入所有缺失的数字后,游戏结束。

示例图片

在这里插入图片描述

基于uniapp开发完整代码如下

<template>
	<view>
		<view class="main">
			<view class="foot">
				<view v-if="!isTip" class="sudoku_area">
					<view v-for="(row, index) of rowList" :key="index" class="sudoku_row"
						:style="{borderRight:(index==2 || index==5)?'2px solid #ae7a36':index==8?'none':'1px solid #dab88a'}">
						<view v-for="(value, cellIndex) of row" :key="cellIndex" class="sudoku_cell"
							:style="{borderBottom:(cellIndex==2 || cellIndex==5)?'2px solid #ae7a36':cellIndex==8?'none':'1px solid #dab88a'}">
							<input v-if="isOkNew(index, cellIndex)" :value="value" style="background: #fffae1;"
								:disabled="isOkNew(index, cellIndex)" />
							<input v-else maxlength="1" type="number" v-model="inputValue"
								style="background: #f8e7a4; font-weight: bold;"
								@input="changeValue(index, cellIndex)" />
						</view>
					</view>
				</view>
				<view v-else class="sudoku_area">
					<view v-for="(row, index) of rightList" :key="index" class="sudoku_row">
						<view v-for="(value, cellIndex) of row" :key="cellIndex" class="sudoku_cell">
							<input style="height:5vh;color: black;" :value="value"
								:disabled="isOkNew(index, cellIndex)" />
						</view>
					</view>
				</view>
			</view>

			<view style="margin-top: 64rpx; display: flex;">
				<button class="button-class" @click="goRestart()">
					重开
				</button>
				<button class="button-class" @click="showTip()">
					答案<span v-if="isTip">{{ count }}s</span>
				</button>
				<button class="button-class" @click="checkShudu()">
					提交
				</button>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				rowList: [], // 数独二维数组
				rowListNew: [], // 题目数组
				rightList: [], // 正确的数独数组
				inputValue: '', // input数值
				isTip: false, // 是否展示提示
				count: 5, // 倒计时
				myTimer: ''
			}
		},
		onLoad() {
			this.generateShuDu()
		},
		methods: {
			// 初始化数独
			generateArr() {
				const arr = []
				for (let i = 0; i < 9; i++) {
					arr[i] = []
					for (let j = 0; j < 9; j++) {
						arr[i][j] = 0
					}
				}
				console.log(arr);
				return arr
			},
			// 生成1-9的随机整数
			generateRandom() {
				return Math.floor(Math.random() * 9 + 1)
			},

			//判断重开
			goRestart() {
				uni.showModal({
					title: '提示',
					content: '重开后将清空已填的数,并且不会保存',
					showCancel: true,
					cancelText: '继续',
					confirmText: '重开',
					success: res => {
						if (res.confirm) {
							this.generateShuDu()
						} else if (res.cancel) {
							return
						}
					},
					fail: () => {},
					complete: () => {}
				});
			},

			// 生成数独
			generateShuDu() {
				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) {
			  const randomNum = Math.floor(Math.random() * 30) + 50
				for (let a = 0; a < randomNum; 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)
				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] === '') {
							uni.showToast({
								title: '数独未填完',
								icon: 'none'
							});
							return
						}
					}
				}
				if (answer.toString() === this.rightList.toString()) {
					uni.showToast({
						title: '答案正确',
						icon: 'none'
					});
				} else {
					uni.showToast({
						title: '答案错误',
						icon: 'none'
					});
				}
			},
			// 提示
			showTip() {
				this.isTip = true
				this.countDown()
			},
			// 倒计时
			countDown() {
				// 有定时器 -> 清除定时器(避免重复设置)
				if (this.myTimer) {
					clearInterval(this.myTimer)
				}
				// 设置定时器
				this.myTimer = setInterval(() => {
					if (this.count > 0) {
						this.count--
						if (this.count === 0) {
							// 倒计时到0时发送请求 并清除定时器
							this.isTip = false
							this.count = 5
							clearInterval(this.myTimer)
						}
					}
				}, 1000)
			}

		}
	}
</script>

<style lang="scss">
	.main {
		display: flex;
		flex-direction: column;
	}

	.sudoku_area {
		border: 2px solid #ae7a36;
		display: flex;
		justify-content: center;
		border-radius: 16rpx;
		overflow: hidden;
	}

	.button-class {
		width: 184rpx;
		height: 88rpx;
		background-color: #fffae1;
		font-size: 32rpx;
		line-height: 88rpx;
		color: #6c4e27;
		border-radius: 24rpx;
	}

	.sudoku_cell {
		width: 76rpx;
		box-sizing: border-box;
		text-align: center;
		line-height: 76rpx;
		color: #6c4e27;
	}

	.sudoku_cell input {
		width: 76rpx;
		height: 76rpx;
	}

	.foot {
		display: flex;
		justify-content: center;
		cursor: pointer;
		margin-top: 32rpx;
	}
</style>
  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值