Die Spiel-Logik
Ausgaben über die Figuren
Das Spiel-Objekt kann über seine Referenzattribute auf die Figuren
zugreifen. So lassen sich bequem Ausgaben erzeugen. Wir beginnen mit dem
Spielfeld. Die Methode geht mit zwei verschachtelten Schleifen Zeile für Zeile
und Spalte für Spalte über das Feld:
fun spielIstFertig(): Boolean {
return f1.gewonnen() || f2.gewonnen()
}
fun druckeSpielfeld() {
for (y in 0..4) {
for (x in 0..4) {
if (x == 2 && y == 2 && !spielIstFertig()) {
print("X ")
} else if (f1.x == x && f1.y == y) {
print("B ")
} else if (f2.x == x && f2.y == y) {
print("R ")
} else {
print(". ")
}
}
println()
}
}
Eine mögliche Ausgabe sieht dann so aus (B = blaue Figur,
R = rote Figur, X = Home-Feld):
. . . . .
. . . B .
R . X . .
. . . . .
. . . . .
Aufgabe 1 - druckeSpielfeld
Ergänze die Methoden spielIstFertig und
druckeSpielfeld in deiner Spiel-Klasse und teste
sie. Erkläre, wofür die Bedingung !spielIstFertig() beim
Home-Feld sorgt.
Den aktuellen Spieler ausgeben
Der aktuelle Spieler steht zu Beginn noch nicht fest – das Attribut
aktuellerSpieler hat den Typ Figur? und kann
null sein. Bevor wir auf seine farbe zugreifen, müssen
wir den Fall null behandeln.
In Kotlin gibt es dabei eine Besonderheit: Da aktuellerSpieler ein
veränderliches Attribut (var) ist, erlaubt der Compiler den direkten
Zugriff nach einer if-Abfrage nicht. Man kopiert den Wert deshalb
zuerst in eine lokale Variable und prüft diese:
fun druckeAktuellenSpieler() {
val spieler = aktuellerSpieler
if (spieler != null) {
println("Am Zug ist ${spieler.farbe}")
}
}
if (aktuellerSpieler != null) {
println(aktuellerSpieler.farbe) }, meldet der Compiler einen Fehler:
Ein var-Attribut könnte sich theoretisch jederzeit ändern, deshalb
verlässt sich Kotlin nicht auf die vorherige Prüfung. Die lokale Variable
spieler dagegen ändert sich nicht – mit ihr funktioniert die
Abfrage.
Aufgabe 2 - null behandeln
Ergänze die Methode druckeAktuellenSpieler. Probiere zum
Vergleich auch die direkte Variante ohne lokale Variable aus und beschreibe
die Fehlermeldung. Erkläre die Bedeutung von null in diesem
Zusammenhang.
Die aktuellen Figuren ausgeben
Die beiden aktuell zu bewegenden Figuren sind immer gesetzt (Typ
Figur), hier ist also keine null-Behandlung nötig:
fun druckeAktuelleFiguren() {
println("Bewege ${aktuelleFigur1.farbe} und ${aktuelleFigur2.farbe}")
}
Aufgabe 3 - druckeGewinner
Schreibe eine Methode druckeGewinner, die „Blau hat gewonnen!"
bzw. „Rot hat gewonnen!" ausgibt, falls eine der Figuren das Home-Feld
erreicht hat.
Münzen werfen und Figuren bewegen
Vor jedem Zug werden zwei Münzen geworfen. Jede Münze bestimmt, ob die blaue
Figur (f1) oder die rote Figur (f2) bewegt wird.
Zufallszahlen erhältst du in Kotlin mit (0..1).random():
fun muenzenWerfen() {
val z1 = (0..1).random()
val z2 = (0..1).random()
aktuelleFigur1 = if (z1 == 0) f1 else f2
aktuelleFigur2 = if (z2 == 0) f1 else f2
}
Zum Bewegen der bestimmten Figuren genügt eine Methode pro Richtung. Sie nutzt die Referenzattribute, ohne zu wissen, ob dahinter die blaue oder rote Figur steckt:
fun nachObenBewegen() {
aktuelleFigur1.gehe(0)
aktuelleFigur2.gehe(0)
}
Aufgabe 4 - Bewegungen und Münzwurf
Ergänze die Methode muenzenWerfen und die vier Methoden
nachObenBewegen, nachRechtsBewegen,
nachUntenBewegen und nachLinksBewegen.
Den Spieler wechseln
Nach jedem Zug ist der andere Spieler an der Reihe. Ein Spieler wird durch seine Figur dargestellt:
fun setzeNeuenSpieler() {
aktuellerSpieler = if (aktuellerSpieler == f1) f2 else f1
}
Aufgabe 5 - Spielerwechsel
Erzeuge ein Spiel und rufe setzeNeuenSpieler mehrmals
hintereinander auf. Welchen Spieler bestimmt der allererste Aufruf, wenn
aktuellerSpieler zu Beginn null ist? Beschreibe das
Verhalten.