Lektion 12 - Tic-Tac-Toe, Eingabe von Zügen

Erstellt von Frithjof Sun, 16 Sep 2007 21:50:00 GMT

Tic-Tac-Toe hast du nun schon soweit implementiert, dass das Spielbrett auf der Konsole erscheint und du auch über den Aufruf einer Methode Züge hinzufügen kannst. Wir machen in dieser Lektion das Spiel interaktiv. Ruby sagt dir, wer als nächstes dran ist und wartet auf die Eingabe des Spielers. Das Eingeben von Werten, die das Rubyprogramm dann weiterverwendet, hast du ja schon in der Lektion 7 ausprobiert, wo du ein Fahrrad über die Tastatur steuern konntest. Aber alles schön der Reihe nach, denn vorher schaffst du noch etwas Ordnung in das Chaos der letzten Lektion.

Programme gliedern

In der Lektion 11 hast du genau vier Methoden entwickelt: spielfeld, print_zeile, print_feld und zug_hinzu. Unterhalb der Methoden geht dann das eigentliche Programm mit dem Erzeugen der Variablen zuege für die Liste der Züge und dem Aufruf des Spielfeldes los. Im Verlauf deiner Arbeiten an dem Spiel Tic-Tac-Toe werden noch einige Methoden hinzu kommen. Auch wird das eigentliche Programm unterhalb der Methoden umfangreicher werden. Den Überblick zu behalten wird zunehmend schwieriger. Dagegen werden wir folgendes tun:
  1. Du legst eine neue Datei mit Namen tictactoe.rb an. In dieser Datei wirst du alle Methoden verwalten.
  2. Das eigentliche Programm behältst du in einer anderen Datei, zum Beispiel für diese Lektion in der Datei lektion_12.rb. In dieser Datei machst du die Methoden aus tictactoe.rb über den require Befehlt bekannt.

So sollte es nach dem Umorganisieren bei dir auch aussehen:

Datei tictactoe.rb


# tictactoe.rb

# Methode, die das Spielfeld im Ausgabebereich 'out' ausgibt
# und dabei auch die in 'zuege' angegebenen Züge mit ausgibt.
# Ist für ein Feld noch kein Zug erfolgt, dann wird die
# Nummer des Feldes ausgegeben. Die Felder sind dabei von
# links nach rechts und oben nach unten von 1 bis 9 fortlaufend
# nummeriert.
def spielfeld(out, zuege)
  out.puts  "/-----------\\" 
  out.print "| " 

  print_zeile(out, 1, zuege)

  out.puts " |" 
  out.puts  "|---|---|---|" 
  out.print "| " 

  print_zeile(out, 2, zuege)

  out.puts " |" 
  out.puts  "|---|---|---|" 
  out.print "| " 

  print_zeile(out, 3, zuege)

  out.puts " |" 
  out.puts "\\-----------/" 
end

# Methode zum Ausgeben einer einzigen Zeile im Ausgabebereich 'out'.
# Welche Zeile ausgegeben werden soll ist in 'zeile' übergeben.
# Die Liste der Züge in 'zuege' brauchen wir hier, um das richtige
# Symbol (X oder O) später in den Feldern ausgeben zu können, 
# oder die Nummer des Feldes.
def print_zeile(out, zeile, zuege)
  spalte = 1
  1.upto(3) do 
    print_feld(spalte, zeile, zuege)
    out.print " | " unless spalte == 3
    spalte += 1
  end
end

# Methode, die ein bestimmtes Feld ausgibt. Entweder wird
# das Symbol für den Spieler ausgegeben, der das Feld besetzt hat,
# oder es wird die laufende Nummer des Feldes ausgegeben.
def print_feld(spalte, zeile, zuege)
  res = (spalte-1)*1 + (zeile-1)*3 + 1
  for z in zuege do
    if z[1] == spalte and z[2] == zeile
      res = (z[0] == :x ? "X" : "O") 
      break
    end
  end
  print res
end

# Methode zum Hinzufügen eines Zuges.
def zug_hinzu(wer, spalte, zeile, zuege)
  # Ein Zug besteht aus einer kleinen Liste mit genau 3 Elementen:
  # 1. Element 'wer': gibt den Spieler an, entweder :x oder :o
  # 2. Element 'spalte': die Spalte, in der der Zug gesetzt werden soll
  # 3. Element 'zeile': die Zeile, in die der Zug gesetzt werden soll
  zuege << [wer, spalte, zeile]
