微信小程序版 九宫格数独游戏

前言

继上次JAVA版的九宫格数独,这几天把java版的迁移到了小程序这边,写一篇记录一下。

核心还是在算法上,话不多说,直接干代码

一、核心算法

先把81个格子填满,填充之前需要先判断当前格子填的数字是否合适?再去挖洞,避免出现无法填充的bug。代码如下【挖洞在后面给出】

1、填满格子

fill(){
	if(this.fillCount == 81){  
		return;  //表示填满返回  
	}  
	if(this.squareNums[parseInt(this.fillCount / 9)][this.fillCount % 9] != 0) {  
		++this.fillCount;  
		this.fill();    //位置不为0,填充下一个  
		return;  
	} else {  
		//从1到9里面选择数字填进去  
		for(var x = 1; x != 11; x++) {
			if(this.fillCount == 81){
				return;  //表示填满返回  
			}  
			if(x == 10 && this.fillCount != 0) {
				--this.fillCount;
				this.squareNums[parseInt(this.fillCount / 9)][this.fillCount % 9] = 0;  
				return;     
			}  
			if(this.checkFillabled(parseInt(this.fillCount / 9), (this.fillCount % 9), x)){  
				this.squareNums[parseInt(this.fillCount / 9)][(this.fillCount % 9)] = x;  
				++this.fillCount;  
				this.fill();  
			}  
		}  
	}  
},

2、判断格子是否能填充指定数值 

checkFillabled(X, Y, FillNum){
	for(var i=0;i<9;i++){
		if(this.squareNums[X][i]==FillNum || this.squareNums[i][Y]==FillNum){
			return false;
		}
	}
	
	var D_X = parseInt(X / 3) * 3;  // [0,3,6]
	var D_Y = parseInt(Y / 3) * 3;  
	for(var count = 0; count < 9; count++) {  
		if(D_X == X && D_Y == Y)  
			continue;  //count / 3 [0,1,2]   count % 3 [0,1,2]
		if(this.squareNums[D_X + parseInt(count/3)][D_Y + count%3] == FillNum)  
			return false;
	}  
	
	return true;
},

3,格子填满就开始挖洞

digholes(count){
    for(var i=0;i<count;i++){
        var rand = parseInt(Math.random()*81)
        this.squareNums[parseInt(rand/9)][rand%9] = 0
    }
}

二、完整代码

核心算法写完就是自由发挥的时候了。游戏页面的完整代码

1、模板

