React-native數獨遊戲(一)數獨生成與校驗
阿新 • • 發佈:2019-02-04
react-native還是蠻火的,前面用它做了一個火車票查詢的,感覺還可以,繼續研究,寫了這個數獨小遊戲,和大家分享一下。
github原始碼地址
第一部分是關於數獨生成的部分,數獨規則很簡單,行列都沒有重複,每個九宮格也不能重複,演算法也是依照此規則去實現。先生成一張完整的數獨表,再去扣掉一些數字,最後變成題目。
我是先行後列去一格一格去放數字的,先放第一行,這個直接打亂順序放入就可以。然後從第二行開始一格一格試數字。
每行初始化一個9個數字的陣列,然後去比較前面和上面的數字,相同的從陣列中去除,然後再比較九宮格中已經放入的數字,從陣列中去除,最後取陣列中的第一個數字放入格子。
發現直接這麼處理經常會碰陣列空了,其實就是當前數獨不成立了,我的做法比較簡單粗暴,直接當前行重新計算,基本上沒碰到算不出來的,有興趣的可以繼續優化,效率最高的方法是一格一格倒退。
//計算完整數獨表
export function _calculateData() {
_initMyFunc();
let count = 0;
let rootArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
//二維陣列存放數獨
let Sudoku = new Array(9);
for (let i = 0; i < 9; i++) {
Sudoku[i] = new Array(9);
}
//打亂陣列後賦值給第一行
_caosArray(rootArray);
_caosArray(rootArray);
Sudoku[0 ] = rootArray.concat();
for (x = 1; x < 9; x++) {
//每行賦值前先打亂陣列,保證與上一行不同
_caosArray(rootArray);
let rowArray = rootArray.concat();
for (y = 0; y < 9; y++) {
//刪除行內重複數字
tempNum = Sudoku[x][y - 1];
rowArray.remove(tempNum);
_caosArray(rowArray);
//刪除列內重複數字,複製一份行陣列,行內迴圈中,保持rowArray每次減一個重複數字
let tempRowArray = rowArray.concat();
for (let m = x - 1; m >= 0; m--) {
tempNum = Sudoku[m][y];
tempRowArray.remove(tempNum);
count++;
}
// console.log('before rowArray=>>>>' + rowArray);
// console.log('before tempRowArray=>>>>' + tempRowArray);
// console.log('before y=>>>>' + y);
//刪除3X3中的重複數字,就是當前行上面兩行說有數字
//計算穿小格中的相對位置
let positionX = x % 3;
let positionY = y % 3;
for (positionX; positionX > 0; positionX--) {
for (let a = 0; a < 3; a++) {
if (a != positionY) {
tempNum = Sudoku[x - positionX][y - positionY + a];
tempRowArray.remove(tempNum);
// console.log("tempNum=>>>>>" + tempNum);
count++;
if (count > 2500)
return -1;
}
}
}
if (tempRowArray.length > 0) {
Sudoku[x][y] = tempRowArray[0];
} else {
_caosArray(rootArray);
rowArray = rootArray.concat();
y = -1;
}
// console.log("after tempRowArray=>>>>>" + tempRowArray);
// console.log("after rowArray=>>>>>" + rowArray);
// console.log("after y=>>>>>" + y);
}
}
console.log(Sudoku);
console.log('計算' + count + '次');
return Sudoku;
}
//打亂一個數組
export function _caosArray(array) {
let temp;
for (i = 0; i < array.length - 1; i++) {
if (Math.random() > 0.5) {
let index = Math.floor(Math.random() * array.length);
temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
}
數獨完成後,就要開始校驗,依然一樣,直接上程式碼
//校驗數獨
export function _checkSudoku(Sudoku) {
let result = {code: 0}
//檢查時候有空格
for (let x = 0; x < 9; x++) {
for (let y = 0; y < 9; y++) {
if (Sudoku[x][y].num == 0) {
result.msg = '請填滿所有空格'
return result
}
}
}
for (let x = 0; x < 9; x++) {
for (let y = 0; y < 9; y++) {
//行是否有相同
for (let z = 8 - y; z > 0; z--) {
if (Sudoku[x][y].num == Sudoku[x][9 - z].num) {
result.msg = '錯誤,請檢查'
return result
}
}
//列是否有相同
for (let z = 8 - x; z > 0; z--) {
if (Sudoku[x][y].num == Sudoku[9 - z][y].num) {
result.msg = '錯誤,請檢查'
return result
}
}
//九宮格是否相同
let positionX = x % 3;
let positionY = y % 3;
for (let m = positionX + 1; m < 3; m++) {
for (let n = 0; n < 3; n++) {
if (n != positionY) {
if (Sudoku[x][y].num == Sudoku[x + m - positionX][y + n - positionY].num) {
console.log('(' + x + ',' + y + ')')
console.log('(' + (x + m) + ',' + (y + n) + ')')
result.msg = '錯誤,請檢查'
return result
}
}
}
}
}
}
result.code = 1
return result
}