Sudokusolver

Ziel des Projektes ist ein Java-Programm mit graphischer Oberfläche zu erstellen, das ein vorgegebenes Sukoku löst.

Planung

Das Programm verwendet das Model-View-Controller-Entwurfsmuster.

View

Beschreibung

  • resetButton: Löscht alle Einträge
  • prüfenKnopf: überprüft, ob alle Eingaben korrekt sind bzw. ob die Belegung lösbar ist
  • lösenKnopf: Gibt, falls möglich, die Lösung an. Fehlende Einträge im Sudoku werden farbig hervorgehoben
  • statusLabel: Statusanzeige, wenn prüfenKnopf bzw. lösenKnopf gedrückt wird
  • prüfenKnopf→ Belegung korrekt, fehlerhaft
  • lösenKnopf → Meldungen wie bei prüfen, Berechnungszeit in s
  • Sudoku-9×9-Textfeld: Eingabe von Zahlen zwischen 1 und 9, bzw. Löschen
  • Bei Eingabe Überprüfung auf Ziffer, sonst keine Darstellung der Eingabe

öffentliche Methoden:

  • void setSudoku(Sudoku sudoku): zeigt Sudoku an
  • void setStatusLabel(String message)
  • Sudoku getSudoku(): neues Sudoku erzeugen

Klassendiagramm

<uml> skinparam classAttributeIconSize 0 class Gui { -privateField +publicField +void setSudoku(Sudoku sudoku) +Sudoku getSudoku() +void setStatusLabel() -Sudoku privateMethod() } </uml>

Implementierung

Gui.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.PlainDocument;
import javax.swing.text.*;
 
/**
 * Über die Klasse GUI kann man die GUI des Sudoku_Programms bearbeiten.
 * Außerdem wird die GUI erzeugt.#
 * Diesmal mit 9x9 Textfeld und angepasster Schriftgröße beim Einfügen der Zahlen, allerdings fehlt das Statuslabel noch
 * Dokumentation eingefügt
 * Leermethoden eingefügt
 * @author Christoph, Bene, Monsi, Simon
 */
public class GUI extends Frame {
    // Anfang Attribute
    private JButton jButton1 = new JButton();
    private JButton jButton2 = new JButton();
    private JButton jButton3 = new JButton();
    private JTextField[][] tabelle = new JTextField[9][9];
 
    private JPanel jPanel1 = new JPanel(null, true);
    private JLabel jLabel1 = new JLabel();
    Sudoku sudoku;
    Controller Controller;
 