<view class="" style="filter: grayscale(0%);font-family:mianfeiziti;">
		<view class="" style="position: fixed;top: 0;left: 0;z-index: 99;width: 100vw;">
			<gui-top-message ref="guitopmsg1">
				<view class="gui-bg-green">
					<text 
					class="message-text gui-block-text gui-color-white gui-icons">&#xe646; 还没选格子呢</text>
				</view>
			</gui-top-message>
			<gui-top-message ref="guitopmsg2">
				<view class="gui-bg-yellow">
					<text 
					class="message-text gui-block-text gui-color-black gui-icons">&#xe646; 行或列已存在相同的填充数</text>
				</view>
			</gui-top-message>
			<view class="buttons">
				<button type="default" @tap="navigateTo('../../pages/shudu/guanqia')">关卡</button>
				<button type="default" @tap="back_step">退一步</button>
				<button type="default" @tap="pauseTemp()">暂停</button>
				<button type="default" @tap="navigateTo('../../pages/shudu/login')">退出</button>
			</view>
			<view class="remarks">
				<view class="rank">
					等级:{{rankText}}
				</view>
				<view class="interval">
					耗时:{{intervalText}}
				</view>
			</view>
			<view class="select-display">
				已选中格子:{{arial.X}} & {{arial.Y}}
			</view>
			<view class="center-container">
				<view class="square-row" v-for="(item,index) in squareNums" :key="index">
					<view :class="[
						{
						'bg-yelow':(parseInt(index/3)==0&&(parseInt(ind/3)==0||parseInt(ind/6)==1))||(parseInt(index/6)==1&&(parseInt(ind/3)==0||parseInt(ind/6)==1)),
						'bg-white':parseInt(index/3)==1&&parseInt(ind/3)==1
						},
						'row-'+index+''+ind
						]" v-for="(num,ind) in item" :key="ind" @tap="selectCheck($event,index,ind)"
						:data-num="num"
					>
						{{num==0?'':num}}
					</view>
				</view>
			</view>
			<view class="bottom-num">
				<button @tap="selectFillNum(1)">1</button>
				<button @tap="selectFillNum(2)">2</button>
				<button @tap="selectFillNum(3)">3</button>
				<button @tap="selectFillNum(4)">4</button>
				<button @tap="selectFillNum(5)">5</button>
				<button @tap="selectFillNum(6)">6</button>
				<button @tap="selectFillNum(7)">7</button>
				<button @tap="selectFillNum(8)">8</button>
				<button @tap="selectFillNum(9)">9</button>
			</view>
			<gui-popup ref="guipopup1">
				<view class="gui-relative gui-box-shadow gui-img-in">
					<view class="win-note">
						好厉害,再接再厉
					</view>
					<image 
					style="width:580rpx;" 
					mode="widthFix" 
					src="../../static/image/victory.jpeg"></image>
					<!-- 关闭按钮 -->
					<text class="gui-block demo-close gui-icons gui-color-white gui-absolute-rt"
					@tap.stop="close1">&#xe78a;</text>
					<view class="win-btn">
						<button type="default" @tap="afterWinFun(0)">关卡</button>
						<button type="default" @tap="afterWinFun(1)">下一关</button>
					</view>
				</view>
			</gui-popup>
		</view>
		<view class="" :style="{background :'url(' + picUrl + ')',backgroundSize:'100% 100%',backgroundRepeat:'no-repeat;',backgroundPosition:'0 100%', filter: 'blur(0px)',height:'100vh',zIndex:-1}">
			
		</view>
	</view>

2、js

const innerAudioContext1 = uni.createInnerAudioContext();
innerAudioContext1.src = uni.graceJS.cdnUrl+'music/fill.mp4';
const innerAudioContext2 = uni.createInnerAudioContext();
innerAudioContext2.src = uni.graceJS.cdnUrl+'music/finish.mp4';
 
