Java实现解数独的小程序

发布时间 - 2026-01-10 22:43:03    点击率:

前言

数独相信很多人都玩过,趣味性很强,十分的耐玩。可有没有程序员想过玩实现一个数独布局的算法呢?算法是个很有意思,很神奇的东西。

算法如下,需要预先给出几个固定的值,目前解决的一个最难的数独是大概26个已知值的情况,理论上应该能解决任意已知值的数独,不过不知道会不会迭代栈溢出……因为在26个已知值的情况下就迭代了3000多次了,囧~~~

结果显示如下:

这是已知值:

1 1 2
1 4 8 
1 5 5
1 6 1
1 7 7
1 8 3
2 1 1
2 2 6
2 4 4
3 5 9
3 7 8
3 8 4
4 7 9
5 8 7
6 1 3
6 6 8
6 7 4
6 8 6
7 3 7
7 6 4
7 7 1
8 3 3
8 6 7
9 3 4
9 4 6
9 7 3
9 8 2

(PS:如9 8 2表示第9行第二列的值是2)

将上面的数字保存到num.txt文件中,再把底下附的源代码保存为Sudoku.java。

然后在cmd命令行模型下输入:

javac Sudoku.java 
java Sudoku <num.txt 

即可得到结果。

这个解法是我之前看到八皇后排列问题的解法后结合应用的,在数独中采用了这种解法,不过应该算是比较暴力的拆解,所以我后面命名成violentBreak。。。

虽然只是一个很小的事,但是能尝试着用编程去解决日常遇到的事,突然觉得很开心,学以致用!

java源代码:

import java.lang.System.*; 
import java.util.ArrayList; 
import java.util.Scanner; 
 
 
/**This class named Sudoku can auto calculate Sudoku but 
*you should input some nums which are already known. 
*For instance: 
*1 5 3 
*2 4 7 
*There two rows means [1][5]=3 [2][4]=7 
*i.e. In row 1 col 5 is value:5 
*you can write all known num into one txt file 
*and input into this program . 
*such as java Sudoku < num.txt 
*/ 
 
/**代码逻辑解析: 
* 1、建立一个9X9矩阵保存数独正确的值 
 2、建立一个9X9列表,每个列表里保存着该位置,数独可以填入的可能值 
  如ArrayList[1][1]={1,2,3}即1,1这个位置的数独可能可以填入其中一个 
  当矩阵该位置已保存了正确值时,清空对应位置的ArrayList 
 3、当列表ArrayList里只有一个可能值时,那个值就是数独的正确值,将该值填入数独矩阵 
  并更新ArrayList 
 
 PS:以上算法只能用于求困难级别的数独,因为我在玩游戏的时候发现,每个时刻必定会有 
  一个数独空位,是只能填入一个值的,所以这个算法才能运行 
  当一个数独(即已知位置的值变少时),可能会出现所有的空位都最起码有两个值时, 
  需要改进算法,通过代入来判断这个数独是否成立 
 
 4、于是后期我加入了暴力破解法,在上面的步骤执行后无法得出数独,即使用暴力破解 
*  
*/ 
 
 
 
public class Sudoku{ 
 //弄十的原因是为了好记忆,0,0不用,只用1-9的list 
 private ArrayList<Integer>[][] availableNum=new ArrayList[10][10]; 
 private int[][] correctNum=new int[10][10]; 
 private Scanner scan=new Scanner(System.in); 
 private int countNum=0; 
  
 
 { 
  for(int i=0;i<10;i++){ 
   for(int j=0;j<10;j++){ 
    availableNum[i][j]=new ArrayList<>(); 
   } 
  } 
 
  for(int row=1;row<10;row++){ 
   for(int col=1;col<10;col++){ 
    for(int i=1;i<10;i++) 
     availableNum[row][col].add(new Integer(i)); 
   } 
  } 
 
  //先都初始化为-1,即此时没有填充数字 
  for(int i=0;i<10;i++) 
   for(int j=0;j<10;j++) 
    correctNum[i][j]=-1; 
 
 
 } 
 
 public Sudoku(){} 
 
 //在对应数独位置插入正确值 
 public void insert(int row,int col,int value){ 
  correctNum[row][col]=value; 
  availableNum[row][col]=null; 
  delete(row,col,value); 
 
 } 
 //每插入一个数值,就删除相应的行列和小框框3X3数独里对应的ArrayList里可能的该值 
 public void delete(int row,int col,int value){ 
  //delte row 
  for(int i=1;i<10;i++){ 
   if (availableNum[row][i]!=null) 
    availableNum[row][i].remove(new Integer(value)); 
  } 
 
  //delete column 
  for(int i=1;i<10;i++){ 
   if (availableNum[i][col]!=null) 
    availableNum[i][col].remove(new Integer(value)); 
  } 
 
  //delete box num 
  int[] itsCenter=judgeCenterPos(row,col); 
  for(int temp1=itsCenter[0]-1;temp1<=itsCenter[0]+1;temp1++) 
   for(int temp2=itsCenter[1]-1;temp2<=itsCenter[1]+1;temp2++) 
    if(availableNum[temp1][temp2]!=null){ 
     availableNum[temp1][temp2].remove(new Integer(value)); 
    } 
 
 } 
 //判断插入的值时处于哪个小框框数独里 
 public int[] judgeCenterPos(int row,int col){ 
  int[] itsCenter=new int[2]; 
  for(int centerRow=2;centerRow<9;centerRow+=3) 
   for(int centerCol=2;centerCol<9;centerCol+=3){ 
    if( Math.abs(row-centerRow)<=1 && 
     Math.abs(col-centerCol)<=1 ){ 
     itsCenter[0]=centerRow; 
     itsCenter[1]=centerCol; 
     return itsCenter; 
    } 
 
   } 
  System.out.println("Some unchecked error was happened"); 
  return itsCenter; 
 
 } 
 
