1
+
1
2
package com .thealgorithms .puzzlesandgames ;
2
3
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 {
4
12
5
13
private Sudoku () {
6
- // prevent instantiation
7
14
}
8
15
9
16
/**
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).
12
23
*
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.
19
29
*/
20
30
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 ) {
30
34
return false ;
31
35
}
32
36
}
33
37
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 ++) {
36
40
if (board [r ][col ] == num ) {
37
41
return false ;
38
42
}
39
43
}
40
44
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 ;
44
49
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 ) {
49
53
return false ;
50
54
}
51
55
}
@@ -55,34 +59,112 @@ public static boolean isSafe(int[][] board, int row, int col, int num) {
55
59
}
56
60
57
61
/**
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.
59
73
*
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.
63
77
*/
64
78
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
+ }
68
96
}
69
97
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 ;
83
113
}
84
114
}
85
115
}
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
+ }
87
169
}
88
170
}
0 commit comments