;
import api from '../../js/api.js'
export default{
	data(){
		return {
			picUrl:uni.graceJS.cdnUrl+'images/bgpost2.jpeg',
			squareNums:[],
			x:0,
			y:0,
			arial:{X:0,Y:0},
			fillCount:0,
			intervalText:"00时00分00秒",
			interval:null,
			second:0,
			minute:0,
			hour:0,
			isPause:false, // 暂停
			backStep:0 ,// 退一步
			pre_arial:{x:0,y:0},
			holesNum:20,// 简单 20 一般 30 困难 40
			rank:0, // 简单  一般  困难
			guanqia:0, // 当前关卡
			isRedirect:false,
			rankText:"",
			voicePlaying:false,
			userInfo: uni.getStorageSync('userinfo')?JSON.parse(uni.getStorageSync('userinfo')):uni.getStorageSync('userinfo'),
		}
	},
	methods:{
		pauseTemp(){
			uni.buttonVoice();
			if(this.isPause)return;
			this.isPause = true
			clearInterval(this.interval)
		},
		navigateTo(url){
			uni.buttonVoice();
			this.isRedirect = true
			clearInterval(this.interval)
			uni.redirectTo({
				url
			})
		},
		open1  : function () {this.$refs.guipopup1.open();},
		close1 : function () {this.$refs.guipopup1.close();},
		afterWinFun(i){
			uni.buttonVoice();
			this.isRedirect = true
			if(i){
				uni.redirectTo({
					url:'../../pages/shudu/main_page?guanqia='+(this.guanqia+1)+'&rank='+this.rank
				})
			}else{
				uni.redirectTo({
					url:'../../pages/shudu/guanqia'
				})
			}
		},
		selectFillNum(num){
			if(!this.arial.X){
				this.openmsg1()
				return;
			}
			if(this.checkFillabled(this.x,this.y,num)){
				this.voicePlay()
				this.backStep = 0
				this.pre_arial = {x:this.x,y:this.y} // 上一步的格子
				this.squareNums[this.x][this.y] = num
				this.$set(this.$data,'squareNums',this.squareNums)
				if(!/0/.test(this.squareNums.join())){
					uni.graceJS.post(
						api.saveGuanQiaData(),
						{w_id:this.userInfo.w_id,time:this.second,rank:this.rank}, {},{},
						(res) => {
							console.log(res)
						}
					);
					clearInterval(this.interval)
					setTimeout(()=>{
						this.open1()
						this.voicePlay2()
					},300)
				}
			}else{
				this.openmsg2()
			}
			
		},
		fill(){
			if(this.fillCount == 81){  
				return;  //表示填满返回  
			}  
			if(this.squareNums[parseInt(this.fillCount / 9)][this.fillCount % 9] != 0) {  
				++this.fillCount;  
				this.fill();    //位置不为0,填充下一个  
				return;  
			} else {  
				//从1到9里面选择数字填进去  
				for(var x = 1; x != 11; x++) {
					if(this.fillCount == 81){
						return;  //表示填满返回  
					}  
					if(x == 10 && this.fillCount != 0) {
						--this.fillCount;
						this.squareNums[parseInt(this.fillCount / 9)][this.fillCount % 9] = 0;  
						return;     
					}  
					if(this.checkFillabled(parseInt(this.fillCount / 9), (this.fillCount % 9), x)){  
						this.squareNums[parseInt(this.fillCount / 9)][(this.fillCount % 9)] = x;  
						++this.fillCount;  
						this.fill();  
					}  
				}  
			}  
		},
		back_step(){
			uni.buttonVoice();
			if(!this.arial.X){
				return;
			}
			if(this.backStep==0){
				this.backStep = 1
				this.squareNums[this.pre_arial.x][this.pre_arial.y] = 0
				this.$set(this.$data,'squareNums',this.squareNums)
			}else{
				uni.showToast({
					title:'都说了退一步你还想退几步?是不是玩不起?',
					icon:'none'
				})
			}
			
		},
		squareInit(){
			let first_layer = [];
			for(var i=0;i<=8;i++){
				let sec_layer = [];
				for(var j=0;j<=8;j++){
					sec_layer.push(0)
				}
				first_layer.push(sec_layer)
			}
			this.squareNums = first_layer
			this.fill()
			this.digholes(this.holesNum)
		},
		selectCheck(e,x,y){
			if(e.target.dataset.num)return;
			uni.buttonVoice();
			var that = this
			if(this.isPause){
				this.isPause = false
				this.interval = setInterval(function(){
					that.second++;
					var s = (that.second%60).toString().padStart(2,0);
					var m = parseInt(that.second/60)==60?'00':(parseInt(that.second/60)).toString().padStart(2,0)
					var h = (parseInt(that.second/3600)).toString().padStart(2,0)
					that.$set(that.$data,'intervalText',h+"时"+m+"分"+s+"秒")
				},1000)
			}
			
			const query = uni.createSelectorQuery().in(this);
			query.select('.row-'+x+''+y).boundingClientRect(function(data){
				console.log(data)
				this.background = 'gray'
			}).exec();
			// query.select('.row-'+x+''+y).backgroundColor = 'gray';
			this.$set(this.$data,'arial',{X:x+1,Y:y+1})
			this.x = x
			this.y = y
		},
		checkFillabled(X, Y, FillNum){
			for(var i=0;i<9;i++){
				if(this.squareNums[X][i]==FillNum || this.squareNums[i][Y]==FillNum){
					return false;
				}
			}
			
			var D_X = parseInt(X / 3) * 3;  // [0,3,6]
			var D_Y = parseInt(Y / 3) * 3;  
			for(var count = 0; count < 9; count++) {  
				if(D_X == X && D_Y == Y)  
					continue;  //count / 3 [0,1,2]   count % 3 [0,1,2]
				if(this.squareNums[D_X + parseInt(count/3)][D_Y + count%3] == FillNum)  
					return false;
			}  
			
			return true;
		},
		digholes(count){
			for(var i=0;i<count;i++){
				var rand = parseInt(Math.random()*81)
				this.squareNums[parseInt(rand/9)][rand%9] = 0
			}
		},
		openmsg2 : function () {
			this.$refs.guitopmsg2.open();
		},
		openmsg1 : function () {
			this.$refs.guitopmsg1.open();
		},
		voicePlay(){
			if(!this.voicePlaying){
				this.voicePlaying = true
				innerAudioContext1.play();
				setTimeout(()=>{
					this.voicePlaying = false
					innerAudioContext1.stop();
				},200)
			}
		},
		voicePlay2(){
			innerAudioContext2.play()
			setTimeout(function(){
				innerAudioContext2.stop()
			},4500)
		},
		switchTime(time){
			var str = ''
			if(time>=3600){
				str += (parseInt(time/3600)).toString().padStart(2,0)+'时'
			}else{
				str += '00时'
			}
			if(time>=60){
				str += (parseInt((time%3600)/60)).toString().padStart(2,0)+'分'
			}else{
				str += '00分'
			}
			str += (parseInt(time%60)).toString().padStart(2,0)+'秒'
			
			return str;
		}
	},
	onLoad(option){
		console.log(option)
		this.guanqia = parseInt(option.guanqia)
		this.rank = option.rank
		uni.setNavigationBarTitle({
			title:'第'+this.guanqia+'关',
		})
		this.rankText = this.rank==0?'简单':(this.rank==1?'一般':'困难')
		
		this.holesNum = this.rank==0?20:(this.rank==1?30:40)
		this.squareInit()
		var that = this
		this.interval = setInterval(function(){
			that.second++;
			that.$set(that.$data,'intervalText',that.switchTime(that.second))
		},1000)
		
	},
	onUnload() {
		clearInterval(this.interval)
	}
}

