Portal > Foren > Offtopic > Projekte unserer Mitglieder > sudokular.com - sudoku on a new level
Antwort
 
Themen-Optionen Thema durchsuchen
Alt 11.12.2007, 12:50 Nach oben    #21
Ben
Benjamin Klaile
 
Benutzerbild von Ben
 
Registriert seit: 02.12.2004
Ort: Remagen
Beiträge: 4.516
Standard

Mach das mal. Durchaus interessant
Ben ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 11.12.2007, 13:43 Nach oben    #22
Erfahrener Benutzer
 
Registriert seit: 02.02.2005
Beiträge: 539
Standard

OK, der Code ist wie gesagt etwas älter. Hab auch gerade festgestellt, dass er nur teilweise kommentiert ist. Hab jetzt mal die nötigsten Kommentare und eine Beispiel-Main-Methode hinzugefügt, bei Fragen einfach die Hand heben (könnte man sicher noch optimieren, z. B. keinen Vector bei getPoss verwenden ... aber so funktioniert er ja erstmal!).

Code:
import java.util.Arrays;
import java.util.Vector;

public class SudoGenerator {
    
    private static int[][] cur = null; // die Matrix komplett ausgefüllt
    
    /**
     * Berechnet alle möglichen Zahlen für eine bestimmte Position in einem vorgegebenen, teilweise
     * ausgefüllten Sudoku-Feld
     * 
     * @param y - Y-Position in der Matrix
     * @param x - X-Position in der Matrix
     * @param mat - die Matrix
     * 
     * @return Ein Array mit allen Möglichen Zahlen zur angegebenen Position
     */
    public static int[] getPoss(int y, int x, int[][] mat) {
        
        Vector<Integer> poss = new Vector<Integer>();
        int quadStartX = (int)(x / 3) * 3; // Startfeld auf der X-Achse des Quadrats, in dem sich die übergebene Position befindet
        int quadStartY = (int)(y / 3) * 3; // Startfeld auf der Y-Achse des Quadrats, in dem sich die übergebene Position befindet
        for (int i = 1; i < 10; i++) { // Der Vector mit allen Zahlen befüllen
            poss.add(i);
        }
        for (int i = 0; i < mat.length; i++) { // Zeilen und Spalten auf bereits angelegte Zahlen überprüfen
            if (i != y && mat[i][x] != 0) {
                if (poss.contains(mat[i][x]) || poss.contains(mat[i][x] - 10)) {
                    poss.removeElement(mat[i][x]);
                    poss.removeElement(mat[i][x] - 10);
                }
            }
            if (i != x && mat[y][i] != 0) {
                if (poss.contains(mat[y][i]) || poss.contains(mat[y][i] - 10)) {
                    poss.removeElement(mat[y][i]);
                    poss.removeElement(mat[y][i] - 10);
                }
            }
        }
        for (int i = 0; i < 3; i++) { // Quadrat wird auf bereits angelegte Zahlen überprüft
            for (int j = 0; j < 3; j++) {
                if (i + quadStartY != y && j + quadStartX != x && mat[i + quadStartY][j + quadStartX] != 0) {
                    poss.removeElement(mat[i + quadStartY][j + quadStartX]);
                    poss.removeElement(mat[i + quadStartY][j + quadStartX] - 10);
                }
            }
        }
        int[] val = new int[poss.size()];
        for (int i = 0; i < val.length; i++) { // Von Vector in Array
            val[i] = poss.get(i);
        }
        return val;
    }
    
    /**
     * Leert das Sudoku-Feld
     */
    public static void blankSudo() {
        
        cur = new int[9][9];
    }
    
    /**
     * Generiert eine Sudoku-Matrix (vollständig ausgefüllt)
     */
    public static boolean generateSudo() {
        
        cur = new int[9][9];
        return generate(0, 0);
    }
    
