added built-in check to the Cell data class to ensure initial values cannot be overridden by the user (even accidentally).
This commit is contained in:
+8
-1
@@ -1,4 +1,5 @@
|
||||
// GUI imports
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.UIManager;
|
||||
import java.awt.BorderLayout;
|
||||
@@ -18,6 +19,7 @@ public class App extends JFrame {
|
||||
|
||||
// Data fields
|
||||
private Settings s;
|
||||
private SudokuChecker sc;
|
||||
|
||||
/**
|
||||
* Create a new App object, initializing the GUI and internal logic.
|
||||
@@ -27,8 +29,12 @@ public class App extends JFrame {
|
||||
s = new Settings();
|
||||
initSetup();
|
||||
nav = new Nav(s, false);
|
||||
board = new Board(s, nav.getLoadedGrid());
|
||||
sc = new SudokuChecker(nav.getLoadedGrid());
|
||||
board = new Board(s, nav.getLoadedGrid(), sc);
|
||||
|
||||
nav.setBoard(board);
|
||||
nav.setChecker(sc);
|
||||
|
||||
add(createApp());
|
||||
}
|
||||
|
||||
@@ -69,6 +75,7 @@ public class App extends JFrame {
|
||||
*/
|
||||
private Root createApp() {
|
||||
Root root = new Root(s);
|
||||
root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS));
|
||||
root.add(nav);
|
||||
root.add(board);
|
||||
|
||||
|
||||
+69
-34
@@ -4,9 +4,12 @@ import java.awt.GridLayout;
|
||||
import java.awt.LayoutManager;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import gui.backend.Settings;
|
||||
import gui.backend.SudokuChecker;
|
||||
import gui.backend.Theme;
|
||||
|
||||
/**
|
||||
* The Board class represents the Sudoku board in the GUI.
|
||||
@@ -22,6 +25,7 @@ import gui.backend.Settings;
|
||||
public class Board extends JPanel {
|
||||
private Settings s;
|
||||
private Cell[][] grid;
|
||||
private SudokuChecker sc;
|
||||
private Cell selected;
|
||||
|
||||
/**
|
||||
@@ -29,10 +33,11 @@ public class Board extends JPanel {
|
||||
*
|
||||
* @param s
|
||||
*/
|
||||
public Board(Settings s, Cell[][] grid) {
|
||||
public Board(Settings s, Cell[][] grid, SudokuChecker sc) {
|
||||
super(new GridLayout(9, 9));
|
||||
this.s = s;
|
||||
this.grid = grid;
|
||||
this.sc = sc;
|
||||
style();
|
||||
createBoard();
|
||||
}
|
||||
@@ -65,13 +70,19 @@ public class Board extends JPanel {
|
||||
* Set up the Board Panel with the appropriate styling.
|
||||
*/
|
||||
private void style() {
|
||||
// TODO: Style the Board Panel.
|
||||
setBackground(s.getTheme().getPrimaryBackground());
|
||||
setForeground(s.getTheme().getPrimaryText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Board Panel with the appropriate cells.
|
||||
*/
|
||||
private void createBoard() {
|
||||
if(s.getAutoFillNotes()) grid = sc.getPossibleValues(grid);
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
for(int j = 0; j < 9; j++) {
|
||||
CellGUI cell = new CellGUI(grid[i][j], s.getCellGUIStartMode());
|
||||
CellGUI cell = new CellGUI(grid[i][j], s.getCellGUIStartMode() || s.getAutoFillNotes(), s.getTheme());
|
||||
add(cell);
|
||||
}
|
||||
}
|
||||
@@ -81,14 +92,15 @@ public class Board extends JPanel {
|
||||
* GUI representation of a single cell in the Sudoku grid.
|
||||
*/
|
||||
private class CellGUI extends JPanel {
|
||||
private static GridLayout noteLayout = new GridLayout(3, 3);
|
||||
private static GridLayout valueLayout = new GridLayout(1, 1);
|
||||
private GridLayout noteLayout = new GridLayout(3, 3);
|
||||
private GridLayout valueLayout = new GridLayout(1, 1);
|
||||
private Theme theme;
|
||||
|
||||
private Cell cell;
|
||||
private JLabel valueLabel;
|
||||
private JLabel[] notesLabels;
|
||||
private Note[] notesLabels = new Note[9];
|
||||
private boolean notes; // true for notes, false for value
|
||||
private boolean startInNotesOrValueMode;
|
||||
private boolean cellGUIStartMode;
|
||||
|
||||
/**
|
||||
* Create a new CellGUI object with the given single cell.
|
||||
@@ -98,24 +110,18 @@ public class Board extends JPanel {
|
||||
* @param cell
|
||||
* @param startInNotesOrValueMode
|
||||
*/
|
||||
public CellGUI(Cell cell, boolean startInNotesOrValueMode) {
|
||||
public CellGUI(Cell cell, boolean notes, Theme theme) {
|
||||
super();
|
||||
this.cell = cell;
|
||||
this.startInNotesOrValueMode = startInNotesOrValueMode;
|
||||
this.notes = notes;
|
||||
this.theme = theme;
|
||||
style();
|
||||
|
||||
// Populate the cell with the appropriate value or notes.
|
||||
if(cell.getValue() == 0) {
|
||||
generateNotes();
|
||||
|
||||
if(startInNotesOrValueMode) {
|
||||
setLayout(noteLayout);
|
||||
notes = true;
|
||||
} else {
|
||||
setLayout(valueLayout);
|
||||
notes = false;
|
||||
notes = !notes;
|
||||
valueLabel = new JLabel("");
|
||||
add(valueLabel);
|
||||
}
|
||||
setNoteMode();
|
||||
} else {
|
||||
valueLabel = new JLabel(Integer.toString(cell.getValue()));
|
||||
add(valueLabel);
|
||||
@@ -131,6 +137,25 @@ public class Board extends JPanel {
|
||||
return cell.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the underlying Cell object.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setValue(int value) {
|
||||
cell.setValue(value);
|
||||
valueLabel.setText(Integer.toString(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the possible values of the underlying Cell object.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setPossibleValues(int[] values) {
|
||||
cell.setPossibleValues(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a possible value to the cell.
|
||||
*
|
||||
@@ -163,44 +188,54 @@ public class Board extends JPanel {
|
||||
* layout of the cell.
|
||||
*/
|
||||
public void setNoteMode() {
|
||||
if(notes) {
|
||||
removeAll();
|
||||
if(notes) {
|
||||
setLayout(valueLayout);
|
||||
repaint();
|
||||
revalidate();
|
||||
|
||||
add(valueLabel);
|
||||
} else {
|
||||
removeAll();
|
||||
setLayout(noteLayout);
|
||||
repaint();
|
||||
revalidate();
|
||||
|
||||
generateNotes();
|
||||
for(int i = 0; i < 9; i++)
|
||||
add(notesLabels[i]);
|
||||
}
|
||||
|
||||
repaint();
|
||||
revalidate();
|
||||
notes = !notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the cell with the appropriate colors from the theme.
|
||||
*/
|
||||
private void style() {
|
||||
setBackground(theme.getPrimaryBackground());
|
||||
setForeground(theme.getPrimaryText());
|
||||
setBorder(new LineBorder(theme.getPrimaryBorder(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the GUI components for the cell.
|
||||
*/
|
||||
private void generateNotes() {
|
||||
if(cell.getPossibleValues().length == 0) {
|
||||
notesLabels = new JLabel[9];
|
||||
for(int i = 0; i < 9; i++) {
|
||||
notesLabels[i] = new Note("", theme);
|
||||
add(notesLabels[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Add the noted possible values to the cell.
|
||||
int index = 0;
|
||||
for(int i = 1; i <= 9; i++) {
|
||||
if(cell.getPossibleValues()[index] == i) {
|
||||
notesLabels[index] = new JLabel(Integer.toString(i));
|
||||
index++;
|
||||
} else {
|
||||
notesLabels[index] = new JLabel("");
|
||||
}
|
||||
add(notesLabels[index]);
|
||||
if(cell.getPossibleValues()[i - 1] == i)
|
||||
notesLabels[i - 1] = new Note(Integer.toString(i), theme);
|
||||
else
|
||||
notesLabels[i - 1] = new Note("", theme);
|
||||
|
||||
add(notesLabels[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ public class Cell {
|
||||
private int col;
|
||||
private int box;
|
||||
private int value;
|
||||
private boolean initValue;
|
||||
|
||||
private List possibleValues;
|
||||
|
||||
/**
|
||||
@@ -41,6 +43,8 @@ public class Cell {
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
this.value = value;
|
||||
initValue = value != 0;
|
||||
|
||||
setBox();
|
||||
possibleValues = new List();
|
||||
}
|
||||
@@ -69,6 +73,8 @@ public class Cell {
|
||||
* @param value
|
||||
*/
|
||||
public void setValue(int value) {
|
||||
if(initValue) return;
|
||||
|
||||
possibleValues.clear();
|
||||
this.value = value;
|
||||
}
|
||||
@@ -99,6 +105,8 @@ public class Cell {
|
||||
* @param value
|
||||
*/
|
||||
public void addPossibleValue(int value) {
|
||||
if(initValue) return;
|
||||
|
||||
if(possibleValues.contains(value)) {
|
||||
return;
|
||||
} else if(value < 1 || value > 9) {
|
||||
@@ -114,6 +122,8 @@ public class Cell {
|
||||
* @param possibleValues
|
||||
*/
|
||||
public void setPossibleValues(int[] possibleValues) {
|
||||
if(initValue) return;
|
||||
|
||||
this.possibleValues = new List(possibleValues);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.io.FileNotFoundException;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import gui.backend.Settings;
|
||||
import gui.backend.SudokuChecker;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JButton;
|
||||
@@ -26,6 +27,7 @@ import javax.swing.JButton;
|
||||
*/
|
||||
public class Nav extends JPanel {
|
||||
private Settings s;
|
||||
private SudokuChecker sc;
|
||||
private File f;
|
||||
private Board b;
|
||||
private Cell[][] grid;
|
||||
@@ -111,6 +113,22 @@ public class Nav extends JPanel {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SudokuChecker object for the Nav bar.
|
||||
*
|
||||
* This is necessary for the Nav bar to be able to interact with the
|
||||
* SudokuChecker object for the solve button. This shouldn't be necessary
|
||||
* to change once the program is running.
|
||||
*/
|
||||
public void setChecker(SudokuChecker sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
private void style() {
|
||||
setBackground(s.getTheme().getPrimaryBackground());
|
||||
setForeground(s.getTheme().getPrimaryText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the GUI for the Nav bar.
|
||||
*
|
||||
@@ -119,6 +137,7 @@ public class Nav extends JPanel {
|
||||
* debugging purposes.
|
||||
*/
|
||||
private void createGUI() {
|
||||
style();
|
||||
JLabel elapsedTime = new JLabel("Elapsed Time: 00:00:00");
|
||||
elapsedTime.setFont(s.getFont()); // TODO: Make custom Label class.
|
||||
JButton solve = new JButton("Solve");
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package gui;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import gui.backend.Theme;
|
||||
|
||||
/**
|
||||
* The Note class represents a single note of a cell in the Sudoku board.
|
||||
*
|
||||
* This is the GUI abstraction for the underlying Cell object, and is used to
|
||||
* display and manage the note for a cell.
|
||||
*/
|
||||
public class Note extends JLabel {
|
||||
private Theme t;
|
||||
|
||||
/**
|
||||
* Create a new Note object with the given text and theme.
|
||||
*
|
||||
* @param text
|
||||
* @param t
|
||||
*/
|
||||
public Note(String text, Theme t) {
|
||||
super(text);
|
||||
this.t = t;
|
||||
style();
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the Note component with the current theme.
|
||||
*/
|
||||
private void style() {
|
||||
setBackground(t.getPrimaryBackground());
|
||||
setForeground(t.getPrimaryText());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package gui;
|
||||
|
||||
import java.awt.LayoutManager;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import gui.backend.Settings;
|
||||
|
||||
@@ -50,6 +50,12 @@ public class Settings {
|
||||
// Default open state for the application.
|
||||
private int defaultOpenState;
|
||||
|
||||
// Theme object storing the colors for the GUI components.
|
||||
private Theme theme;
|
||||
|
||||
// Auto-fill notes
|
||||
private boolean autoFillNotes;
|
||||
|
||||
/**
|
||||
* Create a new Settings object, initializing the default settings
|
||||
* or reading in the settings from settings file if it exists.
|
||||
@@ -244,6 +250,65 @@ public class Settings {
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Theme object stores the colors for the GUI components.
|
||||
*
|
||||
* The available colors for customization are:
|
||||
* - primaryBackground
|
||||
* - secondaryBackground
|
||||
* - primaryText
|
||||
* - secondaryText
|
||||
* - primaryHighlight
|
||||
* - secondaryHighlight
|
||||
* - primaryBorder
|
||||
* - secondaryBorder
|
||||
* - primaryButton
|
||||
* - secondaryButton
|
||||
* - primaryButtonHighlight
|
||||
* - secondaryButtonHighlight
|
||||
* - primaryButtonBorder
|
||||
* - secondaryButtonBorder
|
||||
*
|
||||
* @see Theme
|
||||
* @return
|
||||
*/
|
||||
public Theme getTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme and write it to the settings file.
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
public void setTheme(Theme theme) {
|
||||
this.theme = theme;
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Auto-fill notes setting is a configurable setting, where the user
|
||||
* can specify whether notes should be automatically filled in when a
|
||||
* value is placed in a cell.
|
||||
*
|
||||
* By default, the auto-fill notes setting is set to false.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean getAutoFillNotes() {
|
||||
return autoFillNotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the auto-fill notes setting and write it to the settings file.
|
||||
*
|
||||
* @param autoFillNotes
|
||||
*/
|
||||
public void setAutoFillNotes(boolean autoFillNotes) {
|
||||
this.autoFillNotes = autoFillNotes;
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open and write the settings to the settings file.
|
||||
*
|
||||
@@ -279,6 +344,8 @@ public class Settings {
|
||||
resizable = false;
|
||||
cellGUIStartMode = false;
|
||||
defaultOpenState = 0;
|
||||
theme = new Theme(new File(appDirectory + "default.theme"));
|
||||
autoFillNotes = true;
|
||||
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,44 @@ public class SudokuChecker {
|
||||
*/
|
||||
public SudokuChecker(Cell[][] grid) {
|
||||
this.grid = grid;
|
||||
solve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the possible values for each cell in the Sudoku puzzle.
|
||||
*
|
||||
* Intended to be used for auto-filling in possible values in the GUI.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Cell[][] getPossibleValues(Cell[][] grid) {
|
||||
for(int row = 0; row < grid.length; row++) {
|
||||
for(int col = 0; col < grid[row].length; col++) {
|
||||
if(grid[row][col].getValue() == 0)
|
||||
continue;
|
||||
|
||||
ArrayList<Integer> intersection = intersection(
|
||||
getRowRemainingNumbers(row),
|
||||
getColRemainingNumbers(col)
|
||||
);
|
||||
|
||||
intersection = intersection(
|
||||
intersection,
|
||||
getBoxRemainingNumbers(row, col)
|
||||
);
|
||||
|
||||
// Join the arrays and find the intersection of the three arrays
|
||||
ArrayList<Integer> availableNumbers = new ArrayList<Integer>();
|
||||
for(int i = 0; i < intersection.size(); i++) {
|
||||
availableNumbers.add(intersection.get(i));
|
||||
}
|
||||
|
||||
grid[row][col].setPossibleValues(
|
||||
arrayListToArray(availableNumbers)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,6 +74,7 @@ public class SudokuChecker {
|
||||
* @return Cell[][]
|
||||
*/
|
||||
public Cell[][] getSolution() {
|
||||
solve();
|
||||
return grid;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,10 +71,11 @@ public class Theme {
|
||||
* Sets the theme for the GUI components.
|
||||
*/
|
||||
private void setTheme() {
|
||||
primaryBackground = Color.WHITE;
|
||||
primaryBackground = Color.LIGHT_GRAY;
|
||||
secondaryBackground = Color.LIGHT_GRAY;
|
||||
primaryText = Color.BLACK;
|
||||
primaryText = Color.DARK_GRAY;
|
||||
secondaryText = Color.DARK_GRAY;
|
||||
primaryBorder = Color.BLACK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user