end

Datei lektion_12.rb


# lektion_12.rb

# Bekanntmachen der Methoden aus tictactoe.rb
require 'tictactoe'

# Variable für die Liste der Züge; Sie ist anfangs leer.
zuege = []

# Spielfeld auf der Standardausgabe einmal ausgeben.
spielfeld(STDOUT, zuege)

# Einen Zug zum Testen: O setzt oben links!
zug_hinzu(:o, 1, 1, zuege)

# Neues Spielfeld ausgeben
spielfeld(STDOUT, zuege)

Ab jetzt gilt: Neue Methoden gehören nur noch in die Datei tictactoe.rb, das Programm selbst erweiterst du nur noch in der Datei lektion_12.rb (in den nächsten Lektionen natürlich entsprechend).

Eingabe von Zügen

Genug der Vorarbeiten, jetzt können wir uns der eigentlichen Aufgabe dieser Lektion widmen. Zunächst ändern wir das Programm in lektion_12.rb wie folgt:


# lektion_12.rb

require 'tictactoe'

# Variable für die Liste der Züge; Sie ist anfangs leer.
zuege = []

# Spielfeld auf der Standardausgabe einmal ausgeben.
spielfeld(STDOUT, zuege)

play_2_spieler(STDOUT, STDIN, zuege)

Nach dem Anlegen der leeren Liste für die Züge und der ersten Ausgabe des noch leeren Spielfeldes, rufen wir die Methode play_2_spieler auf. Neu ist hier lediglich die Variable mit dem Namen STDIN. In der letzten Lektion hast du gelernt, dass STDOUT der Name für die Standardausgabe, also die Konsole ist, von wo aus das Programm gestartet wurde. Dann ist natürlich STDIN der Name der Standardeingabe, also ebenfalls der Konsole, von wo aus das Programm gestartet wurde. Von uns aus gesehen handelt es sich zwar immer um dieselbe Konsole, Ruby braucht aber zwei verschiedene Eimer für die Ein- bzw. Ausgabe. Ruby kann nicht in ein und denselben Eimer etwas ausgeben und gleichzeitig aus diesem etwas lesen. Die Namen STDIN und STDOUT sind übrigens die Namen der Griffe der beiden Eimer (engl. handle). Das Betriebssystem (bspw. Windows XP oder Linux) sorgen dann dafür, dass aber sowohl die Ausgaben als auch die Eingaben auf derselben Konsole erscheinen.

Mehr ist hier im Hauptprogramm zunächst nicht zu tun. Machen wir nun weiter in der Datei tictactoe.rb, in der wir ja von nun an alle Methoden verwalten wollen. Du legst in tictactoe.rb die Methode play_2_spieler wie folgt an:


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
end
Die Methode kennt drei Variablen out, ein und zuege, die ihr von außen vom Aufrufer mit übergeben werden. Als erstes definieren wir die beiden Spieler in der Liste spieler. Ein Spieler besteht wiederum aus einer Liste mit 2 Elementen:
  • Das erste Element ist das Symbol, das wir intern zur Unterscheidung der Spieler verwenden, also :o für den Spieler O und :x für den Spieler X.
  • Das zweite Element ist das Zeichen, das wir für die Ausgabe verwenden, also die Großbuchstaben O und X.
Was soll die Methode eigentlich genau machen? Ich schlage folgendes vor:
  1. Sie wählt den Spieler aus, der als nächstes dran ist (oder am Beginn einen, der anfängt).
  2. Sie fordert diesen Spieler auf, eine Zahl von 1 bis 9 einzugeben. Das ist die Nummer für genau das Spielfeld, auf das der Spieler seinen Stein setzen möchte. Es sollte ein noch freies Spielfeld sein.
  3. Sie berechnet für die eingegebene Nummer die Spalte und Zeile des Feldes und
  4. fügt einen neuen Zug in die Liste der Züge ein.
  5. Sie gibt nach erfolgreichem Zug das Spielfeld mit dem neuen Zustand aus.
  6. Sie stellt fest, ob das Spiel jetzt schon zu Ende ist.
  7. Falls es noch nicht zu Ende ist beginnt sie wieder von vorn (das hört sich nach einer Schleife an, oder?)

