Java - oficjalny wynik 4.056s
Główną ideą tego jest, aby nigdy nie przydzielać pamięci, gdy nie jest ona potrzebna. Jedynym wyjątkiem są operacje podstawowe, które i tak powinny zostać zoptymalizowane przez kompilator. Cała reszta jest przechowywana jako maski i tablice operacji wykonanych na każdym kroku, które można cofnąć po zakończeniu kroku rekurencji.
Około połowa wszystkich sudokusów jest rozwiązana całkowicie bez cofania się, ale jeśli zwiększę tę liczbę, ogólny czas wydaje się być wolniejszy. Planuję om przepisać to w C ++ i zoptymalizować jeszcze bardziej, ale ten solver staje się gigantem.
Chciałem wdrożyć jak najwięcej buforowania, co może prowadzić do pewnych problemów. Na przykład, jeśli w tym samym rzędzie znajdują się dwie komórki, które mogą mieć tylko liczbę 6, osiągnęliśmy niemożliwy przypadek i powinniśmy powrócić do śledzenia wstecznego. Ale ponieważ obliczyłem wszystkie opcje za jednym razem, a następnie umieściłem liczby w komórkach z tylko jedną możliwością, nie sprawdziłem dwukrotnie, czy przedtem umieściłem liczbę w tym samym rzędzie. To prowadzi do niemożliwych rozwiązań.
Ponieważ wszystko jest zawarte w tablicach zdefiniowanych u góry, użycie pamięci przez solver wynosi około 216 kB. Główna część wykorzystania pamięci pochodzi z tablicy zawierającej wszystkie łamigłówki i modułów obsługi We / Wy w Javie.
EDYCJA : Mam wersję, która jest teraz przetłumaczona na C ++, ale nie jest znacznie szybsza. Oficjalny czas wynosi około 3,5 sekundy, co nie jest wielką poprawą. Myślę, że głównym problemem z moją implementacją jest to, że trzymam maski jako tablice, a nie maski bitowe. Spróbuję przeanalizować rozwiązanie Arnauld, aby zobaczyć, co można zrobić, aby to poprawić.
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.File;
import java.io.PrintWriter;
public class Sudoku {
final private int[] unsolvedBoard;
final private int[] solvedBoard;
final private int[][] neighbors;
final private int[][] cells;
private static int[] clues;
final private int[][] mask;
final private int[] formattedMask;
final private int[][] placedMask;
final private boolean[][][] lineMask;
final private int[] lineCounters;
final private int[][] sectionCounters;
final private int[][] sectionMask;
private int easySolved;
private boolean isEasy;
private int totEasy;
private int placedNumbers;
public long totTime = 0;
private boolean solutionFound;
public long lastPrint;
private boolean shouldPrint;
private boolean isImpossible = false;
public Sudoku() {
mask = new int[81][9];
formattedMask = new int[81];
placedMask = new int[64][64];
lineMask = new boolean[64][81][9];
sectionCounters = new int[9][27];
sectionMask = new int[9][27];
lineCounters = new int[64];
neighbors = new int[81][20];
unsolvedBoard = new int[81];
solvedBoard = new int[81];
cells = new int[][] {{0 ,1 ,2 ,9 ,10,11,18,19,20},
{3 ,4 ,5 ,12,13,14,21,22,23},
{6 ,7 ,8 ,15,16,17,24,25,26},
{27,28,29,36,37,38,45,46,47},
{30,31,32,39,40,41,48,49,50},
{33,34,35,42,43,44,51,52,53},
{54,55,56,63,64,65,72,73,74},
{57,58,59,66,67,68,75,76,77},
{60,61,62,69,70,71,78,79,80}};
}
final public long solveSudoku(int[] board, int clue) {
long t1 = 0,t2 = 0;
t1 = System.nanoTime();
System.arraycopy(board, 0, unsolvedBoard, 0, 81);
System.arraycopy(board, 0, solvedBoard, 0, 81);
placedNumbers = 0;
solutionFound = false;
isEasy = true;
isImpossible = false;
for (int[] i : mask) {
Arrays.fill(i, 0);
}
for (boolean[][] i : lineMask) {
for (boolean[] j : i) {
Arrays.fill(j, false);
}
}
for (int i = 0; i < 81; i++) {
if (solvedBoard[i] != -1) {
put(i, solvedBoard[i]);
placedNumbers++;
}
}
solve(0, 0);
t2 = System.nanoTime();
easySolved += isEasy ? 1 : 0;
if (solutionFound && placedNumbers == 81) {
totTime += t2-t1;
if (shouldPrint || t2-t1 > 5*1_000_000_000L) {
System.out.print(String.format(
"Solution from %2d clues found in %7s",
clue,
printTime(t1, t2)
));
shouldPrint = false;
if (t2-t1 > 1*1000_000_000L) {
System.out.println();
display2(board, solvedBoard);
}
}
} else {
System.out.println("No solution");
display2(unsolvedBoard, solvedBoard);
return -1;
}
return t2 - t1;
}
final private void solve(int v, int vIndex) {
lineCounters[vIndex] = 0;
int easyIndex = placeEasy(vIndex);
if (isImpossible) {
resetEasy(vIndex, easyIndex);
resetLineMask(vIndex);
return;
}
if (placedNumbers == 81) {
solutionFound = true;
return;
}
// if (true) {
// return;
// }
// either get the next empty cell
// while (v < 81 && solvedBoard[v] >= 0) {
// v++;
// }
// or get the cell with the fewest options
generateFormattedMasks();
int minOptions = 9;
for (int i = 0; i < 81; i++) {
int options = formattedMask[i] & 0xffff;
if (options > 0 && options < minOptions) {
minOptions = options;
v = i;
}
if (options == 0 && solvedBoard[i] == -1) {
isImpossible = true;
}
}
if (!isImpossible) {
for (int c = 0; c < 9; c++) {
if (isPossible(v, c)) {
isEasy = false;
put(v, c);
placedNumbers++;
solve(v + 1, vIndex + 1);
if (solutionFound) {
return;
}
unput(v, c);
placedNumbers--;
}
}
}
resetEasy(vIndex, easyIndex);
resetLineMask(vIndex);
}
final private void resetEasy(int vIndex, int easyIndex) {
for (int i = 0; i < easyIndex; i++) {
int tempv2 = placedMask[vIndex][i];
int c2 = solvedBoard[tempv2];
unput(tempv2, c2);
placedNumbers--;
}
}
final private void resetLineMask(int vIndex) {
if (lineCounters[vIndex] > 0) {
for (int i = 0; i < 81; i++) {
for (int c = 0; c < 9; c++) {
if (lineMask[vIndex][i][c]) {
enable(i, c);
lineMask[vIndex][i][c] = false;
}
}
}
}
isImpossible = false;
}
final private int placeEasy(int vIndex) {
int easyIndex = 0;
int lastPlaced = 0, tempPlaced = 0, easyplaced = 0;
int iter = 0;
while (placedNumbers > lastPlaced+1) {
lastPlaced = placedNumbers;
tempPlaced = 0;
while (placedNumbers > tempPlaced + 5) {
tempPlaced = placedNumbers;
easyIndex = placeNakedSingles(vIndex, easyIndex);
if (isImpossible) {
return easyIndex;
}
}
tempPlaced = 0;
while (placedNumbers < 55*1 && placedNumbers > tempPlaced + 2) {
tempPlaced = placedNumbers;
easyIndex = placeHiddenSingles(vIndex, easyIndex);
if (isImpossible) {
return easyIndex;
}
}
tempPlaced = 0;
while (placedNumbers < 65*1 && placedNumbers > tempPlaced + 1) {
tempPlaced = placedNumbers;
easyIndex = placeNakedSingles(vIndex, easyIndex);
if (isImpossible) {
return easyIndex;
}
}
if (iter < 2 && placedNumbers < 55*1) {
checkNakedTriples(vIndex);
}
if (placedNumbers < 45*1) {
checkNakedDoubles(vIndex);
identifyLines(vIndex);
}
iter++;
}
return easyIndex;
}
final private int placeNakedSingles(int vIndex, int easyIndex) {
generateFormattedMasks();
for (int tempv = 0; tempv < 81; tempv++) {
int possibilities = formattedMask[tempv];
if ((possibilities & 0xffff) == 1) {
possibilities >>= 16;
int c = 0;
while ((possibilities & 1) == 0) {
possibilities >>= 1;
c++;
}
if (isPossible(tempv, c)) {
put(tempv, c);
placedMask[vIndex][easyIndex++] = tempv;
placedNumbers++;
} else {
isImpossible = true;
return easyIndex;
}
} else if (possibilities == 0 && solvedBoard[tempv] == -1) {
isImpossible = true;
return easyIndex;
}
}
return easyIndex;
}
final private int placeHiddenSingles(int vIndex, int easyIndex) {
for (int[] i : sectionCounters) {
Arrays.fill(i, 0);
}
for (int c = 0; c < 9; c++) {
for (int v = 0; v < 81; v++) {
if (isPossible(v, c)) {
int cell = 3 * (v / 27) + ((v / 3) % 3);
sectionCounters[c][v / 9]++;
sectionCounters[c][9 + (v % 9)]++;
sectionCounters[c][18 + cell]++;
sectionMask[c][v / 9] = v;
sectionMask[c][9 + (v % 9)] = v;
sectionMask[c][18 + cell] = v;
}
}
int v;
for (int i = 0; i < 9; i++) {
if (sectionCounters[c][i] == 1) {
v = sectionMask[c][i];
if (isPossible(v, c)) {
put(v, c);
placedMask[vIndex][easyIndex++] = v;
placedNumbers++;
int cell = 3 * (v / 27) + ((v / 3) % 3);
sectionCounters[c][9 + (v%9)] = 9;
sectionCounters[c][18 + cell] = 9;
} else {
isImpossible = true;
return easyIndex;
}
}
}
for (int i = 9; i < 18; i++) {
if (sectionCounters[c][i] == 1) {
v = sectionMask[c][i];
if (isPossible(v, c)) {
put(v, c);
placedMask[vIndex][easyIndex++] = v;
int cell = 3 * (v / 27) + ((v / 3) % 3);
placedNumbers++;
sectionCounters[c][18 + cell]++;
} else {
isImpossible = true;
return easyIndex;
}
}
}
for (int i = 18; i < 27; i++) {
if (sectionCounters[c][i] == 1) {
v = sectionMask[c][i];
if (isPossible(v, c)) {
put(v, c);
placedMask[vIndex][easyIndex++] = v;
placedNumbers++;
} else {
isImpossible = true;
return easyIndex;
}
}
}
}
return easyIndex;
}
final private int getFormattedMask(int v) {
if (solvedBoard[v] >= 0) {
return 0;
}
int x = 0;
int y = 0;
for (int c = 8; c >= 0; c--) {
x <<= 1;
x += mask[v][c] == 0 ? 1 : 0;
y += mask[v][c] == 0 ? 1 : 0;
}
x <<= 16;
return x + y;
}
final private int getCachedMask(int v) {
return formattedMask[v];
}
final private void generateFormattedMasks() {
for (int i = 0; i < 81; i++) {
formattedMask[i] = getFormattedMask(i);
}
}
final private void generateFormattedMasks(int[] idxs) {
for (int i : idxs) {
formattedMask[i] = getFormattedMask(i);
}
}
final private void checkNakedDoubles(int vIndex) {
generateFormattedMasks();
for (int i = 0; i < 81; i++) {
int bitmask = formattedMask[i];
if ((bitmask & 0xffff) == 2) {
for (int j = i+1; j < (i/9+1)*9; j++) {
int bitmask_j = formattedMask[j];
if (bitmask == bitmask_j) {
bitmask >>= 16;
int c0, c1, k = 0;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c0 = k;
bitmask >>= 1;
k++;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c1 = k;
for (int cell = (i/9)*9; cell < (i/9+1)*9; cell++) {
if (cell != i && cell != j) {
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
for (int idx = 0; idx < 81; idx++) {
int i = (idx%9)*9 + idx/9;
int bitmask = formattedMask[i];
if ((bitmask & 0xffff) == 2) {
for (int j = i+9; j < 81; j += 9) {
int bitmask_j = formattedMask[j];
if (bitmask == bitmask_j) {
bitmask >>= 16;
int c0, c1, k = 0;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c0 = k;
bitmask >>= 1;
k++;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c1 = k;
for (int cell = i % 9; cell < 81; cell += 9) {
if (cell != i && cell != j) {
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
for (int idx = 0; idx < 9; idx++) {
for (int i = 0; i < 9; i++) {
int bitmask = formattedMask[cells[idx][i]];
if ((bitmask & 0xffff) == 2) {
for (int j = i+1; j < 9; j++) {
int bitmask_j = formattedMask[cells[idx][j]];
if (bitmask == bitmask_j) {
bitmask >>= 16;
int c0, c1, k = 0;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c0 = k;
bitmask >>= 1;
k++;
while ((bitmask & 1) == 0) {
k++;
bitmask >>= 1;
}
c1 = k;
for (int cellIdx = 0; cellIdx < 9; cellIdx++) {
if (cellIdx != i && cellIdx != j) {
int cell = cells[idx][cellIdx];
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
}
}
final private void checkNakedTriples(int vIndex) {
generateFormattedMasks();
for (int i = 0; i < 81; i++) {
int bitmask = formattedMask[i];
if ((bitmask & 0xffff) == 3) {
for (int j = i+1; j < (i/9+1)*9; j++) {
int bitmask_j = formattedMask[j];
if (bitmask_j > 0 && bitmask == (bitmask | bitmask_j)) {
for (int k = j+1; k < (i/9+1)*9; k++) {
int bitmask_k = formattedMask[k];
if (bitmask_k > 0 && bitmask == (bitmask | bitmask_k)) {
int bitmask_shifted = bitmask >> 16;
int c0, c1, c2, l = 0;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c0 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c1 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c2 = l;
for (int cell = (i/9)*9; cell < (i/9+1)*9; cell++) {
if (cell != i && cell != j && cell != k) {
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c2]) {
disable(cell, c2);
lineMask[vIndex][cell][c2] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
}
}
for (int idx = 0; idx < 81; idx++) {
int i = (idx%9)*9 + idx/9;
int bitmask = formattedMask[i];
if ((bitmask & 0xffff) == 3) {
for (int j = i+9; j < 81; j += 9) {
int bitmask_j = formattedMask[j];
if (bitmask_j > 0 && bitmask == (bitmask | bitmask_j)) {
for (int k = j+9; k < 81; k += 9) {
int bitmask_k = formattedMask[k];
if (bitmask_k > 0 && bitmask == (bitmask | bitmask_k)) {
int bitmask_shifted = bitmask >> 16;
int c0, c1, c2, l = 0;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c0 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c1 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c2 = l;
for (int cell = i%9; cell < 81; cell += 9) {
if (cell != i && cell != j && cell != k) {
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c2]) {
disable(cell, c2);
lineMask[vIndex][cell][c2] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
}
}
for (int idx = 0; idx < 9; idx++) {
for (int i = 0; i < 9; i++) {
int bitmask = formattedMask[cells[idx][i]];
if ((bitmask & 0xffff) == 3) {
for (int j = i+1; j < 9; j++) {
int bitmask_j = formattedMask[cells[idx][j]];
if (bitmask_j > 0 && bitmask == (bitmask | bitmask_j)) {
for (int k = j+1; k < 9; k++) {
int bitmask_k = formattedMask[cells[idx][k]];
if (bitmask_k > 0 && bitmask == (bitmask | bitmask_k)) {
int bitmask_shifted = bitmask >> 16;
int c0, c1, c2, l = 0;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c0 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c1 = l;
bitmask_shifted >>= 1;
l++;
while ((bitmask_shifted & 1) == 0) {
l++;
bitmask_shifted >>= 1;
}
c2 = l;
for (int cellIdx = 0; cellIdx < 9; cellIdx++) {
if (cellIdx != i && cellIdx != j && cellIdx != k) {
int cell = cells[idx][cellIdx];
if (!lineMask[vIndex][cell][c0]) {
disable(cell, c0);
lineMask[vIndex][cell][c0] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c1]) {
disable(cell, c1);
lineMask[vIndex][cell][c1] = true;
lineCounters[vIndex]++;
}
if (!lineMask[vIndex][cell][c2]) {
disable(cell, c2);
lineMask[vIndex][cell][c2] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
}
}
}
}
final private void identifyLines(int vIndex) {
int disabledLines = 0;
int[][] tempRowMask = new int[3][9];
int[][] tempColMask = new int[3][9];
for (int i = 0; i < 9; i++) {
for (int c = 0; c < 9; c++) {
for (int j = 0; j < 3; j++) {
tempRowMask[j][c] = 0;
tempColMask[j][c] = 0;
}
for (int j = 0; j < 9; j++) {
if (mask[cells[i][j]][c] == 0) {
tempRowMask[j/3][c]++;
tempColMask[j%3][c]++;
}
}
int rowCount = 0;
int colCount = 0;
int rowIdx = -1, colIdx = -1;
for (int j = 0; j < 3; j++) {
if (tempRowMask[j][c] > 0) {
rowCount++;
rowIdx = j;
}
if (tempColMask[j][c] > 0) {
colCount++;
colIdx = j;
}
}
if (rowCount == 1) {
for (int j = (i/3)*3; j < (i/3 + 1)*3; j++) {
if (j != i) {
for (int k = rowIdx*3; k < (rowIdx+1)*3; k++) {
int cell = cells[j][k];
if (!lineMask[vIndex][cell][c]) {
disable(cell, c);
lineMask[vIndex][cell][c] = true;
lineCounters[vIndex]++;
}
}
}
}
}
if (colCount == 1) {
for (int j = i % 3; j < 9; j += 3) {
if (j != i) {
for (int k = colIdx; k < 9; k += 3) {
int cell = cells[j][k];
if (!lineMask[vIndex][cell][c]) {
disable(cell, c);
lineMask[vIndex][cell][c] = true;
lineCounters[vIndex]++;
}
}
}
}
}
}
}
}
final private boolean isPossible(int v, int c) {
return mask[v][c] == 0;
}
final private int checkMask(int[][] neighbors, int v, int c) {
int tempValue = 0;
for (int n : neighbors[v]) {
if (mask[n][c] > 0) {
tempValue++;
}
}
return tempValue;
}
final private void put(int v, int c) {
solvedBoard[v] = c;
for (int i : neighbors[v]) {
mask[i][c]++;
}
for (int i = 0; i < 9; i++) {
mask[v][i]++;
}
}
final private void disable(int v, int c) {
mask[v][c]++;
}
final private void unput(int v, int c) {
solvedBoard[v] = -1;
for (int i : neighbors[v]) {
mask[i][c]--;
}
for (int i = 0; i < 9; i++) {
mask[v][i]--;
}
}
final private void enable(int v, int c) {
// enables++;
mask[v][c]--;
}
public String getString(int[] board) {
StringBuilder s = new StringBuilder();
for (int i : board) {
s.append(i+1);
}
return s.toString();
}
public long getTime() {
return totTime;
}
public static String printTime(long t1, long t2) {
String unit = " ns";
if (t2-t1 > 10000) {
unit = " us";
t1 /= 1000; t2 /= 1000;
}
if (t2-t1 > 10000) {
unit = " ms";
t1 /= 1000; t2 /= 1000;
}
if (t2-t1 > 10000) {
unit = " seconds";
t1 /= 1000; t2 /= 1000;
}
return (t2-t1) + unit;
}
public void display(int[] board) {
for (int i = 0; i < 9; i++) {
if (i % 3 == 0) {
System.out.println("+-----+-----+-----+");
}
for (int j = 0; j < 9; j++) {
if (j % 3 == 0) {
System.out.print("|");
} else {
System.out.print(" ");
}
if (board[i*9+j] != -1) {
System.out.print(board[i*9+j]+1);
} else {
System.out.print(" ");
}
}
System.out.println("|");
}
System.out.println("+-----+-----+-----+");
}
public void display2(int[] board, int[] solved) {
for (int i = 0; i < 9; i++) {
if (i % 3 == 0) {
System.out.println("+-----+-----+-----+ +-----+-----+-----+");
}
for (int j = 0; j < 9; j++) {
if (j % 3 == 0) {
System.out.print("|");
} else {
System.out.print(" ");
}
if (board[i*9+j] != -1) {
System.out.print(board[i*9+j]+1);
} else {
System.out.print(" ");
}
}
System.out.print("| ");
for (int j = 0; j < 9; j++) {
if (j % 3 == 0) {
System.out.print("|");
} else {
System.out.print(" ");
}
if (solved[i*9+j] != -1) {
System.out.print(solved[i*9+j]+1);
} else {
System.out.print(" ");
}
}
System.out.println("|");
}
System.out.println("+-----+-----+-----+ +-----+-----+-----+");
}
private boolean contains(int[] a, int v) {
for (int i : a) {
if (i == v) {
return true;
}
}
return false;
}
public void connect() {
for (int i = 0; i < 81; i++) {
for (int j = 0; j < 20; j++) {
neighbors[i][j] = -1;
}
}
int[] n_count = new int[81];
HashMap<Integer,ArrayList<Integer>> map
= new HashMap<Integer,ArrayList<Integer>>();
for (int[] c: cells) {
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int v : c) {
temp.add(v);
}
for (int v : c) {
map.put(v,temp);
}
}
for (int i = 0; i < 81; i++) {
for (int j = (i/9)*9; j < (i/9)*9 + 9; j++) {
if (i != j) {
neighbors[i][n_count[i]++] = j;
}
}
for (int j = i%9; j < 81; j += 9) {
if (i != j) {
neighbors[i][n_count[i]++] = j;
}
}
for (int j : map.get(i)) {
if (i != j) {
if (!contains(neighbors[i], j)) {
neighbors[i][n_count[i]++] = j;
}
}
}
}
}
public static int[][] getInput(String filename) {
int[][] boards;
try (BufferedInputStream in = new BufferedInputStream(
new FileInputStream(filename))) {
BufferedReader r = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8));
int n = Integer.valueOf(r.readLine());
boards = new int[n][81];
clues = new int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < 81; j++) {
int x = r.read();
boards[i][j] = x - 49;
clues[i] += x > 48 ? 1 : 0;
}
r.read();
}
r.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return boards;
}
private int getTotEasy() {
return totEasy;
}
public String getSolution() {
StringBuilder s = new StringBuilder(256);
for (int i : unsolvedBoard) {
s.append(i+1);
}
s.append(",");
for (int i : solvedBoard) {
s.append(i+1);
}
return s.toString();
}
public static void main (String[] args) {
long t0 = System.nanoTime();
Sudoku gc = new Sudoku();
File f;
PrintWriter p;
try {
f = new File("sudoku_output.txt");
p = new PrintWriter(f);
} catch (Exception e) {
return;
}
if (args.length != 1) {
System.out.println("Usage: java Sudoku <input_file>");
return;
}
int[][] boards = gc.getInput(args[0]);
long tinp = System.nanoTime();
gc.connect();
long t1 = System.nanoTime();
p.println(boards.length);
long maxSolveTime = 0;
int maxSolveIndex = 0;
long[] solveTimes = new long[boards.length];
for (int i = 0; i < boards.length; i++) {
long tempTime = System.nanoTime();
if (tempTime - gc.lastPrint > 200_000_000
|| i == boards.length - 1) {
gc.shouldPrint = true;
gc.lastPrint = tempTime;
System.out.print(String.format(
"\r(%7d/%7d) ", i+1, boards.length));
}
long elapsed = gc.solveSudoku(boards[i], gc.clues[i]);
if (elapsed == -1) {
System.out.println("Impossible: " + i);
}
if (elapsed > maxSolveTime) {
maxSolveTime = elapsed;
maxSolveIndex = i;
}
solveTimes[i] = elapsed;
p.println(gc.getSolution());
// break;
}
p.close();
long t2 = System.nanoTime();
Arrays.sort(solveTimes);
System.out.println();
System.out.println("Median solve time: "
+ gc.printTime(0, solveTimes[boards.length/2]));
System.out.println("Longest solve time: "
+ gc.printTime(0, maxSolveTime) + " for board " + maxSolveIndex);
gc.display(boards[maxSolveIndex]);
System.out.println();
System.out.println("Total time (including prints): "
+ gc.printTime(t0,t2));
System.out.println("Sudoku solving time: "
+ gc.printTime(0,gc.getTime()));
System.out.println("Average time per board: "
+ gc.printTime(0,gc.getTime()/boards.length));
System.out.println("Number of one-choice digits per board: "
+ String.format("%.2f", gc.getTotEasy()/(double)boards.length));
System.out.println("Easily solvable boards: " + gc.easySolved);
System.out.println("\nInput time: " + gc.printTime(t0,tinp));
System.out.println("Connect time: " + gc.printTime(tinp,t1));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
}
}