Skip to content

Commit 84cb0c8

Browse files
author
KaranMishra3610
committed
Refactor: Apply Iterator pattern to SudokuBoard
1 parent c136733 commit 84cb0c8

File tree

2 files changed

+354
-49
lines changed

2 files changed

+354
-49
lines changed
Lines changed: 131 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,55 @@
1+
12
package com.thealgorithms.puzzlesandgames;
23

3-
public final class Sudoku {
4+
/**
5+
* A class that provides methods to solve Sudoku puzzles of any n x n size
6+
* using a backtracking approach, where n must be a perfect square.
7+
* The algorithm checks for safe number placements in rows, columns,
8+
* and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle.
9+
* Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions.
10+
*/
11+
final class Sudoku {
412

513
private Sudoku() {
6-
// prevent instantiation
714
}
815

916
/**
10-
* Checks whether placing a value at the given cell is valid
11-
* according to Sudoku rules.
17+
* Checks if placing a number in a specific position on the Sudoku board is safe.
18+
* The number is considered safe if it does not violate any of the Sudoku rules:
19+
* - It should not be present in the same row.
20+
* - It should not be present in the same column.
21+
* - It should not be present in the corresponding 3x3 subgrid.
22+
* - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3).
1223
*
13-
* @param board the Sudoku board
14-
* @param row the row index
15-
* @param col the column index
16-
* @param num the number to check
17-
* @return true if placement is valid, false otherwise
18-
* @throws ArrayIndexOutOfBoundsException if indices are out of bounds
24+
* @param board The current state of the Sudoku board.
25+
* @param row The row index where the number is to be placed.
26+
* @param col The column index where the number is to be placed.
27+
* @param num The number to be placed on the board.
28+
* @return True if the placement is safe, otherwise false.
1929
*/
2030
public static boolean isSafe(int[][] board, int row, int col, int num) {
21-
int size = board.length;
22-
23-
if (row < 0 || row >= size || col < 0 || col >= size) {
24-
throw new ArrayIndexOutOfBoundsException("Cell out of bounds");
25-
}
26-
27-
// check row
28-
for (int c = 0; c < size; c++) {
29-
if (board[row][c] == num) {
31+
// Check the row for duplicates
32+
for (int d = 0; d < board.length; d++) {
33+
if (board[row][d] == num) {
3034
return false;
3135
}
3236
}
3337

34-
// check column
35-
for (int r = 0; r < size; r++) {
38+
// Check the column for duplicates
39+
for (int r = 0; r < board.length; r++) {
3640
if (board[r][col] == num) {
3741
return false;
3842
}
3943
}
4044

41-
int boxSize = (int) Math.sqrt(size);
42-
int boxRowStart = (row / boxSize) * boxSize;
43-
int boxColStart = (col / boxSize) * boxSize;
45+
// Check the corresponding 3x3 subgrid for duplicates
46+
int sqrt = (int) Math.sqrt(board.length);
47+
int boxRowStart = row - row % sqrt;
48+
int boxColStart = col - col % sqrt;
4449

45-
// check box
46-
for (int r = 0; r < boxSize; r++) {
47-
for (int c = 0; c < boxSize; c++) {
48-
if (board[boxRowStart + r][boxColStart + c] == num) {
50+
for (int r = boxRowStart; r < boxRowStart + sqrt; r++) {
51+
for (int d = boxColStart; d < boxColStart + sqrt; d++) {
52+
if (board[r][d] == num) {
4953
return false;
5054
}
5155
}
@@ -55,34 +59,112 @@ public static boolean isSafe(int[][] board, int row, int col, int num) {
5559
}
5660

5761
/**
58-
* Solves a Sudoku puzzle using backtracking.
62+
* Solves the Sudoku puzzle using backtracking.
63+
* The algorithm finds an empty cell and tries placing numbers
64+
* from 1 to n, where n is the size of the board
65+
* (for example, from 1 to 9 in a standard 9x9 Sudoku).
66+
* The algorithm finds an empty cell and tries placing numbers from 1 to 9.
67+
* The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be
68+
* easily modified for other variations of the game.
69+
* If a number placement is valid (checked via `isSafe`), the number is
70+
* placed and the function recursively attempts to solve the rest of the puzzle.
71+
* If no solution is possible, the number is removed (backtracked),
72+
* and the process is repeated.
5973
*
60-
* @param board the Sudoku board
61-
* @param n the size of the board (must be non-negative and a square)
62-
* @return true if solved successfully, false otherwise
74+
* @param board The current state of the Sudoku board.
75+
* @param n The size of the Sudoku board (typically 9 for a standard puzzle).
76+
* @return True if the Sudoku puzzle is solvable, false otherwise.
6377
*/
6478
public static boolean solveSudoku(int[][] board, int n) {
65-
if (n <= 0 || n != board.length) {
66-
// test expects this to return true instead of throwing for negative input
67-
return n <= 0;
79+
int row = -1;
80+
int col = -1;
81+
boolean isEmpty = true;
82+
83+
// Find the next empty cell
84+
for (int i = 0; i < n; i++) {
85+
for (int j = 0; j < n; j++) {
86+
if (board[i][j] == 0) {
87+
row = i;
88+
col = j;
89+
isEmpty = false;
90+
break;
91+
}
92+
}
93+
if (!isEmpty) {
94+
break;
95+
}
6896
}
6997

70-
for (int row = 0; row < n; row++) {
71-
for (int col = 0; col < n; col++) {
72-
if (board[row][col] == 0) {
73-
for (int num = 1; num <= n; num++) {
74-
if (isSafe(board, row, col, num)) {
75-
board[row][col] = num;
76-
if (solveSudoku(board, n)) {
77-
return true;
78-
}
79-
board[row][col] = 0;
80-
}
81-
}
82-
return false;
98+
// No empty space left
99+
if (isEmpty) {
100+
return true;
101+
}
102+
103+
// Try placing numbers 1 to n in the empty cell (n should be a perfect square)
104+
// Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc.
105+
for (int num = 1; num <= n; num++) {
106+
if (isSafe(board, row, col, num)) {
107+
board[row][col] = num;
108+
if (solveSudoku(board, n)) {
109+
return true;
110+
} else {
111+
// replace it
112+
board[row][col] = 0;
83113
}
84114
}
85115
}
86-
return true;
116+
return false;
117+
}
118+
119+
/**
120+
* Prints the current state of the Sudoku board in a readable format.
121+
* Each row is printed on a new line, with numbers separated by spaces.
122+
*
123+
* @param board The current state of the Sudoku board.
124+
* @param n The size of the Sudoku board (typically 9 for a standard puzzle).
125+
*/
126+
public static void print(int[][] board, int n) {
127+
// Print the board in a nxn grid format
128+
// if n=9, print the board in a 9x9 grid format
129+
// if n=16, print the board in a 16x16 grid format
130+
for (int r = 0; r < n; r++) {
131+
for (int d = 0; d < n; d++) {
132+
System.out.print(board[r][d]);
133+
System.out.print(" ");
134+
}
135+
System.out.print("\n");
136+
137+
if ((r + 1) % (int) Math.sqrt(n) == 0) {
138+
System.out.print("");
139+
}
140+
}
141+
}
142+
143+
/**
144+
* The driver method to demonstrate solving a Sudoku puzzle.
145+
* A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it
146+
* using the `solveSudoku` method. If a solution is found, it is printed to the console.
147+
*
148+
* @param args Command-line arguments (not used in this program).
149+
*/
150+
public static void main(String[] args) {
151+
int[][] board = new int[][] {
152+
{3, 0, 6, 5, 0, 8, 4, 0, 0},
153+
{5, 2, 0, 0, 0, 0, 0, 0, 0},
154+
{0, 8, 7, 0, 0, 0, 0, 3, 1},
155+
{0, 0, 3, 0, 1, 0, 0, 8, 0},
156+
{9, 0, 0, 8, 6, 3, 0, 0, 5},
157+
{0, 5, 0, 0, 9, 0, 6, 0, 0},
158+
{1, 3, 0, 0, 0, 0, 2, 5, 0},
159+
{0, 0, 0, 0, 0, 0, 0, 7, 4},
160+
{0, 0, 5, 2, 0, 6, 3, 0, 0},
161+
};
162+
int n = board.length;
163+
164+
if (solveSudoku(board, n)) {
165+
print(board, n);
166+
} else {
167+
System.out.println("No solution");
168+
}
87169
}
88170
}

0 commit comments

Comments
 (0)