Machen wir uns ans Werk!

Den Spieler auswählen, der anfängt


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
end

Das ist einfach. Wir legen fest, der Spieler O fängt immer an. Welcher Spieler gerade dran ist merken wir uns in der Variablen wer. Dort speichern wir den Index in der Spielerliste für den aktuellen Spieler. Der Spieler O ist der erste Spieler in der Liste, also hat wer am Anfang den Wert 0 (Null).

Der Spieler soll die Nummer eines Feldes eingeben


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    out.print "#{spieler[wer][1]} ist am Zug: " 
    nummer = ein.gets.to_i
    break if nummer == 0
  end
end

Natürlich brauchen wir eine Schleife. Wir nehmen die While-Schleife und machen sie zu einer Endlosschleife, indem wir die Schleifenbedingung auf true setzen. Das ist immer wahr, also hört die Schleife nie auf. Damit sie aber aufhört, wenn das Spiel zu Ende ist, oder die Spieler keine Lust mehr haben, bauen wir innerhalb der Schleife ein break zum Abbrechen ein.

In der Schleife fragen wir als erstes den aktuellen Spieler nach der Nummer für seinen nächsten Zug. Dann lesen wir von der Eingabe mit ein.gets die Nummer zunächst als String und verwandeln sie sogleich in eine natürliche Zahl mit dem Befehl to_i und speichern diese Zahl in der Variablen nummer.

Wird die Nummer gleich 0, dann brechen wir die Schleife ab. Null kann die Nummer genau dann werden, wenn der Spieler die Null eingibt, oder er gibt gar keine Zahl ein, sondern Buchstaben oder andere Zeichen. Dann kann der Befehl to_i aus der Eingabe keine natürliche Zahl erzeugen und gibt immer die Zahl Null zurück.

Bestimmen von Spalte und Zeile für die Nummer des Feldes

Ein Zug besteht aus der Angabe des Spielers und der Spalte und Zeile des Feldes, in das der Spieler seinen Stein setzen möchte. Die Nummer des Feldes haben wir nun vom Spieler erfragt. Wie lautet nun aber die Spalte und Zeile zu dieser Nummer? Wir brauchen eine weitere Methode, die diese Berechnung für uns ausführt. Schauen wir sie uns zunächst an und besprechen sie dann später.


# Bestimmt aus der Nummer eines Feldes die Spalte und Zeile
# Angenommen Spalte und Zeilen würden von 0 bis 2 gezählt werden.
# Dann ergeben sich folgende Formeln:

# Spalte, Zeile => Nummer => Formel
# ----------------------------------------
# 0,0           => 1      => 0*1 + 0*3 + 1
# 1,0           => 2      => 1*1 + 0*3 + 1
# 2,0           => 3      => 2*1 + 0*3 + 1
# 0,1           => 4      => 0*1 + 1*3 + 1
# 1,1           => 5      => 1*1 + 1*3 + 1
# 2,1           => 6      => 2*1 + 1*3 + 1
# 0,2           => 7      => 0*1 + 2*3 + 1
# 1,2           => 8      => 1*1 + 2*3 + 1
# 2,2           => 9      => 2*1 + 2*3 + 1
def nummer_in_spalte_zeile(nummer)
  spalte = (nummer - 1) % 3
  zeile  = ((nummer + 2 ) / 3 ) - 1
  # spalte und zeile beginnen aber bei 1, also 1 dazu addieren
  [spalte+1, zeile+1]
end

def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    out.print "#{spieler[wer][1]} ist am Zug: " 
    nummer = ein.gets.to_i
    break if nummer == 0
    spalte, zeile = nummer_in_spalte_zeile(nummer)
  end
end

Die Methode nummer_in_spalte_zeile liefert uns für eine übergebene Nummer eine Liste mit zwei Zahlen: die Spalte und die Zeile an der sich das Feld auf dem Spielfeld mit der Nummer befindet.

