1-
21package com .thealgorithms .puzzlesandgames ;
32
3+ import java .util .Iterator ;
4+ import java .util .NoSuchElementException ;
5+
46/**
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.
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).
1010 */
11- final class Sudoku {
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+ }
1231
13- private Sudoku () {
32+ /**
33+ * Returns the size of the board.
34+ *
35+ * @return the board size
36+ */
37+ public int getSize () {
38+ return size ;
1439 }
1540
1641 /**
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).
42+ * Returns the box (subgrid) size.
2343 *
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.
44+ * @return the size of a subgrid
2945 */
30- public static boolean isSafe (int [][] board , int row , int col , int num ) {
31- // Check the row for duplicates
32- for (int d = 0 ; d < board .length ; d ++) {
33- if (board [row ][d ] == num ) {
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 ;
78+ }
79+
80+ /**
81+ * Checks whether placing a value at the given cell is valid
82+ * according to Sudoku rules.
83+ *
84+ * @param row the row index
85+ * @param col the column index
86+ * @param value the value to check
87+ * @return true if placement is valid, false otherwise
88+ */
89+ public boolean isValid (int row , int col , int value ) {
90+ validateCell (row , col );
91+ if (value <= 0 || value > size ) {
92+ return false ;
93+ }
94+
95+ // check row
96+ for (int c = 0 ; c < size ; c ++) {
97+ if (board [row ][c ] == value ) {
3498 return false ;
3599 }
36100 }
37101
38- // Check the column for duplicates
39- for (int r = 0 ; r < board . length ; r ++) {
40- if (board [r ][col ] == num ) {
102+ // check column
103+ for (int r = 0 ; r < size ; r ++) {
104+ if (board [r ][col ] == value ) {
41105 return false ;
42106 }
43107 }
44108
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 ;
109+ // check box
110+ int boxRowStart = (row / boxSize ) * boxSize ;
111+ int boxColStart = (col / boxSize ) * boxSize ;
49112
50- for (int r = boxRowStart ; r < boxRowStart + sqrt ; r ++) {
51- for (int d = boxColStart ; d < boxColStart + sqrt ; d ++) {
52- if (board [r ][d ] == num ) {
113+ for (int r = 0 ; r < boxSize ; r ++) {
114+ for (int c = 0 ; c < boxSize ; c ++) {
115+ if (board [boxRowStart + r ][boxColStart + c ] == value ) {
53116 return false ;
54117 }
55118 }
@@ -59,112 +122,102 @@ public static boolean isSafe(int[][] board, int row, int col, int num) {
59122 }
60123
61124 /**
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.
125+ * Ensures that the given cell indices are valid.
73126 *
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.
127+ * @param row the row index
128+ * @param col the column index
129+ * @throws IndexOutOfBoundsException if indices are outside the board
77130 */
78- public static boolean solveSudoku (int [][] board , int n ) {
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- }
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" );
96134 }
135+ }
97136
98- // No empty space left
99- if (isEmpty ) {
100- return true ;
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 ;
101153 }
102154
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 ;
113- }
114- }
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 );
115189 }
116- return false ;
117190 }
118191
119192 /**
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).
193+ * Iterator for traversing all cells in the board.
125194 */
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 " );
195+ private class CellIterator implements Iterator <Cell > {
196+ private int row = 0 ;
197+ private int col = 0 ;
136198
137- if ((r + 1 ) % (int ) Math .sqrt (n ) == 0 ) {
138- System .out .print ("" );
199+ @ Override
200+ public boolean hasNext () {
201+ return row < size ;
202+ }
203+
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 ++;
139214 }
215+ return cell ;
140216 }
141217 }
142218
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- }
219+ @ Override
220+ public Iterator <Cell > iterator () {
221+ return new CellIterator ();
169222 }
170223}
0 commit comments