Working parser, file chooser and sample files
This commit is contained in:
parent
175545d3d5
commit
521b3fb05b
6 changed files with 163 additions and 4 deletions
9
app/sample_sudokus/demo_from_lab.txt
Normal file
9
app/sample_sudokus/demo_from_lab.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
0 0 9 0 7 1 3 0 0
|
||||||
|
0 0 1 0 0 0 0 0 0
|
||||||
|
6 0 0 0 9 0 0 4 7
|
||||||
|
5 0 0 9 0 4 0 0 0
|
||||||
|
1 0 4 0 0 0 2 0 9
|
||||||
|
0 0 0 1 0 8 0 0 4
|
||||||
|
7 3 0 0 1 0 0 0 2
|
||||||
|
0 0 0 0 0 0 5 0 0
|
||||||
|
0 0 8 2 4 0 6 0 0
|
|
@ -54,7 +54,23 @@ public class SudokuController {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
view.addCellClickListener(new CellActionListener());
|
view.addFileButtonListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
// Open a file, view handles the parsing internally via SudokuParser
|
||||||
|
int[][] newBoard = view.openFile();
|
||||||
|
|
||||||
|
// If the file was parsed successfully
|
||||||
|
if (newBoard != null) {
|
||||||
|
// Set the model
|
||||||
|
model.setBoard(newBoard);
|
||||||
|
// Update the view
|
||||||
|
view.updateView(model.getBoard());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
view.addCellActionListener(new CellActionListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start the GUI */
|
/** Start the GUI */
|
||||||
|
|
|
@ -4,6 +4,8 @@ import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
|
||||||
|
import sudoku.SudokuParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SolverView is a GUI for the SudokuSolver interface
|
* SolverView is a GUI for the SudokuSolver interface
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +19,8 @@ public class SudokuView extends JFrame {
|
||||||
private JButton resetButton;
|
private JButton resetButton;
|
||||||
/** Button for random */
|
/** Button for random */
|
||||||
private JButton randomButton;
|
private JButton randomButton;
|
||||||
|
/** Button for picking a Sudoku-file */
|
||||||
|
private JButton fileButton;
|
||||||
|
|
||||||
/** Constructor */
|
/** Constructor */
|
||||||
public SudokuView() {
|
public SudokuView() {
|
||||||
|
@ -52,11 +56,13 @@ public class SudokuView extends JFrame {
|
||||||
solveButton = new JButton("Solve");
|
solveButton = new JButton("Solve");
|
||||||
resetButton = new JButton("Reset");
|
resetButton = new JButton("Reset");
|
||||||
randomButton = new JButton("Randomize");
|
randomButton = new JButton("Randomize");
|
||||||
|
fileButton = new JButton("Open file");
|
||||||
|
|
||||||
JPanel buttonPanel = new JPanel();
|
JPanel buttonPanel = new JPanel();
|
||||||
buttonPanel.add(solveButton);
|
buttonPanel.add(solveButton);
|
||||||
buttonPanel.add(resetButton);
|
buttonPanel.add(resetButton);
|
||||||
buttonPanel.add(randomButton);
|
buttonPanel.add(randomButton);
|
||||||
|
buttonPanel.add(fileButton);
|
||||||
|
|
||||||
add(buttonPanel, BorderLayout.SOUTH);
|
add(buttonPanel, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
|
@ -105,6 +111,15 @@ public class SudokuView extends JFrame {
|
||||||
randomButton.addActionListener(listener);
|
randomButton.addActionListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to add ActionListener to file button
|
||||||
|
*
|
||||||
|
* @param listener the ActionListener to add
|
||||||
|
*/
|
||||||
|
public void addFileButtonListener(ActionListener listener) {
|
||||||
|
fileButton.addActionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to add ActionListener to individual cells in the grid
|
* Method to add ActionListener to individual cells in the grid
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -114,7 +129,7 @@ public class SudokuView extends JFrame {
|
||||||
*
|
*
|
||||||
* @param listener the ActionListener to add
|
* @param listener the ActionListener to add
|
||||||
*/
|
*/
|
||||||
public void addCellClickListener(ActionListener listener) {
|
public void addCellActionListener(ActionListener listener) {
|
||||||
for (int row = 0; row < 9; row++) {
|
for (int row = 0; row < 9; row++) {
|
||||||
for (int col = 0; col < 9; col++) {
|
for (int col = 0; col < 9; col++) {
|
||||||
grid[row][col].addActionListener(listener);
|
grid[row][col].addActionListener(listener);
|
||||||
|
@ -183,4 +198,35 @@ public class SudokuView extends JFrame {
|
||||||
public void showErrorMessage(String message) {
|
public void showErrorMessage(String message) {
|
||||||
JOptionPane.showMessageDialog(this, message);
|
JOptionPane.showMessageDialog(this, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to open a file picker dialog
|
||||||
|
*
|
||||||
|
* @return 2D array of integers representing the Sudoku board
|
||||||
|
*/
|
||||||
|
public int[][] openFile() {
|
||||||
|
// Create a file chooser and set all related options
|
||||||
|
JFileChooser fileChooser = new JFileChooser();
|
||||||
|
fileChooser.setCurrentDirectory(new java.io.File("."));
|
||||||
|
fileChooser.setDialogTitle("Select a Sudoku file");
|
||||||
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
fileChooser.setAcceptAllFileFilterUsed(false);
|
||||||
|
|
||||||
|
// Show the file chooser and return if the user cancels
|
||||||
|
int returnValue = fileChooser.showOpenDialog(this);
|
||||||
|
if (returnValue != JFileChooser.APPROVE_OPTION) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the path
|
||||||
|
String filepath = fileChooser.getSelectedFile().getAbsolutePath();
|
||||||
|
|
||||||
|
// Try to parse it
|
||||||
|
try {
|
||||||
|
return SudokuParser.parseSudoku(filepath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
showErrorMessage(e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ public class Solver implements SudokuSolver {
|
||||||
*/
|
*/
|
||||||
private boolean solve(int row, int col) {
|
private boolean solve(int row, int col) {
|
||||||
if (++tries >= 10000) {
|
if (++tries >= 10000) {
|
||||||
if (tries == 10000)
|
|
||||||
System.out.println(String.format("Likely unsolvable. Tries: %d", tries));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
73
app/src/main/java/sudoku/SudokuParser.java
Normal file
73
app/src/main/java/sudoku/SudokuParser.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package sudoku;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
/** Helpers class for parsing Sudoku files */
|
||||||
|
public class SudokuParser {
|
||||||
|
private static final int BOARD_SIZE = 9;
|
||||||
|
|
||||||
|
// * Empty private constructor */
|
||||||
|
private SudokuParser() {
|
||||||
|
// Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Sudoku file and returns a 2D array of integers
|
||||||
|
*
|
||||||
|
* @param filePath Path to the Sudoku file
|
||||||
|
* @return 2D array of integers representing the Sudoku board
|
||||||
|
* @throws IOException If an IO error occurs
|
||||||
|
* @throws FileNotFoundException When the file cannot be found
|
||||||
|
* @throws NumberFormatException When the file contains invalid characters
|
||||||
|
* @throws IllegalArgumentException When the file contains an invalid number of
|
||||||
|
* rows or columns
|
||||||
|
*/
|
||||||
|
public static int[][] parseSudoku(String filePath)
|
||||||
|
throws IOException, FileNotFoundException, NumberFormatException, IllegalArgumentException {
|
||||||
|
int[][] sudokuBoard = new int[BOARD_SIZE][BOARD_SIZE];
|
||||||
|
|
||||||
|
// In practice we could just split the entire file into a single string and then
|
||||||
|
// parse it into an array of integers, which is then partitioned into a 2D
|
||||||
|
// array.
|
||||||
|
// However, this is how the assignment is specified, so we will do it this way.
|
||||||
|
|
||||||
|
// Try to read the file with a BufferedReader
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
|
||||||
|
String line;
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
// While there are lines to read and we haven't reached the end of the board
|
||||||
|
while ((line = reader.readLine()) != null && row < BOARD_SIZE) {
|
||||||
|
// Split it into an array of strings
|
||||||
|
String[] values = line.trim().split("\\s+");
|
||||||
|
|
||||||
|
// Check that the number of columns is correct
|
||||||
|
if (values.length != BOARD_SIZE) {
|
||||||
|
throw new IllegalArgumentException("Invalid number of columns in the Sudoku file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the strings into integers and add them to the board
|
||||||
|
for (int col = 0; col < BOARD_SIZE; col++) {
|
||||||
|
sudokuBoard[row][col] = Integer.parseInt(values[col]); // Throws NumberFormatException
|
||||||
|
}
|
||||||
|
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row != BOARD_SIZE) {
|
||||||
|
throw new IllegalArgumentException("Invalid number of rows in the Sudoku file.");
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new FileNotFoundException("The Sudoku file could not be found.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IOException("An error occurred while reading the Sudoku file.");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new NumberFormatException("The Sudoku file contains invalid characters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sudokuBoard;
|
||||||
|
}
|
||||||
|
}
|
17
app/src/test/java/sudoku/SudokuParserTest.java
Normal file
17
app/src/test/java/sudoku/SudokuParserTest.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package sudoku;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class SudokuParserTest {
|
||||||
|
@Test
|
||||||
|
void constructorTest() {
|
||||||
|
int[][] board;
|
||||||
|
try {
|
||||||
|
board = SudokuParser.parseSudoku("sample_sudokus/demo_from_lab.txt");
|
||||||
|
} catch (Exception e) {
|
||||||
|
board = null;
|
||||||
|
}
|
||||||
|
assertNotNull(board);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue