Compare commits

...

3 commits

5 changed files with 319 additions and 35 deletions

View file

@ -2,10 +2,16 @@ run:
./gradlew run
test:
./gradlew test
./gradlew test --rerun-tasks
doc:
./gradlew javadoc --rerun-tasks
clean:
fd -td -I build -x rm -r
watch:
watchexec -c -w app/src "just test && just run"
watchdoc:
watchexec -c -w app/src "just doc"

View file

@ -0,0 +1,86 @@
package gui;
import sudoku.SudokuSolver;
import java.awt.event.*;
/**
* SolverController is a controller for the SudokuSolver interface
*/
public class SudokuController {
SudokuSolver model;
SudokuView view;
/**
* Constructor
*
* @param model SudokuSolver model
* @param view SudokuView view
*/
public SudokuController(SudokuSolver model, SudokuView view) {
this.model = model;
this.view = view;
// Add action listeners to the buttons
view.addSolveButtonListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Solve the board
model.solve();
// Update the view
view.updateView(model.getBoard());
}
});
view.addResetButtonListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Clear the board
model.clear();
// Update the view
view.updateView(model.getBoard());
}
});
view.addRandomButtonListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Randomize the board
model.randomizeBoard();
// Update the view
view.updateView(model.getBoard());
}
});
view.addCellClickListener(new CellActionListener());
}
/** Start the GUI */
public void start() {
view.setVisible(true);
}
/**
* CellActionListener is an ActionListener for the Sudoku grid cells
*/
private class CellActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Get the row and column from the clicked cell
int row = view.getSelectedRow();
int col = view.getSelectedColumn();
String inputText = view.getCellValue(row, col);
int value = Integer.parseInt(inputText);
// Check if the input is legal and update the model and view
if (model.isLegal(row, col, value)) {
model.set(row, col, value);
view.updateView(model.getBoard());
} else {
view.showErrorMessage("Invalid input. Try again.");
}
}
}
}

View file

@ -0,0 +1,186 @@
package gui;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* SolverView is a GUI for the SudokuSolver interface
*/
public class SudokuView extends JFrame {
/** The grid of text fields */
private JTextField[][] grid;
/** Button for solve */
private JButton solveButton;
/** Button for reset */
private JButton resetButton;
/** Button for random */
private JButton randomButton;
/** Constructor */
public SudokuView() {
setTitle("Sudoku Solver");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
initializeGrid();
initializeButtons();
pack();
setLocationRelativeTo(null);
}
/** Initialize the grid, called by the constructor */
private void initializeGrid() {
grid = new JTextField[9][9];
JPanel gridPanel = new JPanel(new GridLayout(9, 9));
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
grid[row][col] = new JTextField(2);
grid[row][col].setHorizontalAlignment(JTextField.CENTER);
gridPanel.add(grid[row][col]);
}
}
add(gridPanel, BorderLayout.CENTER);
}
/** Initialize the buttons, called by the constructor */
private void initializeButtons() {
solveButton = new JButton("Solve");
resetButton = new JButton("Reset");
randomButton = new JButton("Randomize");
JPanel buttonPanel = new JPanel();
buttonPanel.add(solveButton);
buttonPanel.add(resetButton);
buttonPanel.add(randomButton);
add(buttonPanel, BorderLayout.SOUTH);
}
/**
* Update the view with a new grid
*
* @param newGrid the new grid to display
*/
public void updateView(int[][] newGrid) {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (newGrid[row][col] != 0) {
grid[row][col].setText(String.valueOf(newGrid[row][col]));
} else {
grid[row][col].setText("");
}
}
}
}
/**
* Method to add ActionListener to solve button
*
* @param listener the ActionListener to add
*/
public void addSolveButtonListener(ActionListener listener) {
solveButton.addActionListener(listener);
}
/**
* Method to add ActionListener to reset button
*
* @param listener the ActionListener to add
*/
public void addResetButtonListener(ActionListener listener) {
resetButton.addActionListener(listener);
}
/**
* Method to add ActionListener to randomize button
*
* @param listener the ActionListener to add
*/
public void addRandomButtonListener(ActionListener listener) {
randomButton.addActionListener(listener);
}
/**
* Method to add ActionListener to individual cells in the grid
* <p>
* Assumes that the ActionListener will be the same for all cells
* and that the listener will be capable of determining which cell
* was clicked
*
* @param listener the ActionListener to add
*/
public void addCellClickListener(ActionListener listener) {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
grid[row][col].addActionListener(listener);
}
}
}
/**
* Getter method to retrieve the values from the text fields
*
* @param row the row of the cell
* @param col the column of the cell
* @return the value of the cell
*/
public String getCellValue(int row, int col) {
return grid[row][col].getText();
}
/**
* Method to get the selected row (example implementation)
*
* @return the selected row, or -1 if no cell is selected
*/
public int getSelectedRow() {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (grid[row][col].isFocusOwner()) {
return row;
}
}
}
return -1; // Return -1 if no cell is selected
}
/**
* Method to get the selected column (example implementation)
*
* @return the selected row, or -1 if no cell is selected
*/
public int getSelectedColumn() {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (grid[row][col].isFocusOwner()) {
return col;
}
}
}
return -1; // Return -1 if no cell is selected
}
/**
* Methods to show dialogs
*
* @param message the message to display
* @return the user input
*/
public String showInputDialog(String message) {
return JOptionPane.showInputDialog(this, message);
}
/**
* Method to show error messages
*
* @param message the message to display
*/
public void showErrorMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
}

