题目的原因:课程作业
这是一个课设的作业,对于理解回溯法很有用,所以把他码住。好久没敲这种代码了,边界居然调了半天,尴尬!
作业分析
作业描述:写个数独游戏,具有自动生成数独的功能和人工设定初始盘的功能,并且具有UI界面。
作业分析:
任务一:对于自动生成数独的功能,他的功能实现逻辑是:回溯生成一个数独,然后随机性让部分区域可视(对于玩家),当玩家选择提交时,再判断是否与生成的数独一致。
**任务二:**对于人工设定初始盘的功能,他和上面的自动生成有一些不同,当玩家选择手动生成数独并提交给后台之后,后台通过回溯法对提交的数组进行有解检查,如果无解返回“设定失败”,否则就找到所有的解,并保存全部。当玩家提交answer时,匹配每一种解。
任务一实现
回溯逻辑:对于一个用来保存生成的数组GAME,我们对其进行自上而下从左到右的填充,每次在当前位置(x,y)填充一个数字时,对该数字进行合法判断Iscorrect(x,y),如果不合法,进行回溯;合法进行下一次填充。
注:回溯法一定注意循环的逻辑,以及对continue一定要有充分的了解,不清楚的建议改为break,单步调试几次。特别注意,j=j-2而不是j=j-1!!!
private static int[][] game=new int [9][9];//储存数独
private static int []ranNum= {1,2,3,4,5,6,7,8,9};//随机数生成数组
private int[][] generateGame(){
//初始化数独
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
game[i][j]=0;
//生成数独游戏的所有内容
for(int i=0;i<9;i++) {
int time=0;
for(int j=0;j<9;j++) {
int tem=-1;
tem=getNum(time);
game[i][j]=tem;
if(tem==0) {
//说明已经不能再填充数字了
if(j>0) {
//当j不是第一列时,回溯上一列,由于j已经加了所以是j-2,而不是j--;特别注意
j=j-2;
continue;
}
else {
i--;
j=8;
continue;
}
}
//如果可以获得数字,说明尝试的次数并没有用完
//对数字的合法性进行检查
if(Iscorrect(i,j)) {
time=0;
}
else {//填充失败,继续填充,应该
time++;
j--;
}
}
}
return game;
}
功能模块完善
1、自动生成随机数函数getNum(int time)
对于一个第一次,生成随机数的情况来说(time=0),我们初始化数组。
对于一个进行第九次挑选随机数的情况来说(time=9),我们已经没有数可以供他使用,所以返回不存在。
当进行数字生成时,我们只要保证生成随机数的下标是在MAX(未被使用的数字的下标),就可以实现,千万别忘了把已经使用过的数字和末位交换。
注:这个自己一定要写一下,我错了好几次!!
//生成随机数独
private int getNum(int time) {
//第一次产生随机数
Random r=new Random();
if (time == 0) {
for (int i = 0; i < 9; i++) {
ranNum[i] = i + 1;
}
}
// 第10次填充,表明该位置已经卡住,则返回0,由主程序处理退回
if (time == 9) {
return 0;
}
// 不是第一次填充
// 生成随机数字,该数字是数组的下标,取数组num中该下标对应的数字为随机数字
// int ranNum = (int) (Math.random() * (9 - time));//j2se
int num=r.nextInt(9 - time);//j2me
// 把数字放置在数组倒数第time个位置,
int temp = ranNum[8 - time];
ranNum[8 - time] = ranNum[num];
ranNum[num] = temp;
// 返回数字
return ranNum[8-time];
}
2.合法性判断(一定不要越界)
注:最好写个边界判断函数,我写代码时候越界了,没有输出就狠烦。
private boolean Iscorrect(int i, int j) {
// TODO Auto-generated method stub
if(Checkline(i)&&CheckCol(j)&&CheckBox(i,j)) {
return true;
}
else {
return false;
}
}
//检查3*3是否有重复
private boolean CheckBox(int i, int j) {
//获取左上角进行遍历
int sx=i/3*3;
int sy=j/3*3;
for(int m=0;m<8;m++) {
//说明还没有填充
if(game[sx+m/3][sy+m%3]==0) {
continue;
}
for(int n=m+1;n<9;n++) {
if(game[sx+m/3][sy+m%3]==game[sx+n/3][sy+n%3]) {
//System.out.println("asdfasfa ");
return false;
}
}
}
// TODO Auto-generated method stub
return true;