3、css样式

.message-text{line-height:88rpx; font-size:26rpx; text-align:center;}
.buttons{
	display: flex;
	justify-content: center;
	padding: 40rpx 20rpx;
	button{
		background:linear-gradient(0deg, #bed3e7 , #fff);
	}
}
.remarks{
	padding: 10rpx 20rpx;
	overflow: hidden;
	font-weight: bold;
	background-color: rgba(255,255,255,.7);
	.rank{
		float: left;
	}
	.interval{
		float: right;
	}
}
.center-container{
	width: 96%;
	margin: 30rpx auto;
	.square-row{
		display: flex;
		justify-content: center;
		view{
			width: 80rpx;
			height: 70rpx;
			text-align: center;
			line-height: 70rpx;
			margin: 5rpx;
			background-color:#00ff00;
			font-weight: bold;
			&.bg-yelow{
				background-color:#ffff00;
			}
			&.bg-white{
				background-color:white;
			}
			box-shadow: 10rpx 10rpx 10rpx gray;
		}
	}
}
.bottom-num{
	display: flex;
	justify-content: center;
	button{
		background:linear-gradient(0deg, #bed3e7 , #fff);
	}
}
.select-display{
	text-align: right;
	padding: 20rpx;
	font-weight: bold;
	background-color: rgba(255,255,255,.7);
}
.win-note{
	color: white;
	padding: 10px;
	text-align: center;
	font-weight: bold;
	font-size: 50rpx;
}
.win-btn{
	width: 90%;
	margin: -100rpx auto;
	button{
		width: 200rpx;
		font-size: 30rpx;
		font-weight: bold;
		&:nth-child(1){
			float: left;
			background:linear-gradient(45deg, #9de757 , #fff);
		}
		&:nth-child(2){
			float: right;
			background:linear-gradient(45deg, #fff, #55aaff );
		}
	}
}

三、呈现的结果

【这里建议字体引入,图片的静态资源用cdn,不然会造成页面卡顿,字体无效】

最后 

贴上自己的作品二维码 --- 九宫格数独游戏,希望大家给点建议指导,谢谢查看! 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值