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
}