1
1
package com .thealgorithms .puzzlesandgames ;
2
2
3
- import java .util .Iterator ;
4
- import java .util .NoSuchElementException ;
3
+ public final class Sudoku {
5
4
6
- /**
7
- * Represents a Sudoku board with validation and iteration support.
8
- * The board is always a square grid of size n x n,
9
- * where n must be a perfect square (e.g., 4, 9, 16).
10
- */
11
- class SudokuBoard implements Iterable <SudokuBoard .Cell > {
12
-
13
- private final int size ;
14
- private final int boxSize ;
15
- private final int [][] board ;
16
-
17
- /**
18
- * Constructs a SudokuBoard of the given size.
19
- *
20
- * @param size the dimension of the Sudoku board (must be a perfect square)
21
- * @throws IllegalArgumentException if size is not a positive perfect square
22
- */
23
- public SudokuBoard (int size ) {
24
- if (size <= 0 || Math .sqrt (size ) % 1 != 0 ) {
25
- throw new IllegalArgumentException ("Size must be a perfect square (e.g., 4, 9, 16)" );
26
- }
27
- this .size = size ;
28
- this .boxSize = (int ) Math .sqrt (size );
29
- this .board = new int [size ][size ];
30
- }
31
-
32
- /**
33
- * Returns the size of the board.
34
- *
35
- * @return the board size
36
- */
37
- public int getSize () {
38
- return size ;
39
- }
40
-
41
- /**
42
- * Returns the box (subgrid) size.
43
- *
44
- * @return the size of a subgrid
45
- */
46
- public int getBoxSize () {
47
- return boxSize ;
48
- }
49
-
50
- /**
51
- * Gets the value at the given cell.
52
- *
53
- * @param row the row index
54
- * @param col the column index
55
- * @return the value at the specified cell
56
- * @throws IndexOutOfBoundsException if indices are invalid
57
- */
58
- public int get (int row , int col ) {
59
- validateCell (row , col );
60
- return board [row ][col ];
61
- }
62
-
63
- /**
64
- * Sets the value at the given cell.
65
- *
66
- * @param row the row index
67
- * @param col the column index
68
- * @param value the value to set (0 means empty)
69
- * @throws IndexOutOfBoundsException if indices are invalid
70
- * @throws IllegalArgumentException if value is out of range
71
- */
72
- public void set (int row , int col , int value ) {
73
- validateCell (row , col );
74
- if (value < 0 || value > size ) {
75
- throw new IllegalArgumentException ("Value must be between 0 and " + size );
76
- }
77
- board [row ][col ] = value ;
5
+ private Sudoku () {
6
+ // prevent instantiation
78
7
}
79
8
80
9
/**
81
10
* Checks whether placing a value at the given cell is valid
82
11
* according to Sudoku rules.
83
12
*
13
+ * @param board the Sudoku board
84
14
* @param row the row index
85
15
* @param col the column index
86
- * @param value the value to check
16
+ * @param num the number to check
87
17
* @return true if placement is valid, false otherwise
18
+ * @throws ArrayIndexOutOfBoundsException if indices are out of bounds
88
19
*/
89
- public boolean isValid (int row , int col , int value ) {
90
- validateCell (row , col );
91
- if (value <= 0 || value > size ) {
92
- return false ;
20
+ 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" );
93
25
}
94
26
95
27
// check row
96
28
for (int c = 0 ; c < size ; c ++) {
97
- if (board [row ][c ] == value ) {
29
+ if (board [row ][c ] == num ) {
98
30
return false ;
99
31
}
100
32
}
101
33
102
34
// check column
103
35
for (int r = 0 ; r < size ; r ++) {
104
- if (board [r ][col ] == value ) {
36
+ if (board [r ][col ] == num ) {
105
37
return false ;
106
38
}
107
39
}
108
40
109
- // check box
41
+ int boxSize = ( int ) Math . sqrt ( size );
110
42
int boxRowStart = (row / boxSize ) * boxSize ;
111
43
int boxColStart = (col / boxSize ) * boxSize ;
112
44
45
+ // check box
113
46
for (int r = 0 ; r < boxSize ; r ++) {
114
47
for (int c = 0 ; c < boxSize ; c ++) {
115
- if (board [boxRowStart + r ][boxColStart + c ] == value ) {
48
+ if (board [boxRowStart + r ][boxColStart + c ] == num ) {
116
49
return false ;
117
50
}
118
51
}
@@ -122,102 +55,34 @@ public boolean isValid(int row, int col, int value) {
122
55
}
123
56
124
57
/**
125
- * Ensures that the given cell indices are valid .
58
+ * Solves a Sudoku puzzle using backtracking .
126
59
*
127
- * @param row the row index
128
- * @param col the column index
129
- * @throws IndexOutOfBoundsException if indices are outside the board
130
- */
131
- private void validateCell (int row , int col ) {
132
- if (row < 0 || row >= size || col < 0 || col >= size ) {
133
- throw new IndexOutOfBoundsException ("Cell position out of bounds" );
134
- }
135
- }
136
-
137
- /**
138
- * Represents a single cell on the Sudoku board.
139
- */
140
- public class Cell {
141
- private final int row ;
142
- private final int col ;
143
-
144
- /**
145
- * Constructs a Cell with the given row and column.
146
- *
147
- * @param row the row index
148
- * @param col the column index
149
- */
150
- public Cell (int row , int col ) {
151
- this .row = row ;
152
- this .col = col ;
153
- }
154
-
155
- /**
156
- * Returns the row index of this cell.
157
- *
158
- * @return the row index
159
- */
160
- public int getRow () {
161
- return row ;
162
- }
163
-
164
- /**
165
- * Returns the column index of this cell.
166
- *
167
- * @return the column index
168
- */
169
- public int getCol () {
170
- return col ;
171
- }
172
-
173
- /**
174
- * Gets the current value stored in this cell.
175
- *
176
- * @return the cell value
177
- */
178
- public int getValue () {
179
- return board [row ][col ];
180
- }
181
-
182
- /**
183
- * Sets a value in this cell.
184
- *
185
- * @param value the value to set
186
- */
187
- public void setValue (int value ) {
188
- SudokuBoard .this .set (row , col , value );
189
- }
190
- }
191
-
192
- /**
193
- * Iterator for traversing all cells in the board.
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
194
63
*/
195
- private class CellIterator implements Iterator <Cell > {
196
- private int row = 0 ;
197
- private int col = 0 ;
198
-
199
- @ Override
200
- public boolean hasNext () {
201
- return row < size ;
64
+ 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 ;
202
68
}
203
69
204
- @ Override
205
- public Cell next () {
206
- if (!hasNext ()) {
207
- throw new NoSuchElementException ();
208
- }
209
- Cell cell = new Cell (row , col );
210
- col ++;
211
- if (col == size ) {
212
- col = 0 ;
213
- row ++;
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 ;
83
+ }
214
84
}
215
- return cell ;
216
85
}
217
- }
218
-
219
- @ Override
220
- public Iterator <Cell > iterator () {
221
- return new CellIterator ();
86
+ return true ;
222
87
}
223
88
}
0 commit comments