s n h m r u

Minimallogo des digitalen Schulbuchs inf-schule.de. Schriftzug in Zustandsübergangsdiagramm eines endlichen Automaten.

s n h m r u
i

Fertiges Spiel

So wird gespielt

Zwei Spielerinnen oder Spieler spielen abwechselnd. Beide erstellen ein Tier, das zu Beginn eine bestimmte Menge an Energie und Glückslevel hat. Außerdem besitzen beide eine bestimmte Menge an Futter-Vorrat. In jedem Zug steht eine der folgenden Aktionen zur Auswahl:

Aktion Auswirkung
Tier füttern Die Methode fuettern(menge) wird am aktuellen Tier aufgerufen, wodurch die Energie des Tiers bis auf höchstens 10 erhöht wird. Die angegebene Menge wird vom Futter-Vorrat abgezogen.
Mit dem Tier spielen Die Methode spielen() wird am aktuellen Tier aufgerufen. Dabei verliert das Tier Energie, aber gewinnt Glück.
Futter suchen Der Futtor-Vorrat wird um eine zufällige Menge zwischen 1 und 9 erhöht. Dabei wird die Methode langweilen() am aktuellen Tier aufgerufen, wodurch das Tier Energie und Glück verliert.

Nach jeder Aktion wird geprüft: Ein glückliches Tier, das nicht verhungert ist, gewinnt. Ein trauriges oder verhungertes Tier verliert.

Das BlueJ-Projekt vervollständigen

Die Klasse Spiel ist bereits fertig implementiert. Du kannst in BlueJ eine neue Klasse Spiel erstellen und den folgenden Code in diese Klasse kopieren, um das BlueJ-Projekt zu vervollständigen. Um die Seite nicht zu überladen, versteckt sich der Code hinter dem folgenden Button. Du kannst den gesamten Code kopieren, indem du oben rechts auf Copy klickst.

import kotlin.random.Random

class Spiel {
    
    private data class Spieler(
    val spielerName: String,
    val tier: Tier,
    var futter: Int
    )

    private sealed interface Aktion {
        data object Fuettern : Aktion
        data object Spielen : Aktion
        data object FutterSuchen : Aktion
        data object Beenden : Aktion

        companion object {
        fun fromEingabe(x: Int): Aktion? =
        when (x) {
        1 -> Fuettern
        2 -> Spielen
        3 -> FutterSuchen
        0 -> Beenden
        else -> null
        }
        }
    }

    fun starten() {
        konsoleLeeren()

        val spieler1 = erstelleSpieler(1, startFutter = 5)
        val spieler2 = erstelleSpieler(2, startFutter = 5)

        konsoleLeeren()

        var aktueller = spieler1
        var anderer = spieler2

        while (true) {
            zugBildschirm(aktueller)

            when (val aktion = readAktion()) {
                Aktion.Beenden -> {
                    println()
                    println("Spiel beendet.")
                    return
                }
                Aktion.Fuettern -> fuettern(aktueller)
                Aktion.Spielen -> spielen(aktueller)
                Aktion.FutterSuchen -> futterSuchen(aktueller)
            }

            // Nach jeder Aktion: Konsole leeren und neuen Zustand anzeigen
            konsoleLeeren()
            println("=== Neuer Zustand nach der Aktion ===")
            statusAusgeben(aktueller)
            println()

            if (aktueller.tier.istGluecklich() && !aktueller.tier.istVerhungert()) {
                println()
                println("🎉 ${aktueller.spielerName} gewinnt! ${aktueller.tier.name} ist glücklich.")
                return
            }

            if (aktueller.tier.istTraurig()) {
                println()
                println("😢 ${aktueller.tier.name} ist sehr traurig.")
                println("🏆 ${anderer.spielerName} gewinnt!")
                return
            }

            if (aktueller.tier.energie <= 0) {
                println()
                println("💀 ${aktueller.tier.name} hat keine Energie mehr.")
                println("🏆 ${anderer.spielerName} gewinnt!")
                return
            }

            println()
            print("ENTER für Spielerwechsel …")
            readLine()

            konsoleLeeren()

            aktueller = anderer.also { anderer = aktueller }
        }
    }

    private fun erstelleSpieler(nr: Int, startFutter: Int): Spieler {
        println("=== Daten für Spieler $nr ===")
        val spielerName =
            readText("Name von Spieler $nr: ", fallback = "Spieler $nr")
        val tierName =
            readText("Name des Tieres von $spielerName: ", fallback = "Tier $nr")

        return Spieler(
        spielerName = spielerName,
        tier = Tier(tierName),
        futter = startFutter
        )
    }

