source: Java_Quellcode_SOOP_Vorlesung/rekursion/SudokuSolverRekursiv.java @ 435

Last change on this file since 435 was 435, checked in by tr, 5 years ago

Sudoku: Kleinigkeiten

File size: 4.9 KB
Line 
1package eu.hsrw.tr.prog.vl.rekursion;
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 SudokuSolverRekursiv {
11
12    /**
13     * Testet, ob die Zahl an der Stelle ohne Verletzung der Sudokubedingung
14     * eingefügt werden kann.
15     *
16     * @param a
17     *            9x9 Array mit dem Sudoku
18     * @param zeile
19     *            Zeile der zu prüfenden Zelle
20     * @param spalte
21     *            Spalte der zu prüfenden Zelle
22     * @param kandidat
23     *            Kandidat für die Einfügung
24     * @return false, falls die Kandidatenzahl die Sudkobedingung verletzt,
25     *         sonst true
26     */
27    public static boolean kandidatOK(int[][] a, int zeile, int spalte, int kandidat) {
28        // Feststellen in welchem Block wir eigentlich sind -> wir benötigen die
29        // kleinste Zeile und die kleinste Spalte dieses Blocks als Offset
30        int offsetZ = (zeile / 3) * 3;
31        int offsetS = (spalte / 3) * 3;
32       
33        for (int i = 0; i < a.length; i++) {
34           
35            // teste Zeile, Spalte, Block, in dieser Reihenfolge
36            if (Math.abs(a[zeile][i]) == kandidat
37                || Math.abs(a[i][spalte]) == kandidat
38                || Math.abs(a[offsetZ + i / 3][offsetS + i % 3]) == kandidat) {
39               
40                return false;
41            }
42        }
43        return true;       
44    }
45
46    private static int aufrufe = 0;
47   
48    /**
49     * Löst das übergebene 9x9 Sudoku mittels Brute Force und Backtracking: Es
50     * wird mit dem Feld oben links begonnen und dann rekursiv spalten- und zeilenweise
51     * nach rechts unten gearbeitet. Als erster Wert wird die 1 versucht. Falls
52     * der Versuch einen Konflikt auslöst, wird die Zahl immer weiter erhöht,
53     * bis entweder kein Konflikt mehr auftritt oder die Zahl 9 überschritten
54     * wurde. Falls 9 überschritten wurde, konnte kein passender Eintrag
55     * gefunden werden, das Problem muss also schon weiter vorn liegen. Es wird
56     * um ein Feld zurückgegangen und dort die nächsthöhere Zahl versucht. Ggf.
57     * sind sehr viele Rücksprünge erforderlich, da viele Kombinationen
58     * durchprobiert werden müssen.
59     *
60     * @param a
61     *            zu lösendes Sudoku als 9x9 Array
62     * @param position
63     *            Index des aktuellen Feldes
64     *
65     * @return Indikator, ob eine gültige Einfügung in das Feld gefunden wurde.
66     *
67     */
68    public static boolean solve(int[][] a, int position) {
69        aufrufe++;
70       
71        // sind wir fertig?
72        if (position == 81) {
73            return true;
74        }
75
76        // Zeile und Spalte aus dem Index der aktuellen Position berechnen
77        int zeile = position / 9;
78        int spalte = position % 9;
79
80        // ist das Feld an der aktuellen Position vorbelegt?
81        if (a[zeile][spalte] != 0) {
82            // gehe zum nächsten Feld
83            return solve(a, position + 1);
84        }
85
86        // Zahlen von 1 bis 9 testen: Konnte eingefügt werden, wird rekursiv die
87        // nächste Position angesprungen
88        for (int kandidat = 1; kandidat <= 9; kandidat++) {
89            if (kandidatOK(a, zeile, spalte, kandidat)) {
90                // Zahl an Position einfügen
91                a[zeile][spalte] = kandidat;
92                // Rekursiver Aufruf mit nächster Position
93                if (solve(a, position + 1)) {
94                    // Wir geben ein erhaltenes true weiter nach oben
95                    return true;
96                }
97            }
98        }
99
100        // keine Zahl hat gepasst: Feld an der aktuellen Position nullen und
101        // zurückspringen.
102        // Durch den rekursiven Aufruf dieser Methode kehrt return einen Schritt
103        // nach oben zurück. Dort war die Position noch um 1 kleiner, es wird
104        // also nach vorn gegangen.
105        a[zeile][spalte] = 0;
106        return false;
107    }
108
109    /**
110     * Gibt ein Sudoku auf der Konsole aus
111     *
112     * @param a
113     *            zweidimensionales Array mit dem Sudoku
114     */
115    public static void printSudoku(int[][] a) {
116        System.out.println("\n----------------------");
117
118        for (int i = 0; i < a.length; i++) {
119            System.out.print("|");
120            for (int j = 0; j < a[i].length; j++) {
121                System.out.print(Math.abs(a[i][j]) + " ");
122                if (j % 3 == 2) {
123                    System.out.print("|");
124                }
125            }
126            if (i % 3 == 2) {
127                System.out.print("\n----------------------");
128            }
129            System.out.println();
130        }
131    }
132
133    public static void main(String[] args) {
134
135        // Beispiele für schnell und langsam zu lösende Sudokus
136        int[][] sudokuLeer = new int[9][9];
137
138        int[][] sudokuSchnell = {
139                { 0, 0, 5, 0, 0, 0, 0, 6, 0},
140                { 0, 0, 8, 7, 0, 0, 0, 0, 0},
141                { 0, 0, 0, 0, 3, 0, 0, 0, 9},
142                { 0, 0, 0, 0, 0, 6, 0, 0, 0},
143                { 0, 0, 3, 0, 0, 0, 0, 0, 7},
144                { 0, 0, 0, 5, 0, 0, 0, 4, 0},
145                { 0, 9, 0, 0, 0, 1, 0, 0, 0},
146                { 0, 6, 0, 0, 0, 0, 7, 0, 0},
147                { 0, 0, 0, 0, 0, 5, 0, 0, 8}
148        };
149
150        int[][] sudokuLangsam = {
151                { 0, 0, 0, 0, 0, 0, 0, 0, 0},
152                { 0, 0, 0, 0, 0, 0, 9, 6, 0},
153                { 5, 8, 0, 0, 3, 0, 0, 0, 0},
154                { 0, 7, 0, 0, 0, 5, 0, 0, 0},
155                { 0, 0, 3, 0, 0, 0, 0, 0, 0},
156                { 0, 0, 0, 6, 0, 0, 1, 0, 5},
157                { 0, 0, 0, 0, 0, 0, 0, 7, 0},
158                { 6, 0, 0, 0, 0, 4, 0, 0, 0},
159                { 0, 0, 9, 0, 7, 0, 0, 0, 8}
160        };
161
162        int[][] sudoku;
163        sudoku = sudokuLangsam;
164        // sudoku = sudokuLangsam;
165        // sudoku = sudokuLeer;
166
167        printSudoku(sudoku);
168
169        solve(sudoku, 0);
170       
171        printSudoku(sudoku);
172
173        System.out.println("Aufrufe: " + aufrufe);
174    }
175}
Note: See TracBrowser for help on using the repository browser.