生活随笔
收集整理的這篇文章主要介紹了
使用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 ( ) { 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
= 9 let copyResultArr
= resultArr
let numArr
= [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] for ( let i
= 0 ; i
< 9 ; i
++ ) { const num
= this . judgeCount ( numArr
, resultArr
) let index
= - 1 let minlength
= 9 for ( 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 ) { 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
= 0 for ( 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 . rowList
for ( 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实现的数独游戏 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。