Angenommen, Spalte und Zeile würden wir mit 0, 1, 2 abzählen. Dann berechnet sich die Spalte mit der Formel (nummer - 1) % 3. Das Feld mit der Nummer 6 hat also als Spalte die (6 - 1) % 3 = 5 % 3 = 2, also die dritte Spalte. Den Operator % (der modulo Operator oder Rest-bei-Division Operator) hast du schon kennen gelernt. Er bedeutet: Gib mir den Rest bei der Division! % 3 bedeutet somit: der Rest bei der Division durch 3. Und der Rest ist 2, wenn man die 5 durch 3 teilt. Und 2 ist der Index der dritten Spalte, wenn wir mit 0, 1, 2 zählen.

Die Berechnung der Zeile ist etwas komplizierter, aber durch etwas herumprobieren leicht aus der Tabelle im Kommentar zur Methode nummer_in_spalte_zeile abzulesen. zeile = ((nummer + 2 ) / 3 ) - 1. Hier must du nur bedenken, dass Ruby beim Dividieren mit ganzen Zahlen immer auf die nächstgelegene ganze Zahl abrundet. Für Ruby ist also 8 / 3 gleich 2. Es ist also das Ergebnis der ganzzahligen Division (mit Rest).

Bevor die Methode die berechneten Werte für Spalte und Zeile zurückgibt, muss natürlich noch eine 1 addiert werden, weil wir die Spalten und Zeilen ja doch mit 1, 2, 3 abzählen wollen.

Einfügen des neuen Zuges

Jetzt kennen wir die Spalte und Zeile, die der aktuelle Spieler besetzen will. Wir können nun den neuen Zug in die Zugliste einfügen.


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    out.print "#{spieler[wer][1]} ist am Zug: " 
    nummer = ein.gets.to_i
    break if nummer == 0
    spalte, zeile = nummer_in_spalte_zeile(nummer)
    zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
  end
end

Aber Moment mal! Was ist, wenn der Spieler eine Nummer für ein Feld eingibt, das bereits von seinem Gegenspieler besetzt wurde? Das dürfen wir nicht zulassen. Wir müssen die Methode zug_hinzu aus der letzten Lektion abändern:


# Methode zum Hinzufügen eines Zuges.
def zug_hinzu(wer, spalte, zeile, zuege)
  # Nicht erlauben, wenn das Feld schon besetzt ist
  erlaubt = true
  zuege.each do |zug|
    if zug[1] == spalte and zug[2] == zeile
      # Einen Zug für diese Feld gibt es schon
      erlaubt = false
      break
    end
  end
  # Ein Zug besteht aus einer kleinen Liste mit genau 3 Elementen:
  # 1. Element 'wer': gibt den Spieler an, entweder :x oder :o
  # 2. Element 'spalte': die Spalte, in der der Zug gesetzt werden soll
  # 3. Element 'zeile': die Zeile, in die der Zug gesetzt werden soll
  # ... aber nur, wenn der Zug erlaubt ist!
  zuege << [wer, spalte, zeile] if erlaubt
  erlaubt
end

Die Methode zug_okay liefert nun true zurück, wenn der Zug erlaubt ist und gemacht wurde, andernfalls liefert sie false zurück. Das können wir benutzen, um den Spieler erneut um die Eingabe einer Nummer zu bitten. Wir ändern also unsere bisherige Methode play_2_spieler wie folgt ab:


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    zug_okay = false
    until zug_okay
      out.print "#{spieler[wer][1]} ist am Zug: " 
      nummer = ein.gets.to_i
      break if nummer == 0
      spalte, zeile = nummer_in_spalte_zeile(nummer)
      zug_okay = zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
    end
  end
end

Wir merken uns in der Variablen zug_okay, ob der Zug gemacht werden konnte oder nicht. Solange diese Variable den Wert false hat, wiederholen wir die Aufforderung zur Eingabe eines Zuges. Dafür nehmen wir eine neue Schleife, die Until-Schleife. Sie führt einen Codeblock solange aus, bis die Bedingung wahr wird (until, engl. solange bis) .

Den ersten Wert von zug_okay setzen wir auf false, somit läuft die Until-Schleife zumindest einmal durch.

Den Rückgabewert von zug_hinzu nehmen wir als neuen Wert für zug_okay. Hat der Spieler sich nicht vertippt und eine gültige Zahl eingegeben, dann wurde der Zug hinzugefügt und die Variable zug_okay hat den Wert true. Dann ist die Until-Schleife beendet.

Spielfeld nach dem Zug ausgeben

