Mattis-Schulte / python-sudoku

Sudoku auf Basis eines rekursionsbasierten Backtracking-Algorithmus in Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sudoku (Backtracking-Algorithmus)

Gruppenmitglieder

  • Enno Rockmann: Algorithmus, Qualitätskontrolle, Dokumentation
  • Sajan Sivapatham: UI-Design/-Programmierung, Spiel-Design, Dokumentation
  • Mattis Schulte: Programmierung, Projektleiter, Dokumentation

Zeitplanung

  • 13.09.2022: Grundstruktur und erste Ideen
  • 16.09.2022: Erster Algorithmus
  • 27.09.2022: Laufzeitoptimierung und Vergleich mit anderen Algorithmen
  • 30.09.2022: Terminal-Ausgabe
  • 04.10.2022: Simples Menü und Spiel-Modis
  • 11.10.2022: Grafische Benutzeroberfläche
  • 14.10.2022: Dokumentation und Qualitätskontrolle

Aufgabenbeschreibung

Es soll ein Algorithmus in Python objektorientiert programmiert werden. Es müssen mindestens die Klassen SudokuBoard und SudokuGame existieren. Ein Sudoku-Board „straight forward“ aufzubauen dauert sehr lange, deshalb wird dies zum Beispiel über ein Backtracking-Algorithmus gelöst.

Backtracking

Ein Verfahren, das darauf beruht ein oder mehrere Schritte zurückzugehen, falls keine Lösung gefunden wird. Es kann zu einer oder auch keiner Lösung führen und unter Umständen auch sehr lange Laufzeiten haben.

Die Aufgabe erfordert:

  • die Umsetzung des Spiels in Python unter Berücksichtigung der obigen Vorgaben (es kann auch Alternativen geben, andere Form des Backtrackings z.B.) inkl. Kommentierung des Codes
  • ein Userinterface auf Consolen-Ebene, sodass ein Nutzer das Spiel bedienen kann inkl. der Einführung von Schwierigkeitsgraden (leicht, mittel, schwer) – der User wählt über das Menü den Schwierigkeitsgrad aus und erhält sein Board mit Lücken inkl. Kommentierung des Codes
  • eine Dokumentation/Bericht bestehend aus:
    • der Aufgabenbeschreibung
    • dem Klassenentwurf
    • Beschreibung der Lösung und Besonderheiten
    • Fazit und Selbstreflexion

Klassenentwurf

sudoku-class-diagram

Beschreibung der Lösung

Algorithmen:

Zum Generieren des Sudoku-Boards haben wir uns verschiedene Lösungsansätze überlegt, welche sich grundsätzlich in drei Kategorien einteilen lassen:

  • Mathematisch (wie zum Beispiel durch die Verwendung von Konvolution, was wir nicht näher verfolgt haben, aber eventuelle möglich ist)
  • Backtracking (entweder rekursionsbasiert oder nicht-rekursionsbasiert)
  • Vertauschen (entweder durch das Vertauschen einer einzelnen Zeile, Spalte, 3x3 Abschnitt oder durch das Vertauschen eines kompletten Boards)

Rekursionsbasierter Backtracking-Algorithmus (1,3 ms):
Diese Art von Lösung war, nachdem mathematischen Ansatz die Zweite, die uns in den Sinn kam und die Erste, die wir dann auch tatsächlich ausprogrammiert haben. Sie ist rekursionsbasiert und füllt ein Feld nach dem anderen auf, wodurch wir uns eine sehr gute Performance und gute Lesbarkeit versprochen haben. Dies hat sich auch in der Realität bewahrheitet, auch wenn die Verwendung von Rekursion zugunsten der Performance einiges an Lesbarkeit kostet.

Jedoch haben wir später festgestellt, dass es noch andere Lösungsansätze gibt, die weitaus performanter und lesbarer sind. Allerdings haben wir uns aufgrund der Zuverlässigkeit und Möglichkeit, alle möglichen Sudoku-Boards zu generieren sowie der immer noch mehr als akzeptabler Performance und Lesbarkeit dazu entschieden, diese Lösung weiterhin zu verwenden.