    /**
     * Überprüft, ob die aktuelle Matrix gültig ist
     */
    public static boolean check() {
        
        for (int y = 0; y < cur.length; y++) {
            for (int x = 0; x < cur[y].length; x++) {
                if (cur[y][x] > 0) {
                    if (Arrays.binarySearch(getPoss(y, x, cur), cur[y][x]) < 0) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    /**
     * Löst ein Sudoku-Feld
     */
    public static boolean solveSudo() {
        
        if (!check()) {
            return false;
        }
        for (int y = 0; y < cur.length; y++) {
            for (int x = 0; x < cur[y].length; x++) {
                if (cur[y][x] > 0) {
                    cur[y][x] += 10;
                }
            }
        }
        boolean val = generate(0, 0);
        for (int i = 0; i < cur.length; i++) {
            for (int j = 0; j < cur[i].length; j++) {
                if (cur[i][j] > 9) {
                    cur[i][j] -= 10;
                }
            }
        }
        return val;
    }
    
    /**
     * Erstellt rekursiv ein Sudokufeld mit 9x9 Feldern. Dabei werden zufällig den Regeln von Sudoku entsprechende
     * Zahlen ausgewählt und nacheinander in die jeweiligen Felder eingefügt. Anschließend geschied selbiges für
     * das nächste Feld. Gibt es keine möglichen Zahlen mehr für ein Feld, so wird versucht für das vorhergehende Feld
     * eine andere Zahl zu ermitteln.
     * 
     * @param y - zu bearbeitendes Feld auf der Y-Achse
     * @param x - zu bearbeitendes Feld auf der X-Achse
     * 
     * @return true falls eine mögliche Belegung gefunden wurde, ansonsten false
     */
    public static boolean generate(int y, int x) {
        
        if (y >= cur.length) { // Spielfeld wurde erfolgreich erstellt, wenn das Ende erreicht ist
            return true;
        }
        int[] poss = getPoss(y, x, cur); // Mögliche Zahlen für dieses Feld ermitteln
        int nextX = x + 1; // nächstes Feld auf der X-Achse festlegen
        int nextY = y; // nächstes Feld auf der Y-Achse festlegen
        if (nextX >= cur[y].length) { // falls nächstes Feld auf der X-Achse nicht existiert ...
            nextX = 0;  // ... nächstes Feld auf der X-Achse = 0
            nextY++; // ... nächstes Feld auf der Y-Achse + 1
        }
        if (poss.length == 0) { // Wenn es für dieses Feld keine möglichen Zahlen gibt ...
            if (cur[y][x] < 10) {
                cur[y][x] = 0; // ... setze das aktuelle Feld wieder auf 0
            }
            return false; // ... geb der aufrufenden Methode bescheid
        }
        else if (cur[y][x] == 0 ) {
            cur[y][x] = poss[(int)(Math.random() * poss.length)]; // Wähle eine zufällige Zahl aus den möglichen Zahlen für dieses Feld
        }
        
        while (!generate(nextY, nextX)) { // solange das generieren des nächsten Feldes fehlschlägt
            if (cur[y][x] > 9) {
                return false;
            }
            poss = remove(cur[y][x], poss); // ausgewählte Ziffer löschen, da nachfolgende Methode bei dieser Ziffer keine Zahl setzen kann
            if (poss.length == 0) { // überprüfen ob noch weitere mögliche Zahlen vorhanden sind
                cur[y][x] = 0;
                return false;
            }
            else {
                cur[y][x] = poss[(int)(Math.random() * poss.length)]; // neue Zahl zuweisen
            }
        }
        return true;
    }
    
    /**
     * Entfernt eine bestimmte Zahl aus einem int-Array.
     * 
     * @param ziffer - die zu entfernende Zahl
     * @param kette - das Integer-Array aus dem die Ziffer entfernt werden soll 
     * 
     * @return das übergebene int-Array ohne die übergebene Ziffer
     */
    private static int[] remove(int ziffer, int[] kette) {
        
        int[] array = new int[kette.length - 1];
        for (int i = 0, j = 0; i < kette.length; i++, j++) {
            if (kette[i] != ziffer) {
                array[j] = kette[i];
            }
            else {
                j--;
            }
        }
        return array;
    }
    
    /**
     * @return gibt das erstellte Sudoku-Feld zurück
     * 
     * @see generateSudo()
     * @see createSpielfeld(int showFields)
     */
    public static int[][] getMatrix() {
        return cur;
    }
    
    /**
     * Setzt ein Sudoku-Feld
     */
    public static void setMatrix(int[][] matrix) {
        cur = matrix;
    }
    
    /**
     * Erstellt ein Spielfeld aus der vorher generierten Matrix. Dabei werden zufällige Felder ausgewählt,
     * die schon im Voraus angezeigt werden. Dadurch können für ein und die selbe Matrix mehrere, unterschiedliche
     * Spielfelder erstellt werden. Die Anzahl der vorbelegten Felder richtet sich nach dem übergebenen Parameter.
     * 
     * @param showFields - Anzahl der Felder die ausgefüllt werden sollen
     * 
     * @return gibt ein zweidimensonales Spielfeld der zuvor erstellten Matrix zurück
     * 
     * @see getMatrix()
     * @see generateSudo()
     */
    public static int[][] createSpielfeld(int showFields) {
        
        if (cur == null) { // Wenn noch keine Matrix angelegt wurde eine anlegen
            generateSudo();
        }
        else if (showFields < 0) { // Stellt sicher, dass die Anzahl der vorgeblendten Fenster positiv ist
            showFields *= -1;
        }
        int[][] field = new int[cur.length][cur[0].length]; // Array in welchem das Spielfeld gespeichert wird
        for (int i = 0; i < field.length; i++) { // Verschachtelte Schleife um die bisherige Matrix zu klonen
            for (int j = 0; j < field[i].length; j++) {
                field[i][j] = cur[i][j];
            }
        }
        int clear = field.length * field[0].length - showFields - 1; // So viele Felder werden nicht vorgeblendet
        if (clear > 80) { // Falls mehr Felder nicht vorgeblendet werden sollen, als es überhaupt gibt wird die max. Zahl an Feldern vorgeblendet
            clear = 80;
        }
        int rand1 = 0;
        int rand2 = 0;
        for (int i = clear; i > -1; i--) { // Solange, wie noch zuviele Felder vorgeblendet werden
            rand1 = (int)(Math.random() * field.length); // Zufälliges Feld auf der Y-Achse auswählen
            rand2 = (int)(Math.random() * field[0].length); // Zufälliges Feld auf der X-Achse auswählen
            if (field[rand1][rand2] == 0) { // Ist das Feld schon als nicht vorgeblendet markiert => Schritt zurück gehen
                i++;
            }
            else { // Ansonsten Feld als nicht vorgeblendet markieren
                field[rand1][rand2] = 0;
            }
        }
        return field;
    }
    
    public static void main(String[] args) {
        
        int[][] mat = createSpielfeld((int)(Math.random() * 40 + 22));
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat[i].length; j++) {
                System.out.print(mat[i][j] + " ");
            }
            System.out.println();
        }
        setMatrix(mat);
        System.out.println("\n-----------------\n");
        solveSudo();
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat[i].length; j++) {
                System.out.print(mat[i][j] + " ");
            }
            System.out.println();
        }
    }
}
Gottzilla ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 11.12.2007, 15:30 Nach oben    #23
Johannes Müller
 
