简单的回溯法生成数独游戏

题目的原因:课程作业

这是一个课设的作业,对于理解回溯法很有用,所以把他码住。好久没敲这种代码了,边界居然调了半天,尴尬!

作业分析

作业描述:写个数独游戏,具有自动生成数独的功能和人工设定初始盘的功能,并且具有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;
	
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值