Lektion 12 - Tic-Tac-Toe, Eingabe von Zügen
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:- Du legst eine neue Datei mit Namen tictactoe.rb an. In dieser Datei wirst du alle Methoden verwalten.
- 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.
- Sie wählt den Spieler aus, der als nächstes dran ist (oder am Beginn einen, der anfängt).
- 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.
- Sie berechnet für die eingegebene Nummer die Spalte und Zeile des Feldes und
- fügt einen neuen Zug in die Liste der Züge ein.
- Sie gibt nach erfolgreichem Zug das Spielfeld mit dem neuen Zustand aus.
- Sie stellt fest, ob das Spiel jetzt schon zu Ende ist.
- 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.
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.
