利用程序随机构造N个已解答的数独棋盘
程序代码:
package shudu; import java.util.ArrayList; class Point { public Point() { } public Point(int x, int y) { this.x = x; this.y = y; } public Point(int x, int y, int re) { this.x = x; this.y = y; this.freshTime = re; } // /** // * 当前point 集合所代表的数独的数 // */ // public int currentNum = 1; /** * 一个点在一个宫里面有9中可能的位置,此值为在每个宫中试探的次数 */ public int freshTime = 0; public int x; public int y; public ArrayListavailablePoint = new ArrayList (); static public Point[][] initPoint() { Point[][] p = new Point[9][9]; for (int i = 0; i < p.length; i++) { for (int j = 0; j < p.length; j++) { p[i][j] = new Point(); } } return p; } static public void initEachPoint(Point[] p) { for (int i = 0; i < p.length; i++) { p[i].x=-1; p[i].y=-1; p[i].freshTime=0; } } } public class Main { private int _step = 3; // private int _currentNum=1; private int[][] _rectangle = new int[9][9]; // point 历史记录 private int _history = -1; public Main() { for (int i = 0; i < this._rectangle.length; i++) { for (int j = 0; j < this._rectangle[i].length; j++) { this._rectangle[i][j] = 0; } } } public boolean isTheSame(Point[] p, int count) { int[] x = new int[] { -2, -2, -2, -2, -2, -2, -2, -2, -2, }; int[] y = new int[] { -2, -2, -2, -2, -2, -2, -2, -2, -2, }; for (int i = 0; i <=count; i++) {//唯一bug,<=写成< if (x[p[i].x] == -2) { x[p[i].x] = 0; } else { return true; } if (y[p[i].y] == -2) { y[p[i].y] = 0; } else { return true; } } return false; } public void print(int[][] a) { for (int i = 0; i < a.length; i++) { for (int j = 0; j < a[i].length; j++) { System.out.print(a[i][j] + " "); } System.out.println(); } } public int random(int begin, int end) { return (int) (Math.random() * (end - begin) + begin); } /** * * @param xPos * 参照x坐标 * @param yPos * 参照y坐标 * @param xCol * 实际x坐标 * @param yCol * 实际y坐标 * @return */ public boolean isPosOutOfBoundry(int xPos, int yPos, int xCol, int yCol) { int xEnd = xPos + this._step; int yEnd = yPos + this._step; if ((xCol >= xPos && xCol < xEnd) && (yCol >= yPos && yCol < yEnd)) { return false; } return true; } public Point generateRandomXYPos(int xPos, int yPos) { // int xCol = random(xPos, xPos + this._step); // int yCol = random(yPos, yPos + this._step); Point point = new Point(); // 选取某个宫中的点的位置时,此位置不可用的次数 int num = 0; // 当前随机位置不可生成点 for (int i = xPos; i < xPos + this._step; i++) { for (int j = yPos; j < yPos + this._step; j++) { if (this._rectangle[i][j] != 0) { num++; } else { point.availablePoint.add(new Point(i, j)); } } } point.freshTime = num; return point; } public int[][] generate() { // 以步长为3增加的锚点 int xPos, yPos; // 数独点的坐标 int xCol, yCol; Point[][] p = Point.initPoint(); // 对1-9每个数进行操作 for (int i = 0; i < 2;) { // 初始化点集 // 历史记录是上一次9个宫都满足时所记录的状态 boolean needBack = false; this._history++; if (this._history >= 9) { this._history = 0; } Point.initEachPoint(p[this._history]); // p[this._history][count].currentNum = i + 1; for (xPos = 0; xPos < this._rectangle.length; xPos += this._step) { if (needBack) { break; } for (yPos = 0; yPos < this._rectangle.length; yPos += this._step) { // 宫 int count = ((xPos * this._step) + yPos) / this._step; Point _pPoint = generateRandomXYPos(xPos, yPos); p[this._history][count].freshTime = _pPoint.freshTime; // 在某一个宫处9个小格都满足不了,只能回溯 if (_pPoint.freshTime >= 9) { needBack = true; break; } while (_pPoint.availablePoint.size() > 0) { int k = random(0, _pPoint.availablePoint.size()); p[this._history][count].x = _pPoint.availablePoint.get(k).x; p[this._history][count].y = _pPoint.availablePoint.get(k).y; if (!this.isTheSame(p[this._history], count)) { break; } _pPoint.availablePoint.remove(k); } } } if (needBack) { this._history--; if (this._history < 0) { this._history = 8; } // 清空上一次的,重新随机,,,(有可能会随机一模一样的值) for (int n = 0; n < p[this._history].length; n++) { this._rectangle[p[this._history][n].x][p[this._history][n].y] = 0; } i--; } else { for (int n = 0; n < p[this._history].length; n++) { this._rectangle[p[this._history][n].x][p[this._history][n].y] = i + 1; } i++; } } return this._rectangle; } public static void main(String[] args) { Main main = new Main(); int[][] shudu = main.generate(); main.print(shudu); } }
程序运行结果:随机生成5个不重复的数独棋盘
8 9 3 1 6 5 4 7 2
2 7 6 3 4 8 1 9 5
4 1 5 2 7 9 6 3 8
7 4 1 8 2 6 3 5 9
3 6 8 7 5 9 2 1 4
5 2 9 4 1 3 7 8 6
6 5 4 9 7 1 7 2 3
9 3 2 6 8 4 5 6 1
1 8 7 5 3 2 9 4 8
7 5 1 6 9 3 2 4 8
6 3 8 4 2 7 5 9 1
9 2 4 5 8 1 3 6 7
3 4 6 2 7 9 1 5 8
1 9 7 8 5 4 6 2 3
5 8 2 3 1 6 4 7 9
2 7 9 1 3 8 9 8 4
4 1 3 7 6 5 6 3 2
8 6 5 9 4 2 7 1 5
5 4 3 6 7 2 1 8 7
7 1 2 4 5 8 6 9 3
8 9 6 3 9 1 2 5 4
9 5 4 7 6 3 8 2 1
3 6 7 2 1 4 5 7 9
1 2 8 5 9 8 3 4 6
6 3 9 8 2 7 9 1 5
4 7 5 1 4 6 7 3 2
2 8 1 9 3 5 4 6 8
9 2 3 4 8 5 7 6 1
5 6 1 7 2 3 4 8 9
7 8 4 6 9 1 3 5 2
3 7 6 1 9 7 5 2 4
8 1 2 5 3 4 6 9 8
4 9 5 8 6 2 7 1 3
6 4 7 2 5 7 1 3 9
1 3 8 8 4 6 2 7 5
2 5 9 3 1 9 8 4 6
8 7 5 2 1 4 3 6 9
1 2 3 7 6 5 8 7 4
9 6 4 3 9 8 2 1 5
7 5 1 7 3 2 6 4 7
3 8 9 5 4 6 9 2 1
6 4 2 1 8 9 5 3 8
5 1 9 4 2 3 9 8 6
4 3 6 8 9 7 1 5 2
2 7 8 6 5 1 4 7 3
分析:我是先对下标进行比较,把数独分成九个宫,那么每宫生成一个数字总共生成9个,这九个的横纵坐标都是唯一的,不会出现某两个横坐标或者纵坐标相等的情况;每个小宫里面的数字的位置又有九种可能,回溯条件是,当要对某个宫填值时,首先遍历这个宫,看是否有空位并记录遍历它的次数,如果遍历次数超过九次。那么说明当前要填的数字不能在此宫下填了;但是又因为是九个宫一起填一个数字,所以必须全部回溯,回溯到上一次正确的填值,并且还要把上次正确填的值重置;因为即使你上次的值是对的,但是却填导致这次无路可走,所以上次的要重新随机充填。 以上为止并没有往数独里面填数字,只是在比较下标,如果这次下标验证正确,才往数独里面填值。如果不对,删掉数独里面上次正确的值重来。这样会有个概率性的问题,”上次的值删掉后重新填过后的值还有可能又是上次的”。
心得:通过本次作业,一定程度锻炼了自己的编程能力,对java相关知识更深层次理解和运用,遇到的难题和未解决的疑惑是这个程序的思路大致上没有问题,但运行的结果不尽人意。遇到的难题和未解决的疑惑:同行同列出现了重复的数字,暂时找不出哪里的逻辑出了问题,回溯法还是存在理不清的状态,希望老师能够给出指导。整个程序花费的时间达到3天至4天,想看到最后运行的结果正确,然而却找不到bug,十分无奈。
课外任务:
目前来说,软件工程专业基础课之前没有学过,还有其他一些专业课知识没有掌握,基础相对来说薄弱,需课后花更多的时间自主学习。以下几个技能希望能够有所提升在学习高级软件工程的路上。