@CyborgBeta : es bringt nichts, wenn du anonym postest. Deine Beiträge sind so einzigartig, dass man sofort sieht, dass alle 3 Beiträge von Unregistered von dir sind…
Ich sehe das genauso wie @Marco13 , der aktuelle Zustand wird ja in der aufrufenden Methode gehalten. Der Rückgabewert ist nur dann relevant, wenn dort die Lösung gefunden wurde. Ansonsten wird der gehaltene Zustand verwendet - der Schritt zurück im Backtracking.
Andere Lösung ohne Backtracking
[spoiler]Ja, ich weiß - es geht bei der Aufgabenstellung explizit um Backtracking. Allerdings habe ich vor fast 2 Jahren “woanders” mal einen Sudokusolver entwickelt, der das Problem des Sudoku-Lösens in ein Problem der exakten Überdeckung überführt hat. Der ist äußerst effizient, gerade bei “großen” Sudokus (z. B. 16x16). “Woanders” hat auch ein anderer User einen Solver gepostet, der eine optimierte, entrekursivierte Variante des klassischen rekursiven Ansatzes ist.
Auch ikwudls alias hüte alias CyborgBeta hat einen Beitrag mit seiner Lösung (die Klasse hieß SuMist - ich hab sie in meinen alten Projekten noch gefunden) geleistet. Wie die funktioniert vermag ich jetzt auf die Schnelle nicht zu beurteilen - typischer ikwudls-Code halt.
Ich poste meine Klassen hier einfach mal - der Thread “woanders” ist verloren gegangen…
Das Interface habe ich nur gebaut, damit ich verschiedene Sudoku-Implementierungen besser vergleichen konnte.
public interface Sudoku {
/**
* Solve the sudoku.
*
* @return {code true} if sudoku could be solved
*/
boolean solve();
/**
* @return how many steps were needed to solve the sudoku.
*/
long getSteps();
}```
```package net.byte_welt.sudoku;
import java.util.ArrayList;
import java.util.List;
//import java.util.Collections;
/**
* User: Christian
* Date: 20.07.13
* Time: 13:48
*/
public class SudokuExactCover implements Sudoku {
private final int fixed;
private final MatrixEntry head;
private final List<MatrixEntry> solution;
private long steps = 0;
private final int blockWidth;
private final int totalWidth;
private final int fieldCount;
public SudokuExactCover(int[][] sudoku, int blockWidth) {
this.blockWidth = blockWidth;
totalWidth = blockWidth * blockWidth;
fieldCount = totalWidth * totalWidth;
if (sudoku.length != totalWidth)
throw new IllegalArgumentException("sudoku must be a " + totalWidth + "x" + totalWidth + " array");
for (int[] row : sudoku)
if (row.length != totalWidth)
throw new IllegalArgumentException("sudoku must be a " + totalWidth + "x" + totalWidth + " array");
solution = new ArrayList<>(fieldCount);
head = generateMatrix();
extractFixed(sudoku);
fixed = solution.size();
countRows();
}
private void countRows() {
MatrixEntry p = head.getRight();
while (p != head) {
p.countRows();
p = p.getRight();
}
}
/*private void sortHeads() {
MatrixEntry p = head.getRight();
List<MatrixHead> heads = new ArrayList<MatrixHead>(324 - fixed);
while (p != head) {
heads.add(new MatrixHead(p.getValue(), p));
//p.setValue(p.countRows());
p = p.getRight();
}
Collections.sort(heads);
head.setRight(head);
head.setLeft(head);
for (MatrixHead matrixHead : heads) {
head.insertBefore(matrixHead.getHead());
}
}*/
private void extractFixed(int[][] sudoku) {
MatrixEntry p = head;
for (int i = 0; i < 3 * fieldCount; i++)
p = p.getRight();
for (int col = 0; col < totalWidth; col++) {
for (int row = 0; row < totalWidth; row++) {
p = p.getRight();
if (sudoku[row][col] == 0) continue;
MatrixEntry s = p.get(row, sudoku[row][col] - 1);
s.removeEntry();
solution.add(s);
}
}
}
private MatrixEntry generateMatrix() {
MatrixEntry head = new MatrixEntry();
List<MatrixEntry> headers = generateHeaders(head);
for (int number = 0; number < totalWidth; number++) {
for (int row = 0; row < totalWidth; row++) {
for (int col = 0; col < totalWidth; col++) {
MatrixEntry h = headers.get(number * totalWidth + col);
MatrixEntry entryCol = new MatrixEntry(col, row, number, h);
h.insertAbove(entryCol);
h = headers.get(fieldCount + number * totalWidth + row);
MatrixEntry entryRow = new MatrixEntry(col, row, number, h);
h.insertAbove(entryRow);
h = headers.get(2 * fieldCount + number * totalWidth + col / blockWidth * blockWidth + row / blockWidth);
MatrixEntry entryBlock = new MatrixEntry(col, row, number, h);
h.insertAbove(entryBlock);
h = headers.get(3 * fieldCount + col * totalWidth + row);
MatrixEntry entryField = new MatrixEntry(col, row, number, h);
h.insertAbove(entryField);
entryCol.setLeft(entryField);
entryCol.setRight(entryRow);
entryRow.setLeft(entryCol);
entryRow.setRight(entryBlock);
entryBlock.setLeft(entryRow);
entryBlock.setRight(entryField);
entryField.setLeft(entryBlock);
entryField.setRight(entryCol);
}
}
}
return head;
}
private List<MatrixEntry> generateHeaders(MatrixEntry head) {
List<MatrixEntry> headers = new ArrayList<>(4 * fieldCount);
for (int i = 0; i < 4 * fieldCount; i++) {
MatrixEntry entry = new MatrixEntry();
head.insertBefore(entry);
headers.add(entry);
}
return headers;
}
@Override
public boolean solve() {
steps = 0;
eleminateOnes();
MatrixEntry p = head.getRight();
while (head.getRight() != head) {
p = p.getLower();
steps++;
if (p.getCol() != -1) {
solution.add(p);
if (p.removeEntry()) {
p = head.getRight();
} else {
p = backtrack();
}
} else {
if (solution.size() == fixed) return false;
p = backtrack();
}
}
return head.getRight() == head;
}
private void eleminateOnes() {
MatrixEntry p = head.getRight();
while (p != head) {
steps++;
if (p.getRowCount() == 1) {
p = p.getLower();
solution.add(p);
p.removeEntry();
p = head.getRight();
} else {
p = p.getRight();
}
}
}
private MatrixEntry backtrack() {
MatrixEntry entry = solution.remove(solution.size() - 1);
entry.reinsert();
return entry;
}
@Override
public long getSteps() {
return steps;
}
@Override
public String toString() {
int[][] field = new int[totalWidth][totalWidth];
for (MatrixEntry entry : solution) {
field[entry.getRow()][entry.getCol()] = entry.getValue() + 1;
}
String result = "";
for (int row = 0; row < totalWidth; row++) {
for (int col = 0; col < totalWidth; col++) {
if (col > 0) result += " ";
if (totalWidth > 9 && field[row][col] <= 9) result += " ";
result += field[row][col];
if ((col + 1) % blockWidth == 0 && col + 1 < totalWidth) result += " |";
}
result += "
";
if ((row + 1) % blockWidth == 0 && row + 1 < totalWidth) {
for (int col = 0; col < totalWidth; col++) {
if (col > 0) result += "-";
if (totalWidth > 9) result += "-";
result += "-";
if ((col + 1) % blockWidth == 0 && col + 1 < totalWidth) result += "-+";
}
result += "
";
}
}
return result;
}
}```
```package net.byte_welt.sudoku;
/**
* User: Christian
* Date: 20.07.13
* Time: 17:43
*/
class MatrixEntry /*implements Comparable<MatrixEntry>*/ {
private final int row;
private final int col;
private final MatrixEntry columnHeader;
private MatrixEntry left;
private MatrixEntry right;
private MatrixEntry upper;
private MatrixEntry lower;
private int value;
MatrixEntry() {
row = -1;
col = -1;
value = -1;
left = this;
right = this;
upper = this;
lower = this;
columnHeader = this;
}
MatrixEntry(int col, int row, int value, MatrixEntry columnHeader) {
this.row = row;
this.col = col;
this.columnHeader = columnHeader;
this.value = value;
}
void insertBefore(MatrixEntry entry) {
entry.right = this;
entry.left = left;
left.right = entry;
left = entry;
}
public void insertAbove(MatrixEntry entry) {
entry.lower = this;
entry.upper = upper;
upper.lower = entry;
upper = entry;
}
public void setLeft(MatrixEntry left) {
this.left = left;
}
public MatrixEntry getRight() {
return right;
}
public void setRight(MatrixEntry right) {
this.right = right;
}
MatrixEntry get(int row, int value) {
MatrixEntry result = this.columnHeader;
// Endlosschleife, falls col nicht gefunden wird
/*while (result.value != 243 + col * 9 + row) {
result = result.right;
}*/
// Endlosschleife, falls row nicht gefunden wird
while (result.row != row || result.value != value) {
result = result.lower;
}
return result;
}
private boolean removeRow() {
boolean result = true;
MatrixEntry p = this.right;
while (p != this) {
p.upper.lower = p.lower;
p.lower.upper = p.upper;
p.columnHeader.value--;
if (p.columnHeader.value == 0) result = false;
p = p.right;
}
return result;
}
private boolean removeCol() {
boolean result = true;
columnHeader.left.right = columnHeader.right;
columnHeader.right.left = columnHeader.left;
MatrixEntry p = this.lower;
while (p != this) {
if (p != columnHeader)
if (!p.removeRow()) result = false;
p = p.lower;
}
return result;
}
boolean removeEntry() {
boolean result = true;
MatrixEntry p = this;
do {
if (!p.removeCol()) result = false;
p = p.right;
} while (p != this);
return result;
}
MatrixEntry getLower() {
return lower;
}
private void reinsertRow() {
MatrixEntry p = this.right;
while (p != this) {
p.upper.lower = p;
p.lower.upper = p;
p.columnHeader.value++;
p = p.right;
}
}
private void reinsertCol() {
columnHeader.left.right = columnHeader;
columnHeader.right.left = columnHeader;
MatrixEntry p = this.lower;
while (p != this) {
if (p != columnHeader)
p.reinsertRow();
p = p.lower;
}
}
void reinsert() {
MatrixEntry p = this;
do {
p.reinsertCol();
p = p.right;
} while (p != this);
}
int getCol() {
return col;
}
int getRow() {
return row;
}
int getValue() {
return value;
}
int countRows() {
int result = 0;
MatrixEntry p = columnHeader.lower;
while (p != columnHeader) {
result++;
p = p.lower;
}
columnHeader.value = result;
return result;
}
/*@Override
public int compareTo(MatrixEntry o) {
if (value > o.value) return 1;
if (value < o.value) return -1;
return 0;
}*/
int getRowCount() {
return columnHeader.getValue();
}
}```
```package net.byte_welt.sudoku;
/**
* User: Christian
* Date: 20.07.13
* Time: 21:57
*/
class MatrixHead implements Comparable<MatrixHead> {
private final int rows;
private final MatrixEntry head;
public MatrixHead(int rows, MatrixEntry head) {
this.rows = rows;
this.head = head;
}
MatrixEntry getHead() {
return head;
}
@Override
public int compareTo(MatrixHead o) {
return Integer.compare(rows, o.rows);
}
}```
Die entrekursivierte Lösung vom User bone2:
```package net.byte_welt.sudoku;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SudokuBone2 implements Sudoku {
private long steps = 0;
public class Position implements Comparable<Position> {
private final int x;
private final int y;
private final int count;
public Position(int x, int y, int count) {
this.x = x;
this.y = y;
this.count = count;
}
@Override
public int compareTo(Position o) {
if (count > o.count) {
return -1;
}
if (count < o.count) {
return 1;
}
return 0;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private final int[] columns;
private final int[] rows;
private final int[] squares;
private final int[][] values;
private final int limit;
private final int squareSize;
private final List<Position> positions;
public SudokuBone2(int[][] sudoku, int limit) {
limit *= limit;
values = new int[limit][limit];
rows = new int[limit];
squares = new int[limit];
columns = new int[limit];
Arrays.fill(rows, 1);
Arrays.fill(squares, 1);
Arrays.fill(columns, 1);
squareSize = (int) Math.sqrt(limit);
this.limit = limit;
// prepare
for (int y = 0; y < limit; y++) {
for (int x = 0; x < limit; x++) {
values[y][x] = sudoku[y][x];
rows[y] |= 1 << sudoku[y][x];
columns[x] |= 1 << sudoku[y][x];
squares[x / squareSize + y / squareSize * squareSize] |= 1 << sudoku[y][x];
}
}
// get best order
positions = new ArrayList<>();
Position[][] positionMatrix = new Position[limit][limit];
for (int y = 0; y < limit; y++) {
for (int x = 0; x < limit; x++) {
if (values[y][x] == 0) {
int usedValues = rows[y] | columns[x] | squares[x / squareSize + y / squareSize * squareSize];
int c = 0;
for (int i = 1; i <= limit; i++) {
if ((usedValues & (1 << i)) != 0) {
c++;
}
}
Position posi = new Position(x, y, c);
positionMatrix[y][x] = posi;
positions.add(posi);
}
}
}
Collections.sort(positions);
}
@Override
public boolean solve() {
steps = 0;
solveSudoku(0);
return true;
}
@Override
public long getSteps() {
return steps;
}
@Override
public String toString() {
String result = "";
for (int[] aRow : values) {
result += Arrays.toString(aRow) + "
";
}
return result;
}
private boolean solveSudoku(int current) {
steps++;
if (current >= positions.size()) {
return true;
}
int x = positions.get(current).getX();
int y = positions.get(current).getY();
int square = x / squareSize + y / squareSize * squareSize;
int usedValues = rows[y] | columns[x] | squares[square];
for (int i = 1; i <= limit; i++) {
if (((1 << i) & usedValues) == 0) {
int shifted = 1 << i;
rows[y] |= shifted;
columns[x] |= shifted;
squares[square] |= shifted;
values[y][x] = i;
if (solveSudoku(current + 1)) {
return true;
}
rows[y] ^= shifted;
columns[x] ^= shifted;
squares[square] ^= shifted;
}
}
values[y][x] = 0;
return false;
}
}```
Eine Main-Klasse mit Beispielsudokus (den Benchmark würde ich heute anders machen...):
```package net.byte_welt.sudoku;
import java.util.ArrayList;
import java.util.List;
/**
* User: Christian
* Date: 16.07.13
* Time: 18:51
*/
public class Main {
public static void main(String[] args) {
int[][] easy16x16 = {
{3, 0, 14, 0, 15, 7, 4, 16, 0, 0, 6, 5, 0, 0, 0, 0},
{12, 0, 0, 0, 0, 0, 0, 11, 0, 10, 16, 13, 0, 5, 0, 0},
{0, 0, 0, 0, 6, 9, 5, 0, 0, 0, 0, 0, 13, 12, 8, 14},
{7, 11, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0},
{0, 13, 1, 0, 9, 12, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0},
{10, 0, 15, 0, 0, 16, 0, 13, 0, 11, 0, 6, 9, 0, 0, 0},
{0, 0, 16, 0, 0, 0, 0, 5, 0, 1, 12, 7, 10, 13, 0, 0},
{11, 9, 12, 0, 0, 0, 2, 10, 0, 0, 15, 0, 3, 7, 0, 5},
{13, 3, 8, 0, 4, 2, 12, 7, 0, 0, 9, 0, 0, 0, 16, 0},
{0, 0, 0, 0, 0, 11, 0, 8, 0, 16, 0, 2, 0, 9, 15, 0},
{9, 0, 11, 2, 0, 0, 0, 0, 0, 4, 7, 10, 0, 0, 3, 8},
{0, 0, 0, 16, 0, 1, 0, 9, 0, 0, 0, 8, 0, 4, 2, 0},
{0, 1, 9, 14, 2, 10, 11, 0, 0, 0, 0, 0, 8, 0, 0, 16},
{16, 6, 10, 15, 0, 8, 9, 0, 0, 0, 13, 12, 0, 0, 0, 11},
{0, 12, 0, 0, 5, 3, 15, 4, 0, 0, 0, 0, 14, 0, 0, 7},
{0, 0, 0, 0, 16, 0, 0, 0, 11, 15, 8, 0, 0, 0, 1, 4}
};
int[][] hard16x16 = {
{0, 0, 0, 8, 3, 0, 0, 0, 9, 12, 10, 2, 0, 0, 11, 14},
{0, 0, 0, 10, 6, 13, 0, 0, 16, 0, 0, 0, 0, 0, 4, 9},
{0, 0, 0, 15, 0, 0, 11, 16, 0, 4, 0, 0, 0, 12, 13, 0},
{0, 14, 5, 3, 0, 12, 0, 0, 0, 0, 0, 6, 0, 0, 2, 16},
{0, 8, 0, 0, 11, 0, 10, 0, 6, 0, 7, 0, 9, 0, 5, 2},
{0, 0, 1, 16, 0, 0, 13, 0, 0, 15, 3, 0, 0, 6, 0, 0},
{10, 12, 0, 0, 0, 14, 0, 0, 5, 0, 16, 8, 15, 0, 0, 0},
{0, 0, 0, 0, 0, 4, 0, 5, 11, 0, 0, 13, 0, 0, 0, 0},
{0, 0, 0, 0, 12, 0, 0, 7, 10, 0, 13, 0, 0, 0, 0, 0},
{0, 0, 0, 6, 16, 10, 0, 13, 0, 0, 12, 0, 0, 0, 9, 8},
{0, 0, 14, 0, 0, 11, 15, 0, 0, 16, 0, 0, 3, 10, 0, 0},
{2, 11, 0, 12, 0, 5, 0, 8, 0, 6, 0, 15, 0, 0, 7, 0},
{15, 5, 0, 0, 14, 0, 0, 0, 0, 0, 2, 0, 12, 1, 16, 0},
{0, 3, 4, 0, 0, 0, 12, 0, 1, 9, 0, 0, 13, 0, 0, 0},
{6, 10, 0, 0, 0, 0, 0, 1, 0, 0, 5, 11, 4, 0, 0, 0},
{16, 1, 0, 0, 4, 15, 6, 3, 0, 0, 0, 12, 11, 0, 0, 0}
};
int[][][] sudokus = {
{{0, 0, 0, 0, 0, 0, 0, 1, 0}, {4, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 5, 0, 4, 0, 7}, {0, 0, 8, 0, 0, 0, 3, 0, 0}, {0, 0, 1, 0, 9, 0, 0, 0, 0}, {3, 0, 0, 4, 0, 0, 2, 0, 0}, {0, 5, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 8, 0, 6, 0, 0, 0}},
{{0, 3, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 9, 5, 0, 0, 0}, {0, 0, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 0}, {4, 0, 0, 8, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 2, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, {0, 0, 0, 0, 0, 0, 0, 7, 0}},
{{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 3, 0, 8, 5}, {0, 0, 1, 0, 2, 0, 0, 0, 0}, {0, 0, 0, 5, 0, 7, 0, 0, 0}, {0, 0, 4, 0, 0, 0, 1, 0, 0}, {0, 9, 0, 0, 0, 0, 0, 0, 0}, {5, 0, 0, 0, 0, 0, 0, 7, 3}, {0, 0, 2, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 9}},
{{0, 0, 0, 0, 0, 0, 0, 1, 2}, {0, 0, 0, 0, 0, 0, 0, 0, 3}, {0, 0, 2, 3, 0, 0, 4, 0, 0}, {0, 0, 1, 8, 0, 0, 0, 0, 5}, {0, 6, 0, 0, 7, 0, 8, 0, 0}, {0, 0, 0, 0, 0, 9, 0, 0, 0}, {0, 0, 8, 5, 0, 0, 0, 0, 0}, {9, 0, 0, 0, 4, 0, 5, 0, 0}, {4, 7, 0, 0, 0, 6, 0, 0, 0}},
{{0, 2, 0, 0, 5, 0, 7, 0, 0}, {4, 0, 0, 1, 0, 0, 0, 0, 6}, {8, 0, 0, 0, 0, 3, 0, 0, 0}, {2, 0, 0, 0, 0, 8, 0, 0, 3}, {0, 4, 0, 0, 2, 0, 5, 0, 0}, {0, 0, 0, 6, 0, 0, 0, 1, 0}, {0, 0, 2, 0, 9, 0, 0, 0, 0}, {0, 9, 0, 0, 0, 0, 0, 0, 5}, {7, 0, 4, 0, 0, 0, 9, 0, 0}},
{{0, 0, 0, 0, 0, 0, 0, 0, 3}, {0, 0, 1, 0, 0, 5, 6, 0, 0}, {0, 9, 0, 0, 4, 0, 0, 7, 0}, {0, 0, 0, 0, 0, 9, 0, 5, 0}, {7, 0, 0, 0, 0, 0, 0, 0, 8}, {0, 5, 0, 4, 0, 2, 0, 0, 0}, {0, 8, 0, 0, 2, 0, 0, 9, 0}, {0, 0, 3, 5, 0, 0, 1, 0, 0}, {6, 0, 0, 0, 0, 0, 0, 0, 0}},
{{1, 2, 0, 3, 0, 0, 0, 0, 4}, {3, 5, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 5, 4, 0, 0, 2, 0, 0}, {6, 0, 0, 0, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 8, 0, 9, 0}, {0, 0, 3, 1, 0, 0, 5, 0, 0}, {0, 0, 0, 0, 0, 9, 0, 7, 0}, {0, 0, 0, 0, 6, 0, 0, 0, 8}},
{{1, 0, 0, 0, 0, 0, 0, 0, 2}, {0, 9, 0, 4, 0, 0, 0, 5, 0}, {0, 0, 6, 0, 0, 0, 7, 0, 0}, {0, 5, 0, 9, 0, 3, 0, 0, 0}, {0, 0, 0, 0, 7, 0, 0, 0, 0}, {0, 0, 0, 8, 5, 0, 0, 4, 0}, {7, 0, 0, 0, 0, 0, 6, 0, 0}, {0, 3, 0, 0, 0, 9, 0, 8, 0}, {0, 0, 2, 0, 0, 0, 0, 0, 1}},
{{0, 0, 0, 0, 0, 0, 0, 3, 9}, {0, 0, 0, 0, 0, 1, 0, 0, 5}, {0, 0, 3, 0, 5, 0, 8, 0, 0}, {0, 0, 8, 0, 9, 0, 0, 0, 6}, {0, 7, 0, 0, 0, 2, 0, 0, 0}, {1, 0, 0, 4, 0, 0, 0, 0, 0}, {0, 0, 9, 0, 8, 0, 0, 5, 0}, {0, 2, 0, 0, 0, 0, 6, 0, 0}, {4, 0, 0, 7, 0, 0, 0, 0, 0}},
{{1, 2, 0, 3, 0, 0, 0, 0, 0}, {4, 0, 0, 0, 0, 0, 3, 0, 0}, {0, 0, 3, 0, 5, 0, 0, 0, 0}, {0, 0, 4, 2, 0, 0, 5, 0, 0}, {0, 0, 0, 0, 8, 0, 0, 0, 9}, {0, 6, 0, 0, 0, 5, 0, 7, 0}, {0, 0, 1, 5, 0, 0, 2, 0, 0}, {0, 0, 0, 0, 9, 0, 0, 6, 0}, {0, 0, 0, 0, 0, 7, 0, 0, 8}},
{{0, 0, 3, 0, 0, 6, 0, 8, 0}, {0, 0, 0, 1, 0, 0, 2, 0, 0}, {0, 0, 0, 0, 7, 0, 0, 0, 4}, {0, 0, 9, 0, 0, 8, 0, 6, 0}, {0, 3, 0, 0, 4, 0, 0, 0, 1}, {0, 7, 0, 2, 0, 0, 0, 0, 0}, {3, 0, 0, 0, 0, 5, 0, 0, 0}, {0, 0, 5, 0, 0, 0, 6, 0, 0}, {9, 8, 0, 0, 0, 0, 0, 5, 0}},
{{1, 0, 0, 0, 0, 0, 0, 0, 9}, {0, 0, 6, 7, 0, 0, 0, 2, 0}, {0, 8, 0, 0, 0, 0, 4, 0, 0}, {0, 0, 0, 0, 7, 5, 0, 3, 0}, {0, 0, 5, 0, 0, 2, 0, 0, 0}, {0, 6, 0, 3, 0, 0, 0, 0, 0}, {0, 9, 0, 0, 0, 0, 8, 0, 0}, {6, 0, 0, 0, 4, 0, 0, 0, 1}, {0, 0, 2, 5, 0, 0, 0, 6, 0}},
{{0, 0, 9, 0, 0, 0, 4, 0, 0}, {0, 7, 0, 3, 0, 0, 0, 2, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 7}, {1, 0, 0, 8, 0, 0, 0, 0, 6}, {0, 0, 0, 0, 1, 0, 0, 7, 0}, {0, 0, 0, 0, 5, 6, 0, 0, 0}, {3, 0, 0, 0, 0, 5, 0, 0, 1}, {0, 4, 0, 0, 0, 0, 0, 9, 0}, {0, 0, 2, 0, 0, 0, 7, 0, 0}},
{{0, 0, 0, 0, 9, 0, 0, 5, 0}, {0, 1, 0, 0, 0, 0, 0, 3, 0}, {0, 0, 2, 3, 0, 0, 7, 0, 0}, {0, 0, 4, 5, 0, 0, 0, 7, 0}, {8, 0, 0, 0, 0, 0, 2, 0, 0}, {0, 0, 0, 0, 0, 6, 4, 0, 0}, {0, 9, 0, 0, 1, 0, 0, 0, 0}, {0, 8, 0, 0, 6, 0, 0, 0, 0}, {0, 0, 5, 4, 0, 0, 0, 0, 7}},
{{4, 0, 0, 0, 3, 0, 0, 0, 0}, {0, 0, 0, 6, 0, 0, 8, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 5, 0, 0, 9, 0}, {0, 8, 0, 0, 0, 0, 6, 0, 0}, {0, 7, 0, 2, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 2, 7, 0, 0}, {5, 0, 3, 0, 0, 0, 0, 4, 0}, {9, 0, 0, 0, 0, 0, 0, 0, 0}},
{{7, 0, 8, 0, 0, 0, 3, 0, 0}, {0, 0, 0, 2, 0, 1, 0, 0, 0}, {5, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 2, 6}, {3, 0, 0, 0, 8, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 9, 0}, {0, 9, 0, 6, 0, 0, 0, 0, 4}, {0, 0, 0, 0, 7, 0, 5, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}},
{{3, 0, 7, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 9, 1}, {8, 0, 0, 0, 0, 0, 0, 0, 0}, {4, 0, 0, 0, 0, 0, 7, 0, 0}, {0, 0, 0, 1, 6, 0, 0, 0, 0}, {0, 0, 0, 2, 5, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 3, 8, 0}, {0, 9, 0, 0, 0, 0, 5, 0, 0}, {0, 2, 0, 6, 0, 0, 0, 0, 0}},
{{0, 0, 0, 0, 0, 0, 0, 0, 8}, {0, 0, 3, 0, 0, 0, 4, 0, 0}, {0, 9, 0, 0, 2, 0, 0, 6, 0}, {0, 0, 0, 0, 7, 9, 0, 0, 0}, {0, 0, 0, 0, 6, 1, 2, 0, 0}, {0, 6, 0, 5, 0, 2, 0, 7, 0}, {0, 0, 8, 0, 0, 0, 5, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 2, 0}, {4, 0, 5, 0, 0, 0, 0, 0, 3}},
{{0, 0, 0, 0, 0, 0, 0, 1, 0}, {4, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 5, 0, 4, 0, 7}, {0, 0, 8, 0, 0, 0, 3, 0, 0}, {0, 0, 1, 0, 9, 0, 0, 0, 0}, {3, 0, 0, 4, 0, 0, 2, 0, 0}, {0, 5, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 8, 0, 6, 0, 0, 0}},
{{0, 0, 0, 0, 0, 0, 0, 1, 2}, {0, 0, 0, 0, 3, 5, 0, 0, 0}, {0, 0, 0, 6, 0, 0, 0, 7, 0}, {7, 0, 0, 0, 0, 0, 3, 0, 0}, {0, 0, 0, 4, 0, 0, 8, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 2, 0, 0, 0, 0}, {0, 8, 0, 0, 0, 0, 0, 4, 0}, {0, 5, 0, 0, 0, 0, 6, 0, 0}},
{{1, 0, 0, 0, 0, 0, 0, 0, 2}, {0, 9, 0, 4, 0, 0, 0, 5, 0}, {0, 0, 6, 0, 0, 0, 7, 0, 0}, {0, 5, 0, 3, 0, 4, 0, 0, 0}, {0, 0, 0, 0, 6, 0, 0, 0, 0}, {0, 0, 0, 0, 5, 8, 0, 4, 0}, {0, 0, 2, 0, 0, 0, 6, 0, 0}, {0, 3, 0, 0, 0, 9, 0, 8, 0}, {7, 0, 0, 0, 0, 0, 0, 0, 1}},
{{0, 0, 0, 0, 0, 1, 0, 2, 0}, {3, 0, 0, 0, 4, 0, 5, 0, 0}, {0, 0, 0, 6, 0, 0, 0, 0, 7}, {0, 0, 2, 0, 0, 0, 0, 0, 1}, {0, 8, 0, 0, 9, 0, 0, 3, 0}, {4, 0, 0, 0, 0, 0, 8, 0, 0}, {5, 0, 0, 0, 0, 2, 0, 0, 0}, {0, 9, 0, 0, 3, 0, 4, 0, 0}, {0, 0, 6, 7, 0, 0, 0, 0, 0}}
};
//warmup
for (int i = 0; i < 5; i++) {
for (int[][] s : sudokus) {
Sudoku sudoku = new SudokuExactCover(s, 3);
//Sudoku sudoku = new SudokuBone2(s, 3);
sudoku.solve();
}
}
List<Result> results = new ArrayList<>(24);
long totalStartTime = System.currentTimeMillis();
for (int[][] s : sudokus) {
long startTime = System.currentTimeMillis();
Sudoku sudoku = new SudokuExactCover(s, 3);
//Sudoku sudoku = new SudokuBone2(s, 3);
sudoku.solve();
long finishTime = System.currentTimeMillis();
results.add(new Result(startTime, finishTime, sudoku));
}
Sudoku sudoku = new SudokuExactCover(hard16x16, 4);
//Sudoku sudoku = new SudokuBone2(hard16x16, 4);
long startTime = System.currentTimeMillis();
sudoku.solve();
long finishTime = System.currentTimeMillis();
results.add(new Result(startTime, finishTime, sudoku));
sudoku = new SudokuExactCover(easy16x16, 4);
//Sudoku sudoku = new SudokuBone2(easy16x16, 4);
startTime = System.currentTimeMillis();
sudoku.solve();
finishTime = System.currentTimeMillis();
results.add(new Result(startTime, finishTime, sudoku));
long totalFinishTime = System.currentTimeMillis();
long totalSteps = 0;
for (Result result : results) {
totalSteps += result.getSteps();
System.out.println("steps: " + result.getSteps());
System.out.println("time : " + (result.getFinishTime() - result.getStartTime()) + " ms");
System.out.println(result.getSolution());
System.out.println("");
}
System.out.println("total steps: " + totalSteps);
System.out.println("total time : " + (totalFinishTime - totalStartTime) + " ms");
}
private static class Result {
private final long startTime;
private final long finishTime;
private final Sudoku solution;
private Result(long startTime, long finishTime, Sudoku solution) {
this.startTime = startTime;
this.finishTime = finishTime;
this.solution = solution;
}
private long getStartTime() {
return startTime;
}
private long getFinishTime() {
return finishTime;
}
private long getSteps() {
return solution.getSteps();
}
private String getSolution() {
return solution.toString();
}
}
}```[/spoiler]
Hier findet man übrigens 50.000 lösbare Sudokus, mit denen man super testen kann:
https://sudoku-solver-qt.googlecode.com/svn-history/r96/data/top50000.sdm