    // Ende Attribute
    /**
     * Erzeugen der einzelnen Komponenten der GUI und Setzen der Einstellungen
     */
    public GUI(Controller c) {
 
        // Frame-Initialisierung
        super();
        Controller = c;
        sudoku=new Sudoku();
        addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent evt) {
                    dispose();
                }
            });
        int frameWidth = 363;
        int frameHeight = 500;
        setSize(frameWidth, frameHeight);
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (d.width - getSize().width) / 2;
        int y = (d.height - getSize().height) / 2;
        setLocation(x, y);
        setResizable(false);
        Panel cp = new Panel(null);
        add(cp);
        // Anfang Komponenten
 
        jButton1.setBounds(8, 352, 105, 41);
        jButton1.setText("Prüfen");
        jButton1.setMargin(new Insets(2, 2, 2, 2));
        jButton1.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    jButton1_ActionPerformed(evt);
                }
            });
        cp.add(jButton1);
        jButton2.setBounds(124, 352, 105, 41);
        jButton2.setText("Reset");
        jButton2.setMargin(new Insets(2, 2, 2, 2));
        jButton2.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    jButton2_ActionPerformed(evt);
                }
            });
        cp.add(jButton2);
        jButton3.setBounds(240, 352, 105, 41);
        jButton3.setText("Lösen");
        jButton3.setMargin(new Insets(2, 2, 2, 2));
        jButton3.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    jButton3_ActionPerformed(evt);
                }
            });
        cp.add(jButton3);
 
        jPanel1.setBounds(8, 8, 337, 337);
 
        for (int j = 0; j < 9; j++) {
 
            for (int i = 0; i < 9; i++) {
                tabelle[j][i] = new JTextField();
                jPanel1.add(tabelle[j][i]);
                tabelle[j][i].setDocument(new SetMaxText(1));
                tabelle[j][i].setBounds(0 + i * 37, 0 + j * 37, 37, 37);
                Font f = new Font("arial", 4, 25);
                tabelle[j][i].setFont(f);
                tabelle[j][i].setHorizontalAlignment(JTextField.CENTER);
 
            }
 
        }
 
        cp.add(jPanel1);
        jLabel1.setBounds(200,400,200,70);
        jLabel1.setText("");
        cp.add(jLabel1);
        // Ende Komponenten
 
        setVisible(true);
    }
 
    // Anfang Methoden
    /**
     * Wenn der Knopf gedrückt wird, wird die Methode des Controllers aufgerufen um die entsprechende Funktion zu erfüllen.
     */
    public void jButton1_ActionPerformed(ActionEvent evt) {
        Controller.checkSudoku();
    }
 
    /**
     * Wenn der Knopf gedrückt wird, wird die Methode des Controllers aufgerufen um die entsprechende Funktion zu erfüllen.
     */
    public void jButton2_ActionPerformed(ActionEvent evt) {
        Controller.resetSudoku();
    }
 
    /**
     * Wenn der Knopf gedrückt wird, wird die Methode des Controllers aufgerufen um die entsprechende Funktion zu erfüllen.
     */
    public void jButton3_ActionPerformed(ActionEvent evt) {
        Controller.solveSudoku();
    }
 
    // Ende Methoden
 
    public void setSudoku(Sudoku sudoku) {
        for (int j = 1; j <= 9; j++) {
 
            for (int i = 1; i <= 9; i++) {
                if(sudoku.getNumber(i,j)==0){
                    tabelle[i-1][j-1].setText("");
                }else{
                    tabelle[i-1][j-1].setText(Integer.toString(sudoku.getNumber(i, j)));
                }
            }
 
        }
    }
 
    public void setStatuslabel(String message) {
        jLabel1.setText(message);
    }
 
    public Sudoku getSudoku() {
 
        for (int j = 1; j <= 9; j++) {
 
            for (int i = 1; i <= 9; i++) {
                if((tabelle[i-1][j-1].getText()).equals("")){
                    sudoku.setNumber(i, j, 0);    
                }
                else{
                    sudoku.setNumber(i, j, Integer.parseInt(tabelle[i-1][j-1].getText()));                    
                }
            }
 
        }
        return sudoku;
 
    }
    /**
     *  Begrenzung der Zeichen im JTextField auf 1
     */
    class SetMaxText extends PlainDocument {
        private int limit;
        // optional uppercase conversion
        private boolean toUppercase = false;
 
        SetMaxText(int limit) {
            super();
            this.limit = limit;
        }
 
        public void insertString(int offset, String str, AttributeSet attr)
        throws BadLocationException {
            if (str == null)
                return;
 
            if ((getLength() + str.length()) <= limit) {
                if (toUppercase)
                    str = str.toUpperCase();
                super.insertString(offset, str, attr);
            }
        }
    }
}

Model

Beschreibung

Der Model besteht aus der zwei Klassen:

  • Sudoku repräsentiert ein Sudoku als Zahlenarray und kann auf korrekte Belegung überprüfen
  • Sudokusolver löst ein Sudoku

Klasse Sudoku

öffentliche Methoden der Klasse Sudoku:

  • Konstruktor Sudoku(): erzeugt leeres Sudoku
  • void setNumber(int row, int column, int number)
  • boolean checkSudoku()

Klassendiagramm der Klasse Sudoku

<uml> skinparam classAttributeIconSize 0 class Sudoku { -privateField +publicField +Sudoku() +void setNumber(int row, int column, int number) +boolean checkSudoku() +int getNumber(int row, int column) } </uml>

Implementierung der Klasse Sudoku

Sudoku.java
/**
 * Die Klasse Sudoku sorgt für das überprüfen des Sudokus und dem übergeben von zahlen !
 * @author Mirko,Nicolai,Julian
 */
 
public class Sudoku
{   
 
    private int[][] sudoku = new int[9][9];
    int number;
 
    public Sudoku(){
        //erzeuge Sudoku aus View
    }
 
    /**
     * Diese Methode dient lediglich als Hilfe
     */
 
    public void ausgabe(){
        for(int row = 0; row<9 ; row++){
            for(int column = 0; column < 9; column++){
                System.out.print(sudoku[row][column]+" ");
 
            }
            System.out.println(" ");
        }
        System.out.println("");
    }
 
    /**
     * Diese Methode setzt eine zahl in einem bestimmten Feld
     * @param number die Zahl, die gesetzt werden soll
     * @param row die Reihe in der die Zahl gesetzt werden soll
     * @param column die Spalte in der die Zahl gesetzt werden soll
     */
 