Das ist einfach, dafür haben wir ja schon eine Methode.


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    zug_okay = false
    until zug_okay
      out.print "#{spieler[wer][1]} ist am Zug: " 
      nummer = ein.gets.to_i
      break if nummer == 0
      spalte, zeile = nummer_in_spalte_zeile(nummer)
      zug_okay = zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
    end
    spielfeld(out, zuege)
  end
end

Feststellen, ob das Spiel schon zu Ende ist


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    zug_okay = false
    until zug_okay
      out.print "#{spieler[wer][1]} ist am Zug: " 
      nummer = ein.gets.to_i
      break if nummer == 0
      spalte, zeile = nummer_in_spalte_zeile(nummer)
      zug_okay = zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
    end
    spielfeld(out, zuege)
    break if ist_beendet?(zuege) or !zug_okay
  end
end

Wir verlassen die While-Schleife, wenn das Spiel beendet ist, oder der Spieler bewusst eine 0 (Null) oder einen Buchstaben eingegeben hatte, um das Spiel zu beenden. Dann nämlich hatte die Until-Schleife keine Chance, die Variable zug_okay auf true zu setzen, weil zuvor das break die Until-Schleife unterbrochen hat.

Es bleibt noch die Methode ist_beendet? zu implementieren.


def ist_beendet?(zuege)
  zuege.size >= 9
end

Das Spiel ist aus, wenn 9 oder mehr Züge (mehr als 9 können eigentlich nicht vorkommen, wenn zug_hinzu richtig arbeitet) gemacht wurden. Wir schicken dazu die Nachricht size (engl. Größe) an die Zugliste und erhalten damit die Anzahl der Elemente in der Zugliste zurück.

Es könnte aber passieren, dass wir aus Versehen eine ungültige Zugliste übergeben, eine die es gar nicht gibt. Wir testen also lieber vorher, ob die Variable zuege nicht den Wert nil hat. Dazu verwenden wir den ternären Operator, den du auch schon kennst, weil man so den Test in einer Zeile unterbringt:


def ist_beendet?(zuege)
  zuege == nil ? false : zuege.size >= 9
end

Nächster Spieler ist dran


def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    zug_okay = false
    until zug_okay
      out.print "#{spieler[wer][1]} ist am Zug: " 
      nummer = ein.gets.to_i
      break if nummer == 0
      spalte, zeile = nummer_in_spalte_zeile(nummer)
      zug_okay = zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
    end
    spielfeld(out, zuege)
    break if ist_beendet?(zuege) or !zug_okay
    wer += 1
    wer %= 2
  end
  spieler[wer]
end

Wir erhöhen den Index für die Spielerliste um 1. Es gibt aber nur den Index 0 und den Index 1. Wenn wir schon bei 1 sind und noch eines dazu addieren wären wir bei 2. Somit machen wir anschließend noch einmal eine Division durch 2 mit Rest und nehmen den Rest als neuen Wert für unseren Index. So können wir sicherstellen, dass der Index immer abwechselnd 0 oder 1 ist.

Irgendwann erfolgt durch den Aufruf von ist_beendet? ein break in der While-Schleife, spätestens nach 9 gültigen Zügen. Dann geben wir als letztes in unserer Methode das Symbol des aktuellen Spielers zurück. Das brauchen wir dann in den nächsten Lektionen, um erkennen zu können, wer den letzten Zug gemacht hat und evtl. der Sieger ist.

Zum Schluß hier alle Methoden, die neuen und die, die wir geändert haben:


# tictactoe.rb

# Methode, die das Spielfeld im Ausgabebereich 'out' ausgibt
# und dabei auch die in 'zuege' angegebenen Züge mit ausgibt.
# Ist für ein Feld noch kein Zug erfolgt, dann wird die
# Nummer des Feldes ausgegeben. Die Felder sind dabei von
# links nach rechts und oben nach unten von 1 bis 9 fortlaufend
# nummeriert.
def spielfeld(out, zuege)
  out.puts  "/-----------\\" 
  out.print "| " 

  print_zeile(out, 1, zuege)

  out.puts " |" 
  out.puts  "|---|---|---|" 
  out.print "| " 

  print_zeile(out, 2, zuege)

  out.puts " |" 
  out.puts  "|---|---|---|" 
  out.print "| " 

  print_zeile(out, 3, zuege)

  out.puts " |" 
  out.puts "\\-----------/" 
