偶然想起来写一个数独的小游戏自己没事的时候玩一玩,锻炼锻炼思路。
先上效果截图
数独生成的算法,参见博客:数独生成算法
数独游戏的最基础的在于生成数独,由于生成数独的算法运算问题,为了简化,本次数独的生成使用了 10 个基类,每次生成数独的时候随机从是个基类中选取一个模板,在根据模板将对应的 a--i 的字母 随机与 1--9 分别对应,然后生成一个数独。
数独模板基类
public class StandShudu {
/**
* 从10个基准数组中抽取一个基准数组
* 然后将 a-i 随机分配 1-9
* 随机赋予 a--i的值为不重复的 1--9 的值 生成一个数组
* 有多少种可能我也不会算,反正够玩的了
*/
public String[][] getStand(int index){
switch (index){
case 0:
return stand0;
case 1:
return stand1;
case 2:
return stand2;
case 3:
return stand3;
case 4:
return stand4;
case 5:
return stand5;
case 6:
return stand6;
case 7:
return stand7;
case 8:
return stand8;
case 9:
return stand9;
default:
return stand0;
}
}
private String[][] stand1=new String[][]{
{"c","h","e","b","i","a","g","f","d",},
{"f","b","d","g","e","c","h","a","i",},
{"g","i","a","d","f","h","c","e","b",},
{"h","g","i","e","d","b","a","c","f",},
{"a","d","f","c","g","i","b","h","e",},
{"e","c","b","h","a","f","i","d","g",},
{"b","e","c","f","h","g","d","i","a",},
{"i","f","g","a","c","d","e","b","h",},
{"d","a","h","i","b","e","f","g","c",}
};
private String[][] stand2=new String[][]{
{"a","c","f","b","d","e","h","i","g",},
{"b","g","d","h","i","a","f","c","e",},
{"h","i","e","f","c","g","b","a","d",},
{"d","f","b","g","e","c","a","h","i",},
{"g","a","i","d","h","f","c","e","b",},
{"e","h","c","i","a","b","g","d","f",},
{"i","e","g","a","f","h","d","b","c",},
{"c","b","h","e","g","d","i","f","a",},
{"f","d","a","c","b","i","e","g","h",}
};
private String[][] stand3=new String[][]{
{"f","g","h","e","i","d","b","a","c",},
{"e","b","c","f","a","g","i","h","d",},
{"d","a","i","c","h","b","f","e","g",},
{"i","f","d","a","g","e","c","b","h",},
{"b","h","a","i","d","c","g","f","e",},
{"c","e","g","b","f","h","a","d","i",},
{"h","c","b","g","e","f","d","i","a",},
{"a","d","f","h","c","i","e","g","b",},
{"g","i","e","d","b","a","h","c","f",}
};
private String[][] stand4=new String[][]{
{"i","a","h","b","c","f","d","e","g",},
{"f","d","e","g","i","h","b","c","a",},
{"b","c","g","e","a","d","i","f","h",},
{"g","i","f","c","b","a","h","d","e",},
{"d","h","a","f","g","e","c","i","b",},
{"e","b","c","h","d","i","a","g","f",},
{"a","g","b","i","e","c","f","h","d",},
{"h","e","i","d","f","b","g","a","c",},
{"c","f","d","a","h","g","e","b","i",}
};
private String[][] stand5=new String[][]{
{"h","e","d","b","f","g","a","c","i",},
{"c","i","a","d","e","h","b","g","f",},
{"f","b","g","a","i","c","e","h","d",},
{"a","f","i","e","g","d","h","b","c",},
{"d","g","h","c","b","f","i","a","e",},
{"e","c","b","h","a","i","d","f","g",},
{"g","d","e","f","h","b","c","i","a",},
{"b","a","f","i","c","e","g","d","h",},
{"i","h","c","g","d","a","f","e","b",}
};
private String[][] stand6=new String[][]{
{"i","g","b","f","a","h","e","c","d",},
{"c","a","h","d","g","e","i","b","f",},
{"f","d","e","b","c","i","h","a","g",},
{"b","c","a","e","d","g","f","h","i",},
{"g","e","i","h","f","a","b","d","c",},
{"h","f","d","c","i","b","a","g","e",},
{"a","i","c","g","b","f","d","e","h",},
{"d","h","f","a","e","c","g","i","b",},
{"e","b","g","i","h","d","c","f","a",}
};
private String[][] stand7=new String[][]{
{"d","g","c","i","e","f","b","h","a",},
{"f","e","h","a","b","c","g","i","d",},
{"a","b","i","d","g","h","c","f","e",},
{"e","a","g","f","d","b","i","c","h",},
{"i","c","d","e","h","g","f","a","b",},
{"b","h","f","c","i","a","e","d","g",},
{"h","d","b","g","f","i","a","e","c",},
{"c","f","e","b","a","d","h","g","i",},
{"g","i","a","h","c","e","d","b","f",}
};
private String[][] stand8=new String[][]{
{"e","f","g","a","d","c","b","h","i",},
{"d","i","h","b","g","f","a","e","c",},
{"c","a","b","e","h","i","d","f","g",},
{"i","h","f","d","b","g","c","a","e",},
{"g","e","a","i","c","h","f","d","b",},
{"b","d","c","f","e","a","g","i","h",},
{"a","c","e","h","f","b","i","g","d",},
{"h","b","i","g","a","d","e","c","f",},
{"f","g","d","c","i","e","h","b","a",}
};
private String[][] stand9=new String[][]{
{"d","a","g","e","f","c","h","i","b",},
{"f","b","i","g","d","h","e","a","c",},
{"e","c","h","i","b","a","g","d","f",},
{"h","d","f","c","a","e","b","g","i",},
{"i","g","a","b","h","f","c","e","d",},
{"c","e","b","d","i","g","f","h","a",},
{"a","f","c","h","e","i","d","b","g",},
{"g","h","d","a","c","b","i","f","e",},
{"b","i","e","f","g","d","a","c","h",}
};
private String[][] stand0=new String[][]{
{"a","b","i","g","d","e","c","h","f",},
{"c","h","f","b","a","i","e","d","g",},
{"e","d","g","c","f","h","b","i","a",},
{"d","e","b","a","h","c","g","f","i",},
{"h","i","c","f","g","b","d","a","e",},
{"g","f","a","i","e","d","h","c","b",},
{"i","c","h","e","b","f","a","g","d",},
{"b","g","d","h","i","a","f","e","c",},
{"f","a","e","d","c","g","i","b","h",}
};
获取数独的类 ,随机获取一个模板,然后用 1--9 填充
public class ShuduData {
private int[][] number = new int[9][9];
private StandShudu standShudu=new StandShudu();
private Random random=new Random();
public int[][] generateShuDu(){
/*** 获取随机的模板 **/
String[][] stand=standShudu.getStand(random.nextInt(10));
/** 带选择数字列表 **/
ArrayList<Integer> data=new ArrayList<Integer>();
data.add(1); data.add(2); data.add(3);
data.add(4); data.add(5); data.add(6);
data.add(7); data.add(8); data.add(9);
/*** 随机存储排序 **/
int[] s=new int[9];
int index=0;
while (index<9){
int t=random.nextInt(data.size());
s[index]=data.get(t);
data.remove(t);
index++;
}
/** 根据模板按照获取的随机序列进行数据填充 **/
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
number[i][j]=s[getIndex(stand[i][j])-1];
}
}
return number;
}
private Integer getIndex(String s){
switch (s){
case "a":
return 1;
case "b":
return 2;
case "c":
return 3;
case "d":
return 4;
case "e":
return 5;
case "f":
return 6;
case "g":
return 7;
case "h":
return 8;
case "i":
return 9;
default:
return 1;
}
}
使用此方法虽然不能 模拟出数独的所有的可能,但是为了简化算法采用此方法。
根据获取的数独数组初始化游戏界面
/**
* 初始化数据
*/
private fun initSize(){
data= emptyArray()
data= ShuduData().generateShuDu()
val initData=Array(9) { IntArray(9) }
for(i in 0 until 9){
for(j in 0 until smd){
val ranNum = random.nextInt(9)
initData[i][ranNum]=data[i][ranNum]
}
}
nv_01.number=initData
}
smd 为数独的难易程度(即每一列的提示数据的个数)
由于数独的不确定性,当所有的数字被填满时,并不能用最初获取的数独数组与填完的数组进行比对校验(在数组中部分数据的位置具有不确定性)。填玩的数组需要根据数独的校验方法进行校验(即横竖不相同,所在的小的 3 * 3 的数组里面也不能相同)。校验的算法如下:
//校验
private void checkIsRight(){
boolean right=true;
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
int node=number[i][j];
//此位置尚未填写
if(node==0){
listener.onResultIsTrue(false,-1);
return;
}
//横向检查是否有相同的项 ,检查当前节点往后的节点
for(int sx=i+1;sx<9;sx++){
if(node==number[sx][j]){
right=false;
error[sx][j]=node;
error[i][j]=node;
}
}
//纵向检查是否有相同的项 ,检查当前节点往下的节点
for(int sy=j+1;sy<9;sy++){
if(node==number[i][sy]){
right=false;
error[i][sy]=node;
error[i][j]=node;
}
}
//根据下标判断 当前节点所在的 3 X 3 的格子中数字是否重复
//已重复的数字放入 error 数组对应的下标
int xi=i/3;
int yi=j/3;
for(int vx=0;vx<3;vx++){
for(int vy=0;vy<3;vy++){
if((3*xi+vx)!=i && (3*yi+vy)!=j){
if(node==number[3*xi+vx][3*yi+vy]){
right=false;
error[3*xi+vx][3*yi+vy]=node;
error[i][j]=node;
}
}
}
}
}
}
listener.onResultIsTrue(right,0);
}
此外本项目中还包括了 ShareSdk微信QQ的分享,以及bmob后端云的简单使用。详情见项目源码。
码云中国 git 源码链接:Android 数独