Die Programmiersprache Ruby (German Edition)
9×9-
# Sudoku-Puzzles.
#
# Einige in dieser Implementierung verwendete Definitionen und
# Begriffe:
#
# - Jedes Element eines Puzzles heißt "Zelle".
# - Zeilen und Spalten haben Nummern von 0 bis 8, und die Koordinaten
# [0,0] bezeichnen die Zelle in der linken oberen Ecke des Puzzles.
# - Die neun 3×3-Teilgitter heißen "Boxen" und sind ebenfalls von 0 bis 8
# nummeriert und von links nach rechts sowie von oben nach unten
# geordnet. Die Box in der linken oberen Ecke ist Box 0. Die Box in
# der rechten oberen Ecke ist Box 2. Die Box in der Mitte ist Box 4.
# Die Box in der rechten unteren Ecke ist Box 8.
#
# Neues Puzzle mit Sudoku::Puzzle.new erzeugen, wobei der interne Zustand
# als String oder Array von Strings angegeben wird. Die String(s) sollten
# die Zeichen 1 bis 9 für einen vorgegebenen Wert und '.' für Zellen
# ohne festgelegten Wert verwenden. Whitespace in der Eingabe wird ignoriert.
#
# Lese- und Schreibzugriff auf einzelne Zellen des Puzzles werden mithilfe
# der Operatoren [] und []= durchgeführt, die zweidimensionale
# [Zeile,Spalte]-Indizes erwarten. Diese Methoden verwenden die Ziffern
# (nicht Zeichen) 0 bis 9 für Zellinhalte. 0 steht für einen unbekannten
# Wert.
# Das Prädikat has_duplicates? gibt true zurück, wenn das Puzzle
# ungültig ist, weil irgendeine Zeile, Spalte oder Box dieselbe Ziffer
# zweimal enthält.
#
# Die Methode each_unknown ist ein Iterator, der die Zellen des Puzzles in
# einer Schleife durchgeht und den verknüpften Block einmal für jede Zelle
# mit unbekanntem Wert aufruft.
#
# Die Methode possible gibt ein Array von Integern aus dem Bereich 1..9
# zurück. Die Elemente des Arrays sind die einzigen in der angegebenen
# Zelle zulässigen Werte. Wenn dieses Array leer ist, dann ist das Puzzle
# überspezifiziert und kann nicht gelöst werden. Wenn das Array nur ein
# Element hat, muss dieses Element der Wert für diese Zelle des
# Puzzles sein.
#
class Puzzle
# Diese Konstanten werden zur Übersetzung zwischen der internen
# String-Darstellung eines Puzzles und der internen Speicherung verwendet.
ASCII = ".123456789"
BIN = "\000\001\002\003\004\005\006\007\010\011"
# Dies ist die Initialisierungsmethode für die Klasse. Sie wird auto-
# matisch für neue Puzzle-Instanzen aufgerufen, die mit Puzzle.new
# erzeugt werden. Übergeben Sie das Eingabepuzzle als Array von Zeilen
# oder als einzelnen String. Verwenden Sie die ASCII-Ziffern 1 bis 9
# sowie das Zeichen '.' für unbekannte Zellen. Whitespace, einschließlich
# Zeilenumbrüche, wird entfernt.
def initialize(lines)
if (lines.respond_to? :join) # Sieht Argument wie Array aus Zeilen aus?
s = lines.join # Dann zu einzelnem String vereinen
else # Andernfalls String annehmen
s = lines.dup # Eine private Kopie davon erstellen
end
# Whitespace (incl. Zeilenumbrüche) aus den Daten entfernen
# '!' zeigt an, dass dies eine Mutator-Methode ist, die den String
# direkt modifiziert, anstatt eine Kopie zu erstellen.
s.gsub!(/\s/, "") # /\s/ ist ein Regexp für beliebigen Whitespace.
# Eine Ausnahme auslösen, wenn die Eingabe die falsche Größe hat
# Beachten Sie, dass wir unless statt if verwenden, und zwar
# in seiner Modifier-Form.
raise Invalid, "Gitter falscher Größe" unless s.size == 81
# Auf ungültige Zeichen prüfen und Position des ersten speichern
# Beachten Sie, dass wir die Werte gleichzeitig zuweisen und prüfen.
if i = s.index(/[^123456789\.]/)
# Ungültiges Zeichen in die Fehlermeldung einschließen
# Beachten Sie den Ruby-Ausdruck in #{} im String-Literal.
raise Invalid, "Illegales Zeichen #{s[i,1]} im Puzzle"
end
# Die folgenden zwei Zeilen konvertieren unseren String aus ASCII-
# Zeichen in ein Array von Integern; dafür werden zwei mächtige
# String-Methoden verwendet. Das Ergebnis-Array wird in der Instanz-
# variablen @grid gespeichert. Die Zahl 0 steht für einen unbe-
# kannten Wert.
s.tr!(ASCII, BIN) # ASCII-Zeichen in Bytes übersetzen
@grid = s.unpack('c*') # Nun die Bytes in ein Array von Zahlen entpacken
# Prüfen, ob Zeilen, Spalten und Boxen keine Duplikate enthalten
raise Invalid, "Anfangspuzzle enthält Duplikate" if has_duplicates?
end
# Zustand des Puzzles als String von 9 Zeilen mit je 9 Zeichen
# (plus Zeilenumbruch) zurückgeben
def to_s
# Diese Methode wird mithilfe einer einzelnen Zeile Ruby-Magie
# implementiert, die die Schritte der Methode initialize()
Weitere Kostenlose Bücher