    public void setNumber(int row, int column, int number){
        sudoku[row-1][column-1] = number;
    }
 
    /**
     * Diese Methode gibt die Zahl in der spalte und reihe zurück
     * @param row reihe der zahl
     * @param column spalte der zahl
     */
 
    public int getNumber(int row, int column){
        return sudoku[row-1][column-1];
    }
 
    /**
     * Diese Methode überprüft ob die Zahl in der Reihe nur einmal vorkommt
     * @param row die Reihe die überpüft wird, beginndend bei 0
     */
 
    private boolean checkRow(int row){
        boolean[] usedNumbers = new boolean[10];
        for(int i = 0; i < 9; i++){
            int zahl=sudoku[row][i];
            if(usedNumbers[zahl]==true && zahl>0){
                return false;
            }
            else{
                usedNumbers[zahl] = true;
 
            }
        }
        return true ;
    }
 
    /**
     * Diese Methode überprüft ob die Zahl in der Spalte nur einmal vorkommt
     * @param column die Spalte die überpüft wird (beginnend bei 0)
     */
 
    private boolean checkColumn(int column){
        boolean[] usedNumbers = new boolean[10];
        for(int j = 0; j < 9; j++){
            int zahl=sudoku[j][column];
            if(usedNumbers[zahl]==true && zahl>0){
                return false;
            }
            else{
                usedNumbers[zahl] = true;
            }
        }
        return true;
    }
 
    /**
     * Diese Methode überprüft ob jede Zahl in jedem 3x3 Feld nur einmal vorkommt
     * @param row Nummer der Reihe, in dem das 3x3-Feld beginnt (Start mit 0)
     * @param column Nummer der Spalte, in dem das 3x3-Feld beginnt (Start mit 0)
     */
 
    private boolean checkField(int row, int column ){
        boolean[] usedNumbers = new boolean[10];
        for (int i = row; i < row+3; i++){
            for( int j=column; j< column+3; j++){
                int zahl=sudoku[i][j];
                System.out.println(zahl);
                if(usedNumbers[zahl]==true && zahl>0){
                    return false;
                }
                else{
                    usedNumbers[zahl] = true;
                }
            }
        }
        return true;
    }
 
    public boolean checkSudoku(){
 
        for(int i = 0; i < 9; i++){
            if(!(checkColumn(i) && checkRow(i))){
                return false;
            }     
        }
 
        for (int i = 0; i < 7; i=i+3){
            for(int j = 0; j < 7; j = j+3){
                if (checkField(i,j) != true){
                    return false;
                }                
            }
        }
        return true;
    }
 
    public void getCopy(){
        for(int i = 0; i < 9; i++){
            for(int j = 0; j < 9; j++){
 
            }
 
        }
 
 
 
 
    }
}

Klasse SudokuSolver

öffentliche Methoden der Klasse SudokuSolver:

  • Sudoku solve(Sudoku sudoku): gibt gelöstes Sudoku zurück oder Null
  • int getNumberOfSolutions(Sudoku sudoku)

Klassendiagramm der Klasse SudokuSolver

<uml> skinparam classAttributeIconSize 0 class SudokuSolver{ -privateField +publicField +Sudoku solve(Sudoku sudoku) +int getNumberOfSolutions(Sudoku sudoku) } </uml>

Implementierung der Klasse SudokuSolver

SudokuSolver.java
/**
 *  Die Klasse SudokuSolver löst ein Sudoku und kann die Anzahl der Lösungsmöglichkeiten berechnen.
 *  @author Alexander May, Lukas Herbst, Dominik Hohmann
 *  @version v3.0
 */
 
public class SudokuSolver{
    public Sudoku sudoku;
 
    SudokuSolver (){
        sudoku=new Sudoku();
        sudoku.setNumber(1, 1, 5);
        sudoku.setNumber(1, 2, 5);
        sudoku.setNumber(1, 3, 5);
        sudoku.setNumber(1, 4, 5);
        sudoku.setNumber(1, 5, 5);
        sudoku.setNumber(1, 6, 5);
        sudoku.setNumber(1, 7, 5);
        sudoku.setNumber(1, 8, 5);
        sudoku.setNumber(1, 9, 5);
        sudoku.setNumber(2, 1, 5);
        sudoku.ausgabe();
        System.out.println(naechstesLeeresFeld()[0]+" "+naechstesLeeresFeld()[1]);
 
    }
 
