1 /****************************************************************************
4 * Created on den 30 december 2005, 01:04
7 * Sudoku puzzle generator and solver based on the suexg and suexk by
8 * Gunter Stertenbrink. Suexg and suexk are C implementations of the
9 * Dancing Links algorithm by Donald Knuth and optimized for performance
10 * which means that certain cleanup work has been done. There is still
11 * lots of these activities left to do, however, the code is nasty and
12 * hard to read - but extremely efficient.
14 * The code is public domain so feel free to use it.
15 *****************************************************************************/
17 package net.sourceforge.plantuml.sudoku;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.util.Date;
22 import java.util.Random;
24 /*******************************************************************************
25 * dlx_solver solve any Sudoku in a fraction of a second. Input is a string of
26 * dots and digits representing the puzzle to solve and output is the solved
29 * @author Rolf Sandberg
30 ******************************************************************************/
32 static final int M = 8; // change this for larger grids. Use symbols as in
34 static final int M2 = M * M;
35 static final int M4 = M2 * M2;
37 /** Pseudo-random number generator */
39 return random.nextLong();
42 int A0[][] = new int[M2 + 9][M2 + 9], A[][] = new int[M2 + 9][M2 + 9], Rows[] = new int[4 * M4 + 9],
43 Cols[] = new int[M2 * M4 + 9], Row[][] = new int[4 * M4 + 9][M2 + 9];
44 int Col[][] = new int[M2 * M4 + 9][5], Ur[] = new int[M2 * M4 + 9], Uc[] = new int[4 * M4 + 9], V[] = new int[M2
46 int C[] = new int[M4 + 9], I[] = new int[M4 + 9], T[] = new int[M2 * M4 + 9], P[] = new int[M2 * M4 + 9];
47 int Mr[] = { 0, 1, 63, 1023, 4095, 16383, 46655, 131071, 262143 };
48 int Mc[] = { 0, 1, 63, 511, 1023, 4095, 8191, 16383, 16383 };
49 int Mw[] = { 0, 1, 3, 15, 15, 31, 63, 63, 63 };
51 int nocheck = 0, max, _try_;
53 int min, clues, gu, tries;
54 long Node[] = new long[M4 + 9];
55 long nodes, tnodes, solutions, vmax, smax, time0, time1, t1, x1;
57 int q, a, p, i, i1, j, k, l, r, r1, c, c1, c2, n, N = 0, N2, N4, m, m0, m1, x, y, s;
58 char L[] = { '.', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
59 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e',
60 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
63 /** State machine states */
64 static final int M6 = 10;
65 static final int M7 = 11;
66 static final int RESTART = 12;
67 static final int M22 = 13;
68 static final int M3 = 14;
69 static final int M44 = 15;
70 static final int NEXT_TRY = 16;
71 static final int END = 30;
74 * Solver function. Input parameter: A puzzle to solve Output: The solved
77 String solve(String puzzle) {
78 System.out.println("puzzle = "+puzzle);
79 String result = new String();
98 if (puzzle.length() < N4) {
99 return "Error, puzzle incomplete";
102 while (STATE != END) {
107 for (x = 0; x < N2; x++)
108 for (y = 0; y < N2; y++) {
109 c = puzzle.charAt(x * N2 + y);
112 if (c == '-' || c == '.' || c == '0' || c == '*') {
116 while (L[j] != c && j <= N2)
134 for (i = 0; i <= N4; i++)
141 for (x = 1; x <= N2; x++)
142 for (y = 1; y <= N2; y++)
143 for (s = 1; s <= N2; s++) {
146 Col[r][1] = x * N2 - N2 + y;
147 Col[r][4] = (N * ((x - 1) / N) + (y - 1) / N) * N2 + s + N4;
149 Col[r][3] = x * N2 - N2 + s + N4 * 2;
150 Col[r][2] = y * N2 - N2 + s + N4 * 3;
152 for (c = 1; c <= m; c++)
155 for (r = 1; r <= n; r++)
156 for (c = 1; c <= Cols[r]; c++) {
162 for (x = 0; x < N2; x++)
163 for (y = 0; y < N2; y++)
166 for (i = 0; i <= n; i++)
168 for (i = 0; i <= m; i++)
173 for (x = 1; x <= N2; x++)
174 for (y = 1; y <= N2; y++)
175 if (A[x - 1][y - 1] > 0) {
176 r = x * N4 - N4 + y * N2 - N2 + A[x - 1][y - 1];
178 for (j = 1; j <= Cols[r]; j++) {
180 if (Uc[c1] > 0 && nocheck == 0) {
187 for (k = 1; k <= Rows[c1]; k++) {
192 if (STATE == NEXT_TRY)
195 if (STATE == NEXT_TRY)
198 if (rnd > 0 && rnd != 17 && rnd != 18)
201 for (c = 1; c <= m; c++) {
203 for (r = 1; r <= Rows[c]; r++)
204 if (Ur[Row[c][r]] == 0)
219 if (i > N4 || m0 > 0) {
228 for (c = 1; c <= m; c++)
250 if ((rnd & 255) == 18)
251 if ((nodes & 1) > 0) {
254 while (Uc[c] > 0 || V[c] != 2)
259 if ((rnd & 255) == 17) {
260 c1 = (int) (MWC() & Mc[N]);
262 c1 = (int) (MWC() & Mc[N]);
265 for (c = c1; c <= m; c++)
272 for (c = 1; c < c1; c++)
284 if (I[i] > Rows[c]) {
297 if (q > 0 && i > 32 && i < 65)
298 if ((MWC() & 127) < q) {
305 y = ((r - 1) % k) / j + 1;
312 y = ((r - 1) % k) / j + 1;
316 for (x = 0; x < j; x++)
317 for (y = 0; y < j; y++)
318 result = result.concat(String.valueOf(L[A[x][y]]));
319 result = result.concat(" #\n");
323 for (j = 1; j <= Cols[r]; j++) {
328 for (j = 1; j <= Cols[r]; j++) {
331 for (k = 1; k <= Rows[c1]; k++) {
335 for (l = 1; l <= Cols[r1]; l++) {
339 if (Uc[c2] + V[c2] < 1)
341 if (Uc[c2] == 0 && V[c2] < 2)
349 if (rnd > 99 && nodes > rnd) {
356 if (solutions >= smax) {
357 System.out.println("smax xolutions found");
359 System.out.print("+");
365 System.out.print("-");
381 for (j = 1; j <= Cols[r]; j++) {
385 for (k = 1; k <= Rows[c1]; k++) {
390 for (l = 1; l <= Cols[r1]; l++) {
400 y = ((r - 1) % k) / j + 1;
410 time1 = System.currentTimeMillis();
420 for (i = 1; i < 33; i++)
422 System.out.println("clues: " + clues + " estimated solutions:" + yy + " time " + x1 + "ms");
427 if ((p == 0 || p == 1) && tnodes <= 999999) {
428 if (solutions >= smax)
429 result = result.concat("More than " + solutions + " solutions ( bad sudoku!! ), rating "
430 + (100 * tnodes / solutions) + ", time " + x1 + " ms");
431 else if (solutions == 1)
432 result = result.concat(solutions + " solution, rating " + (100 * tnodes) + ", time " + x1
434 else if (solutions == 0)
435 result = result.concat("0 solutions, no rating possible, time " + x1 + " ms");
437 result = result.concat(solutions + " solutions ( bad sudoku!! ), rating "
438 + (100 * tnodes / solutions) + ", time " + x1 + " ms");
444 System.out.println(solutions);
448 if (p == 0 || p == 1) {
449 System.out.println(solutions + " solution(s), rating " + (100 * tnodes) + ", time " + x1 + "ms");
453 for (i = 1; i <= N4; i++) {
455 System.out.print(Node[i]);
457 System.out.println();
459 System.out.println(x);
463 } // end of switch statement
464 } // end of while loop
472 for (i = 1; i <= m; i++) {
473 a = (int) ((MWC() >> 8) & Mc[N]);
475 a = (int) ((MWC() >> 8) & Mc[N]);
481 for (c = 1; c <= m; c++) {
486 for (c = 1; c <= m; c++)
489 for (r = 1; r <= n; r++)
490 for (i = 1; i <= Cols[r]; i++) {
497 for (i = 1; i <= n; i++) {
498 a = (int) ((MWC() >> 8) & Mr[N]);
500 a = (int) ((MWC() >> 8) & Mr[N]);
506 for (r = 1; r <= n; r++) {
511 for (r = 1; r <= n; r++)
514 for (c = 1; c <= m; c++)
515 for (i = 1; i <= Rows[c]; i++) {
522 for (r = 1; r <= n; r++) {
523 for (i = 1; i <= Cols[r]; i++) {
524 a = (int) ((MWC() >> 8) & 7);
526 a = (int) ((MWC() >> 8) & 7);
532 for (i = 1; i <= Cols[r]; i++)
535 for (i = 1; i <= Cols[r]; i++)
539 for (c = 1; c <= m; c++) {
540 for (i = 1; i <= Rows[c]; i++) {
541 a = (int) ((MWC() >> 8) & Mw[N]);
543 a = (int) ((MWC() >> 8) & Mw[N]);
549 for (i = 1; i <= Rows[c]; i++)
552 for (i = 1; i <= Rows[c]; i++)
558 private final Random random;
560 /** Creates a new instance of dlx_solver */
561 public dlx_solver(Random random) {
562 this.random = random;
566 /*******************************************************************************
567 * dlx_generator generate single solution locally minimized Sudoku puzzles.
568 * Locally minimized means that all keys that can be removed without creating a
569 * degenerate Sudoku (multiple solutions) are removed.
570 ******************************************************************************/
571 class dlx_generator {
573 return random.nextLong();
576 int Rows[] = new int[325], Cols[] = new int[730], Row[][] = new int[325][10], Col[][] = new int[730][5],
577 Ur[] = new int[730], Uc[] = new int[325], V[] = new int[325], W[] = new int[325];
578 int P[] = new int[88], A[] = new int[88], C[] = new int[88], I[] = new int[88], Two[] = new int[888];
579 char B[] = { '0', '1', '1', '1', '2', '2', '2', '3', '3', '3', '1', '1', '1', '2', '2', '2', '3', '3', '3', '1',
580 '1', '1', '2', '2', '2', '3', '3', '3', '4', '4', '4', '5', '5', '5', '6', '6', '6', '4', '4', '4', '5',
581 '5', '5', '6', '6', '6', '4', '4', '4', '5', '5', '5', '6', '6', '6', '7', '7', '7', '8', '8', '8', '9',
582 '9', '9', '7', '7', '7', '8', '8', '8', '9', '9', '9', '7', '7', '7', '8', '8', '8', '9', '9', '9' };
583 char H[][] = new char[326][7];
585 int b, f, s1, m0, c1, r1, l, i1, m1, m2, a, p, i, j, k, r, c, d, n = 729, m = 324, x, y, s, z, fi;
586 int mi1, mi2, q7, part, nt, rate, nodes, solutions, min, samples, sam1, clues;
587 char L[] = { '.', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
589 /** State machine states */
590 static final int M0S = 10;
591 static final int M0 = 11;
592 static final int MR1 = 12;
593 static final int MR3 = 13;
594 static final int MR4 = 14;
595 static final int M2 = 15;
596 static final int M3 = 16;
597 static final int M4 = 17;
598 static final int M9 = 18;
599 static final int MR = 19;
600 static final int END = 20;
601 static final int M6 = 21;
603 /** Set to true to generate debug output */
606 /** Output trace messages */
609 System.out.println(s);
612 private final Random random;
614 public dlx_generator(Random random) {
615 dbg("In constructor");
616 this.random = random;
620 * Save the generated Sudoku to a file.
622 void saveSudokuToFile(String s) {
623 FileOutputStream FO = null;
624 byte[] buffer = new byte[s.length() + 1];
627 while (i < s.length()) {
628 buffer[i] = (byte) s.charAt(i);
633 FO = new FileOutputStream("generated_sudoku.sdk");
636 } catch (IOException IOE) {
637 // Well, well, well....
643 * Initialization code for both generate() and rate()
646 for (i = 0; i < 888; i++) {
654 for (x = 1; x <= 9; x++)
655 for (y = 1; y <= 9; y++)
656 for (s = 1; s <= 9; s++) {
659 Col[r][1] = x * 9 - 9 + y;
660 Col[r][2] = (B[x * 9 - 9 + y] - 48) * 9 - 9 + s + 81;
661 Col[r][3] = x * 9 - 9 + s + 81 * 2;
662 Col[r][4] = y * 9 - 9 + s + 81 * 3;
665 for (c = 1; c <= m; c++)
668 for (r = 1; r <= n; r++)
669 for (c = 1; c <= Cols[r]; c++) {
676 for (x = 1; x <= 9; x++)
677 for (y = 1; y <= 9; y++) {
687 for (b = 1; b <= 9; b++)
688 for (s = 1; s <= 9; s++) {
698 for (x = 1; x <= 9; x++)
699 for (s = 1; s <= 9; s++) {
709 for (y = 1; y <= 9; y++)
710 for (s = 1; s <= 9; s++) {
723 public long rate(String puzzle) {
731 for (i = 0; i < 88; i++)
736 while (STATE != END) {
740 for (i = 1; i <= 81; i++) {
741 c = puzzle.charAt(i - 1);
744 if (c == '-' || c == '.' || c == '0' || c == '*') {
747 while (L[j] != c && j <= 9)
763 for (f = 0; f < z; f++) {
765 if (Solutions != 1) {
782 for (i = 1; i <= 81; i++)
783 System.out.println(L[A[i]]);
784 System.out.println();
795 System.out.println(nt / z);
801 System.out.println("hint: " + H[mi2]);
805 } // End of switch statement
806 } // End of while loop
810 public String[] generate(int Samples, int Rate) {
812 String result[] = new String[Samples];
814 dbg("Entering generate");
820 for (i = 0; i < samples; i++)
821 result[i] = new String();
823 // Set to 1 for rating, set to 2 for rating and hint
832 dbg("Entering state machine");
835 while (STATE != END) {
839 if (sam1 >= samples) {
845 for (i = 1; i <= 81; i++)
851 i1 = (int) ((MWC() >> 8) & 127);
864 s = (int) ((MWC() >> 9) & 15);
890 for (i = 1; i <= 81; i++) {
891 x = (int) ((MWC() >> 8) & 127);
893 x = (int) ((MWC() >> 8) & 127);
900 for (i1 = 1; i1 <= 81; i1++) {
910 for (f = 0; f < 100; f++) {
918 result[sam1] = result[sam1].concat("Rating:" + nt + "# ");
920 result[sam1] = result[sam1].concat("hint: " + String.valueOf(H[mi2]).substring(0, 4) + " #\n");
922 result[sam1] = result[sam1].concat("\n");
925 for (i = 1; i <= 81; i++) {
926 result[sam1] = result[sam1].concat(String.valueOf(L[A[i]]));
928 result[sam1] = result[sam1].concat("\n");
931 result[sam1] = result[sam1].concat("\n");
934 dbg("Default case. New state M0S");
937 } // end of switch statement
938 } // end of while loop
943 // returns 0 (no solution), 1 (unique sol.), 2 (more than
947 for (i = 0; i <= n; i++)
949 for (i = 0; i <= m; i++)
953 for (i = 1; i <= 81; i++)
956 r = i * 9 - 9 + A[i];
958 for (j = 1; j <= Cols[r]; j++) {
964 for (k = 1; k <= Rows[d]; k++) {
970 for (c = 1; c <= m; c++) {
972 for (r = 1; r <= Rows[c]; r++)
973 if (Ur[Row[c][r]] == 0)
983 dbg("Solve: Entering state machine");
985 while (STATE != END) {
991 if ((i > 81) || (m0 > 0)) {
1003 for (c = 1; c <= m; c++)
1025 // break in for loop detected, continue breaking
1030 c2 = (MWC() & Two[(int) w]);
1032 c2 = (MWC() & Two[(int) w]);
1034 C[i] = W[(int) c2 + 1];
1039 if (I[i] > Rows[c]) {
1052 for (j = 1; j <= Cols[r]; j++) {
1057 for (j = 1; j <= Cols[r]; j++) {
1059 for (k = 1; k <= Rows[c1]; k++) {
1063 for (l = 1; l <= Cols[r1]; l++) {
1066 if (Uc[(int) c2] + V[(int) c2] < 1)
1068 if (Uc[(int) c2] == 0 && V[(int) c2] < 2)
1077 if (solutions > 1) {
1093 for (j = 1; j <= Cols[r]; j++) {
1096 for (k = 1; k <= Rows[c1]; k++) {
1100 for (l = 1; l <= Cols[r1]; l++) {
1118 } // end of switch statement
1119 } // end of while statement
1126 * @author Rolf Sandberg
1129 class xxxDLXEngine {
1130 dlx_generator generator;
1133 public xxxDLXEngine(Random random) {
1134 generator = new dlx_generator(random);
1135 solver = new dlx_solver(random);
1138 String generate(int minrating, int maxrating) {
1139 // Date t = new Date();
1140 // long start = t.getTime();
1141 // int tries = 0, i, samples = 5;
1143 String ss[] = generator.generate(1, 0);
1147 // First arg: rand seed
1148 // Second arg: #samples, ignored if <= 0
1149 // Third arg: rating and hints, ignored if <= 0
1151 // Task: Find a Sudoku with a rating in a specified interval.
1152 // Do it by generating samples and examine them
1153 // Continue until an appropriate puzzle is found.
1154 // while(tries < 9999999) {
1157 // ss = generator.generate(samples, 0);
1158 // for(i = 0; i < samples; i++) {
1159 // rating = generator.rate(ss[i].replace("\n","").trim());
1160 // if(rating > minrating && rating < maxrating) {
1164 // System.out.println(minrating + ", " + maxrating + ", " + rating + ",
1170 long rate(String s) {
1171 return generator.rate(s);
1174 String solve(String s) {
1175 String result = solver.solve(s);
1180 public class DLXEngine {
1181 dlx_generator generator;
1184 public DLXEngine(Random random) {
1185 generator = new dlx_generator(random);
1186 solver = new dlx_solver(random);
1189 public String generate(int minrating, int maxrating){
1190 int tries = 0, i, samples = 5;
1192 String ss[] = new String[samples];
1194 for(tries = 0; tries < samples; tries++)
1195 ss[tries] = new String();
1199 // First arg: rand seed
1200 // Second arg: #samples, ignored if <= 0
1201 // Third arg: rating and hints, ignored if <= 0
1203 // Task: Find a Sudoku with a rating in a specified interval.
1204 // Do it by generating samples and examine them
1205 // Continue until an appropriate puzzle is found.
1206 while(tries < 9999999) {
1208 ss = generator.generate(samples, 0);
1209 for(i = 0; i < samples; i++) {
1210 rating = generator.rate(ss[i].replace("\n","").trim());
1211 if(rating > minrating && rating < maxrating) {
1212 System.out.println(minrating + ", " + maxrating + ", " + rating);
1220 public long rate(String s) {
1221 return generator.rate(s);
1224 public String solve(String s){
1225 String result = solver.solve(s);