source: Java_Quellcode_SOOP_Vorlesung/arrays/SudokuSolver.java @ 240

Last change on this file since 240 was 240, checked in by tr, 8 years ago

Variablenname im Sudokusolver angepasst

File size: 6.2 KB
Line 
1package eu.hsrw.tr.prog.vl.arrays;
2
3/**
4 * Löst 9x9 Sudokus mittels Brute Force und Backtracking: Durchprobieren von
5 * oben links nach unten rechts
6 *
7 * @author Thomas Richter
8 *
9 */
10public class SudokuSolver {
11
12    /**
13     * Testet, ob die Zahl bereits in der angegebenen Zeile des Sudokus vorkommt
14     *
15     * @param a
16     *            9x9 Array mit dem Sudoku
17     * @param zeile
18     *            zu prüfende Zeile
19     * @param zahl
20     *            zu prüfende Zahl
21     * @return false, falls die Zahl vorkommt, sonst true
22     */
23    public static boolean zeileOK(int[][] a, int zeile, int zahl) {
24        for (int i = 0; i < a.length; i++) {
25            if (Math.abs(a[zeile][i]) == zahl) {
26                return false;
27            }
28        }
29        return true;
30    }
31
32    /**
33     * Testet, ob die Zahl bereits in der angegebenen Spalte des Sudokus
34     * vorkommt
35     *
36     * @param a
37     *            9x9 Array mit dem Sudoku
38     * @param spalte
39     *            zu prüfende Spalte
40     * @param zahl
41     *            zu prüfende Zahl
42     * @return false, falls die Zahl vorkommt, sonst true
43     */
44    public static boolean spalteOK(int[][] a, int spalte, int zahl) {
45        for (int i = 0; i < a.length; i++) {
46            if (Math.abs(a[i][spalte]) == zahl) {
47                return false;
48            }
49        }
50        return true;
51    }
52
53    /**
54     * Testet, ob die Zahl bereits in dem 3x3 Block vorkommt, in dem das durch
55     * zeile und spalte festgelegte Feld liegt
56     *
57     * @param a
58     *            9x9 Array mit dem Sudoku
59     * @param zeile
60     *            Zeile des Elements, dessen 3x3 Block getestet werden soll
61     * @param spalte
62     *            Spalte des Elements, dessen 3x3 Block getestet werden soll
63     * @param zahl
64     *            zu prüfende Zahl
65     * @return false, falls die Zahl vorkommt, sonst true
66     */
67    public static boolean blockOK(int[][] a, int zeile, int spalte, int zahl) {
68        // Feststellen in welchem Block wir eigentlich sind -> wir benötigen die
69        // kleinste Zeile und die kleinste Spalte dieses Blocks
70        int minZeile = (zeile / 3) * 3;
71        int minSpalte = (spalte / 3) * 3;
72
73        for (int i = minZeile; i < minZeile + 3; i++) {
74            for (int j = minSpalte; j < minSpalte + 3; j++) {
75                if (Math.abs(a[i][j]) == zahl) {
76                    return false;
77                }
78            }
79        }
80        return true;
81    }
82
83    /**
84     * Löst das übergebene 9x9 Sudoku mittels Brute Force und Backtracking: Es
85     * wird mit dem Feld oben links begonnen und dann spalten- und zeilenweise
86     * nach rechts unten gearbeitet. Als erster Wert wird die 1 versucht. Falls
87     * der Versuch einen Konflikt auslöst, wird die Zahl immer weiter erhöht,
88     * bis entweder kein Konflikt mehr auftritt oder die Zahl 10 erreicht wurde.
89     * Falls 10 erreicht wurde konnte kein passender Eintrag gefunden werden,
90     * das Problem muss also schon weiter vorn liegen. Es wird um ein Feld
91     * zurückgegangen und dort die nächsthöhere Zahl versucht. Ggf. sind sehr
92     * viele Rücksprünge erforderlich, da viele Kombinationen durchprobiert
93     * werden müssen.
94     *
95     * @param a
96     *            zu lösendes Sudoku als 9x9 Array
97     */
98    public static void solve(int[][] a) {
99        // wir beginnen oben links und gehen nach unten rechts durch
100        // Nummer des Feldes: 0..80
101        int feld = 0;
102        // zähle die Rücksprünge (nur zu Informationszwecken)
103        int rueckspruenge = 0;
104
105        while (feld < 81) {
106            // Zeile und Spalte aus der Nummer des Feldes bestimmen
107            int zeile = feld / 9;
108            int spalte = feld % 9;
109
110            // Es werden nur Felder bearbeitet, die nicht negativ sind.
111            // negative Zahlen sind die Startbelegung -> überspringen
112            if (a[zeile][spalte] >= 0) {
113
114                // Versuche, eine Zahl im Feld a[zeile][spalte] einzubauen
115                // Beginne mit der aktuellen Zahl + 1: anfangs 0 + 1
116                int kandidat = a[zeile][spalte] + 1;
117
118                // testen, ob die Zahl einen Sudoku-Fehler verursacht
119                // bei Fehler: Zahl erhöhen
120                while (!zeileOK(a, zeile, kandidat) ||
121                       !spalteOK(a, spalte, kandidat) ||
122                       !blockOK(a, zeile, spalte, kandidat)) {
123                    kandidat++;
124                }
125
126                // Warum sind wir aus der Schleife rausgekommen?
127                if (kandidat < 10) {
128                    // zahl < 10 hat keinen Fehler verursacht -> eintragen
129                    a[zeile][spalte] = kandidat;
130                    // weiterrücken zum nächsten Feld
131                    feld++;
132
133                } else {
134                    // zahl == 10 -> keine passende Zahl gefunden -> zurückgehen
135                    // Feld auf 0 zurücksetzen damit der Test nicht verfälscht
136                    // wird
137                    a[zeile][spalte] = 0;
138
139                    // Wir dürfen nicht auf ein Feld mit negativem Eintrag
140                    // zurückspringen, da die negativen Zahlen die Startbelegung
141                    // kennzeichnen -> Zurück bis Inhalt nicht mehr negativ
142                    do {
143                        feld--;
144                        rueckspruenge++;
145                    } while (a[feld / 9][feld % 9] < 0);
146                }
147
148            } else {
149                // Zahl war negativ -> weiterrücken
150                feld++;
151            }
152        }
153        System.out.println("Rücksprünge: " + rueckspruenge);
154    }
155
156    /**
157     * Gibt ein Sudoku auf der Konsole aus
158     *
159     * @param a
160     *            zweidimensionales Array mit dem Sudoku
161     */
162    public static void printSudoku(int[][] a) {
163        System.out.println("\n----------------------");
164
165        for (int i = 0; i < a.length; i++) {
166            System.out.print("|");
167            for (int j = 0; j < a[i].length; j++) {
168                System.out.print(Math.abs(a[i][j]) + " ");
169                if (j % 3 == 2) {
170                    System.out.print("|");
171                }
172            }
173            if (i % 3 == 2) {
174                System.out.print("\n----------------------");
175            }
176            System.out.println();
177        }
178    }
179
180    public static void main(String[] args) {
181
182        // Beispiele für schnell und langsam zu lösende Sudokus
183        int[][] sudokuLeer = new int[9][9];
184
185        int[][] sudokuSchnell = {
186                { 0,  0, -5,  0,  0,  0,  0, -6,  0},
187                { 0,  0, -8, -7,  0,  0,  0,  0,  0},
188                { 0,  0,  0,  0, -3,  0,  0,  0, -9},
189                { 0,  0,  0,  0,  0, -6,  0,  0,  0},
190                { 0,  0, -3,  0,  0,  0,  0,  0, -7},
191                { 0,  0,  0, -5,  0,  0,  0, -4,  0},
192                { 0, -9,  0,  0,  0, -1,  0,  0,  0},
193                { 0, -6,  0,  0,  0,  0, -7,  0,  0},
194                { 0,  0,  0,  0,  0, -5,  0,  0, -8}
195        };
196
197        int[][] sudokuLangsam = {
198                {  0,  0,  0,  0,  0,  0,  0,  0,  0},
199                {  0,  0,  0,  0,  0,  0, -9, -6,  0},
200                { -5, -8,  0,  0, -3,  0,  0,  0,  0},
201                {  0, -7,  0,  0,  0, -5,  0,  0,  0},
202                {  0,  0, -3,  0,  0,  0,  0,  0,  0},
203                {  0,  0,  0, -6,  0,  0, -1,  0, -5},
204                {  0,  0,  0,  0,  0,  0,  0, -7,  0},
205                { -6,  0,  0,  0,  0, -4,  0,  0,  0},
206                {  0,  0, -9,  0, -7,  0,  0,  0, -8}
207        };
208
209        int[][] sudoku;
210        sudoku = sudokuSchnell;
211        // sudoku = sudokuLangsam;
212        // sudoku = sudokuLeer;
213
214        printSudoku(sudoku);
215
216        solve(sudoku);
217
218        printSudoku(sudoku);
219    }
220}
Note: See TracBrowser for help on using the repository browser.