我们在上次讲解了如何快速高效生成数独完全解的算法思路,具体的就是通过回溯结合随机数,再通过分治的思想来处理。今天我们将用实际代码来实现该算法思想,具体实现的java代码如下:
package com.liu.project; 
public class
NumLogic
{    
private String
game;//游戏题面
private char
bBlock[][]=new char[9][9];//大九宫格
private
charbase[]={'1','2','3','4','5','6','7','8','9'};//基本字符元素
private int
used[]=new int[9];//记录本块使用的位置
private int
usable[]=new int[9];//记录本块可用位置的个数
public String
getGame() {//获取游戏谜面
      
returngame;
}
public
NumLogic(int greed){//greed为游戏等级
      
init();//初始化
     
while(creatBBlock()==0){//创建大九宫格
     
      
init();//恢复初始化,重新产生
     
}
      
this.game=getNum();//返回结果
}
public void
init(){//初始化
 for(int i=0;i<9;i++){
      
 for(int j=0;j<9;j++){
      
      
 bBlock[i][j]='0';//初始化大九宫格
      
 }
   }
}
public String
getNum(){//返回数独谜面
      
Strings="";
      
for(inti=0;i<9;i++){
   
      
      
for(int j=0;j<9;j++) {
      
      
      
s+=bBlock[i][j];//取出每个元素
      
      
}
      
}
      
returns;//返回结果
}
public
int creatBBlock(){//创建大九宫格
      
for(intelementloca=1;elementloca<=9;elementloca++){    
      
      
 //element表示base中1-9九个数字中的每个元素
      
   for(int i=0;i
      
      
  used[i]=-1;//复位填入位置记录
      
      
  usable[i]=-1;
      
   }
      int
looptime=0;
      
      
for(int flag=1;flag<=9;flag++){
      
      
      
//flag表示1-9九个小九宫格中的每个九宫格的编号,排序从上至下从左至右
     
      
      
//若未赋初值,则获取可用区域个数 
      
      
 if(usable[flag-1]==-1)  usable[flag-1]=getAllusable(flag,base[elementloca-1]);//赋初值
      
      
 if(usable[flag-1]==1)used[flag-1]=-1; //若该块可用区域只有一块,则将该块已用区域数复位   
      
       
//先检查本块九宫格是否有可用区域
      
      
      
 
if(usable[flag-1]==0){//为0,开始回溯
      
      
      
 
usable[flag-1]--;//复位当前块可用区域数 
      
      
      
 
if(flag==1){//回溯到第一块时       
      
     
      
      
  flag--;
      
      
      
      
 looptime++;
      
      
      
  }else{//其他块
      
      
      
      
 
     
      
  //恢复上一块填入的数字
      
      
      
 if(
used[3][used[flag-2]%3+((flag-2)%3)*3]='0';
      
      
      
 flag-=2;//回到上一块 
      
      
      
      
      
  } 
 
      
      
      
 continue ;//继续循环
      
      
  }
      
        
if(looptime>1){
      
       
      
  return 0;
      
         
}
      
      
 boolean
loadover=false;//随机数尝试循环控制标志             
      
     
 
while(!loadover){     
//在九宫格随机位置尝试填入元素,如果装载符合规则完成退出循环                  
      
     
int
seed=(int)(Math.random()*100)%9;//产生随机数0-8,表示该元素填入小九宫格的位置
 
      
      if(bBlock1)%3)*3]=='0'&&seed!=used[flag-
     
     
     
     
     
     
     
 1]&&checkRule(-1])){    
      
       
      
//符合规则的话,在大九宫格中装载该元素
      
       
      
bBlock[seed/3-1)%3)*3]=base[elementloca-1];
 
      
       
      
used[flag-1]=seed;//记录本次填入的位置              
      
           
usable[flag-1]-=1;//可用位置减一
      
           
//记录当前使用的位置      
      
        
    
loadover=true;//跳出随机尝试循环体 
  
      
       
}    
      
    
}
      
       
//某一块数据装载结束,进入下一块数据装载 
     
      
      
}             
      
      
}
      
return1;
  }
 
public boolean
checkRule(int flag,intlocation,char
element){//检查是否符合数独规则
      
for(inti=0;i<9;i++){    
//检查元素是否重复
      
//检查改行是否有元素重复
      
if(bBlock[location/3+((flag-1)/3)*3][i]==element)returnfalse;
      
//检查该列是否有元素重复
      
if(bBlock[i][location%3+((flag-1)%3)*3]==element)returnfalse;
      
}
      
returntrue;//没有的话返回true,符合规则
}
 
public int
getAllusable(int
flag,charelement){//返回可用空间的个数
      
intcount=0;
      
for(inti=0;i<9;i++)
      
if(bBlock[i/3+((flag-1)/3)*3][i%3+((flag-1)%3)*3]=='0'&&checkRule(flag,i,element)){
      
      
count++;//检测到可用位置则自增
      
}
     
return count;//返回可用空间个数
}
}