end

# Methode zum Ausgeben einer einzigen Zeile im Ausgabebereich 'out'.
# Welche Zeile ausgegeben werden soll ist in 'zeile' übergeben.
# Die Liste der Züge in 'zuege' brauchen wir hier, um das richtige
# Symbol (X oder O) später in den Feldern ausgeben zu können, 
# oder die Nummer des Feldes.
def print_zeile(out, zeile, zuege)
  spalte = 1
  1.upto(3) do 
    print_feld(spalte, zeile, zuege)
    out.print " | " unless spalte == 3
    spalte += 1
  end
end

# Methode, die ein bestimmtes Feld ausgibt. Entweder wird
# das Symbol für den Spieler ausgegeben, der das Feld besetzt hat,
# oder es wird die laufende Nummer des Feldes ausgegeben.
def print_feld(spalte, zeile, zuege)
  res = (spalte-1)*1 + (zeile-1)*3 + 1
  for z in zuege do
    if z[1] == spalte and z[2] == zeile
      res = (z[0] == :x ? "X" : "O") 
      break
    end
  end
  print res
end

# Methode zum Hinzufügen eines Zuges.
def zug_hinzu(wer, spalte, zeile, zuege)
  # Nicht erlauben, wenn das Feld schon besetzt ist
  erlaubt = true
  zuege.each do |zug|
    if zug[1] == spalte and zug[2] == zeile
      # Einen Zug für diese Feld gibt es schon
      erlaubt = false
      break
    end
  end
  # Ein Zug besteht aus einer kleinen Liste mit genau 3 Elementen:
  # 1. Element 'wer': gibt den Spieler an, entweder :x oder :o
  # 2. Element 'spalte': die Spalte, in der der Zug gesetzt werden soll
  # 3. Element 'zeile': die Zeile, in die der Zug gesetzt werden soll
  zuege << [wer, spalte, zeile] if erlaubt
  erlaubt
end

# Berechnete die spalte und zeile für die Nummer eines Feldes
def nummer_in_spalte_zeile(num)
  spalte = ((num-1) % 3)
  zeile = (((num + 2 ) / 3 ) - 1)
  [spalte+1, zeile+1]
end

# Schaut nach, ob das Spiel schon aus ist
def ist_beendet?(zuege)
  zuege == nil ? false : zuege.size >= 9
end

# Lässt 2 Spieler miteinander spielen
def play_2_spieler(out, ein, zuege)
  spieler = [[:o, 'O'], [:x, 'X']]
  wer = 0
  while true
    zug_okay = false
    until zug_okay
      out.print "#{spieler[wer][1]} ist am Zug: " 
      nummer = ein.gets.to_i
      break if nummer == 0
      spalte, zeile = nummer_in_spalte_zeile(nummer)
      zug_okay = zug_hinzu(spieler[wer][0], spalte, zeile, zuege)
    end
    spielfeld(out, zuege)
    break if ist_beendet?(zuege) or !zug_okay
    wer += 1
    wer %= 2
  end
  spieler[wer]
end

Peter und Livia

Peter: Das Spiel ist doch nicht erst beendet, wenn 9 gültige Züge gemacht wurden! So wie das Programm bisher läuft, kann man noch weiterspielen, obwohl schon einer der Spieler 3 Steine in einer Reihe hat.

Livia: Das stimmt. Das Rubyprogramm kann noch nicht erkennen, wann ein Spieler gewonnen hat. Das könntest du noch in die Methode ist_beendet? einbauen. Warte bis zur nächsten Lektion.

Peter: Die Methode ist_beendet? hat ein Fragezeichen im Namen. Was bedeutet das?

Livia: Alle Methoden in Ruby, die wahr oder falsch (true oder false) zurückgeben, sollte man durch dieses an den Namen angehängte Fragezeichen von außen schon als solche Methode erkennbar machen. Es zwingt dich aber niemand dazu. Nur ist es beim Lesen des Codes schöner.

Trackbacks

Verwenden Sie den folgenden Link zur Rückverlinkung von Ihrer eigenen Seite:
http://www.rubykids.de/trackbacks?month=09&year=2007&article_id=lektion-12-tic-tac-toe-eingabe&day=16

Meine Nachricht

Einen Kommentar hinterlassen

Comments