View file

@ -1,40 +1,34 @@
package sudoku;
/** Solver is a class that implements the SudokuSolver interface */
public class Solver implements SudokuSolver {
private int[][] board = null;
private int tries = 0;
/** Constructor */
public Solver() {
board = new int[9][9];
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public void setBoard(int[][] board) {
this.board = board;
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public int[][] getBoard() {
return board;
}
/**
* Resets the board to all zeros
*/
/** Resets the board to all zeros */
@Override
public void clear() {
board = new int[9][9];
}
/**
* {@inheritDoc}
*/
/*{@inheritDoc} */
@Override
public boolean solve() {
return solve(0, 0);
@ -98,9 +92,7 @@ public class Solver implements SudokuSolver {
randomizeBoard(3);
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public void randomizeBoard(int difficulty) {
int amount_prefilled = (difficulty * 9) + 1;
@ -121,9 +113,7 @@ public class Solver implements SudokuSolver {
}
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public void set(int row, int col, int val) {
if (row < 9 && col < 9) {
@ -131,9 +121,7 @@ public class Solver implements SudokuSolver {
}
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public int get(int row, int col) {
if (row < 9 && col < 9) {
@ -142,9 +130,7 @@ public class Solver implements SudokuSolver {
return 0;
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
@Override
public boolean isLegal(int row, int col, int num) {
// Sanity check
@ -174,9 +160,7 @@ public class Solver implements SudokuSolver {
return true;
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public boolean isSolvable() {
// We want to work on a copy
int[][] copy = new int[9][9];

View file

@ -1,12 +1,34 @@
package sudoku;
import gui.SudokuController;
import gui.SudokuView;
/** SolverMain is the main class for the Sudoku Solver */
public class SolverMain {
private Solver model;
private SudokuView view;
private SudokuController controller;
/** Constructor */
SolverMain() {
model = new Solver();
view = new SudokuView();
controller = new SudokuController(model, view);
}
/** Start the GUI */
void start() {
controller.start();
}
/**
* Main method
*
* @param args command line arguments
*/
public static void main(String[] args) {
Solver s = new Solver();
System.out.println(s.toString());
s.randomizeBoard();
System.out.println(s.toString());
s.solve();
System.out.println(s.toString());
SolverMain main = new SolverMain();
main.start();
}
}