Sudoku refactor (#3556)

* BacktrackingAlgorithm refactor

* DancingLinks refactor
This commit is contained in:
Grzegorz Piwowarek 2018-01-31 18:50:37 +01:00 committed by GitHub
parent bd9a87c137
commit 43a4d08c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 78 deletions

View File

@ -3,25 +3,25 @@ package com.baeldung.algorithms.sudoku;
import java.util.stream.IntStream; import java.util.stream.IntStream;
public class BacktrackingAlgorithm { public class BacktrackingAlgorithm {
private static int BOARD_SIZE = 9;
private static int SUBSECTION_SIZE = 3;
private static int BOARD_START_INDEX = 0;
private static int NO_VALUE = 0;
private static int MIN_VALUE = 1;
private static int MAX_VALUE = 9;
public static int[][] board = { private static final int BOARD_SIZE = 9;
{ 8, 0, 0, 0, 0, 0, 0, 0, 0 }, private static final int SUBSECTION_SIZE = 3;
{ 0, 0, 3, 6, 0, 0, 0, 0, 0 }, private static final int BOARD_START_INDEX = 0;
{ 0, 7, 0, 0, 9, 0, 2, 0, 0 },
{ 0, 5, 0, 0, 0, 7, 0, 0, 0 }, private static final int NO_VALUE = 0;
{ 0, 0, 0, 0, 4, 5, 7, 0, 0 }, private static final int MIN_VALUE = 1;
{ 0, 0, 0, 1, 0, 0, 0, 3, 0 }, private static final int MAX_VALUE = 9;
{ 0, 0, 1, 0, 0, 0, 0, 6, 8 },
{ 0, 0, 8, 5, 0, 0, 0, 1, 0 }, private static int[][] board = {
{ 0, 9, 0, 0, 0, 0, 4, 0, 0 } {8, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 3, 6, 0, 0, 0, 0, 0},
{0, 7, 0, 0, 9, 0, 2, 0, 0},
{0, 5, 0, 0, 0, 7, 0, 0, 0},
{0, 0, 0, 0, 4, 5, 7, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 3, 0},
{0, 0, 1, 0, 0, 0, 0, 6, 8},
{0, 0, 8, 5, 0, 0, 0, 1, 0},
{0, 9, 0, 0, 0, 0, 4, 0, 0}
}; };
public static void main(String[] args) { public static void main(String[] args) {
@ -30,7 +30,7 @@ public class BacktrackingAlgorithm {
solver.printBoard(); solver.printBoard();
} }
public void printBoard() { private void printBoard() {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) { for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) { for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
System.out.print(board[row][column] + " "); System.out.print(board[row][column] + " ");
@ -39,7 +39,7 @@ public class BacktrackingAlgorithm {
} }
} }
public boolean solve(int[][] board) { private boolean solve(int[][] board) {
for (int r = BOARD_START_INDEX; r < BOARD_SIZE; r++) { for (int r = BOARD_START_INDEX; r < BOARD_SIZE; r++) {
for (int c = BOARD_START_INDEX; c < BOARD_SIZE; c++) { for (int c = BOARD_START_INDEX; c < BOARD_SIZE; c++) {
if (board[r][c] == NO_VALUE) { if (board[r][c] == NO_VALUE) {
@ -47,9 +47,8 @@ public class BacktrackingAlgorithm {
board[r][c] = k; board[r][c] = k;
if (isValid(board, r, c) && solve(board)) { if (isValid(board, r, c) && solve(board)) {
return true; return true;
} else {
board[r][c] = NO_VALUE;
} }
board[r][c] = NO_VALUE;
} }
return false; return false;
} }
@ -58,16 +57,22 @@ public class BacktrackingAlgorithm {
return true; return true;
} }
public boolean isValid(int[][] board, int r, int c) { private boolean isValid(int[][] board, int r, int c) {
return (rowConstraint(board, r) && return rowConstraint(board, r) &&
columnConstraint(board, c) && columnConstraint(board, c) &&
subsectionConstraint(board, r, c)); subsectionConstraint(board, r, c);
} }
private boolean subsectionConstraint(int[][] board, int r, int c) { private boolean subsectionConstraint(int[][] board, int r, int c) {
boolean[] constraint = new boolean[BOARD_SIZE]; boolean[] constraint = new boolean[BOARD_SIZE];
for (int i = (r / SUBSECTION_SIZE) * SUBSECTION_SIZE; i < (r / SUBSECTION_SIZE) * SUBSECTION_SIZE + SUBSECTION_SIZE; i++) { int subsectionRowStart = (r / SUBSECTION_SIZE) * SUBSECTION_SIZE;
for (int j = (c / SUBSECTION_SIZE) * SUBSECTION_SIZE; j < (c / SUBSECTION_SIZE) * SUBSECTION_SIZE + SUBSECTION_SIZE; j++) { int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE;
int subsectionColumnStart = (c / SUBSECTION_SIZE) * SUBSECTION_SIZE;
int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE;
for (int i = subsectionRowStart; i < subsectionRowEnd; i++) {
for (int j = subsectionColumnStart; j < subsectionColumnEnd; j++) {
if (!checkConstraint(board, i, constraint, j)) return false; if (!checkConstraint(board, i, constraint, j)) return false;
} }
} }
@ -76,23 +81,19 @@ public class BacktrackingAlgorithm {
private boolean columnConstraint(int[][] board, int c) { private boolean columnConstraint(int[][] board, int c) {
boolean[] constraint = new boolean[BOARD_SIZE]; boolean[] constraint = new boolean[BOARD_SIZE];
for (int i = BOARD_START_INDEX; i < BOARD_SIZE; i++) { return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
if (!checkConstraint(board, i, constraint, c)) return false; .allMatch(i -> checkConstraint(board, i, constraint, c));
}
return true;
} }
private boolean rowConstraint(int[][] board, int r) { private boolean rowConstraint(int[][] board, int r) {
boolean[] constraint = new boolean[BOARD_SIZE]; boolean[] constraint = new boolean[BOARD_SIZE];
for (int i = BOARD_START_INDEX; i < BOARD_SIZE; i++) { return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
if (!checkConstraint(board, r, constraint, i)) return false; .allMatch(i -> checkConstraint(board, r, constraint, i));
}
return true;
} }
private boolean checkConstraint(int[][] board, int r, boolean[] constraint, int c) { private boolean checkConstraint(int[][] board, int r, boolean[] constraint, int c) {
if (board[r][c] >= MIN_VALUE && board[r][c] <= MAX_VALUE) { if (board[r][c] != NO_VALUE) {
if (constraint[board[r][c] - 1] == false) { if (!constraint[board[r][c] - 1]) {
constraint[board[r][c] - 1] = true; constraint[board[r][c] - 1] = true;
} else { } else {
return false; return false;
@ -100,4 +101,4 @@ public class BacktrackingAlgorithm {
} }
return true; return true;
} }
} }

View File

@ -4,7 +4,7 @@ class ColumnNode extends DancingNode {
int size; int size;
String name; String name;
public ColumnNode(String n) { ColumnNode(String n) {
super(); super();
size = 0; size = 0;
name = n; name = n;

View File

@ -50,10 +50,9 @@ public class DancingLinks {
private ColumnNode makeDLXBoard(boolean[][] grid) { private ColumnNode makeDLXBoard(boolean[][] grid) {
final int COLS = grid[0].length; final int COLS = grid[0].length;
final int ROWS = grid.length;
ColumnNode headerNode = new ColumnNode("header"); ColumnNode headerNode = new ColumnNode("header");
ArrayList<ColumnNode> columnNodes = new ArrayList<ColumnNode>(); List<ColumnNode> columnNodes = new ArrayList<>();
for (int i = 0; i < COLS; i++) { for (int i = 0; i < COLS; i++) {
ColumnNode n = new ColumnNode(Integer.toString(i)); ColumnNode n = new ColumnNode(Integer.toString(i));
@ -62,10 +61,10 @@ public class DancingLinks {
} }
headerNode = headerNode.R.C; headerNode = headerNode.R.C;
for (int i = 0; i < ROWS; i++) { for (boolean[] aGrid : grid) {
DancingNode prev = null; DancingNode prev = null;
for (int j = 0; j < COLS; j++) { for (int j = 0; j < COLS; j++) {
if (grid[i][j] == true) { if (aGrid[j]) {
ColumnNode col = columnNodes.get(j); ColumnNode col = columnNodes.get(j);
DancingNode newNode = new DancingNode(col); DancingNode newNode = new DancingNode(col);
if (prev == null) if (prev == null)
@ -82,21 +81,21 @@ public class DancingLinks {
return headerNode; return headerNode;
} }
public DancingLinks(boolean[][] cover) { DancingLinks(boolean[][] cover) {
header = makeDLXBoard(cover); header = makeDLXBoard(cover);
} }
public void runSolver() { public void runSolver() {
answer = new LinkedList<DancingNode>(); answer = new LinkedList<>();
search(0); search(0);
} }
public void handleSolution(List<DancingNode> answer) { private void handleSolution(List<DancingNode> answer) {
int[][] result = parseBoard(answer); int[][] result = parseBoard(answer);
printSolution(result); printSolution(result);
} }
int size = 9; private int size = 9;
private int[][] parseBoard(List<DancingNode> answer) { private int[][] parseBoard(List<DancingNode> answer) {
int[][] result = new int[size][size]; int[][] result = new int[size][size];
@ -120,12 +119,12 @@ public class DancingLinks {
return result; return result;
} }
public static void printSolution(int[][] result) { private static void printSolution(int[][] result) {
int N = result.length; int N = result.length;
for (int i = 0; i < N; i++) { for (int[] aResult : result) {
String ret = ""; StringBuilder ret = new StringBuilder();
for (int j = 0; j < N; j++) { for (int j = 0; j < N; j++) {
ret += result[i][j] + " "; ret.append(aResult[j]).append(" ");
} }
System.out.println(ret); System.out.println(ret);
} }

View File

@ -1,39 +1,37 @@
package com.baeldung.algorithms.sudoku; package com.baeldung.algorithms.sudoku;
import java.util.*; import java.util.Arrays;
public class DancingLinksAlgorithm { public class DancingLinksAlgorithm {
private static int BOARD_SIZE = 9; private static final int BOARD_SIZE = 9;
private static int SUBSECTION_SIZE = 3; private static final int SUBSECTION_SIZE = 3;
private static int NO_VALUE = 0; private static final int NO_VALUE = 0;
private static int CONSTRAINTS = 4; private static final int CONSTRAINTS = 4;
private static int MIN_VALUE = 1; private static final int MIN_VALUE = 1;
private static int MAX_VALUE = 9; private static final int MAX_VALUE = 9;
private static int COVER_START_INDEX = 1; private static final int COVER_START_INDEX = 1;
public static int[][] board = { private static int[][] board = {
{ 8, 0, 0, 0, 0, 0, 0, 0, 0 }, {8, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 3, 6, 0, 0, 0, 0, 0 }, {0, 0, 3, 6, 0, 0, 0, 0, 0},
{ 0, 7, 0, 0, 9, 0, 2, 0, 0 }, {0, 7, 0, 0, 9, 0, 2, 0, 0},
{ 0, 5, 0, 0, 0, 7, 0, 0, 0 }, {0, 5, 0, 0, 0, 7, 0, 0, 0},
{ 0, 0, 0, 0, 4, 5, 7, 0, 0 }, {0, 0, 0, 0, 4, 5, 7, 0, 0},
{ 0, 0, 0, 1, 0, 0, 0, 3, 0 }, {0, 0, 0, 1, 0, 0, 0, 3, 0},
{ 0, 0, 1, 0, 0, 0, 0, 6, 8 }, {0, 0, 1, 0, 0, 0, 0, 6, 8},
{ 0, 0, 8, 5, 0, 0, 0, 1, 0 }, {0, 0, 8, 5, 0, 0, 0, 1, 0},
{ 0, 9, 0, 0, 0, 0, 4, 0, 0 } {0, 9, 0, 0, 0, 0, 4, 0, 0}
}; };
public static void main(String[] args) { public static void main(String[] args) {
DancingLinksAlgorithm solver = new DancingLinksAlgorithm(); DancingLinksAlgorithm solver = new DancingLinksAlgorithm();
solver.solve(board); solver.solve(board);
} }
public boolean solve(int[][] board) { private void solve(int[][] board) {
boolean[][] cover = initializeExactCoverBoard(board); boolean[][] cover = initializeExactCoverBoard(board);
DancingLinks dlx = new DancingLinks(cover); DancingLinks dlx = new DancingLinks(cover);
dlx.runSolver(); dlx.runSolver();
return true;
} }
private int getIndex(int row, int col, int num) { private int getIndex(int row, int col, int num) {
@ -54,7 +52,7 @@ public class DancingLinksAlgorithm {
} }
} }
} }
// Row constrain. // Row constrain.
for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) {
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
@ -74,7 +72,7 @@ public class DancingLinksAlgorithm {
} }
} }
} }
// Subsection constraint // Subsection constraint
for (int br = COVER_START_INDEX; br <= BOARD_SIZE; br += SUBSECTION_SIZE) { for (int br = COVER_START_INDEX; br <= BOARD_SIZE; br += SUBSECTION_SIZE) {
for (int bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) { for (int bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) {

View File

@ -39,11 +39,11 @@ class DancingNode {
this.U.D = this.D.U = this; this.U.D = this.D.U = this;
} }
public DancingNode() { DancingNode() {
L = R = U = D = this; L = R = U = D = this;
} }
public DancingNode(ColumnNode c) { DancingNode(ColumnNode c) {
this(); this();
C = c; C = c;
} }