Skip to content

Commit 5a92386

Browse files
committed
Add new algorithm Sudoku Solver in Backtracking
1 parent 842ff52 commit 5a92386

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.thealgorithms.backtracking;
2+
3+
/**
4+
* Java program for Sudoku Solver using Backtracking Algorithm.
5+
* Solves a given Sudoku puzzle by filling the empty cells (denoted by '0') with
6+
* valid digits (1-9).
7+
*/
8+
public final class SudokuSolver {
9+
private SudokuSolver() {
10+
}
11+
12+
/**
13+
* Check if placing a number in a specific cell is valid.
14+
* Validity is checked based on the row, column, and 3x3 subgrid.
15+
*
16+
* @param board The 9x9 Sudoku board
17+
* @param row The row index
18+
* @param col The column index
19+
* @param num The number to be placed in the cell
20+
* @return true if placing the number is valid, false otherwise
21+
*/
22+
public static boolean isValidMove(final int[][] board, final int row, final int col, final int num) {
23+
// Check the row
24+
for (int x = 0; x < 9; x++) {
25+
if (board[row][x] == num) {
26+
return false;
27+
}
28+
}
29+
30+
// Check the column
31+
for (int x = 0; x < 9; x++) {
32+
if (board[x][col] == num) {
33+
return false;
34+
}
35+
}
36+
37+
// Check the 3x3 sub-grid
38+
int startRow = row / 3 * 3;
39+
int startCol = col / 3 * 3;
40+
for (int i = 0; i < 3; i++) {
41+
for (int j = 0; j < 3; j++) {
42+
if (board[startRow + i][startCol + j] == num) {
43+
return false;
44+
}
45+
}
46+
}
47+
48+
return true;
49+
}
50+
51+
/**
52+
* Solve the Sudoku puzzle using backtracking.
53+
*
54+
* @param board The 9x9 Sudoku board
55+
* @return true if the puzzle is solved, false if no solution exists
56+
*/
57+
public static boolean solveSudoku(final int[][] board) {
58+
// Traverse the board
59+
for (int row = 0; row < 9; row++) {
60+
for (int col = 0; col < 9; col++) {
61+
// Empty cell found
62+
if (board[row][col] == 0) {
63+
// Try placing numbers 1-9 in the empty cell
64+
for (int num = 1; num <= 9; num++) {
65+
if (isValidMove(board, row, col, num)) {
66+
board[row][col] = num;
67+
68+
// Recursively try to solve the board with the new number
69+
if (solveSudoku(board)) {
70+
return true; // Solution found
71+
}
72+
board[row][col] = 0; // Backtrack
73+
}
74+
}
75+
return false; // No valid number can be placed in this cell
76+
}
77+
}
78+
}
79+
80+
return true; // Sudoku is solved if no empty cells are left
81+
}
82+
83+
/**
84+
* Print the current state of the Sudoku board.
85+
*
86+
* @param board The 9x9 Sudoku board
87+
*/
88+
public static void printBoard(final int[][] board) {
89+
for (int i = 0; i < 9; i++) {
90+
for (int j = 0; j < 9; j++) {
91+
System.out.print(board[i][j] + " ");
92+
}
93+
System.out.println();
94+
}
95+
}
96+
97+
public static void main(String[] args) {
98+
// Example 9x9 Sudoku board with some cells pre-filled and some cells empty (0)
99+
int[][] board = {
100+
{ 5, 3, 0, 0, 7, 0, 0, 0, 0 },
101+
{ 6, 0, 0, 1, 9, 5, 0, 0, 0 },
102+
{ 0, 9, 8, 0, 0, 0, 0, 6, 0 },
103+
{ 8, 0, 0, 0, 6, 0, 0, 0, 3 },
104+
{ 4, 0, 0, 8, 0, 3, 0, 0, 1 },
105+
{ 7, 0, 0, 0, 2, 0, 0, 0, 6 },
106+
{ 0, 6, 0, 0, 0, 0, 2, 8, 0 },
107+
{ 0, 0, 0, 4, 1, 9, 0, 0, 5 },
108+
{ 0, 0, 0, 0, 8, 0, 0, 7, 9 }
109+
};
110+
111+
System.out.println("Original Sudoku Board:");
112+
printBoard(board);
113+
114+
// Solve the Sudoku puzzle
115+
if (solveSudoku(board)) {
116+
System.out.println("\nSolved Sudoku Board:");
117+
printBoard(board);
118+
} else {
119+
System.out.println("\nNo solution exists for the given Sudoku puzzle.");
120+
}
121+
}
122+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
5+
import static org.junit.jupiter.api.Assertions.assertFalse;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
/**
10+
* Test class for SudokuSolver using JUnit 5.
11+
* This class verifies the correctness of the Sudoku solver algorithm.
12+
*/
13+
class SudokuSolverTest {
14+
15+
/**
16+
* Test case for solving a solvable Sudoku puzzle.
17+
*/
18+
@Test
19+
void testForValidSudoku() {
20+
int[][] board = {
21+
{ 5, 3, 0, 0, 7, 0, 0, 0, 0 },
22+
{ 6, 0, 0, 1, 9, 5, 0, 0, 0 },
23+
{ 0, 9, 8, 0, 0, 0, 0, 6, 0 },
24+
{ 8, 0, 0, 0, 6, 0, 0, 0, 3 },
25+
{ 4, 0, 0, 8, 0, 3, 0, 0, 1 },
26+
{ 7, 0, 0, 0, 2, 0, 0, 0, 6 },
27+
{ 0, 6, 0, 0, 0, 0, 2, 8, 0 },
28+
{ 0, 0, 0, 4, 1, 9, 0, 0, 5 },
29+
{ 0, 0, 0, 0, 8, 0, 0, 7, 9 }
30+
};
31+
32+
// Solve the Sudoku puzzle
33+
boolean solved = SudokuSolver.solveSudoku(board);
34+
35+
// Check that the puzzle is solvable
36+
assertTrue(solved, "The Sudoku puzzle should be solvable.");
37+
38+
// Expected output for a solved puzzle
39+
int[][] expected = {
40+
{ 5, 3, 4, 6, 7, 8, 9, 1, 2 },
41+
{ 6, 7, 2, 1, 9, 5, 3, 4, 8 },
42+
{ 1, 9, 8, 3, 4, 2, 5, 6, 7 },
43+
{ 8, 5, 9, 7, 6, 1, 4, 2, 3 },
44+
{ 4, 2, 6, 8, 5, 3, 7, 9, 1 },
45+
{ 7, 1, 3, 9, 2, 4, 8, 5, 6 },
46+
{ 9, 6, 1, 5, 3, 7, 2, 8, 4 },
47+
{ 2, 8, 7, 4, 1, 9, 6, 3, 5 },
48+
{ 3, 4, 5, 2, 8, 6, 1, 7, 9 }
49+
};
50+
51+
// Verify the solved board matches the expected result
52+
assertArrayEquals(expected, board);
53+
}
54+
55+
/**
56+
* Test case for unsolvable Sudoku puzzle.
57+
*/
58+
@Test
59+
void testForUnsolvableSudoku() {
60+
int[][] board = {
61+
{ 5, 3, 0, 0, 7, 0, 0, 0, 0 },
62+
{ 6, 0, 0, 1, 9, 5, 0, 0, 0 },
63+
{ 0, 9, 8, 0, 0, 0, 0, 6, 0 },
64+
{ 8, 0, 0, 0, 6, 0, 0, 0, 3 },
65+
{ 4, 0, 0, 8, 0, 3, 0, 0, 1 },
66+
{ 7, 0, 0, 0, 2, 0, 0, 0, 6 },
67+
{ 0, 6, 0, 0, 0, 0, 2, 8, 0 },
68+
{ 0, 0, 0, 4, 1, 9, 0, 0, 5 },
69+
{ 0, 0, 0, 0, 8, 0, 0, 7, 9 }
70+
};
71+
72+
// Modify the puzzle to make it unsolvable (e.g., repeat numbers)
73+
board[0][0] = 5;
74+
75+
// Attempt to solve the unsolvable puzzle
76+
boolean solved = SudokuSolver.solveSudoku(board);
77+
78+
// Check that the puzzle is not solvable
79+
assertFalse(solved, "The Sudoku puzzle should be unsolvable.");
80+
}
81+
82+
/**
83+
* Test case for an already solved Sudoku puzzle.
84+
*/
85+
@Test
86+
void testForAlreadySolvedSudoku() {
87+
int[][] board = {
88+
{ 5, 3, 4, 6, 7, 8, 9, 1, 2 },
89+
{ 6, 7, 2, 1, 9, 5, 3, 4, 8 },
90+
{ 1, 9, 8, 3, 4, 2, 5, 6, 7 },
91+
{ 8, 5, 9, 7, 6, 1, 4, 2, 3 },
92+
{ 4, 2, 6, 8, 5, 3, 7, 9, 1 },
93+
{ 7, 1, 3, 9, 2, 4, 8, 5, 6 },
94+
{ 9, 6, 1, 5, 3, 7, 2, 8, 4 },
95+
{ 2, 8, 7, 4, 1, 9, 6, 3, 5 },
96+
{ 3, 4, 5, 2, 8, 6, 1, 7, 9 }
97+
};
98+
99+
// Check that the board is already solved
100+
boolean solved = SudokuSolver.solveSudoku(board);
101+
102+
// Check that no changes are made to the already solved board
103+
assertTrue(solved, "The Sudoku board should be already solved.");
104+
}
105+
106+
/**
107+
* Test case for solving an empty Sudoku puzzle (no empty cells).
108+
*/
109+
@Test
110+
void testForEmptySudoku() {
111+
int[][] board = {
112+
{ 5, 3, 4, 6, 7, 8, 9, 1, 2 },
113+
{ 6, 7, 2, 1, 9, 5, 3, 4, 8 },
114+
{ 1, 9, 8, 3, 4, 2, 5, 6, 7 },
115+
{ 8, 5, 9, 7, 6, 1, 4, 2, 3 },
116+
{ 4, 2, 6, 8, 5, 3, 7, 9, 1 },
117+
{ 7, 1, 3, 9, 2, 4, 8, 5, 6 },
118+
{ 9, 6, 1, 5, 3, 7, 2, 8, 4 },
119+
{ 2, 8, 7, 4, 1, 9, 6, 3, 5 },
120+
{ 3, 4, 5, 2, 8, 6, 1, 7, 9 }
121+
};
122+
123+
// Solve the "already filled" puzzle
124+
boolean solved = SudokuSolver.solveSudoku(board);
125+
126+
// Check that the board is already solved
127+
assertTrue(solved, "The Sudoku board should be solved (no empty cells).");
128+
}
129+
}

0 commit comments

Comments
 (0)