Cool, ihr seid ja auch Rätsel-Freaks!
Ich beschäftige mich grade mit nem ähnlichen Programm - auch 9 Felder, 2 Spieler. Wisst ihr evtl., wie der auf die Codezeile 5 kommt bzw. die Formel?
Suag, sig.
--------------------------------------------------------------
...eine Methode, die uns ein bestimmtes Feld ausgibt. Schauen wir sie uns zunächst an.
01 # Methode, die ein bestimmtes Feld ausgibt. Entweder wird
02 # das Symbol für den Spieler ausgegeben, der das Feld besetzt hat,
03 # oder es wird die laufende Nummer des Feldes ausgegeben.
04 def print_feld(spalte, zeile, zuege)
05 feld = (spalte-1)*1 + (zeile-1)*3 + 1
06 for zug in zuege do
07 if zug[1] == spalte and zug[2] == zeile
08 feld = (zug[0] ==

? "X" : "O")
09 break
10 end
11 end
12 print feld
13 end
Die Methode ist zwar kurz, aber es passiert hier eine Menge. Ich habe die Zeilen daher einmal nummeriert. Die Methode bekommt nun also die aktuelle Zeile und Spalte des Feldes, das sie ausgeben soll. Zusätzlich bekommt sie noch die Liste aller bisher gemachten Züge.
Die Methode muss nun folgendes machen:
Die laufende Nummer für das Feld berechnen.
Nachschauen, ob für das Feld bereits ein Zug existiert.
Wenn ein Zug existiert, feststellen, welcher Spieler ihn gemacht hat und dann die laufende Nummer mit dem entsprechenden Zeichen für den Spieler überschreiben.
Schauen wir uns zuerst die Berechnung der laufenden Nummer von 1 bis 9 an. Das passiert in Zeile 05 in obigem Code.
...
05 feld = (spalte-1)*1 + (zeile-1)*3 + 1
...
Die laufende Nummer wird durch eine mathematische Formel aus der Spalte und der Zeile bestimmt. Erforderlich ist dabei, dass die Zeilen und Spalten jeweils von 1 bis 3 von links nach rechts bzw. von oben nach unten gezählt werden. Wenn du nicht glaubst, dass das funktioniert, dann probier einfach alle Möglichkeiten für die Formel aus. Zum Beispiel, welche Nummer muss in Spalte 3 und Zeile 2 stehen (das Feld in der Mitte ganz rechts außen)?
-------------------------------------------------------------
Skade hat geschrieben:
Ohne den Spass verderben zu wollen (mehr, um Anregungen zu geben): Dieses Problem lässt sich sehr effizient mit einem Constraint Solver beschreiben und lösen. In dem lassen sich schnell 4 Bedingungen ausdrücken:
* Alle Spalten der Gesamtmatrix enthalten nur unterschiedliche Ziffern
* Alle Zeilen der Gesamtmatrix enthalten nur unterschiedliche Ziffern
* Jede Submatrix enthält nur unterschiedliche Zahlen
* Vorbelegte Zellen (im Constraint-Sprech "Variablen") dürfen ihren Wert nicht ändern
Natürlich nimmt einem das den Spass, die Constraint-Auflösung selbst zu programmieren

. Kurz gesagt wird der Solver dann den gesamten Lösungsraum effizient durchlaufen und die erste oder alle Lösungen ausgeben.
Ich wollte eigentlich ein Beispiel programmieren, aber es gibt einen guten Solver in Ruby, der auch noch ein gutes Beispiel mitbringt:
require 'rubygems'
require 'gecoder'
require 'enumerator'
# Solves the sudoku problem: http://en.wikipedia.org/wiki/Soduko
# The sudoku we want to solve (0 represents that the square is empty).
sudoku = Matrix[
[0,0,0, 2,0,5, 0,0,0],
[0,9,0, 0,0,0, 7,3,0],
[0,0,2, 0,0,9, 0,6,0],
[2,0,0, 0,0,0, 4,0,9],
[0,0,0, 0,7,0, 0,0,0],
[6,0,9, 0,0,0, 0,0,1],
[0,8,0, 4,0,0, 1,0,0],
[0,6,3, 0,0,0, 0,8,0],
[0,0,0, 6,0,8, 0,0,0]]
solution = Gecode.solve do
# Verify that the input is of a valid size.
n = sudoku.row_size
sub_matrix_size = Math.sqrt(n).round
unless sudoku.square? and sub_matrix_size**2 == n
raise ArgumentError, 'Incorrect value matrix size.'
end
sub_count = sub_matrix_size
# Create the squares and initialize them.
squares_is_an int_var_matrix(n, n, 1..n)
sudoku.row_size.times do |i|
sudoku.column_size.times do |j|
squares[i,j].must == sudoku[i,j] unless sudoku[i,j] == 0
end
end
# Constraints.
n.times do |i|
# All rows must contain distinct numbers.
squares.row(i).must_be.distinct(:strength => :domain)
# All columns must contain distinct numbers.
squares.column(i).must_be.distinct(:strength => :domain)
# All sub-matrices must contain distinct numbers.
squares.minor(
(i % sub_count) * sub_matrix_size,
sub_matrix_size,
(i / sub_count) * sub_matrix_size,
sub_matrix_size).must_be.distinct(:strength => :domain)
end
# Branching, we use first-fail heuristic.
branch_on squares, :variable => :smallest_size, :value => :min
end.squares.values
# Output the solved sudoku in a grid.
puts solution.enum_slice(sudoku.row_size).map{ |slice| slice.join(' ') }.join($/)
Achtung, läuft nur unter Ruby 1.8 und benötigt:
gem install gecoder-with-gecode
Gruß,
Skade