codemistic / Data-Structures-and-Algorithms

A repository to help the open-source community with DSA related contributions
MIT License
381 stars 351 forks source link

Sudoku solver into a User Interface (UI) application #756

Open Ansari-Shamaila opened 1 month ago

Ansari-Shamaila commented 1 month ago

How It Works: UI Creation: The SudokuUI class creates a 9x9 grid using JTextField for user input. Input Parsing: The parseInput() method reads the values from the text fields and converts them to an integer array (board). Sudoku Solving: When the "Solve" button is clicked, the solveSudoku() method is triggered, which solves the puzzle using the SudokuOptimized class and displays the solution in the UI. Output Display: After solving, the solution is displayed in the grid, and a message dialog informs the user if the puzzle was solved or unsolvable.

import javax.swing.; import java.awt.; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;

public class SudokuUI extends JFrame {

private static final int SIZE = 9;  // Size of the Sudoku grid
private JTextField[][] grid = new JTextField[SIZE][SIZE];  // 9x9 JTextFields for the grid
private int[][] board = new int[SIZE][SIZE];  // Sudoku board

public SudokuUI() {
    setTitle("Sudoku Solver");
    setSize(600, 600);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(new BorderLayout());

    // Create the Sudoku grid panel
    JPanel gridPanel = new JPanel(new GridLayout(SIZE, SIZE));
    for (int row = 0; row < SIZE; row++) {
        for (int col = 0; col < SIZE; col++) {
            grid[row][col] = new JTextField();
            grid[row][col].setHorizontalAlignment(JTextField.CENTER);
            grid[row][col].setFont(new Font("Arial", Font.BOLD, 20));
            grid[row][col].setBorder(BorderFactory.createLineBorder(Color.BLACK));
            gridPanel.add(grid[row][col]);
        }
    }

    // Button panel with "Solve" button
    JPanel buttonPanel = new JPanel();
    JButton solveButton = new JButton("Solve");
    solveButton.setFont(new Font("Arial", Font.BOLD, 16));
    solveButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            solveSudoku();
        }
    });
    buttonPanel.add(solveButton);

    // Add panels to the frame
    add(gridPanel, BorderLayout.CENTER);
    add(buttonPanel, BorderLayout.SOUTH);
}

// Parse the Sudoku grid from the UI into the board array
private void parseInput() {
    for (int row = 0; row < SIZE; row++) {
        for (int col = 0; col < SIZE; col++) {
            String text = grid[row][col].getText();
            if (text.isEmpty()) {
                board[row][col] = 0;  // Empty cells are represented as 0
            } else {
                board[row][col] = Integer.parseInt(text);
            }
        }
    }
}

// Display the solved Sudoku on the UI
private void displaySolution() {
    for (int row = 0; row < SIZE; row++) {
        for (int col = 0; col < SIZE; col++) {
            grid[row][col].setText(String.valueOf(board[row][col]));
        }
    }
}

// Solve the Sudoku using the existing solver algorithm
private void solveSudoku() {
    parseInput();  // Parse the UI input into the board array

    // Create an instance of the Sudoku solver with the current board
    SudokuOptimized solver = new SudokuOptimized(board);
    if (solver.solve()) {
        displaySolution();  // Display the solution on the UI
        JOptionPane.showMessageDialog(this, "Sudoku Solved!");
    } else {
        JOptionPane.showMessageDialog(this, "Unsolvable Sudoku");
    }
}

public static void main(String[] args) {
    // Create and display the Sudoku UI
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            SudokuUI sudokuUI = new SudokuUI();
            sudokuUI.setVisible(true);
        }
    });
}

}

class SudokuOptimized {

private int[][] board;
public static final int EMPTY = 0;
public static final int SIZE = 9;

public SudokuOptimized(int[][] board) {
    this.board = board;
}

// Check if a number can be placed at a specific cell
private boolean isSafe(int row, int col, int num) {
    int boxRowStart = row - row % 3;
    int boxColStart = col - col % 3;

    for (int i = 0; i < SIZE; i++) {
        if (board[row][i] == num || board[i][col] == num || 
            board[boxRowStart + i / 3][boxColStart + i % 3] == num) {
            return false;
        }
    }
    return true;
}

// Find the next empty cell (used for backtracking)
private int[] findNextEmptyCell() {
    for (int row = 0; row < SIZE; row++) {
        for (int col = 0; col < SIZE; col++) {
            if (board[row][col] == EMPTY) {
                return new int[] {row, col};
            }
        }
    }
    return null;
}

// Solve the Sudoku using backtracking
public boolean solve() {
    int[] emptyCell = findNextEmptyCell();
    if (emptyCell == null) return true;  // No empty cell, puzzle solved

    int row = emptyCell[0];
    int col = emptyCell[1];

    for (int num = 1; num <= SIZE; num++) {
        if (isSafe(row, col, num)) {
            board[row][col] = num;
            if (solve()) return true;
            board[row][col] = EMPTY;
        }
    }
    return false;
}

} Output: sudoku