日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用VUE实现的数独游戏

發布時間:2023/12/31 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用VUE实现的数独游戏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面

數獨游戲是個很有意思的數學游戲,實現一個數獨游戲對自己的思維邏輯也有那么一點挑戰,所以用VUE實現了一個。如果你喜歡這個游戲,,這是完整代碼Github地址,下載下來可以直接玩;如果你也想自己做一個數獨游戲,那么我可以把我的思路分享給你。

詳細思路

  • 解析數獨規則
    數獨的結構是個9x9的九宮格布局,每個九宮格內是不重復的1-9數字,然后每行每列都是不重復的1-9數字,規則不算復雜

    DOM結構
  • <div class="sudoku_area" :class="{'sudoku_start': gamestart}"><div class="sudoku_row" v-for="(row, index) in rowList" :key="index"><div class="sudoku_cell" v-for="(value, cellIndex) in row" :key="cellIndex"><input></div></div></div>

    結構簡單明了,使用flex布局實現

  • 游戲邏輯
    想要實現一個數獨游戲,本質上就是隨機生成一個符合數獨規則的9x9的表格,然后隨機對里面一些數字進行隱藏讓玩家填寫,游戲難度可以通過隱藏的數量或者游戲時長限制來實現,此處最大的問題在于如何生成一個符合數獨規則的數據。

  • 生成一個符合數獨規則的數列
    i. 確定數據的格式
    我在網上看別人的例子有的人會采用以坐標為key的對象來保存數據,也有以單個九宮格內數據為一個數組的二維數組的模式,我最初的思路是以每行或者每列數據為一個數組的二維數組實現,但是后來還是采用了以九宮格為單位的二維數組為格式,具體原因下面會說到
    ii. 初始化數獨中特殊位置三個九宮格的數據

    上面就是數獨的九個九宮格,其中0、4、8或者2、4、6是比較特別的,因為這三個行列之間互不關聯,(這也是我采用九宮格數組形式的原因,其實行列數組也行,就是采用行列數組的話這一段寫起來不太簡潔,就放棄了)所以可以優先生成這三個九宮格的數據,生成方式也很簡單就是給1-9的數組進行隨機排列就行

  • getKeyBlock () { // 0,4,8關鍵九宮格塊使用隨機排序生成const indexArr = [0, 4, 8]for (let i = 0; i < indexArr.length; i++) {const index = indexArr[i]const row = [1, 2, 3, 4, 5, 6, 7, 8, 9]this.rowList[index] = row.sort(() => Math.random() > 0.5 ? -1 : 1)} }

    我這里采用的是0、4、8三個,你想用2、4、6也沒問題。有了這三個九宮格其他九宮格的數據生成也就有了約束規則,所以下面重點來了
    iii. 其他九宮格的數據生成
    先貼我的代碼再詳細解釋一番

    getOtherBlock (colIndexArr, rowIndexArr, index) { // 其余位置九宮格塊生成,傳入同行已生成的九宮格的數組下標、同列已生成的九宮格下標與當前九宮格下標const rowList = []const colList = []const row = [1, 2, 3, 4, 5, 6, 7, 8, 9]for (let i = 0; i < rowIndexArr.length; i++) { // 按照列把同列九宮格數據拆成二維數組用來判斷重復const rowArr = this.rowList[rowIndexArr[i]]rowList[i] = [[rowArr[0], rowArr[3], rowArr[6]], [rowArr[1], rowArr[4], rowArr[7]], [rowArr[2], rowArr[5], rowArr[8]]]}for (let i = 0; i < colIndexArr.length; i++) { // 按照行把同行九宮格數據拆成二維數組用來判斷重復const colArr = this.rowList[colIndexArr[i]]colList[i] = [[colArr[0], colArr[1], colArr[2]], [colArr[3], colArr[4], colArr[5]], [colArr[6], colArr[7], colArr[8]]]}const resultArr = []for (let i = 0; i < 9; i++) { // 對九宮格內每個格子進行循環篩選出每個格子的可填入的數字const rowIndex = i % 3 // 用來比較的列數組下標const colIndex = parseInt(i / 3) // 用來比較的行數組下標const getUsableValue = function (value) { // 這里是判斷重復的方法,是可以優化的let count = 0 // 判斷重復次數for (let j = 0; j < rowList.length; j++) {if (rowList[j][rowIndex].some(val => val == value)) { // 判斷重復count++}}for (let j = 0; j < colList.length; j++) {if (colList[j][colIndex].some(val => val == value)) {count++}}return count < 1}resultArr[i] = row.filter(getUsableValue) // 把每個格子的可選數字放入一個二維數組里}this.getResultArr(resultArr, index)},getResultArr (resultArr, index) { // 根據單個九宮格塊每個格子的可能值選出合適的值填入let realArr = []realArr.length = 9let copyResultArr = resultArrlet numArr = [1, 2, 3, 4, 5, 6, 7, 8, 9]for (let i = 0; i < 9; i++) { // 再次來個循環const num = this.judgeCount(numArr, resultArr) // 這個方法是判斷九個格子里可填數字里可填的最少的,例如[[1, 2, 3], [1, 2]]中3是最少的會優先填入(這個方法我并沒有測試是否會優化數組生成速度,所以可以用1-9按順序填入)let index = -1let minlength = 9for (let j = 0; j < resultArr.length; j++) { // 循環可選數字數組if (resultArr[j].indexOf(num) > -1) { // 判斷當前數組是否包含當前填入的數字if (minlength >= resultArr[j].length) { // 這里是判斷每個格子的可選數字個數,優先給最少的填入(這個方法我也同樣沒試是否會加快數獨生成速度,所以也可以不要)minlength = resultArr[j].lengthindex = j}resultArr[j].splice(resultArr[j].indexOf(num), 1) // 移掉已經填入的數字}}numArr.splice(numArr.indexOf(num), 1) // 移掉已經用掉的數字if (index > -1) { // 這里是判斷當前九宮格里的數據都符合規則,如果不符合,生成的數組里會出現empty,這是我們用來判斷生成是否成功的依據resultArr[index] = []realArr[index] = num}}this.rowList[index] = realArr},judgeCount (numArr, resultArr) { // 此處用來把可填數字中最少的數字優先填入let onlyNum = {num: 0,count: 9}for (let i = 0; i < numArr.length; i++) { // 依舊是個循環,這里就是按順序查找匹配數最少的數字const index = numArr[i]let count = 0for (let j = 0; j < resultArr.length; j++) {if (resultArr[j].indexOf(index) > -1) {count++}}if (count < onlyNum.count) {onlyNum = {num: index,count: count}}}return onlyNum.num}

    先對著我的注釋看一看,這一段代碼寫的不太好,各種for循環,我是懶得優化就都放在在這里。當然此處重要的是思路,下面我分解一下思路。
    首先,特殊位置的九宮格已經確定了,所以其他九宮格都會受到已完成的九宮格的影響,我是按照順序生成的,也就會知道當一個九宮格要生成的時候,那些與它有關系的九宮格已經生成了,所以要先找到這些九宮格,按照同行與同列拆分它們的數據方便比對;其次,獲取了同行同列的數據就可以開始比對,此處的比對是可以優化的重點,(數獨生成失敗的原因是之前生成的同行同列九宮格里的與當前格子同行同列的數據已經把1-9占完了,當前格子就不能填了,因為不符合數獨的規則了。)在生成單個九宮格的時候要盡可能避免這種情況發生,我的思路是先找可填數字里能填格子最少的數字優先填,再找格子里可選數字最少的優先填;最后,當你獲取了每個格子可以填什么就可以按照自己的想法填入數據,每個格子都填上數據的時候你就成功地完成了一個九宮格的填充。
    iv. 所有九宮格都填滿數字就說明你成功的生成了一個數獨
    當你能按規則填充完每一個九宮格的時候也就說明你可以生成一個數獨了,但是這種方法不能保證每次都會生成一個完美的數獨,非常容易失敗,所以生成數獨的方式要不斷循環直到生成一個符合規則的數據為止

    createSudoku () { // 生成數獨,生成的不符合要求就會重新生成this.getKeyBlock()this.getOtherBlock([0], [4], 1)if (this.rowList[1].filter(val => val).length < 9) {this.createSudoku()return}this.getOtherBlock([0, 1], [8], 2)if (this.rowList[2].filter(val => val).length < 9) {this.createSudoku()return}this.getOtherBlock([4], [0], 3)if (this.rowList[3].filter(val => val).length < 9) {this.createSudoku()return}this.getOtherBlock([3, 4], [2, 8], 5)if (this.rowList[5].filter(val => val).length < 9) {this.createSudoku()return}this.getOtherBlock([8], [0, 3], 6)if (this.rowList[6].filter(val => val).length < 9) {this.createSudoku()return}this.getOtherBlock([6, 8], [1, 4], 7)if (this.rowList[7].filter(val => val).length < 9) {this.createSudoku()return}this.countZero() // 倒計時this.courseRating() // 隱藏一部分格子讓玩家自己填}

    這里的優化步驟就是在某個九宮格生成的數據失敗后立刻重新生成數獨,特殊位置的九宮格也要重新生成,因為我試過特殊位置九宮格如果不更新,生成的次數會多很多。此時已經可以生成一個數獨了,關鍵部分已經完成了,其他都是簡單部分了

  • 把數獨變成可互動的游戲
    這里就簡單了,就是使用隨機數隨機隱藏一些格子可輸入讓用戶填寫

    白色的是填寫的(隨便填的),灰色的是生成的,空白處是可以輸入的,接下來只要判斷玩家填完之后的答案對不對就行了
  • 檢查填寫結果是否正確
    可能有些人會想直接拿我們生成的數獨數列對比一下就行了,這樣是不對的,空白的格子很多的話,最終答案不會只有一個,所以我們還是要老老實實按照數獨的規則來驗證
  • judgeSudoku () { // 判斷數獨填寫結果let answer = this.rowListfor (const key in this.cellValueList) {const element = this.cellValueList[key]if (element) {const keyIndex = key.split('-')answer[keyIndex[1]][keyIndex[2]] = parseInt(element)} else {alert('數獨未填完')return}}if (this.judgeBlock(answer) && this.judgeCol(answer) && this.judgeRow(answer)) {alert('答案正確')} else {alert('答案錯誤')}},judgeCol (answer) { // 判斷每一行for (let i = 0; i < 9; i += 3) {for (let j = 0; j < 9; j += 3) {const arr = (answer[i].slice(j, j + 3) + ',' + answer[i + 1].slice(j, j + 3) + ',' + answer[i + 2].slice(j, j + 3)).split(',')if (this.isRepeat(arr)) {return false}}}return true},judgeRow (answer) { // 判斷每一列for (let i = 0; i < 3; i++) {for (let j = 0; j < 3; j++) {const arr = [answer[i][j], answer[i][j + 3], answer[i][j + 6], answer[i + 3][j], answer[i + 3][j + 3], answer[i + 3][j + 6], answer[i + 6][j], answer[i + 6][j + 3], answer[i + 6][j + 6]]if (this.isRepeat(arr)) {return false}}}return true},judgeBlock (answer) { // 判斷每個九宮格塊for (let i = 0; i < 9; i++) {if (this.isRepeat(answer[i])) {return false}}return true},isRepeat (arr) { // 判斷數組中數據不重復return new Set(arr).size < 9}

    這一段就很好理解了,先判斷有沒有填完,填完了先查最好查的按九宮格查是否有重復的情況,(判斷重復用的是Set,這個方法很好用),然后是按行按列查,有錯誤就直接返回false,此時我們已經做完了一個完整的數獨游戲

    提升游戲性

    后面的東西就不太重要了,因為我們當前已經完成數獨游戲的主要功能了,后續內容是讓這個變得更加向游戲一點
    具體思路:
    i. 可以添加游戲時間限制提升游戲難度
    2、可以添加難度選擇器讓玩家自由選擇難度,難度選擇會影響時限與隱藏的格子數量
    3、當難度過高是玩家可以主動結束游戲,顯示我們生成的那個數獨
    4、在美化一下樣式加點圖片什么的,讓這個東西看起來更好看
    這是我的截圖

    好了,教程結束了,細節的話需要自己看一下我的代碼,希望大家每天都有進步啊

    總結

    以上是生活随笔為你收集整理的使用VUE实现的数独游戏的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。