235 lines
7.1 KiB
Java
235 lines
7.1 KiB
Java
package gui;
|
|
|
|
import java.awt.Dimension;
|
|
import java.awt.GridLayout;
|
|
import java.awt.LayoutManager;
|
|
import java.awt.event.KeyAdapter;
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.event.KeyListener;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
|
|
import javax.swing.JPanel;
|
|
import javax.swing.Box;
|
|
|
|
import gui.backend.Cell;
|
|
import gui.backend.Settings;
|
|
import gui.backend.SudokuChecker;
|
|
|
|
/**
|
|
* The Board class represents the Sudoku board in the GUI.
|
|
*
|
|
* It contains all other related GUI components, and is the main JPanel for
|
|
* the board. Accessible information from the Board includes:
|
|
* - the current state of the board, including filled values and notes;
|
|
* - the current difficulty;
|
|
* - the current time since the puzzle was started;
|
|
* - the current hints available; and
|
|
* - the current number of mistakes.
|
|
*/
|
|
public class Board extends JPanel {
|
|
private Settings s;
|
|
private Cell[][] grid;
|
|
private Cell[][] solvedGrid;
|
|
private CellGUI[][] gridGUI;
|
|
private SudokuChecker sc;
|
|
private CellGUI selected;
|
|
|
|
/**
|
|
* Create a new Board object with the default styling from settings.
|
|
*
|
|
* @param s
|
|
*/
|
|
public Board(Settings s, Cell[][] grid, SudokuChecker sc) {
|
|
super(new GridLayout(9, 9));
|
|
this.s = s;
|
|
this.grid = grid;
|
|
this.sc = sc;
|
|
solvedGrid = new SudokuChecker(Cell.copyGrid(grid)).getSolution();
|
|
|
|
style();
|
|
createBoard();
|
|
}
|
|
|
|
private KeyListener createKeyListener() {
|
|
return new KeyListener() {
|
|
@Override
|
|
public void keyTyped(KeyEvent e) {}
|
|
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {}
|
|
|
|
@Override
|
|
public void keyReleased(KeyEvent e) {
|
|
char key = e.getKeyChar();
|
|
if(selected.cell.isInitValue()) return;
|
|
|
|
// Backspace key code is 0
|
|
if(e.getKeyCode() == e.VK_BACK_SPACE) {
|
|
selected.removeValue();
|
|
selected.repaint();
|
|
selected.revalidate();
|
|
return;
|
|
}
|
|
|
|
if(!Character.isDigit(key)) return;
|
|
|
|
if(!selected.isInNotesMode()) {
|
|
if(s.getAutoCheckValues()) {
|
|
int row = selected.cell.getRow();
|
|
int col = selected.cell.getCol();
|
|
int expected = solvedGrid[row][col].getValue();
|
|
selected.setValue(Character.getNumericValue(key), expected);
|
|
} else {
|
|
selected.setValue(Character.getNumericValue(key));
|
|
}
|
|
} else {
|
|
selected.addPossibleValue(Character.getNumericValue(key));
|
|
}
|
|
|
|
selected.repaint();
|
|
selected.revalidate();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the grid of the Board.
|
|
*
|
|
* @return
|
|
*/
|
|
public Cell[][] getGrid() {
|
|
return grid;
|
|
}
|
|
|
|
/**
|
|
* Set the grid of the Board to the given grid.
|
|
*
|
|
* Intended to be used when loading a new puzzle.
|
|
*
|
|
* @param grid
|
|
*/
|
|
public void setGrid(Cell[][] grid) {
|
|
this.grid = grid;
|
|
gridGUI = null;
|
|
selected = null;
|
|
|
|
removeAll();
|
|
createBoard();
|
|
repaint();
|
|
revalidate();
|
|
}
|
|
|
|
/**
|
|
* Set up the Board Panel with the appropriate styling.
|
|
*/
|
|
private void style() {
|
|
setBackground(s.getTheme().getPrimaryBackground());
|
|
setForeground(s.getTheme().getPrimaryText());
|
|
}
|
|
|
|
/**
|
|
* Select the given cell and highlight all cells in the same row, column,
|
|
* and box.
|
|
*
|
|
* Intended to be used in conjunction with a MouseListener.
|
|
*
|
|
* @param cell
|
|
*/
|
|
private void select(Cell cell) {
|
|
for(int n = 0; n < 9; n++) {
|
|
int row = cell.getRow();
|
|
int col = cell.getCol();
|
|
boolean colInSameBox =
|
|
(gridGUI[n][col].cell.getBox() ==
|
|
cell.getBox());
|
|
|
|
boolean rowInSameBox =
|
|
(gridGUI[row][n].cell.getBox() ==
|
|
cell.getBox());
|
|
|
|
if(colInSameBox && !rowInSameBox) {
|
|
gridGUI[row][n].select();
|
|
continue;
|
|
} else if(!colInSameBox && rowInSameBox) {
|
|
gridGUI[n][col].select();
|
|
continue;
|
|
} else if(colInSameBox && rowInSameBox) continue;
|
|
|
|
gridGUI[n][col].select();
|
|
gridGUI[row][n].select();
|
|
}
|
|
|
|
int boxRow = cell.getRow() / 3;
|
|
int boxCol = cell.getCol() / 3;
|
|
for(int n = 0; n < 3; n++) {
|
|
for(int m = 0; m < 3; m++) {
|
|
int row = boxRow * 3 + n;
|
|
int col = boxCol * 3 + m;
|
|
|
|
// Skip the user-selected cell for clearer highlighting.
|
|
if(row == cell.getRow() && col == cell.getCol()) continue;
|
|
|
|
gridGUI[row][col].select();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the Board Panel with the appropriate cells.
|
|
*/
|
|
private void createBoard() {
|
|
if(s.getAutoFillNotes()) grid = sc.getPossibleValues(grid);
|
|
gridGUI = new CellGUI[9][9];
|
|
|
|
for(int i = 0; i < 9; i++) {
|
|
for(int j = 0; j < 9; j++) {
|
|
CellGUI cell = new CellGUI(
|
|
grid[i][j],
|
|
s.getCellGUIStartMode(),
|
|
s.getTheme(),
|
|
s.getCellDimensions()
|
|
);
|
|
cell.addMouseListener(new MouseListener() {
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
// Left click
|
|
if(e.getButton() == 1) {
|
|
if(selected != null) select(selected.cell);
|
|
|
|
// Deselect the cell if it is already selected.
|
|
if(selected == cell) {
|
|
selected = null;
|
|
return;
|
|
}
|
|
|
|
select(cell.cell);
|
|
selected = cell;
|
|
selected.requestFocusInWindow();
|
|
selected.addKeyListener(createKeyListener());
|
|
} else if(e.getButton() == 3) {
|
|
cell.setNoteMode();
|
|
return;
|
|
}
|
|
}
|
|
@Override
|
|
public void mousePressed(MouseEvent e) {}
|
|
@Override
|
|
public void mouseReleased(MouseEvent e) {}
|
|
@Override
|
|
public void mouseEntered(MouseEvent e) {
|
|
cell.select();
|
|
}
|
|
@Override
|
|
public void mouseExited(MouseEvent e) {
|
|
cell.select();
|
|
}
|
|
|
|
});
|
|
|
|
gridGUI[i][j] = cell;
|
|
add(gridGUI[i][j]);
|
|
}
|
|
}
|
|
}
|
|
} |