最近心血来潮想制作一个数独游戏,说干咱就干。刚刚好前一阶段学习了es6,可以用这个项目来当做一个小练习。
目前开发已经完成,由于只是基本功能,页面样式并不是很华丽,下面我们先开看看长什么样子。
大概页面就长这个样子,页面有三个按钮,分别是检查,重玩,换题。
- 检查就是检查当你填满是否成功。
- 重玩就是放弃你所填的,重新开始本局游戏。
- 换题就是重新换个题目。
下面是游戏中截图。
;
;
最后这个图我比较偷懒。直接生成的,并没有自己填。
下面就来看看代码吧。
里面最重要的就数算法了吧。我使用是回溯法,废话不多说直接上代码。先来看一下生成数独的算法。大概就是把数独分成81格,从1-81分别生成,没生成一个格都要去判断一下每一行,每一列,每一宫是否满足规则。如果不满足则回溯。下面是生成数独的方法。
//生成数独 const makeArray=(arr, n)=>{ if(n == 81) { return arr; } let x = Math.floor(n / 9); let y = n % 9; if(arr[x][y] == 0) { let index = 0; let arrn = makeRandomArray(9); for(let i = 0; i < arrn.length; i++) { arr[x][y] = arrn[i]; if(checkArrayByIndex(arr, x, y)) { let endArr = makeArray(arr, n + 1); if(!checkArrayHasZero(arr)) return endArr; } } arr[x][y] = 0; //回溯 } else { makeArray(arr, n + 1); } return arr; }
当生成完数组之后,就可以生成游戏所用的数独,其实则是隐藏其中的格子。
//对二维数组进行随机n位置0 const resetZeroByArray=(arr,n)=>{ let k=0; while(k<n){ let ranNum=randomNumber(81); let x = Math.floor((ranNum-1) / 9); let y = ranNum % 9; if(arr[x][y]!=0){ arr[x][y]=0; k++; } } return arr; }
最后则是当玩家填完数组之后再去验证这个数独是否满足规则。
//判断二维数组是否是完整数独 checkSudoArray(arr){ let sign=true; //检查数组中是否含有0,如果有0立刻返回false if(checkArrayHasZero(arr))return false; //对每一行每一列每一宫进行检查 for(let i=0;i<9;i++){ let rowSign=checkedRow(arr,i); let colSign=checkedCol(arr,i); let gongSign=checkedGongByNum(arr,i+1); if(!(rowSign&&colSign&&gongSign)){ sign=false; }; } return sign; } //根据坐标检查九宫格 const checkArrayByIndex = (arr, x, y) => { let signRow = false; let signCol = false; let signGong = false; //检查行 signRow = checkedRow(arr, x); //检查列 signCol = checkedCol(arr, y); //检查宫 signGong = checkedGongByIndex(arr, x, y); if(signRow && signCol && signGong) { return true; } else { return false; } }
这样算法大概就介绍完了。接下来来看看页面。页面我是把二维数组直接放在父模板中,然后先去初始化然后根据这个数组去生成grid。
<div class="sudoMain" > <Row class="numRow" type="flex" v-for="(row,i) in arr" justify="center"> <i-col class="numCol" v-for="(cell,j) in row" :data-x='i' :data-y='j'><div class="spanDiv" @click="cellClick($event,i,j)">{{arr[i][j]==0?"":arr[i][j]}}</div></i-col> </Row> </div>
一定要记得把每个坐标赋值到元素上,这样可以进行接下来的操作都很方便。接来下用户选择的数字面板单独写出来,通过点击事件进行隐藏或者显示。
selectClick(e,i,j){ this.showSelectPop=false; this.arr[this.selectX][this.selectY]=(i-1)*3+j; }
介绍的大体差不多了,代码已经上传到github,如果想看源码的话可以直接上github下载。地址是:https://github.com/like2372/sudoVue.git。