Vertauschen eines schon fertigen Boards (0,2 ms):
Unser nächster Lösungsansatz war das Vertauschen von Zeilen, Spalten und 3x3 Quadraten eines schon hinterlegten Boards. Dadurch würde jegliche Form von Überprüfung unnötig und auch Zufall sollte keinerlei Rolle mehr in der Laufzeit spielt, womit eine lineare Zeitkomplexität erreicht werden würde.

Nach etwas Suchen im Internet haben wir dann diese Lösung gefunden und den Code von Java in Python übersetzt, um ihn mit unserer Backtracking-Lösung zu vergleichen (wie genau der Code funktioniert ist auch in dem StackOverflow-Post beschrieben). Das Ergebnis hat uns tatsächlich etwas überrascht, da wir einen größeren Performance-Unterschied erwartet haben. Bei weiterer Überlegung macht das Ergebnis aber Sinn und bestätigt uns in der Annahme, dass unser Backtracking-Algorithmus nicht schlecht ist. Der Nachteil dieser Lösung ist jedoch, dass der Code im Vergleich schwer verständlich ist.

Vertauschen eines einzigen 3x3 Quadrat bzw. Zeile (0,008 ms):

Unsere tatsächliche Lösung weicht hiervon geringfügig ab, folgt dabei aber weiterhin dem gleichen Prinzip.

Eine weitere Lösungsmöglichkeit, die uns eingefallen ist, ist ein einziges 3x3 Quadrat wie unten in der Abbildung zu vertauschen. Unser Ziel dabei war es, die Lösung mit der kürzesten Laufzeit und der geringsten Länge an Code zu finden, ohne dabei auf andere Dinge Rücksicht zu nehmen. Was wir unserer Meinung nach auch erreicht haben. Hierbei entsteht jedoch der Nachteil, das deutliche Muster zu erkennen sind. Des Weiteren ist die Anzahl der verschiedenen Sudoku-Boards, die mit dieser Methode erstellt werden können, auf 9! (362880) begrenzt.

sudoku-permutation-2

Ausgabe und Spieldesign:

Bei der Ausgabe haben wir uns zunächst auf ein Spiel in der Konsolenebene geeinigt und dies implementiert. Später wollten wir dann aus Gründen der Übersichtlichkeit und Benutzererfahrung stattdessen eine GUI verwenden. Für das Spieldesign wollten wir das Spiel so unkompliziert wie möglich gestalten, daher lassen wir den User beispielsweise keine falschen Zahlen eingeben, sondern weisen ihn sofort auf seinen Fehler hin.

Für die Schwierigkeitsstufen haben wir uns auf folgende drei Optionen geeinigt:

  • Einfach (56 Felder)
  • Mittel (46 Felder)
  • Schwierig (36 Felder)

Terminal:

  1 2 3   4 5 6   7 8 9
A   2   |   3   | 8 7 9
B     9 | 7   1 |   3 4
C 3 6 7 | 9 8   |      
  ------+-------+------
D     3 |       |   2 7
E     2 |     8 | 5   1
F       |     7 |   8 3
  ------+-------+------
G 2 1 6 | 4 7   |   9  
H     8 |       |   4  
I     4 |     3 |   1  

Grafische Benutzeroberfläche:
Leider nicht fertig geworden...

Besonderheiten

  • Kurze Laufzeit
  • Simpler Code
  • Mehrere Lösungsansätze

Fazit und Selbstreflexion

Das Projekt war interessant und hat viel Spaß gemacht, da wir auch privat Sudoku spielen. Der Basiscode stand sehr schnell, daher haben wir die meiste Zeit daran gearbeitet, ihn zu verbessern. Dadurch haben wir es geschafft, sehr schnell sehr gute Sudoku-Boards erstellen zu können, weshalb wir mit dem Ergebnis auch zufrieden sind. Die GUI ist leider nicht fertig geworden, da wir uns zu sehr auf den Algorithmus konzentriert haben und zu spät die Aufgaben aufgeteilt haben. Am Anfang haben wir alles gemeinsam bearbeitet, was dazu führte, dass meistens nur 1-2 Leute aktiv am Code gearbeitet haben. Weshalb wir später die Dokumentation, die GUI, den Algorithmus und sonstiges untereinander aufgeteilt haben, damit am Ende jeder eine Aufgabe hat.

About

Sudoku auf Basis eines rekursionsbasierten Backtracking-Algorithmus in Python


Languages

Language:Python 100.0%