 //判断空格里所能填的数字是不是只能有一个,当返回-1时通过检测报错 
 public int[] judgeIfOnlyOne(){ 
 
  for(int row=1;row<10;row++) 
   for(int col=1;col<10;col++){ 
    if(availableNum[row][col]!=null) 
     if(availableNum[row][col].size()==1) 
      return new int[]{row,col}; 
   } 
 
  return new int[]{-1,-1}; 
 
 } 
 
 // 判断为唯一,但是空格里还有多于1个的数时,我们直接将哪个正确的值填入 
 public void insertIfCan(){ 
 
  for(int row=1;row<=7;row+=3){ 
   for(int col=1;col<=7;col+=3){ 
    for(int z=1;z<10;z++){ 
     int count=0; 
     Integer temp=new Integer(z); 
     int itemp=0,jtemp=0; 
     outer: 
     for(int i=row;i<row+3;i++){ 
      for(int j=col;j<col+3;j++){ 
       if(availableNum[i][j]!=null){ 
        if(availableNum[i][j].contains(temp)){ 
         count++; 
         itemp=i; 
         jtemp=j; 
         if (count>1) 
          break outer; 
        } 
       } 
      } 
     } 
     if(count==1 && itemp!=0){ 
      insert(itemp,jtemp,z); 
     } 
    } 
     
   } 
  } 
 } 
 
 
 
 
 
 
 //判断数独的矩阵是否填满,没有则继续 
 public boolean judgeMatrixFull(){ 
  for(int i=1;i<10;i++) 
   for(int j=1;j<10;j++) 
    if(correctNum[i][j]==-1) 
     return false; 
  return true; 
 } 
 
 //先输入已知位置的数字 
 public void inputNumKnown(){ 
  while(scan.hasNextInt()){ 
   int row=scan.nextInt(); 
   int col=scan.nextInt(); 
   int value=scan.nextInt(); 
   insert(row,col,value); 
   delete(row,col,value); 
  } 
 } 
 
  
 
 //打印数独结果 
 public void printSudoku(){ 
  printSudoku(correctNum); 
   
 } 
 
 public void printSudoku(int[][] arr){ 
  System.out.println("Sudoku result:"); 
  for(int i=1;i<10;i++){ 
   for(int j=1;j<10;j++) 
    System.out.print(arr[i][j]+" "); 
   System.out.println(" "); 
  } 
 } 
 
 public void printList(){ 
  for(int i=1;i<10;i++) 
   for(int j=1;j<10;j++){ 
    System.out.print(i+" "+j+":"); 
    if(availableNum[i][j]!=null) 
     for(int z=0;z<availableNum[i][j].size();z++){ 
      System.out.print(availableNum[i][j].get(z)+" "); 
     } 
    System.out.println(" "); 
   } 
 } 
 
 
 
 
 //暴力破解 
 public void violentBreak(){ 
  int i=1,j=1; 
  outer: 
  for(;i<10;i++) 
   for(;j<10;j++) 
    if(correctNum[i][j]!=-1) 
     break outer; 
 
  violentInsert(i,j,correctNum[i][j],correctNum); 
 } 
 
 
 public void violentInsert(int row,int col,int value,int[][] arr){ 
  countNum++; 
  int[][] tempMatrix=new int[10][10]; 
 
  for(int i=1;i<10;i++) 
   for(int j=1;j<10;j++) 
    tempMatrix[i][j]=arr[i][j]; 
 
  tempMatrix[row][col]=value; 
  //不能insert的话说明填满了 
  int[] insertPos=canInsert(tempMatrix); 
  if(insertPos[0]==-1){ 
   System.out.println("all insert is done.This is the last Sudoku:"); 
   printSudoku(tempMatrix); 
   return; 
  } 
 
 
  for(int val=1;val<=10;val++){ 
   if(val==10){ 
    tempMatrix=null; //让JVM回收垃圾 
    //System.out.println("value=10 happened."); 
    return; 
   } 
   if(judgeIfViolentInsert(insertPos[0],insertPos[1],val,tempMatrix)){ 
    //System.out.println("insert happened."); 
    violentInsert(insertPos[0],insertPos[1],val,tempMatrix); 
   } 
  } 
 
 } 
 