Benutzerbild von $traight-$hoota
 
Registriert seit: 15.09.2005
Ort: Königreich Flieden
Beiträge: 551
Standard

was bringt denn poss.removeElement(mat[i][x] - 10);??
__________________
Weißt Bescheid - Scheiß wie weit
$traight-$hoota ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 12.12.2007, 07:26 Nach oben    #24
Erfahrener Benutzer
 
Registriert seit: 02.02.2005
Beiträge: 539
Standard

Wenn ein Sudoku nicht neu erstellt, sondern gelöst werden soll, so werden alle bereits eingetragenen Zahlen + 10 genommen, damit ich beim Backtracing feststellen kann, ob es sich um eine vorgeblendete und somit nicht veränderbare, oder um eine "normale" Zahl, die ich verändern darf, handelt. Und auf diese Zahlen muss natürlich auch geprüft werden.
Gottzilla ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
PingBacks sind an
RefBacks sind aus

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
JInternal Frame Fehler asenodin Desktop-Applikationen und Grafik 11 26.12.2006 23:56
Vokabeltrainer asenodin Allgemeine Java-Programmierung 9 28.05.2006 21:04
Problem mit getText()-Methode Paule Allgemeine Java-Programmierung 5 19.03.2005 20:38
(re)paint Funktion für geometrische Figuren ??? netchamber Desktop-Applikationen und Grafik 2 19.03.2005 09:46
kl. Zeichenprogramm - Farbe wird nicht gesetzt :*( pro_evo Desktop-Applikationen und Grafik 6 04.02.2005 16:28


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:51 Uhr.


Powered by vBulletin® Version 3.7.4 (Deutsch)
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45