    private fun zugBildschirm(spieler: Spieler) {
        println("===================================")
        println("${spieler.spielerName}, du bist am Zug")
        println("Du hast noch ${spieler.futter} Futter-Portionen")
        println("===================================")
        println("${spieler.tier.name}s Zustand")
        println("Energie   : ${spieler.tier.energie}")
        println("Glückslevel : ${spieler.tier.glueckslevel}")
        println()

        println("Aktionen:")
        println("1) ${spieler.tier.name} füttern")
        println("2) Mit ${spieler.tier.name} spielen")
        println("3) Futter suchen")
        println("0) Spiel beenden")
        println()
    }

    private fun statusAusgeben(spieler: Spieler) {
        println("Übrige Futtermenge : ${spieler.futter}")
        println()
        println("${spieler.tier.name}s Zustand")
        println("Energie   : ${spieler.tier.energie}")
        println("Glueckslevel : ${spieler.tier.glueckslevel}")
    }

    private fun readAktion(): Aktion {
        while (true) {
            val eingabe = readInt("Bitte Zahl eingeben: ")
            val aktion = Aktion.fromEingabe(eingabe)
            if (aktion != null) return aktion
            println("Ungültige Eingabe.")
        }
    }

    private fun fuettern(spieler: Spieler) {
        if (spieler.futter <= 0) {
            println("Kein Futter vorhanden!")
            return
        }

        val menge = readIntInRange(
            "Wie viel Futter soll ${spieler.tier.name} bekommen (1–${spieler.futter})? ",
            1,
                spieler.futter
        )

        spieler.futter -= menge
            spieler.tier.fuettern(menge)

        println("${spieler.spielerName} füttert ${spieler.tier.name} mit $menge.")
    }

    private fun spielen(spieler: Spieler) {
            spieler.tier.spielen()
        println("${spieler.spielerName} spielt mit ${spieler.tier.name}.")
    }

    private fun futterSuchen(spieler: Spieler) {
        val gefunden = Random.nextInt(1, 10)
        spieler.futter += gefunden
            spieler.tier.langweilen()
        println("${spieler.spielerName} sucht Futter und findet $gefunden.")
    }

    private fun konsoleLeeren() {
        print('\u000C') // Form Feed
    }

    private fun readText(prompt: String, fallback: String): String {
        print(prompt)
        return readLine()?.trim().takeUnless { it.isNullOrBlank() } ?: fallback
    }

    private fun readInt(prompt: String): Int {
        while (true) {
            print(prompt)
            val x = readLine()?.trim()?.toIntOrNull()
            if (x != null) return x
            println("Bitte eine ganze Zahl eingeben.")
        }
    }

    private fun readIntInRange(prompt: String, min: Int, max: Int): Int {
        while (true) {
            val x = readInt(prompt)
            if (x in min..max) return x
            println("Bitte eine Zahl zwischen $min und $max eingeben.")
        }
    }
}

Aufgabe 1

Erstelle die Klasse Spiel entsprechend der obigen Beschreibung und teste sie, indem du ein Spiel-Objekt erstellst und die Methode starten() aufrufst.

Zufallszahlen

Aktuell ist der Verlauf des Spiels sehr vorhersehbar, da die Aktionen der Spieler immer die gleichen Auswirkungen haben. Um das Spiel interessanter zu machen, können wir bei den Methoden spielen und langweilen Zufallszahlen verwenden, um die energie und den glueckslevel des Tiers zufällig - innerhalb eines bestimmten Bereichs - zu verändern. Das folgende Code-Fragment demonstriert die Verwendung von Zufallszahlen in Kotlin.

fun main() {
    var zahl = 5
    println(zahl)

    zahl = zahl + (2..4).random()
    println(zahl)
}

Wenn du in späteren Abschnitten noch einmal Zufallszahlen verwenden möchtest, und nicht mehr genau weißt, wie das funktioniert, kannst du in den Tipps zu Kotlin nachschauen, wo die Verwendung von Zufallszahlen ausführlich erklärt wird.

Wenn du genau wissen möchtest was hier passiert ...

Der Ausdruck (2..4) erzeugt ein Objekt vom Typ IntRange, das die Zahlen 2, 3 und 4 enthält. So wie du an einem Objekt der Klasse Tier die Methode fuettern() aufrufen kannst, kannst du an einem Objekt der Klasse IntRange die Methode random() aufrufen. Die Methode random() wählt zufällig eine dieser Zahlen aus und gibt sie zurück. In diesem Fall könnte also entweder 2, 3 oder 4 zu der Variable zahl addiert werden.

Aufgabe 2

  • Lasse das obige Programmfragment mehrmals laufen und erläutere die Ausgabe.
  • Nutze Zufallszahlen, um die Werte der Attribute energie und glueckslevel bei den Methoden spielen und langweilen nicht immer um den gleichen Wert zu verändern, sondern um einen zufälligen Wert.

Aufgabe 3

Teste dein Spiel, also spiele es :-) Passe bei Bedarf die konkreten Zahlenwerte an, so dass das Spiel gut spielbar ist.

Suche

v
100.123.2.1.6 Fertiges Spiel
Kopieren durch Anklicken

Rückmeldung geben