1 package io.github.skenvy;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5
6 public class Sudoku {
7
8
9
10
11
12
13 private final int boardSize;
14
15
16
17
18
19
20 public int[][][][] board;
21
22
23
24
25 public boolean[][][][] cellFilled;
26
27
28 boolean[][][][][] placeCanContain;
29
30
31 boolean[][][] numberPresentG;
32
33
34 boolean[][][] numberPresentRowCol;
35
36
37 public boolean[][][][] errorInSquare;
38
39
40 ArrayList<String> digest = new ArrayList<String>();
41
42
43 ArrayList<String> operations = new ArrayList<String>();
44
45
46 public Sudoku() {
47 this.boardSize = 3;
48 initialiseBoardVariables();
49 }
50
51
52 public Sudoku(int size) {
53 this.boardSize = size;
54 initialiseBoardVariables();
55 }
56
57
58 public Sudoku(int[][][][] boardIn) throws InvlalidSudokuCongiguration {
59 this.boardSize = boardIn.length;
60 if (boardIn.length == boardIn[0].length & boardIn.length == boardIn[0][0].length & boardIn.length == boardIn[0][0][0].length) {
61 initialiseBoardVariables();
62 this.board = boardIn;
63 } else {
64 throw new InvlalidSudokuCongiguration("Invalid board lengths in incoming array, not a proper matrix of grids, each a matrix of cells");
65 }
66 }
67
68
69
70
71 public final class InvlalidSudokuCongiguration extends Exception {
72
73 public InvlalidSudokuCongiguration(String string) {
74 super(string);
75 }
76
77 }
78
79
80 private void initialiseBoardVariables() {
81 board = new int[boardSize][boardSize][boardSize][boardSize];
82 cellFilled = new boolean[boardSize][boardSize][boardSize][boardSize];
83 placeCanContain = new boolean[boardSize][boardSize][boardSize][boardSize][(boardSize * boardSize)];
84 numberPresentG = new boolean[(boardSize * boardSize)][boardSize][boardSize];
85 numberPresentRowCol = new boolean[2][(boardSize * boardSize)][(boardSize * boardSize)];
86 errorInSquare = new boolean[boardSize][boardSize][boardSize][boardSize];
87 }
88
89 public static void main(String[] args) {
90 final Sudoku puzzle = new Sudoku(2);
91 String[] boardContents = new String[4];
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 boardContents[0] = "S_1_2_3_4_E";
125 boardContents[1] = "S_4_3_2_1_E";
126 boardContents[2] = "S_2_0_0_0_E";
127 boardContents[3] = "S_0_1_0_0_E";
128 puzzle.readBoardIn(boardContents);
129 puzzle.initialiseBoard();
130 puzzle.solveBoard();
131 puzzle.printBoardOut();
132 System.out.println("done");
133 puzzle.printDigest();
134 puzzle.printOperations();
135 }
136
137
138
139
140
141
142 public void readBoardIn(String[] boardRows) {
143 int boardRow = 0;
144 int boardColumn = 0;
145 int gridRow = 0;
146 int gridColumn = 0;
147 int previousIndex = 0;
148
149 for (int j0 = 0; j0 < (boardSize * boardSize); j0++) {
150
151 gridRow = j0 % boardSize;
152
153 boardRow = (j0 - gridRow) / boardSize;
154
155 previousIndex = 0;
156
157 for (int j1 = 0; j1 < (boardSize * boardSize); j1++) {
158
159 gridColumn = j1 % boardSize;
160
161 boardColumn = (j1 - gridColumn) / boardSize;
162
163 int stringIntStartIndex = boardRows[j0].indexOf('_', previousIndex) + 1;
164 int stringIntEndIndex = boardRows[j0].indexOf('_', stringIntStartIndex);
165 String stringInt = boardRows[j0].substring(stringIntStartIndex, stringIntEndIndex);
166 int parsedInt = Integer.parseInt(stringInt);
167
168 board[boardRow][boardColumn][gridRow][gridColumn] = parsedInt;
169 previousIndex = stringIntEndIndex;
170 if (parsedInt != 0) {
171 operations.add("Read Board In: Place " + boardRow + ", " + boardColumn + ", " + gridRow + ", " + gridColumn + " contains " + stringInt);
172 }
173 }
174 }
175 }
176
177
178 public void printBoardOut() {
179 int boardRow = 0;
180 int boardColumn = 0;
181 int gridRow = 0;
182 int gridColumn = 0;
183 String mess;
184 for (int j0 = 0; j0 < (boardSize * boardSize); j0++) {
185 mess = "Row " + (j0) + ": S_";
186 gridRow = j0 % boardSize;
187 boardRow = (j0 - gridRow) / boardSize;
188 for (int j1 = 0; j1 < (boardSize * boardSize); j1++) {
189 gridColumn = j1 % boardSize;
190 boardColumn = (j1 - gridColumn) / boardSize;
191 mess = mess.concat("" + board[boardRow][boardColumn][gridRow][gridColumn] + "_");
192 }
193 mess = mess.concat("E");
194 textFieldAdd(mess);
195 }
196 }
197
198
199 public boolean initialiseBoard() {
200 digest.add("Digest Start");
201 operations.add("Operations Start");
202 if (!boardCheckValid()) {
203 textFieldAdd("Board Check: Failure");
204 return false;
205 }
206 textFieldAdd("Board Check: Pass");
207 initialisePlaceCanContain(false);
208 return true;
209 }
210
211 public void initialisePlaceFilled() {
212 for (int k0 = 0; k0 < boardSize; k0++) {
213 for (int k1 = 0; k1 < boardSize; k1++) {
214 for (int k2 = 0; k2 < boardSize; k2++) {
215 for (int k3 = 0; k3 < boardSize; k3++) {
216 if ((board[k0][k1][k2][k3] >= 1) && (board[k0][k1][k2][k3] <= (boardSize * boardSize))) {
217 cellFilled[k0][k1][k2][k3] = true;
218 operations.add("Place " + k0 + ", " + k1 + ", " + k2 + ", " + k3 + " filled with " + board[k0][k1][k2][k3]);
219 } else {
220 operations.add("Place " + k0 + ", " + k1 + ", " + k2 + ", " + k3 + " is empty");
221 cellFilled[k0][k1][k2][k3] = false;
222 }
223 }
224 }
225 }
226 }
227 }
228
229 public void initialisePlaceCanContain(boolean clear) {
230 if (clear) {
231 for (int k0 = 0; k0 < boardSize; k0++) {
232 for (int k1 = 0; k1 < boardSize; k1++) {
233 for (int k2 = 0; k2 < boardSize; k2++) {
234 for (int k3 = 0; k3 < boardSize; k3++) {
235 for (int k4 = 0; k4 < (boardSize * boardSize); k4++) {
236 placeCanContain[k0][k1][k2][k3][k4] = true;
237 }
238 }
239 }
240 }
241 }
242 } else {
243 initialisePlaceCanContain(true);
244 initialiseNumberPresentGridRowCol(false);
245 updatePlaceCanContain();
246 }
247 }
248
249 public void updatePlaceCanContain() {
250 for (int k0 = 0; k0 < boardSize; k0++) {
251 for (int k1 = 0; k1 < boardSize; k1++) {
252 for (int k2 = 0; k2 < boardSize; k2++) {
253 for (int k3 = 0; k3 < boardSize; k3++) {
254 if (!cellFilled[k0][k1][k2][k3]) {
255 for (int k4 = 0; k4 < (boardSize * boardSize); k4++) {
256 if (numberPresentRowCol[0][k4][k2 + k0 * board.length] || numberPresentRowCol[1][k4][k3 + k1 * board.length] || numberPresentG[k4][k0][k1]) {
257 placeCanContain[k0][k1][k2][k3][k4] = false;
258 }
259 }
260 }
261 }
262 }
263 }
264 }
265 }
266
267 public void initialiseNumberPresentGridRowCol(boolean clear) {
268 if (clear) {
269 for (int k0 = 0; k0 < (boardSize * boardSize); k0++) {
270 for (int k1 = 0; k1 < boardSize; k1++) {
271 for (int k2 = 0; k2 < boardSize; k2++) {
272 numberPresentG[k0][k1][k2] = false;
273 }
274 }
275 }
276 for (int k0 = 0; k0 < 2; k0++) {
277 for (int k1 = 0; k1 < (boardSize * boardSize); k1++) {
278 for (int k2 = 0; k2 < (boardSize * boardSize); k2++) {
279 numberPresentRowCol[k0][k1][k2] = false;
280 }
281 }
282 }
283 } else {
284 updateNumberPresentGridRowCol();
285 }
286 }
287
288 public void updateNumberPresentGridRowCol() {
289 for (int k0 = 0; k0 < boardSize; k0++) {
290 for (int k1 = 0; k1 < boardSize; k1++) {
291 for (int k2 = 0; k2 < boardSize; k2++) {
292 for (int k3 = 0; k3 < boardSize; k3++) {
293 if (cellFilled[k0][k1][k2][k3]) {
294 numberPresentRowCol[0][board[k0][k1][k2][k3] - 1][k2 + k0 * board.length] = true;
295 numberPresentRowCol[1][board[k0][k1][k2][k3] - 1][k3 + k1 * board.length] = true;
296 numberPresentG[board[k0][k1][k2][k3] - 1][k0][k1] = true;
297 }
298 }
299 }
300 }
301 }
302 }
303
304 public boolean boardCheckValid() {
305 initialisePlaceFilled();
306 initialiseNumberPresentGridRowCol(true);
307 for (int k0 = 0; k0 < boardSize; k0++) {
308 for (int k1 = 0; k1 < boardSize; k1++) {
309 for (int k2 = 0; k2 < boardSize; k2++) {
310 for (int k3 = 0; k3 < boardSize; k3++) {
311 if (cellFilled[k0][k1][k2][k3]) {
312 if (numberPresentRowCol[0][board[k0][k1][k2][k3] - 1][k2 + k0 * boardSize]) {
313 textFieldAdd("Error in row " + (k2 + k0 * boardSize));
314 return false;
315 } else if (numberPresentRowCol[1][board[k0][k1][k2][k3] - 1][k3 + k1 * boardSize]) {
316 textFieldAdd("Error in column " + (k3 + k1 * boardSize));
317 return false;
318 } else if (numberPresentG[board[k0][k1][k2][k3] - 1][k0][k1]) {
319 textFieldAdd("Error in grid (R,C): (" + k0 + ", " + k1 + ")");
320 return false;
321 } else {
322 numberPresentRowCol[0][board[k0][k1][k2][k3] - 1][k2 + k0 * boardSize] = true;
323 numberPresentRowCol[1][board[k0][k1][k2][k3] - 1][k3 + k1 * boardSize] = true;
324 numberPresentG[board[k0][k1][k2][k3] - 1][k0][k1] = true;
325 }
326 }
327 }
328 }
329 }
330 }
331 return true;
332 }
333
334 public void boardCheckErrors() {
335 int[][][] appearsTimes = new int[3][(boardSize * boardSize)][(boardSize * boardSize)];
336 for (int j0 = 0; j0 < 3; j0++) {
337 for (int j1 = 0; j1 < (boardSize * boardSize); j1++) {
338 for (int j2 = 0; j2 < (boardSize * boardSize); j2++) {
339 appearsTimes[j0][j1][j2] = 0;
340 }
341 }
342 }
343 for (int j0 = 0; j0 < boardSize; j0++) {
344 for (int j1 = 0; j1 < boardSize; j1++) {
345 for (int k0 = 0; k0 < boardSize; k0++) {
346 for (int k1 = 0; k1 < boardSize; k1++) {
347 if (cellFilled[j0][j1][k0][k1]) {
348 if (0 < board[j0][j1][k0][k1] && board[j0][j1][k0][k1] <= (boardSize * boardSize)) {
349 appearsTimes[0][j0 * boardSize + j1][board[j0][j1][k0][k1] - 1]++;
350 appearsTimes[1][j0 * boardSize + k0][board[j0][j1][k0][k1] - 1]++;
351 appearsTimes[2][j1 * boardSize + k1][board[j0][j1][k0][k1] - 1]++;
352 }
353 }
354 }
355 }
356 }
357 }
358 for (int j0 = 0; j0 < boardSize; j0++) {
359 for (int j1 = 0; j1 < boardSize; j1++) {
360 for (int k0 = 0; k0 < boardSize; k0++) {
361 for (int k1 = 0; k1 < boardSize; k1++) {
362 if (0 < board[j0][j1][k0][k1] && board[j0][j1][k0][k1] <= (boardSize * boardSize)) {
363 if (appearsTimes[0][j0 * 3 + j1][board[j0][j1][k0][k1] - 1] > 1 || appearsTimes[1][j0 * 3 + k0][board[j0][j1][k0][k1] - 1] > 1 || appearsTimes[2][j1 * 3 + k1][board[j0][j1][k0][k1] - 1] > 1) {
364 errorInSquare[j0][j1][k0][k1] = true;
365 } else {
366 errorInSquare[j0][j1][k0][k1] = false;
367 }
368 }
369 }
370 }
371 }
372 }
373 }
374
375 public boolean errorExists() {
376 boardCheckErrors();
377 boolean check = false;
378 for (int k0 = 0; k0 < boardSize; k0++) {
379 for (int k1 = 0; k1 < boardSize; k1++) {
380 for (int k2 = 0; k2 < boardSize; k2++) {
381 for (int k3 = 0; k3 < boardSize; k3++) {
382 if (errorInSquare[k0][k1][k2][k3]) {
383 check = true;
384 }
385 }
386 }
387 }
388 }
389 return check;
390 }
391
392 public boolean boardCheckComplete() {
393 for (int k0 = 0; k0 < boardSize; k0++) {
394 for (int k1 = 0; k1 < boardSize; k1++) {
395 for (int k2 = 0; k2 < boardSize; k2++) {
396 for (int k3 = 0; k3 < boardSize; k3++) {
397 if (!cellFilled[k0][k1][k2][k3]) {
398 return false;
399 }
400 }
401 }
402 }
403 }
404 return true;
405 }
406
407 public int boardCheckPlacesFilled() {
408 int count = 0;
409 for (int k0 = 0; k0 < boardSize; k0++) {
410 for (int k1 = 0; k1 < boardSize; k1++) {
411 for (int k2 = 0; k2 < boardSize; k2++) {
412 for (int k3 = 0; k3 < boardSize; k3++) {
413 if (cellFilled[k0][k1][k2][k3]) {
414 count++;
415 }
416 }
417 }
418 }
419 }
420 return count;
421 }
422
423 public void printDigest() {
424 for (int k = 0; k < digest.size(); k++) {
425 System.out.println(digest.get(k));
426 }
427 }
428
429 public String[] digestAsArray() {
430 String[] out = new String[digest.size()];
431 for (int k = 0; k < digest.size(); k++) {
432 out[k] = digest.get(k);
433 }
434 return out;
435 }
436
437 public void printOperations() {
438 for (int k = 0; k < operations.size(); k++) {
439 System.out.println(operations.get(k));
440 }
441 }
442
443 public String[] operationsAsArray() {
444 String[] out = new String[operations.size()];
445 for (int k = 0; k < operations.size(); k++) {
446 out[k] = operations.get(k);
447 }
448 return out;
449 }
450
451 public void textFieldAdd(String a) {
452 digest.add(a);
453 operations.add(a);
454 }
455
456 public void solveBoard() {
457 if (!solveBoardEasy()) {
458 if (!solveBoardModerate()) {
459 printBoardOut();
460 if (!solveBoardHard()) {
461 textFieldAdd("Couldn't solve this board with existing techniques.");
462 }
463 }
464 }
465 }
466
467 public boolean solveBoardEasy() {
468 if (boardCheckComplete()) {
469 textFieldAdd("Board already solved");
470 return true;
471 }
472 int unsolvedSquares = (boardSize * boardSize) * (boardSize * boardSize) - boardCheckPlacesFilled();
473 int countSoleCandidates = 0;
474 int countUniqueCandidates = 0;
475 for (int q = 0; q < unsolvedSquares; q++) {
476 countSoleCandidates += iterateSoleCandidate();
477 if (countSoleCandidates == unsolvedSquares) {
478 break;
479 } else {
480 unsolvedSquares -= countSoleCandidates;
481 }
482 countUniqueCandidates += iterateUniqueCandidate();
483 if (countUniqueCandidates == unsolvedSquares) {
484 break;
485 } else {
486 unsolvedSquares -= countUniqueCandidates;
487 }
488 if ((countSoleCandidates == 0) && (countUniqueCandidates == 0)) {
489 break;
490 }
491 }
492 if (boardCheckComplete()) {
493 textFieldAdd("Board was easy!");
494 textFieldAdd("Board solved in " + countSoleCandidates + " solo candidate steps");
495 textFieldAdd("Board solved in " + countUniqueCandidates + " unique candidate steps");
496 return true;
497 }
498 textFieldAdd("Board was not easy!");
499 textFieldAdd("Board Unsolved; Performed " + countSoleCandidates + " solo candidate steps");
500 textFieldAdd("Board Unsolved; Performed " + countUniqueCandidates + " unique candidate steps");
501 return false;
502 }
503
504 public boolean solveBoardModerate() {
505 if (boardCheckComplete()) {
506 return true;
507 }
508 int unsolvedSquares = (boardSize * boardSize) * (boardSize * boardSize) - boardCheckPlacesFilled();
509 int countSoleCandidates = 0;
510 int countUniqueCandidates = 0;
511 int countReduceRowColByGrid = 0;
512 int countReduceGridByRowCol = 0;
513 for (int q = 0; q < unsolvedSquares; q++) {
514 countSoleCandidates += iterateSoleCandidate();
515 if (countSoleCandidates == unsolvedSquares) {
516 break;
517 } else {
518 unsolvedSquares -= countSoleCandidates;
519 }
520 countUniqueCandidates += iterateUniqueCandidate();
521 if (countUniqueCandidates == unsolvedSquares) {
522 break;
523 } else {
524 unsolvedSquares -= countUniqueCandidates;
525 }
526 countReduceRowColByGrid += iterateReductionOfCanContainInRowColByGrid();
527 countReduceGridByRowCol += iterateReductionOfCanContainInGridByRowCol();
528 }
529 if (boardCheckComplete()) {
530 textFieldAdd("Board was moderate!");
531 textFieldAdd("Board solved with " + countReduceRowColByGrid + " row/column reductions by grid steps");
532 textFieldAdd("Board solved with " + countReduceGridByRowCol + " grid reductions by grid steps");
533 textFieldAdd("Board solved in a further " + countSoleCandidates + " solo candidate steps");
534 textFieldAdd("Board solved in a further " + countUniqueCandidates + " unique candidate steps");
535 return true;
536 }
537 textFieldAdd("Board was not moderate!");
538 textFieldAdd("Board Unsolved; Performed " + countReduceRowColByGrid + " row/column reductions by grid steps");
539 textFieldAdd("Board Unsolved; Performed " + countReduceGridByRowCol + " grid reductions by grid steps");
540 textFieldAdd("Board Unsolved; Performed a further " + countSoleCandidates + " solo candidate steps");
541 textFieldAdd("Board Unsolved; Performed a further " + countUniqueCandidates + " unique candidate steps");
542 return false;
543 }
544
545 public boolean solveBoardHard() {
546 if (boardCheckComplete()) {
547 return true;
548 }
549 int unsolvedSquares = (boardSize * boardSize) * (boardSize * boardSize) - boardCheckPlacesFilled();
550 int countSoleCandidates = 0;
551 int countUniqueCandidates = 0;
552 int countReduceRowColByGrid = 0;
553 int countReduceGridByRowCol = 0;
554 int countReduceSubVis = 0;
555 int countReduceSubHid = 0;
556 for (int q = 0; q < unsolvedSquares; q++) {
557 countSoleCandidates += iterateSoleCandidate();
558 if (countSoleCandidates == unsolvedSquares) {
559 break;
560 } else {
561 unsolvedSquares -= countSoleCandidates;
562 }
563 countUniqueCandidates += iterateUniqueCandidate();
564 if (countUniqueCandidates == unsolvedSquares) {
565 break;
566 } else {
567 unsolvedSquares -= countUniqueCandidates;
568 }
569 countReduceRowColByGrid += iterateReductionOfCanContainInRowColByGrid();
570 countReduceGridByRowCol += iterateReductionOfCanContainInGridByRowCol();
571 countReduceSubVis += iterateReductionOfCanContainSubsetVisible();
572 countReduceSubHid += iterateReductionOfCanContainSubsetHidden();
573 }
574 if (boardCheckComplete()) {
575 textFieldAdd("Board was hard!");
576 textFieldAdd("Board solved with " + countReduceSubVis + " subset reductions by visible subsets steps");
577 textFieldAdd("Board solved with " + countReduceSubHid + " subset reductions by hidden subsets steps");
578 textFieldAdd("Board solved in a further " + countReduceRowColByGrid + " row/column reductions by grid steps");
579 textFieldAdd("Board solved in a further " + countReduceGridByRowCol + " grid reductions by grid steps");
580 textFieldAdd("Board solved in a further " + countSoleCandidates + " solo candidate steps");
581 textFieldAdd("Board solved in a further " + countUniqueCandidates + " unique candidate steps");
582 return true;
583 }
584 textFieldAdd("Board was not hard!");
585 textFieldAdd("Board Unsolved; Performed " + countReduceSubVis + " subset reductions by visible subsets steps");
586 textFieldAdd("Board Unsolved; Performed " + countReduceSubHid + " subset reductions by hidden subsets steps");
587 textFieldAdd("Board Unsolved; Performed a further " + countReduceRowColByGrid + " row/column reductions by grid steps");
588 textFieldAdd("Board Unsolved; Performed a further " + countReduceGridByRowCol + " grid reductions by grid steps");
589 textFieldAdd("Board Unsolved; Performed a further " + countSoleCandidates + " solo candidate steps");
590 textFieldAdd("Board Unsolved; Performed a further " + countUniqueCandidates + " unique candidate steps");
591 return false;
592 }
593
594 public int iterateSoleCandidate() {
595
596 int count = 0;
597 while (checkSoleCandidate()) {
598
599 count++;
600 }
601 return count;
602 }
603
604 public boolean checkSoleCandidate() {
605 int candidates = 0;
606 int candidate = 0;
607 for (int k0 = 0; k0 < boardSize; k0++) {
608 for (int k1 = 0; k1 < boardSize; k1++) {
609 for (int k2 = 0; k2 < boardSize; k2++) {
610 for (int k3 = 0; k3 < boardSize; k3++) {
611 if (!cellFilled[k0][k1][k2][k3]) {
612 candidates = 0;
613 for (int k4 = 0; k4 < (boardSize * boardSize); k4++) {
614 if (placeCanContain[k0][k1][k2][k3][k4]) {
615 candidate = k4;
616 candidates += 1;
617 }
618 }
619 if (candidates == 1) {
620 board[k0][k1][k2][k3] = candidate + 1;
621 cellFilled[k0][k1][k2][k3] = true;
622 deliminatePotential(k0, k1, k2, k3, candidate);
623 return true;
624 }
625 }
626 }
627 }
628 }
629 }
630 return false;
631 }
632
633 public int iterateUniqueCandidate() {
634
635 int count = 0;
636 while (checkUniqueCandidate()) {
637
638 count++;
639 }
640 return count;
641 }
642
643 public boolean checkUniqueCandidate() {
644 int gridRowColX = 0;
645 int gridRowColY = 0;
646 int grcX = 0;
647 int grcY = 0;
648 int candidates = 0;
649 int candR0 = 0;
650 int candC0 = 0;
651 int candR1 = 0;
652 int candC1 = 0;
653 for (int val = 0; val < (boardSize * boardSize); val++) {
654 for (int outerGridRowCol = 0; outerGridRowCol < (boardSize * boardSize); outerGridRowCol++) {
655 gridRowColY = outerGridRowCol % boardSize;
656 gridRowColX = (outerGridRowCol - gridRowColY) / boardSize;
657
658 if (!numberPresentG[val][gridRowColX][gridRowColY]) {
659 candidates = 0;
660 candR0 = gridRowColX;
661 candC0 = gridRowColY;
662 candR1 = 0;
663 candC1 = 0;
664 for (int innerGridRowCol = 0; innerGridRowCol < (boardSize * boardSize); innerGridRowCol++) {
665 grcY = innerGridRowCol % boardSize;
666 grcX = (innerGridRowCol - grcY) / boardSize;
667 if (!cellFilled[gridRowColX][gridRowColY][grcX][grcY] && placeCanContain[gridRowColX][gridRowColY][grcX][grcY][val]) {
668 candR1 = grcX;
669 candC1 = grcY;
670 candidates += 1;
671 }
672 }
673 if (candidates == 1) {
674 board[candR0][candC0][candR1][candC1] = val + 1;
675 cellFilled[candR0][candC0][candR1][candC1] = true;
676 deliminatePotential(candR0, candC0, candR1, candC1, val);
677
678 return true;
679 }
680 }
681
682 if (!numberPresentRowCol[0][val][outerGridRowCol]) {
683 candidates = 0;
684 candR0 = gridRowColX;
685 candC0 = 0;
686 candR1 = gridRowColY;
687 candC1 = 0;
688 for (int innerGridRowCol = 0; innerGridRowCol < (boardSize * boardSize); innerGridRowCol++) {
689 grcY = innerGridRowCol % boardSize;
690 grcX = (innerGridRowCol - grcY) / boardSize;
691 if (!cellFilled[gridRowColX][grcX][gridRowColY][grcY] && placeCanContain[gridRowColX][grcX][gridRowColY][grcY][val]) {
692 candC0 = grcX;
693 candC1 = grcY;
694 candidates += 1;
695 }
696 }
697 if (candidates == 1) {
698 board[candR0][candC0][candR1][candC1] = val + 1;
699 cellFilled[candR0][candC0][candR1][candC1] = true;
700 deliminatePotential(candR0, candC0, candR1, candC1, val);
701
702 return true;
703 }
704 }
705
706 if (!numberPresentRowCol[1][val][outerGridRowCol]) {
707 candidates = 0;
708 candR0 = 0;
709 candC0 = gridRowColX;
710 candR1 = 0;
711 candC1 = gridRowColY;
712 for (int innerGridRowCol = 0; innerGridRowCol < (boardSize * boardSize); innerGridRowCol++) {
713 grcY = innerGridRowCol % boardSize;
714 grcX = (innerGridRowCol - grcY) / boardSize;
715 if (!cellFilled[grcX][gridRowColX][grcY][gridRowColY] && placeCanContain[grcX][gridRowColX][grcY][gridRowColY][val]) {
716 candR0 = grcX;
717 candR1 = grcY;
718 candidates += 1;
719 }
720 }
721 if (candidates == 1) {
722 board[candR0][candC0][candR1][candC1] = val + 1;
723 cellFilled[candR0][candC0][candR1][candC1] = true;
724 deliminatePotential(candR0, candC0, candR1, candC1, val);
725
726 return true;
727 }
728 }
729 }
730 }
731 return false;
732 }
733
734 public int iterateReductionOfCanContainInRowColByGrid() {
735 int count = 0;
736 while (reductionOfCanContainInRowColByGrid()) {
737 count++;
738 }
739 return count;
740 }
741
742 public boolean reductionOfCanContainInRowColByGrid() {
743 int rowVal = 0;
744 boolean[] rows = new boolean[boardSize];
745 int rowsVal = 0;
746 int colVal = 0;
747 boolean[] cols = new boolean[boardSize];
748 int colsVal = 0;
749 int deliminatedSquares = 0;
750 for (int jq = 0; jq < boardSize; jq++) {
751 rows[jq] = false;
752 cols[jq] = false;
753 }
754 for (int j0 = 0; j0 < boardSize; j0++) {
755 for (int j1 = 0; j1 < boardSize; j1++) {
756 for (int val = 0; val < (boardSize * boardSize); val++) {
757 if (!numberPresentG[val][j0][j1]) {
758 for (int jq = 0; jq < boardSize; jq++) {
759 rows[jq] = false;
760 cols[jq] = false;
761 }
762 for (int k0 = 0; k0 < boardSize; k0++) {
763 for (int k1 = 0; k1 < boardSize; k1++) {
764 if (!cellFilled[j0][j1][k0][k1] && placeCanContain[j0][j1][k0][k1][val]) {
765 rows[k0] = true;
766 cols[k1] = true;
767 }
768 }
769 }
770 rowsVal = 0;
771 colsVal = 0;
772 for (int jq = 0; jq < boardSize; jq++) {
773 if (rows[jq]) {
774 rowsVal++;
775 rowVal = jq;
776 }
777 if (cols[jq]) {
778 colsVal++;
779 colVal = jq;
780 }
781 }
782 if (rowsVal == 1) {
783 for (int jthC = 0; jthC < (boardSize * boardSize); jthC++) {
784 int jthC1 = jthC % boardSize;
785 int jthC0 = (jthC - jthC1) / boardSize;
786 if (j1 != jthC0) {
787 if (!cellFilled[j0][jthC0][rowVal][jthC1] && placeCanContain[j0][jthC0][rowVal][jthC1][val]) {
788 deliminatedSquares++;
789 placeCanContain[j0][jthC0][rowVal][jthC1][val] = false;
790 }
791 }
792 }
793 if (deliminatedSquares > 0) {
794 return true;
795 }
796 }
797 if (colsVal == 1) {
798 for (int jthR = 0; jthR < (boardSize * boardSize); jthR++) {
799 int jthR1 = jthR % boardSize;
800 int jthR0 = (jthR - jthR1) / boardSize;
801 if (j0 != jthR0) {
802 if (!cellFilled[jthR0][j1][jthR1][colVal] && placeCanContain[jthR0][j1][jthR1][colVal][val]) {
803 deliminatedSquares++;
804 placeCanContain[jthR0][j1][jthR1][colVal][val] = false;
805 }
806 }
807 }
808 if (deliminatedSquares > 0) {
809 return true;
810 }
811 }
812 }
813 }
814 }
815 }
816 return false;
817 }
818
819 public int iterateReductionOfCanContainInGridByRowCol() {
820 int count = 0;
821 while (reductionOfCanContainInGridByRowCol()) {
822 count++;
823 }
824 return count;
825 }
826
827 public boolean reductionOfCanContainInGridByRowCol() {
828 int deliminations = 0;
829 int candidates = 0;
830 for (int val = 0; val < (boardSize * boardSize); val++) {
831 for (int jthCheckRow = 0; jthCheckRow < (boardSize * boardSize); jthCheckRow++) {
832 if (!numberPresentRowCol[0][val][jthCheckRow]) {
833 int jthCheckRow1 = jthCheckRow % boardSize;
834 int jthCheckRow0 = (jthCheckRow - jthCheckRow1) / boardSize;
835 for (int jthIgnore = 0; jthIgnore < boardSize; jthIgnore++) {
836 candidates = 0;
837 for (int jthSelect = 0; jthSelect < boardSize; jthSelect++) {
838 if (jthSelect != jthIgnore) {
839 for (int jthRotate = 0; jthRotate < boardSize; jthRotate++) {
840 if (!cellFilled[jthCheckRow0][jthSelect][jthCheckRow1][jthRotate] && placeCanContain[jthCheckRow0][jthSelect][jthCheckRow1][jthRotate][val]) {
841 candidates++;
842 }
843 }
844 }
845 }
846 if (candidates == 0) {
847
848 for (int jthRotateR = 0; jthRotateR < boardSize; jthRotateR++) {
849 for (int jthRotateC = 0; jthRotateC < boardSize; jthRotateC++) {
850 if (jthRotateR != jthCheckRow1) {
851 if (!cellFilled[jthCheckRow0][jthIgnore][jthRotateR][jthRotateC] && placeCanContain[jthCheckRow0][jthIgnore][jthRotateR][jthRotateC][val]) {
852 placeCanContain[jthCheckRow0][jthIgnore][jthRotateR][jthRotateC][val] = false;
853 deliminations++;
854 }
855 }
856 }
857 }
858 if (deliminations > 0) {
859 return true;
860 }
861 }
862 }
863 }
864 }
865 for (int jthCheckC = 0; jthCheckC < (boardSize * boardSize); jthCheckC++) {
866 if (!numberPresentRowCol[1][val][jthCheckC]) {
867 int jthCheckC1 = jthCheckC % boardSize;
868 int jthCheckC0 = (jthCheckC - jthCheckC1) / boardSize;
869 for (int jthIgnore = 0; jthIgnore < boardSize; jthIgnore++) {
870 candidates = 0;
871 for (int jthSelect = 0; jthSelect < boardSize; jthSelect++) {
872 if (jthSelect != jthIgnore) {
873 for (int jthRotate = 0; jthRotate < boardSize; jthRotate++) {
874 if (!cellFilled[jthSelect][jthCheckC0][jthRotate][jthCheckC1] && placeCanContain[jthSelect][jthCheckC0][jthRotate][jthCheckC1][val]) {
875 candidates++;
876 }
877 }
878 }
879 }
880 if (candidates == 0) {
881
882 for (int jthRotateR = 0; jthRotateR < boardSize; jthRotateR++) {
883 for (int jthRotateC = 0; jthRotateC < boardSize; jthRotateC++) {
884 if (jthRotateC != jthCheckC1) {
885 if (!cellFilled[jthIgnore][jthCheckC0][jthRotateR][jthRotateC] && placeCanContain[jthIgnore][jthCheckC0][jthRotateR][jthRotateC][val]) {
886 placeCanContain[jthIgnore][jthCheckC0][jthRotateR][jthRotateC][val] = false;
887 deliminations++;
888 }
889 }
890 }
891 }
892 if (deliminations > 0) {
893 return true;
894 }
895 }
896 }
897 }
898 }
899 }
900 return false;
901 }
902
903 public int iterateReductionOfCanContainSubsetVisible() {
904 int count = 0;
905 while (reductionOfCanContainSubsetVisible()) {
906 count++;
907 }
908 return count;
909 }
910
911
912 public boolean reductionOfCanContainSubsetVisible() {
913 int minimumSubsetPresent = 0;
914 int numberOfTrueSubsets = 0;
915 int deliminations = 0;
916 int numberOfVisibleSubsets = 0;
917 int visibleSubsetIndex = 0;
918 int s00 = 0;
919 int s01 = 0;
920 int s10 = 0;
921 int s11 = 0;
922 for (int subsetSize = 2; subsetSize < (boardSize * boardSize) - 1; subsetSize++) {
923 int[] theSubset = new int[subsetSize];
924 boolean subsetFound = false;
925 int[][][] subsets = new int[boardSize][boardSize][subsetSize];
926 int[][] visibleSubsets = new int[(boardSize * boardSize)][subsetSize];
927 int[] visibleSubsetCount = new int[(boardSize * boardSize)];
928 int[] subsetFoundAt = new int[(boardSize * boardSize)];
929 boolean[][] subsetSizeTrue = new boolean[boardSize][boardSize];
930 for (int j0 = 0; j0 < boardSize; j0++) {
931 for (int j1 = 0; j1 < boardSize; j1++) {
932 subsetFound = false;
933
934 for (int k0 = 0; k0 < boardSize; k0++) {
935 for (int k1 = 0; k1 < boardSize; k1++) {
936 subsetSizeTrue[k0][k1] = false;
937 }
938 }
939 for (int k0 = 0; k0 < boardSize; k0++) {
940 for (int k1 = 0; k1 < boardSize; k1++) {
941 minimumSubsetPresent = 0;
942 if (!cellFilled[j0][j1][k0][k1]) {
943 for (int val = 0; val < (boardSize * boardSize); val++) {
944 if (placeCanContain[j0][j1][k0][k1][val]) {
945 if (minimumSubsetPresent < subsetSize) {
946 subsets[k0][k1][minimumSubsetPresent] = val;
947 minimumSubsetPresent++;
948 if (minimumSubsetPresent == subsetSize) {
949 subsetSizeTrue[k0][k1] = true;
950 } else {
951 subsetSizeTrue[k0][k1] = false;
952 }
953 } else {
954 subsetSizeTrue[k0][k1] = false;
955 }
956 }
957 }
958 }
959 }
960 }
961
962 numberOfTrueSubsets = 0;
963 for (int k0 = 0; k0 < boardSize; k0++) {
964 for (int k1 = 0; k1 < boardSize; k1++) {
965 if (subsetSizeTrue[k0][k1]) {
966 subsetFoundAt[numberOfTrueSubsets] = k0 * boardSize + k1;
967 numberOfTrueSubsets++;
968 }
969 visibleSubsetCount[k0 * boardSize + k1] = 0;
970 }
971 }
972 if (numberOfTrueSubsets >= subsetSize) {
973 numberOfVisibleSubsets = 1;
974 visibleSubsetIndex = 1;
975 s01 = subsetFoundAt[0] % boardSize;
976 s00 = (subsetFoundAt[0] - s01) / boardSize;
977 visibleSubsets[0] = subsets[s00][s01];
978 visibleSubsetCount[0] = 1;
979 outer: for (int q0 = 1; q0 < numberOfTrueSubsets; q0++) {
980 s01 = subsetFoundAt[q0] % boardSize;
981 s00 = (subsetFoundAt[q0] - s01) / boardSize;
982 inner: for (int q1 = 0; q1 < visibleSubsetIndex; q1++) {
983
984 if (Arrays.equals(subsets[s00][s01], visibleSubsets[q1])) {
985
986 visibleSubsetCount[q1]++;
987 break inner;
988 } else if (q1 == (visibleSubsetIndex - 1)) {
989 visibleSubsets[visibleSubsetIndex] = subsets[s00][s01];
990 visibleSubsetCount[visibleSubsetIndex]++;
991 visibleSubsetIndex++;
992 break inner;
993 }
994 }
995 }
996 for (int q = 0; q < visibleSubsetIndex; q++) {
997 if (visibleSubsetCount[q] == subsetSize) {
998 subsetFound = true;
999 theSubset = visibleSubsets[q];
1000 break;
1001 }
1002 }
1003 }
1004
1005 if (subsetFound) {
1006
1007
1008
1009
1010
1011
1012
1013 for (int k0 = 0; k0 < boardSize; k0++) {
1014 for (int k1 = 0; k1 < boardSize; k1++) {
1015 if (!cellFilled[j0][j1][k0][k1]) {
1016 if (Arrays.equals(subsets[k0][k1], theSubset) && subsetSizeTrue[k0][k1]) {
1017 continue;
1018 } else {
1019 for (int subsetIter = 0; subsetIter < subsetSize; subsetIter++) {
1020 if (placeCanContain[j0][j1][k0][k1][theSubset[subsetIter]]) {
1021 placeCanContain[j0][j1][k0][k1][theSubset[subsetIter]] = false;
1022 deliminations++;
1023 }
1024 }
1025 }
1026 }
1027 }
1028 }
1029 if (deliminations > 0) {
1030 System.out.println("Visible subset in grid " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1031
1032
1033
1034
1035 return true;
1036 } else {
1037 subsetFound = false;
1038 }
1039 }
1040
1041 for (int k0 = 0; k0 < boardSize; k0++) {
1042 for (int k1 = 0; k1 < boardSize; k1++) {
1043 subsetSizeTrue[k0][k1] = false;
1044 }
1045 }
1046 for (int k0 = 0; k0 < boardSize; k0++) {
1047 for (int k1 = 0; k1 < boardSize; k1++) {
1048 minimumSubsetPresent = 0;
1049 if (!cellFilled[j0][k0][j1][k1]) {
1050 for (int val = 0; val < (boardSize * boardSize); val++) {
1051 if (placeCanContain[j0][k0][j1][k1][val]) {
1052 if (minimumSubsetPresent < subsetSize) {
1053 subsets[k0][k1][minimumSubsetPresent] = val;
1054 minimumSubsetPresent++;
1055 if (minimumSubsetPresent == subsetSize) {
1056 subsetSizeTrue[k0][k1] = true;
1057 } else {
1058 subsetSizeTrue[k0][k1] = false;
1059 }
1060 } else {
1061 subsetSizeTrue[k0][k1] = false;
1062 }
1063 }
1064 }
1065 }
1066 }
1067 }
1068
1069 numberOfTrueSubsets = 0;
1070 for (int k0 = 0; k0 < boardSize; k0++) {
1071 for (int k1 = 0; k1 < boardSize; k1++) {
1072 if (subsetSizeTrue[k0][k1]) {
1073 subsetFoundAt[numberOfTrueSubsets] = k0 * boardSize + k1;
1074 numberOfTrueSubsets++;
1075 }
1076 visibleSubsetCount[k0 * boardSize + k1] = 0;
1077 }
1078 }
1079 if (numberOfTrueSubsets >= subsetSize) {
1080 numberOfVisibleSubsets = 1;
1081 visibleSubsetIndex = 1;
1082 s01 = subsetFoundAt[0] % boardSize;
1083 s00 = (subsetFoundAt[0] - s01) / boardSize;
1084 visibleSubsets[0] = subsets[s00][s01];
1085 visibleSubsetCount[0] = 1;
1086 outer: for (int q0 = 1; q0 < numberOfTrueSubsets; q0++) {
1087 s01 = subsetFoundAt[q0] % boardSize;
1088 s00 = (subsetFoundAt[q0] - s01) / boardSize;
1089 inner: for (int q1 = 0; q1 < visibleSubsetIndex; q1++) {
1090 if (Arrays.equals(subsets[s00][s01], visibleSubsets[q1])) {
1091 visibleSubsetCount[q1]++;
1092 break inner;
1093 } else if (q1 == (visibleSubsetIndex - 1)) {
1094 visibleSubsets[visibleSubsetIndex] = subsets[s00][s01];
1095 visibleSubsetCount[visibleSubsetIndex]++;
1096 visibleSubsetIndex++;
1097 break inner;
1098 }
1099 }
1100 }
1101 for (int q = 0; q < visibleSubsetIndex; q++) {
1102 if (visibleSubsetCount[q] == subsetSize) {
1103 subsetFound = true;
1104 theSubset = visibleSubsets[q];
1105 break;
1106 }
1107 }
1108 }
1109
1110 if (subsetFound) {
1111 for (int k0 = 0; k0 < boardSize; k0++) {
1112 for (int k1 = 0; k1 < boardSize; k1++) {
1113 if (!cellFilled[j0][k0][j1][k1]) {
1114 if (Arrays.equals(subsets[k0][k1], theSubset) && subsetSizeTrue[k0][k1]) {
1115 continue;
1116 } else {
1117 for (int subsetIter = 0; subsetIter < subsetSize; subsetIter++) {
1118 if (placeCanContain[j0][k0][j1][k1][theSubset[subsetIter]]) {
1119 placeCanContain[j0][k0][j1][k1][theSubset[subsetIter]] = false;
1120 deliminations++;
1121 }
1122 }
1123 }
1124 }
1125 }
1126 }
1127 if (deliminations > 0) {
1128 System.out.println("Visible subset in row " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1129 return true;
1130 } else {
1131 subsetFound = false;
1132 }
1133 }
1134
1135 for (int k0 = 0; k0 < boardSize; k0++) {
1136 for (int k1 = 0; k1 < boardSize; k1++) {
1137 subsetSizeTrue[k0][k1] = false;
1138 }
1139 }
1140 for (int k0 = 0; k0 < boardSize; k0++) {
1141 for (int k1 = 0; k1 < boardSize; k1++) {
1142 minimumSubsetPresent = 0;
1143 if (!cellFilled[k0][j0][k1][j1]) {
1144 for (int val = 0; val < (boardSize * boardSize); val++) {
1145 if (placeCanContain[k0][j0][k1][j1][val]) {
1146 if (minimumSubsetPresent < subsetSize) {
1147 subsets[k0][k1][minimumSubsetPresent] = val;
1148 minimumSubsetPresent++;
1149 if (minimumSubsetPresent == subsetSize) {
1150 subsetSizeTrue[k0][k1] = true;
1151 } else {
1152 subsetSizeTrue[k0][k1] = false;
1153 }
1154 } else {
1155 subsetSizeTrue[k0][k1] = false;
1156 }
1157 }
1158 }
1159 }
1160 }
1161 }
1162
1163 numberOfTrueSubsets = 0;
1164 for (int k0 = 0; k0 < boardSize; k0++) {
1165 for (int k1 = 0; k1 < boardSize; k1++) {
1166 if (subsetSizeTrue[k0][k1]) {
1167 subsetFoundAt[numberOfTrueSubsets] = k0 * boardSize + k1;
1168 numberOfTrueSubsets++;
1169 }
1170 visibleSubsetCount[k0 * boardSize + k1] = 0;
1171 }
1172 }
1173 if (numberOfTrueSubsets >= subsetSize) {
1174 numberOfVisibleSubsets = 1;
1175 visibleSubsetIndex = 1;
1176 s01 = subsetFoundAt[0] % boardSize;
1177 s00 = (subsetFoundAt[0] - s01) / boardSize;
1178 visibleSubsets[0] = subsets[s00][s01];
1179 visibleSubsetCount[0] = 1;
1180 outer: for (int q0 = 1; q0 < numberOfTrueSubsets; q0++) {
1181 s01 = subsetFoundAt[q0] % boardSize;
1182 s00 = (subsetFoundAt[q0] - s01) / boardSize;
1183 inner: for (int q1 = 0; q1 < visibleSubsetIndex; q1++) {
1184 if (Arrays.equals(subsets[s00][s01], visibleSubsets[q1])) {
1185 visibleSubsetCount[q1]++;
1186 break inner;
1187 } else if (q1 == (visibleSubsetIndex - 1)) {
1188 visibleSubsets[visibleSubsetIndex] = subsets[s00][s01];
1189 visibleSubsetCount[visibleSubsetIndex]++;
1190 visibleSubsetIndex++;
1191 break inner;
1192 }
1193 }
1194 }
1195 for (int q = 0; q < visibleSubsetIndex; q++) {
1196 if (visibleSubsetCount[q] == subsetSize) {
1197 subsetFound = true;
1198 theSubset = visibleSubsets[q];
1199 break;
1200 }
1201 }
1202 }
1203
1204 if (subsetFound) {
1205 for (int k0 = 0; k0 < boardSize; k0++) {
1206 for (int k1 = 0; k1 < boardSize; k1++) {
1207 if (!cellFilled[k0][j0][k1][j1]) {
1208 if (Arrays.equals(subsets[k0][k1], theSubset) && subsetSizeTrue[k0][k1]) {
1209 continue;
1210 } else {
1211 for (int subsetIter = 0; subsetIter < subsetSize; subsetIter++) {
1212 if (placeCanContain[k0][j0][k1][j1][theSubset[subsetIter]]) {
1213 placeCanContain[k0][j0][k1][j1][theSubset[subsetIter]] = false;
1214 deliminations++;
1215 }
1216 }
1217 }
1218 }
1219 }
1220 }
1221 if (deliminations > 0) {
1222 System.out.println("Visible subset in column " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1223 return true;
1224 } else {
1225 subsetFound = false;
1226 }
1227 }
1228 }
1229 }
1230 }
1231 return false;
1232 }
1233
1234 public int iterateReductionOfCanContainSubsetHidden() {
1235 int count = 0;
1236 while (reductionOfCanContainSubsetHidden()) {
1237 count++;
1238 }
1239 return count;
1240 }
1241
1242 public boolean reductionOfCanContainSubsetHidden() {
1243 int[] valueIncidence = new int[(boardSize * boardSize)];
1244 int valuesIncidental = 0;
1245 int subsetSquares = 0;
1246 int s0 = 0;
1247 int s1 = 0;
1248 boolean[] hiddenValue = new boolean[(boardSize * boardSize)];
1249 boolean subsetCaptured;
1250 boolean subsetChecked;
1251 ArrayList<Integer> hiddenValues = new ArrayList<Integer>();
1252 ArrayList<Integer> hiddenSubsetSquares = new ArrayList<Integer>();
1253 PermutationComputation permVals = new PermutationComputation();
1254 PermutationComputation permSquares = new PermutationComputation();
1255 int deliminations = 0;
1256 for (int subsetSize = 2; subsetSize < (boardSize * boardSize) - 1; subsetSize++) {
1257 int[] theSubset = new int[subsetSize];
1258 int[] theSquares = new int[subsetSize];
1259 for (int j0 = 0; j0 < boardSize; j0++) {
1260 for (int j1 = 0; j1 < boardSize; j1++) {
1261
1262 subsetCaptured = false;
1263 subsetChecked = false;
1264 valuesIncidental = 0;
1265 hiddenValues.clear();
1266 for (int q = 0; q < (boardSize * boardSize); q++) {
1267 valueIncidence[q] = 0;
1268 hiddenValue[q] = false;
1269 }
1270 for (int k0 = 0; k0 < boardSize; k0++) {
1271 for (int k1 = 0; k1 < boardSize; k1++) {
1272 if (!cellFilled[j0][j1][k0][k1]) {
1273 for (int q = 0; q < (boardSize * boardSize); q++) {
1274 if (placeCanContain[j0][j1][k0][k1][q]) {
1275 valueIncidence[q]++;
1276 }
1277 }
1278 }
1279 }
1280 }
1281 for (int q = 0; q < (boardSize * boardSize); q++) {
1282 if (valueIncidence[q] == subsetSize) {
1283 valuesIncidental++;
1284 }
1285 }
1286 if (valuesIncidental >= subsetSize) {
1287 subsetCaptured = true;
1288 }
1289
1290 if (subsetCaptured) {
1291 hiddenSubsetSquares.clear();
1292 subsetSquares = 0;
1293 for (int q = 0; q < (boardSize * boardSize); q++) {
1294 if (valueIncidence[q] == subsetSize) {
1295 hiddenValue[q] = true;
1296 hiddenValues.add(q);
1297 }
1298 }
1299 for (int k0 = 0; k0 < boardSize; k0++) {
1300 for (int k1 = 0; k1 < boardSize; k1++) {
1301 if (!cellFilled[j0][j1][k0][k1]) {
1302 valuesIncidental = 0;
1303 for (int q = 0; q < (boardSize * boardSize); q++) {
1304 if (placeCanContain[j0][j1][k0][k1][q] && hiddenValue[q]) {
1305 valuesIncidental++;
1306 }
1307 }
1308 if (valuesIncidental >= subsetSize) {
1309 hiddenSubsetSquares.add(k0 * 3 + k1);
1310 subsetSquares++;
1311 }
1312 }
1313 }
1314 }
1315 if (subsetSquares >= subsetSize) {
1316 boolean[][] subsets = new boolean[subsetSquares][hiddenValues.size()];
1317 boolean falseDeclared = true;
1318 for (int square = 0; square < subsetSquares; square++) {
1319 for (int vals = 0; vals < hiddenValues.size(); vals++) {
1320 s1 = hiddenSubsetSquares.get(square) % boardSize;
1321 s0 = (hiddenSubsetSquares.get(square) - s1) / boardSize;
1322 if (placeCanContain[j0][j1][s0][s1][hiddenValues.get(vals)]) {
1323 subsets[square][vals] = true;
1324 } else {
1325 subsets[square][vals] = false;
1326 }
1327 }
1328 }
1329 permVals.clear();
1330 permVals.permutationCompute(subsetSize, hiddenValues.size());
1331 permSquares.clear();
1332 permSquares.permutationCompute(subsetSize, subsetSquares);
1333 outer: for (int square = 0; square < permSquares.size(); square++) {
1334 for (int vals = 0; vals < permVals.size(); vals++) {
1335 falseDeclared = false;
1336 for (int b0 = 0; b0 < subsetSize; b0++) {
1337 for (int b1 = 0; b1 < subsetSize; b1++) {
1338 if (!subsets[permSquares.getget(square, b1)][permVals.getget(vals, b0)]) {
1339 falseDeclared = true;
1340 }
1341 }
1342 }
1343 if (!falseDeclared) {
1344 theSubset = permVals.get(vals);
1345 theSquares = permSquares.get(square);
1346 for (int h = 0; h < subsetSize; h++) {
1347 theSubset[h] = hiddenValues.get(theSubset[h]);
1348 theSquares[h] = hiddenSubsetSquares.get(theSquares[h]);
1349 }
1350 subsetChecked = true;
1351 break outer;
1352 }
1353 }
1354 }
1355 }
1356 }
1357
1358 if (subsetChecked) {
1359 ArrayList<Integer> subVoids = new ArrayList<Integer>();
1360 for (int h = 0; h < subsetSize; h++) {
1361 subVoids.add(theSubset[h]);
1362 }
1363 for (int h = 0; h < subsetSize; h++) {
1364 s1 = theSquares[h] % boardSize;
1365 s0 = (theSquares[h] - s1) / boardSize;
1366 for (int val = 0; val < (boardSize * boardSize); val++) {
1367 if (placeCanContain[j0][j1][s0][s1][val] && !subVoids.contains(val)) {
1368 placeCanContain[j0][j1][s0][s1][val] = false;
1369 deliminations++;
1370 }
1371 }
1372 }
1373 if (deliminations > 0) {
1374 System.out.println("Hidden subset in grid " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1375 return true;
1376 } else {
1377 subsetChecked = false;
1378 }
1379 }
1380
1381 subsetCaptured = false;
1382 subsetChecked = false;
1383 valuesIncidental = 0;
1384 hiddenValues.clear();
1385 for (int q = 0; q < (boardSize * boardSize); q++) {
1386 valueIncidence[q] = 0;
1387 hiddenValue[q] = false;
1388 }
1389 for (int k0 = 0; k0 < boardSize; k0++) {
1390 for (int k1 = 0; k1 < boardSize; k1++) {
1391 if (!cellFilled[j0][k0][j1][k1]) {
1392 for (int q = 0; q < (boardSize * boardSize); q++) {
1393 if (placeCanContain[j0][k0][j1][k1][q]) {
1394 valueIncidence[q]++;
1395 }
1396 }
1397 }
1398 }
1399 }
1400 for (int q = 0; q < (boardSize * boardSize); q++) {
1401 if (valueIncidence[q] == subsetSize) {
1402 valuesIncidental++;
1403 }
1404 }
1405 if (valuesIncidental >= subsetSize) {
1406 subsetCaptured = true;
1407 }
1408
1409 if (subsetCaptured) {
1410 hiddenSubsetSquares.clear();
1411 subsetSquares = 0;
1412 for (int q = 0; q < (boardSize * boardSize); q++) {
1413 if (valueIncidence[q] == subsetSize) {
1414 hiddenValue[q] = true;
1415 hiddenValues.add(q);
1416 }
1417 }
1418 for (int k0 = 0; k0 < boardSize; k0++) {
1419 for (int k1 = 0; k1 < boardSize; k1++) {
1420 if (!cellFilled[j0][k0][j1][k1]) {
1421 valuesIncidental = 0;
1422 for (int q = 0; q < (boardSize * boardSize); q++) {
1423 if (placeCanContain[j0][k0][j1][k1][q] && hiddenValue[q]) {
1424 valuesIncidental++;
1425 }
1426 }
1427 if (valuesIncidental >= subsetSize) {
1428 hiddenSubsetSquares.add(k0 * 3 + k1);
1429 subsetSquares++;
1430 }
1431 }
1432 }
1433 }
1434 if (subsetSquares >= subsetSize) {
1435 boolean[][] subsets = new boolean[subsetSquares][hiddenValues.size()];
1436 boolean falseDeclared = true;
1437 for (int square = 0; square < subsetSquares; square++) {
1438 for (int vals = 0; vals < hiddenValues.size(); vals++) {
1439 s1 = hiddenSubsetSquares.get(square) % boardSize;
1440 s0 = (hiddenSubsetSquares.get(square) - s1) / boardSize;
1441 if (placeCanContain[j0][s0][j1][s1][hiddenValues.get(vals)]) {
1442 subsets[square][vals] = true;
1443 } else {
1444 subsets[square][vals] = false;
1445 }
1446 }
1447 }
1448 permVals.clear();
1449 permVals.permutationCompute(subsetSize, hiddenValues.size());
1450 permSquares.clear();
1451 permSquares.permutationCompute(subsetSize, subsetSquares);
1452 outer: for (int square = 0; square < permSquares.size(); square++) {
1453 for (int vals = 0; vals < permVals.size(); vals++) {
1454 falseDeclared = false;
1455 for (int b0 = 0; b0 < subsetSize; b0++) {
1456 for (int b1 = 0; b1 < subsetSize; b1++) {
1457 if (!subsets[permSquares.getget(square, b1)][permVals.getget(vals, b0)]) {
1458 falseDeclared = true;
1459 }
1460 }
1461 }
1462 if (!falseDeclared) {
1463 theSubset = permVals.get(vals);
1464 theSquares = permSquares.get(square);
1465 for (int h = 0; h < subsetSize; h++) {
1466 theSubset[h] = hiddenValues.get(theSubset[h]);
1467 theSquares[h] = hiddenSubsetSquares.get(theSquares[h]);
1468 }
1469 subsetChecked = true;
1470 break outer;
1471 }
1472 }
1473 }
1474 }
1475
1476 }
1477
1478 if (subsetChecked) {
1479 ArrayList<Integer> subVoids = new ArrayList<Integer>();
1480 for (int h = 0; h < subsetSize; h++) {
1481 subVoids.add(theSubset[h]);
1482 }
1483 for (int h = 0; h < subsetSize; h++) {
1484 s1 = theSquares[h] % boardSize;
1485 s0 = (theSquares[h] - s1) / boardSize;
1486 for (int val = 0; val < (boardSize * boardSize); val++) {
1487 if (placeCanContain[j0][s0][j1][s1][val] && !subVoids.contains(val)) {
1488 placeCanContain[j0][s0][j1][s1][val] = false;
1489 deliminations++;
1490 }
1491 }
1492 }
1493 if (deliminations > 0) {
1494 System.out.println("Hidden subset in row " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1495 return true;
1496 } else {
1497 subsetChecked = false;
1498 }
1499 }
1500
1501 subsetCaptured = false;
1502 subsetChecked = false;
1503 valuesIncidental = 0;
1504 hiddenValues.clear();
1505 for (int q = 0; q < (boardSize * boardSize); q++) {
1506 valueIncidence[q] = 0;
1507 hiddenValue[q] = false;
1508 }
1509 for (int k0 = 0; k0 < boardSize; k0++) {
1510 for (int k1 = 0; k1 < boardSize; k1++) {
1511 if (!cellFilled[k0][j0][k1][j1]) {
1512 for (int q = 0; q < (boardSize * boardSize); q++) {
1513 if (placeCanContain[k0][j0][k1][j1][q]) {
1514 valueIncidence[q]++;
1515 }
1516 }
1517 }
1518 }
1519 }
1520 for (int q = 0; q < (boardSize * boardSize); q++) {
1521 if (valueIncidence[q] == subsetSize) {
1522 valuesIncidental++;
1523 }
1524 }
1525 if (valuesIncidental >= subsetSize) {
1526 subsetCaptured = true;
1527 }
1528
1529 if (subsetCaptured) {
1530 hiddenSubsetSquares.clear();
1531 subsetSquares = 0;
1532 for (int q = 0; q < (boardSize * boardSize); q++) {
1533 if (valueIncidence[q] == subsetSize) {
1534 hiddenValue[q] = true;
1535 hiddenValues.add(q);
1536 }
1537 }
1538 for (int k0 = 0; k0 < boardSize; k0++) {
1539 for (int k1 = 0; k1 < boardSize; k1++) {
1540 if (!cellFilled[k0][j0][k1][j1]) {
1541 valuesIncidental = 0;
1542 for (int q = 0; q < (boardSize * boardSize); q++) {
1543 if (placeCanContain[k0][j0][k1][j1][q] && hiddenValue[q]) {
1544 valuesIncidental++;
1545 }
1546 }
1547 if (valuesIncidental >= subsetSize) {
1548 hiddenSubsetSquares.add(k0 * 3 + k1);
1549 subsetSquares++;
1550 }
1551 }
1552 }
1553 }
1554 if (subsetSquares >= subsetSize) {
1555 boolean[][] subsets = new boolean[subsetSquares][hiddenValues.size()];
1556 boolean falseDeclared = true;
1557 for (int square = 0; square < subsetSquares; square++) {
1558 for (int vals = 0; vals < hiddenValues.size(); vals++) {
1559 s1 = hiddenSubsetSquares.get(square) % boardSize;
1560 s0 = (hiddenSubsetSquares.get(square) - s1) / boardSize;
1561 if (placeCanContain[s0][j0][s1][j1][hiddenValues.get(vals)]) {
1562 subsets[square][vals] = true;
1563 } else {
1564 subsets[square][vals] = false;
1565 }
1566 }
1567 }
1568 permVals.clear();
1569 permVals.permutationCompute(subsetSize, hiddenValues.size());
1570 permSquares.clear();
1571 permSquares.permutationCompute(subsetSize, subsetSquares);
1572 outer: for (int square = 0; square < permSquares.size(); square++) {
1573 for (int vals = 0; vals < permVals.size(); vals++) {
1574 falseDeclared = false;
1575 for (int b0 = 0; b0 < subsetSize; b0++) {
1576 for (int b1 = 0; b1 < subsetSize; b1++) {
1577 if (!subsets[permSquares.getget(square, b1)][permVals.getget(vals, b0)]) {
1578 falseDeclared = true;
1579 }
1580 }
1581 }
1582 if (!falseDeclared) {
1583 theSubset = permVals.get(vals);
1584 theSquares = permSquares.get(square);
1585 for (int h = 0; h < subsetSize; h++) {
1586 theSubset[h] = hiddenValues.get(theSubset[h]);
1587 theSquares[h] = hiddenSubsetSquares.get(theSquares[h]);
1588 }
1589 subsetChecked = true;
1590 break outer;
1591 }
1592 }
1593 }
1594 }
1595 }
1596
1597 if (subsetChecked) {
1598 ArrayList<Integer> subVoids = new ArrayList<Integer>();
1599 for (int h = 0; h < subsetSize; h++) {
1600 subVoids.add(theSubset[h]);
1601 }
1602 for (int h = 0; h < subsetSize; h++) {
1603 s1 = theSquares[h] % boardSize;
1604 s0 = (theSquares[h] - s1) / boardSize;
1605 for (int val = 0; val < (boardSize * boardSize); val++) {
1606 if (placeCanContain[s0][j0][s1][j1][val] && !subVoids.contains(val)) {
1607 placeCanContain[s0][j0][s1][j1][val] = false;
1608 deliminations++;
1609 }
1610 }
1611 }
1612 if (deliminations > 0) {
1613 System.out.println("Hidden subset in column " + (j0 * 3 + j1) + " of size " + subsetSize + ", " + Arrays.toString(theSubset));
1614 return true;
1615 } else {
1616 subsetChecked = false;
1617 }
1618 }
1619 }
1620 }
1621 }
1622 return false;
1623 }
1624
1625
1626 public void deliminatePotential(int k0, int k1, int k2, int k3, int k4) {
1627 numberPresentRowCol[0][k4][k2 + k0 * board.length] = true;
1628 numberPresentRowCol[1][k4][k3 + k1 * board.length] = true;
1629 numberPresentG[k4][k0][k1] = true;
1630 for (int j0 = 0; j0 < boardSize; j0++) {
1631 for (int j1 = 0; j1 < boardSize; j1++) {
1632 placeCanContain[k0][j0][k2][j1][k4] = false;
1633 placeCanContain[j0][k1][j1][k3][k4] = false;
1634 placeCanContain[k0][k1][j0][j1][k4] = false;
1635 }
1636 }
1637 }
1638
1639 public int[] subsetCollisionAt(int subsetSize, int numberOfTrueSubsets, int[] subsetFoundAt, int[][][] subsets) {
1640 int[] collisionsAt = new int[subsetSize];
1641 int numberOfPerfectCollisions = 0;
1642 subsetCollisionAtRolling(subsetSize, numberOfTrueSubsets, subsetFoundAt, subsets);
1643
1644 return collisionsAt;
1645 }
1646
1647 public void subsetCollisionAtRolling(int subsetSize, int numberOfTrueSubsets, int[] subsetFoundAt, int[][][] subsets) {
1648 int q1 = 0;
1649 int q0 = 0;
1650 for (int q = 0; q < numberOfTrueSubsets; q++) {
1651 subsetCollisionAtRolling(subsetSize, numberOfTrueSubsets - 1, subsetFoundAt, subsets);
1652 q1 = subsetFoundAt[q] % boardSize;
1653 q0 = (subsetFoundAt[q] - q1) / boardSize;
1654
1655
1656
1657
1658 }
1659 }
1660
1661 public boolean placeCanContainCheckDoesCollide(int j0, int j1, int j2, int j3, int k0, int k1, int k2, int k3, int collisions) {
1662 int counted = 0;
1663 for (int q = 0; q < (boardSize * boardSize); q++) {
1664 if (placeCanContain[j0][j1][j2][j3][q] && placeCanContain[k0][k1][k2][k3][q]) {
1665 counted++;
1666 }
1667 }
1668 if (counted >= collisions) {
1669 return true;
1670 }
1671 return false;
1672 }
1673
1674 public boolean[] placeCanContainCheckCollision(int j0, int j1, int j2, int j3, int k0, int k1, int k2, int k3) {
1675 boolean[] collidingValues = new boolean[(boardSize * boardSize)];
1676 for (int q = 0; q < (boardSize * boardSize); q++) {
1677 if (placeCanContain[j0][j1][j2][j3][q] && placeCanContain[k0][k1][k2][k3][q]) {
1678 collidingValues[q] = true;
1679 } else {
1680 collidingValues[q] = false;
1681 }
1682 }
1683 return collidingValues;
1684 }
1685
1686 }