Start. Have fun, Helmut
- Code: Select all
- //---------------- File Sudoku.java ------------------
 import java.awt.BorderLayout;
 import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.EmptyStackException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Stack;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 public class Sudoku extends JDialog implements ActionListener {
 private static final boolean DEBUG = false;
 
 private Cell[][][][] cells;
 private JButton startButton;
 private Stack stack = new Stack();
 
 Sudoku() {
 setModal(true);
 setTitle("Sudoku");
 initComponents();
 layoutWindow();
 setInitialSize();
 centerOnScreen();
 }
 
 private void setInitialSize() {
 Dimension preferredSize = getPreferredSize();
 Dimension minimumSize = getMinimumSize();
 int width = Math.max(preferredSize.width, minimumSize.width);
 int height = Math.max(preferredSize.height, minimumSize.height);
 setSize(width, height);
 }
 private void centerOnScreen() {
 Dimension size = getToolkit().getScreenSize();
 setLocation((size.width - getWidth()) / 2, (size.height - getHeight()) / 2 - 20);
 }
 private void initComponents() {
 cells = new Cell[3][3][3][3];
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 cells[row1][col1][row2][col2] = new Cell();
 }
 }
 }
 }
 startButton = new JButton("Start");
 startButton.addActionListener(this);
 }
 
 private void layoutWindow() {
 Container pane = getContentPane();
 pane.setLayout(new BorderLayout());
 JPanel cellPanel = new JPanel();
 cellPanel.setLayout(new GridLayout(3, 3));
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 JPanel panel = new JPanel();
 panel.setLayout(new GridLayout(3, 3));
 panel.setBorder(BorderFactory.createEmptyBorder(2, 2, 0, 2));
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 panel.add(cells[row1][col1][row2][col2]);
 }
 }
 cellPanel.add(panel);
 }
 }
 pane.add(cellPanel, BorderLayout.CENTER);
 pane.add(startButton, BorderLayout.SOUTH);
 }
 
 public void actionPerformed(ActionEvent e) {
 if (checkCells()) {
 disableCells();
 startButton.setEnabled(false);
 Thread solver = new SolverThread();
 solver.start();
 } else {
 JOptionPane.showMessageDialog(this, "Ungültige Eingabe!", "Sudoku",
 JOptionPane.ERROR_MESSAGE);
 }
 }
 
 private boolean checkCells() {
 initPossibleValues(true);
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 Cell cell = cells[row1][col1][row2][col2];
 if (!cell.isValuePossible(cell.getValue())) {
 return false;
 }
 }
 }
 }
 }
 return true;
 }
 private void disableCells() {
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 cells[row1][col1][row2][col2].setInputEnabled(false);
 }
 }
 }
 }
 }
 
 private class SolverThread extends Thread {
 public void run() {
 solv();
 }
 private void solv() {
 int count = countInitialValues();
 debug("Initial count: " + count);
 boolean solvable = true;
 Choice chosen = null;
 while (count < 81 && solvable) {
 if (chosen == null) {
 int size = 1;
 do {
 chosen = chooseValue(size);
 size++;
 } while (chosen == null && size <= 9);
 } else {
 chosen = chooseNextValue(chosen);
 }
 if (chosen != null) {
 setValue(chosen.row1, chosen.col1, chosen.row2, chosen.col2, chosen.value);
 stack.push(chosen);
 count++;
 if (updatePossibleValues(chosen.row1, chosen.col1, chosen.row2, chosen.col2, chosen.value)) {
 chosen = null;
 } else {
 debug("Wrong way, must backtrack...");
 try {
 do {
 chosen = (Choice)stack.pop();
 unsetValue(chosen.row1, chosen.col1, chosen.row2, chosen.col2);
 count--;
 } while (chosen.choices.size() == 1);
 initPossibleValues(false);
 } catch (EmptyStackException x) {
 debug("Stack is Empty");
 solvable = false;
 }
 }
 } else {
 debug("No value found");
 solvable = false;
 }
 }
 if (!solvable) {
 JOptionPane.showMessageDialog(Sudoku.this, "Not solvable!", "Sudoku",
 JOptionPane.ERROR_MESSAGE);
 }
 }
 }
 private int countInitialValues() {
 int count = 0;
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 if (cells[row1][col1][row2][col2].getValue() != null) {
 count++;
 }
 }
 }
 }
 }
 return count;
 }
 
 private void initPossibleValues(boolean all) {
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 Cell cell = cells[row1][col1][row2][col2];
 if (all || cell.getValue() == null) {
 for (int i = 1; i < 10; i++) {
 cell.getPossibleValues().add(new Integer(i));
 }
 Set values = new HashSet();
 values.addAll(collectMasterCellValues(row1, col1, row2, col2));
 values.addAll(collectRowValues(row1, col1, row2, col2));
 values.addAll(collectColumnValues(row1, col1, row2, col2));
 cell.getPossibleValues().removeAll(values);
 debug("Possible values " + row1 + "," + col1 + "," + row2 + "," + col2 + ": " + cell.getPossibleValues());
 }
 }
 }
 }
 }
 }
 
 private Set collectMasterCellValues(int row1, int col1, int row2, int col2) {
 Set values = new HashSet();
 for (int r2 = 0; r2 < 3; r2++) {
 for (int c2 = 0; c2 < 3; c2++) {
 if (r2 != row2 || c2 != col2) {
 Integer value = cells[row1][col1][r2][c2].getValue();
 if (value != null) {
 values.add(value);
 }
 }
 }
 }
 return values;
 }
 
 private Set collectRowValues(int row1, int col1, int row2, int col2) {
 Set values = new HashSet();
 for (int c1 = 0; c1 < 3; c1++) {
 if (c1 != col1) {
 for (int c2 = 0; c2 < 3; c2++) {
 Integer value = cells[row1][c1][row2][c2].getValue();
 if (value != null) {
 values.add(value);
 }
 }
 }
 }
 return values;
 }
 private Set collectColumnValues(int row1, int col1, int row2, int col2) {
 Set values = new HashSet();
 for (int r1 = 0; r1 < 3; r1++) {
 if (r1 != row1) {
 for (int r2 = 0; r2 < 3; r2++) {
 Integer value = cells[r1][col1][r2][col2].getValue();
 if (value != null) {
 values.add(value);
 }
 }
 }
 }
 return values;
 }
 
 private boolean updatePossibleValues(int row1, int col1, int row2, int col2, Integer value) {
 return updateMasterCell(row1, col1, row2, col2, value) &&
 updateRow(row1, col1, row2, col2, value) &&
 updateColumn(row1, col1, row2, col2, value);
 }
 private boolean updateMasterCell(int row1, int col1, int row2, int col2, Integer value) {
 for (int r2 = 0; r2 < 3; r2++) {
 for (int c2 = 0; c2 < 3; c2++) {
 if (r2 != row2 || c2 != col2) {
 Cell cell = cells[row1][col1][r2][c2];
 if (cell.getValue() == null) {
 cell.getPossibleValues().remove(value);
 debug("Possible values " + row1 + "," + col1 + "," + r2 + "," + c2 + ": " + cell.getPossibleValues());
 if (cell.getPossibleValues().isEmpty()) {
 return false;
 }
 }
 }
 }
 }
 return true;
 }
 
 private boolean updateRow(int row1, int col1, int row2, int col2, Integer value) {
 for (int c1 = 0; c1 < 3; c1++) {
 if (c1 != col1) {
 for (int c2 = 0; c2 < 3; c2++) {
 Cell cell = cells[row1][c1][row2][c2];
 if (cell.getValue() == null) {
 cell.getPossibleValues().remove(value);
 debug("Possible values " + row1 + "," + c1 + "," + row2 + "," + c2 + ": " + cell.getPossibleValues());
 if (cell.getPossibleValues().isEmpty()) {
 return false;
 }
 }
 }
 }
 }
 return true;
 }
 
 private boolean updateColumn(int row1, int col1, int row2, int col2, Integer value) {
 for (int r1 = 0; r1 < 3; r1++) {
 if (r1 != row1) {
 for (int r2 = 0; r2 < 3; r2++) {
 Cell cell = cells[r1][col1][r2][col2];
 if (cell.getValue() == null) {
 cell.getPossibleValues().remove(value);
 debug("Possible values " + r1 + "," + col1 + "," + r2 + "," + col2 + ": " + cell.getPossibleValues());
 if (cell.getPossibleValues().isEmpty()) {
 return false;
 }
 }
 }
 }
 }
 return true;
 }
 
 private Choice chooseValue(int size) {
 for (int row1 = 0; row1 < 3; row1++) {
 for (int col1 = 0; col1 < 3; col1++) {
 for (int row2 = 0; row2 < 3; row2++) {
 for (int col2 = 0; col2 < 3; col2++) {
 Cell cell = cells[row1][col1][row2][col2];
 if (cell.getValue() == null && cell.getPossibleValues().size() == size) {
 Integer value = (Integer)cell.getPossibleValues().iterator().next();
 debug("Choosing " + value + " from " + cell.getPossibleValues());
 return new Choice(row1, col1, row2, col2, value, cell.getPossibleValues());
 }
 }
 }
 }
 }
 return null;
 }
 
 private Choice chooseNextValue(Choice chosen) {
 chosen.choices.remove(chosen.value);
 chosen.value = (Integer)chosen.choices.iterator().next();
 debug("Choosing next " + chosen.value + " from " + chosen.choices);
 return chosen;
 }
 private void setValue(int row1, int col1, int row2, int col2, Integer value) {
 Cell cell = cells[row1][col1][row2][col2];
 cell.setValue(value);
 debug("Value set " + row1 + "," + col1 + "," + row2 + "," + col2 + ": " + value);
 }
 private void unsetValue(int row1, int col1, int row2, int col2) {
 Cell cell = cells[row1][col1][row2][col2];
 Integer value = cell.getValue();
 cell.setValue(null);
 debug("Value unset " + row1 + "," + col1 + "," + row2 + "," + col2 + ": " + value);
 }
 
 private static void debug(String s) {
 if (DEBUG) {
 System.out.println(s);
 }
 }
 
 public static void main(String[] args) {
 Sudoku sudoku = new Sudoku();
 sudoku.show();
 System.exit(0);
 }
 
 private static class Choice {
 int row1;
 int col1;
 int row2;
 int col2;
 Integer value;
 Set choices;
 
 Choice(int row1, int col1, int row2, int col2, Integer value, Set choices) {
 this.row1 = row1;
 this.col1 = col1;
 this.row2 = row2;
 this.col2 = col2;
 this.value = value;
 this.choices = choices;
 }
 }
 }
 //---------------- File Cell.java ------------------
 import java.awt.Color;
 import java.awt.Dimension;
 import java.util.HashSet;
 import java.util.Set;
 import javax.swing.JTextField;
 public class Cell extends JTextField {
 
 private boolean inputEnabled = true;
 private Integer value;
 private Set possibleValues;
 
 Cell() {
 setHorizontalAlignment(JTextField.CENTER);
 setPreferredSize(new Dimension(20, 22));
 
 possibleValues = new HashSet(9);
 for (int i = 1; i < 10; i++) {
 possibleValues.add(new Integer(i));
 }
 showValue();
 }
 
 private void showValue() {
 setForeground(isValuePossible(value) ? Color.BLACK : Color.RED);
 String text = value == null ? "" : value.toString();
 setText(text);
 }
 void setInputEnabled(boolean b) {
 inputEnabled = b;
 setEnabled(b);
 }
 
 void setValue(Integer value) {
 this.value = value;
 showValue();
 }
 
 Integer getValue() {
 if (inputEnabled) {
 String text = getText();
 if (text.length() > 0) {
 try {
 value = new Integer(text);
 } catch (NumberFormatException x) {
 value = new Integer(99);
 }
 } else {
 value = null;
 }
 showValue();
 }
 return value;
 }
 Set getPossibleValues() {
 return possibleValues;
 }
 
 boolean isValuePossible(Integer value) {
 return value == null || possibleValues.contains(value);
 }
 }


