看到很多人写了数独终盘生成算法,于是心血来潮,自己写了一个。
一、生成规则
1、按顺序将1~9填入宫格中;
2、检查所在行、列及小九宫格是否存在相同数字
3、若存在相同数字则将数字加1 ,重复第2步
这样就得到了初始的数独终盘,如下图
二、打乱顺序
1、随机交换某两行(只能是同一个九宫格内的两行)
2、随机交换某两列(只能是同一个九宫格内的两列)
得到终盘
三、去掉部分数字,这样就得到了最终的数独了(可根据难度去掉不同数量的数字)
上面的效果是用VBA在Excel中生成的。
下面附上JAVA代码
1 import java.util.Random;
2
3 public final class Sudu {
4 static final int SIZE = 9;
5 static final int CELL_SIZE = 3;
6 static final int LEVEL_MAX = 10;
7 static int[][] suduAry = new int[SIZE][SIZE];
8
9 /**
10 * 生成数独
11 * @param level 难度级别 1~10
12 * @return
13 */
14 public static int[][] generate(int level) {
15 Random random = new Random();
16 int n = random.nextInt(9) + 1;
17 for(int i=0;i<SIZE;i++) {
18 for(int j=0;j<SIZE;j++) {
19 int p = Math.floorDiv(i, CELL_SIZE);
20 int q = Math.floorDiv(j, CELL_SIZE);
21 for(int k=0;k<SIZE;k++) {
22 if(checkColumn(n, j) && checkRow(n, i) && checkNineCells(n, p, q)) {
23 suduAry[i][j] = n;
24 break;
25 } else {
26 n = n % SIZE + 1;
27 }
28 }
29 }
30 n = n % SIZE + 1;
31 }
32 upset();
33 maskCells(level);
34
35 return suduAry;
36 }
37
38 private static void maskCells(int level) {
39 int min, max;
40 level %= LEVEL_MAX;
41 if(level == 0) level = LEVEL_MAX;
42
43 if(level <4) {
44 min = 20;
45 max = 15;
46 } else if(level < 7) {
47 min = 40;
48 max = 10;
49 } else if(level < 10) {
50 min = 50;
51 max = 10;
52 } else {
53 min = 60;
54 max = 5;
55 }
56
57 Random random = new Random();
58 int count = random.nextInt(max) + min;
59 for(int i=0;i<count;i++) {
60 do {
61 int n = random.nextInt(SIZE);
62 int m = random.nextInt(SIZE);
63 if(suduAry[n][m] > 0) {
64 suduAry[n][m] = 0;
65 break;
66 }
67 }while(true);
68 }
69 }
70
71 /**
72 * 随机打乱顺序
73 */
74 private static void upset() {
75 Random random = new Random();
76 //按行交换
77 for(int i=0;i<SIZE;i++) {
78 int n = random.nextInt(CELL_SIZE);
79 int p = random.nextInt(CELL_SIZE) * CELL_SIZE + n;
80 for(int j=0;j<SIZE;j++) {
81 int tmp = suduAry[i][j];
82 suduAry[i][j] = suduAry[p][j];
83 suduAry[p][j] = tmp;
84 }
85 }
86 //按列交换
87 for(int i=0;i<SIZE;i++) {
88 int n = random.nextInt(CELL_SIZE);
89 int p = random.nextInt(CELL_SIZE) * CELL_SIZE + n;
90 for(int j=0;j<SIZE;j++) {
91 int tmp = suduAry[j][i];
92 suduAry[j][i] = suduAry[j][p];
93 suduAry[j][p] = tmp;
94 }
95 }
96 }
97
98 /**
99 * 检查某行
100 * @param n
101 * @param row
102 * @return
103 */
104 private static boolean checkRow(int n, int row) {
105 boolean result = true;
106
107 for(int i=0;i<SIZE;i++) {
108 if(suduAry[row][i] == n) {
109 result = false;
110 break;
111 }
112 }
113
114 return result;
115 }
116 /**
117 * 检查某列
118 * @param n
119 * @param col
120 * @return
121 */
122 private static boolean checkColumn(int n, int col) {
123 boolean result = true;
124 for(int i=0;i<SIZE;i++) {
125 if(suduAry[i][col] == n) {
126 result = false;
127 break;
128 }
129 }
130 return result;
131 }
132
133 /**
134 * 检查小九宫格
135 * @param n
136 * @param x
137 * @param y
138 * @return
139 */
140 private static boolean checkNineCells(int n, int x, int y) {
141 boolean result = true;
142 int sx = x * 3, sy = y * 3;
143
144 for(int i=sx; i<sx+3;i++) {
145 for(int j=sy;j<sy+3;j++) {
146 if(suduAry[i][j] == n) {
147 result = false;
148 break;
149 }
150 }
151 if(!result) break;
152 }
153
154 return result;
155 }
156 }