    /**
     * Die Methode solve braucht als Eingabewert ein Sudoku. Dieses Sudoku wird dann vollständig gelöst zurückgegeben.
     * @param sudoku zu lösendes Sudoku
     * @return das vollständig gelöste Sudoku
     */
    public Sudoku solve(Sudoku sudoku){
        if(naechstesLeeresFeld()!=null){
            int nextRow= naechstesLeeresFeld()[0];
            int nextColumn=naechstesLeeresFeld()[1];
 
            for(int n = 1; n<=9; n++){
                sudoku.setNumber(nextRow,nextColumn,n);
                if (sudoku.checkSudoku()==true){
                    solve(sudoku);
                }
            }
        }
        else{
            //Lösung gefunden 
 
        }
        return sudoku;
    }
 
    /**
     * Die Methode getNumberOfSolutions bekommt als Eingabewert ein Sudoku. Dann berechnet die Methode die Anzahl der Lösungsmöglichkeiten.
     * @param sudoku Sudoku, dessen Lösungsmöglichkeiten berechnet werden soll
     * @return Zahl der möglichen Lösungen
     */
    public int getNumberOfSolutions(Sudoku sudoku){
 
 
 
 
        return 0;
    }
 
    /**
     * Die Methode naechstesLeeresFeld bestimmt die Reihe und Spalte des nächsten freien Feldes und gibt diese in einem Array mit zwei Stellen zurück
     */
 
    public int [] naechstesLeeresFeld(){
        int[] rueckgabe=null;
 
        for(int x = 1; x<=9; x++){
            for(int i=1; i<=9; i++){
                if (sudoku.getNumber(x,i)<1){
                    // Nulleintrag gefunden
                    rueckgabe= new int [2];
                    rueckgabe[0]=x;
                    rueckgabe[1]=i;
                    return rueckgabe;
                }   
 
            }
        }
        return rueckgabe;
 
    }
}

Controller

Beschreibung

Reagiert auf die Knöpfe der GUI, Schnittstelle zwischen View und Model

öffentliche Methoden:

  • void resetSudoku()
  • void checkSudoku()
  • void solveSudoku()

Klassendiagramm

<uml> skinparam classAttributeIconSize 0 class Controller{ -privateField +publicField +void resetSudoku() +void checkSudoku() +void solveSudoku() } </uml>

Implementierung

Controller.java
 public class Controller
{
    private GUI gui;
    private Sudoku sudoku;
 
    public Controller()
    {
 
    }
 
    public void setGUI(GUI newGUI)
    {
        gui = newGUI;
    }
 
    public void setSudoku(Sudoku newSudoku)
    {
        sudoku = newSudoku;
    }
 
    public void resetSudoku()
    {
        sudoku = new Sudoku();
        gui.setSudoku(sudoku);
    }
 
    public void checkSudoku()
    {
 
        if ((sudoku = gui.getSudoku()) == null)
        {
            gui.setStatuslabel("Fehler im Sudoku!");
        }
        else {
            if (sudoku.checkSudoku() == true)
            {
                gui.setStatuslabel("Belegung ist richtig!");
            }
            else
            {
                gui.setStatuslabel("Belegung ist nicht richtig!");
            }
        }
    }
 
    public void solveSudoku()
    {
        sudoku = gui.getSudoku();
        SudokuSolver solver = new SudokuSolver();
 
        gui.setStatuslabel("Wird berechnet!");
        Sudoku geloest = solver.solve(sudoku);
 
        if (geloest != null)
        {
            gui.setSudoku(geloest);
            gui.setStatuslabel("Sudoku wurde gelöst!" + solver.getNumberOfSolutions(geloest));
 
        }
        else
        {
            gui.setStatuslabel("Sudoku ist nicht lösbar!");
        }
    }
}

SudokuMainClass

Beschreibung

Die Klasse SudokuMainClass initialisiert bei Programmstart alle Programmteile. Sie sorgt für die Erzeugung von Model, View und Controller.

öffentliche Methoden:

  • void main(String args[])

Klassendiagramm

<uml> skinparam classAttributeIconSize 0 class SudokuMainClass{ -privateField +publicField +void main(String args[]) } </uml>

Implementierung

SudokuMainClass.java
public class SudokuMainClass
{
    public static void main(String[] args)
    {
        Controller controller = new Controller();
        GUI fenster = new GUI("GUI");
        Sudoku sudoku = new Sudoku();
 
        controller.setGUI(fenster);
        controller.setSudoku(sudoku);
    }
}
Cookies helfen bei der Bereitstellung von Inhalten. Durch die Nutzung dieser Seiten erklären Sie sich damit einverstanden, dass Cookies auf Ihrem Rechner gespeichert werden. Weitere Information
Drucken/exportieren