 public int[] canInsert(int[][] tempMatrix){ 
  int[] pos={-1,-1}; 
  for(int i=1;i<10;i++) 
   for(int j=1;j<10;j++){ 
    if(tempMatrix[i][j]==-1){ 
     pos[0]=i; 
     pos[1]=j; 
     return pos; 
    } 
   } 
  return pos; 
 } 
 
 
 public boolean judgeIfViolentInsert(int row,int col,int value,int[][] tempMatrix){ 
  for(int j=1;j<10;j++) 
   if(value==tempMatrix[row][j]) 
    return false; 
 
  for(int i=1;i<10;i++) 
   if(value==tempMatrix[i][col]) 
    return false; 
 
 
  int[] itsCenter=judgeCenterPos(row,col); 
  for(int temp1=itsCenter[0]-1;temp1<=itsCenter[0]+1;temp1++) 
   for(int temp2=itsCenter[1]-1;temp2<=itsCenter[1]+1;temp2++) 
    if(value==tempMatrix[temp1][temp2]) 
     return false; 
 
  return true; 
 } 
 
 
 //数独开始运算的函数 
 public void start(){ 
  int[] nextInsert=new int[2]; 
  int count=0; 
  this.inputNumKnown(); 
 
  while(!judgeMatrixFull()){ 
   nextInsert=judgeIfOnlyOne(); 
   if(nextInsert[0]==-1){ 
    this.insertIfCan(); 
    count++; 
    if(count==15){ 
     System.out.println("Cannot fullfill this sodoku through finding the only one left."); 
     System.out.println("count:"+count); 
     break; 
    } 
    continue; 
 
   } 
   int value=availableNum[nextInsert[0]][nextInsert[1]].get(0); 
   insert(nextInsert[0],nextInsert[1],value); 
  } 
 
  printSudoku(); 
  //满了就不用暴力破解了 
  if(judgeMatrixFull()) 
   return; 
  System.out.println("Now we should break this Sudoku by violent method."); 
  violentBreak(); 
  System.out.println("Recursion times:"+countNum); 
 } 
 
 
 
 
 public static void main(String[] args){ 
 
  Sudoku test1=new Sudoku(); 
  test1.start(); 
   
  int[] a=new int[2]; 
  System.out.println(a); 
  System.out.println(a[0]); 
 
 } 
 
} 

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。


# java数独代码  # java数独  # java数独游戏源代码  # java 实现迷宫回溯算法示例详解  # java回溯算法解数独问题  # Java实现走迷宫回溯算法  # Java基于循环递归回溯实现八皇后问题算法示例  # Java实现数独小游戏  # python实现数独游戏 java简单实现数独游戏  # Java基于二维数组实现的数独问题示例  # java版数独游戏界面实现(二)  # 简单实现java数独游戏  # 教你怎么用Java回溯算法解数独  # 数独  # 填入  # 格里  # 满了  # 建立一个  # 源代码  # 这是  # 迭代  # 几个  # 是个  # 会有  # 我在  # 很多人  # 学以致用  # 会不会  # 少时  # 采用了  # 很强  # 只有一个  # 想过 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑  长沙企业网站制作哪家好,长沙水业集团官方网站?  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  Laravel如何与Pusher实现实时通信?(WebSocket示例)  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  Laravel用户密码怎么加密_Laravel Hash门面使用教程  香港服务器WordPress建站指南:SEO优化与高效部署策略  如何正确选择百度移动适配建站域名?  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  济南网站建设制作公司,室内设计网站一般都有哪些功能?  Python面向对象测试方法_mock解析【教程】  如何在阿里云高效完成企业建站全流程?  Laravel安装步骤详细教程_Laravel环境搭建指南  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  如何用AI帮你把自己的生活经历写成一个有趣的故事?  深圳网站制作平台,深圳市做网站好的公司有哪些?  Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧  canvas 画布在主流浏览器中的尺寸限制详细介绍  javascript中闭包概念与用法深入理解  javascript基于原型链的继承及call和apply函数用法分析  想要更高端的建设网站,这些原则一定要坚持!  网站制作壁纸教程视频,电脑壁纸网站?  高端网站建设与定制开发一站式解决方案 中企动力  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Laravel如何实现全文搜索功能?(Scout和Algolia示例)  如何用PHP快速搭建高效网站?分步指南  图册素材网站设计制作软件,图册的导出方式有几种?  使用C语言编写圣诞表白程序  什么是javascript作用域_全局和局部作用域有什么区别?  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  如何在IIS7上新建站点并设置安全权限?  详解vue.js组件化开发实践  小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像  如何在香港服务器上快速搭建免备案网站?  Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】  公司门户网站制作流程,华为官网怎么做?  猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】  如何用PHP快速搭建CMS系统?  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  如何在Windows虚拟主机上快速搭建网站?  黑客如何通过漏洞一步步攻陷网站服务器?  iOS验证手机号的正则表达式  Laravel如何使用Vite进行前端资源打包?(配置示例)  Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤  如何在VPS电脑上快速搭建网站?  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  如何在云主机上快速搭建网站?