Skip to content

Indra dev #5699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
106 changes: 106 additions & 0 deletions src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.thealgorithms.backtracking;

/**
* Solves a Sudoku of any level and prints solved Sudoku.
* This class is a utility and should not be instantiated.
* @author Indraneela Doradla (<a href="https://github.com/captiosus1">git-Indraneela Doradla</a>)
*/
public final class SudokuSolver {

/**
* Private constructor to prevent instantiation.
*/
private SudokuSolver() {
// Utility class
}

/**
* Solves the Sudoku using backtracking.
* @param board the Sudoku grid
* @return boolean indicating if the Sudoku can be solved
*/
public static boolean solveSudoku(int[][] board) {
int r = -1;
int c = -1;
boolean isEmpty = true;

// Find the first empty position
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == 0) {
r = i;
c = j;
isEmpty = false;
break;
}
}
if (!isEmpty) {
break;
}
}

// If no empty position is found, the Sudoku is solved
if (isEmpty) {
return true;
}

// Try filling the empty position with numbers from 1 to 9
for (int num = 1; num <= 9; num++) {
if (isSafe(board, r, c, num)) {
board[r][c] = num;
if (solveSudoku(board)) {
return true; // Successfully solved
}
board[r][c] = 0; // Backtrack
}
}

return false; // No solution found, backtrack
}

/**
* Checks if placing a number at the given position is valid.
* @param board the Sudoku grid
* @param r row index
* @param c column index
* @param val the value to place
* @return boolean indicating if it's safe to place the value
*/
public static boolean isSafe(int[][] board, int r, int c, int val) {
// Check the row and column
for (int i = 0; i < board.length; i++) {
if (board[i][c] == val || board[r][i] == val) {
return false;
}
}

// Check the 3x3 subgrid
int sqrt = (int) Math.sqrt(board.length);
int boxRowStart = r - r % sqrt;
int boxColStart = c - c % sqrt;

for (int i = boxRowStart; i < boxRowStart + sqrt; i++) {
for (int j = boxColStart; j < boxColStart + sqrt; j++) {
if (board[i][j] == val) {
return false;
}
}
}

return true;
}

/**
* Prints the Sudoku grid.
* @param board the Sudoku grid
*/
public static void printSudoku(int[][] board) {
for (int[] row : board) {
for (int num : row) {
System.out.print(num + " ");
}
System.out.println();
}
System.out.println();
}
}
77 changes: 77 additions & 0 deletions src/test/java/com/thealgorithms/others/SudokuTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.thealgorithms.others;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

import org.junit.jupiter.api.Test;

public class SudokuTest {

@Test
public void testSolvableSudoku() {
int[][] board = new int[][] {
{3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 0, 0, 0, 0, 0, 0, 0},
{0, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 0, 0}
};

assertTrue(Sudoku.solveSudoku(board, board.length), "The puzzle should be solvable.");
}

@Test
public void testUnsolvableSudoku() {
int[][] board = new int[][] {
{3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 1, 0, 0, 0, 0, 0, 0},
{9, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 1, 0}
};

assertFalse(Sudoku.solveSudoku(board, board.length), "The puzzle should be unsolvable.");
}

@Test
public void testEmptySudoku() {
int[][] board = new int[][] {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
};

assertTrue(Sudoku.solveSudoku(board, board.length), "An empty puzzle should be solvable.");
}

@Test
public void testAlreadySolvedSudoku() {
int[][] board = new int[][] {
{5, 3, 4, 6, 7, 8, 9, 1, 2},
{6, 7, 2, 1, 9, 5, 3, 4, 8},
{1, 9, 8, 3, 4, 2, 5, 6, 7},
{8, 5, 9, 7, 6, 1, 4, 2, 3},
{4, 2, 6, 8, 5, 3, 7, 9, 1},
{7, 1, 3, 9, 2, 4, 8, 5, 6},
{9, 6, 1, 5, 3, 7, 2, 8, 4},
{2, 8, 7, 4, 1, 9, 6, 3, 5},
{3, 4, 5, 2, 8, 6, 1, 7, 9}
};

assertTrue(Sudoku.solveSudoku(board, board.length), "An already solved puzzle should return true.");
}
}