Tracks
/
Cairo
Cairo
/
Übungen
/
Rollenspiel
Rollenspiel

Rollenspiel

Lernübung

Einführung

Null-Referenzen

Wenn du schon einmal eine andere Programmiersprache benutzt hast (C/C++, Python, Java, Ruby, Lisp usw.), ist dir wahrscheinlich schon einmal null oder nil begegnet. Mit null oder nil zeigen diese Sprachen an, dass eine bestimmte Variable keinen Wert hat. Dadurch passiert es allerdings leicht (und häufig), dass man versehentlich eine null-Variable verwendet. Wie du dir vorstellen kannst, kann der Versuch, eine Funktion aufzurufen, die es gar nicht gibt, oder auf einen Wert zuzugreifen, den es nicht gibt, zu allerlei Bugs und Abstürzen führen. Der Erfinder von null nannte es sogar seinen „Milliarden-Dollar-Fehler“.

Der Typ Option

Um diese Probleme zu vermeiden, können Cairo-Variablen das Enum Option verwenden, um das Fehlen eines Werts sicher darzustellen. Dieses Enum hat zwei Varianten: None, das Äquivalent zu null in Cairo, und Some(T), wobei T ein Wert eines beliebigen Typs ist.

Das sieht so aus:

enum Option<T> {
    None,
    Some(T),
}

Du kannst dir Option als eine Sicherheitsschicht zwischen dir und den Problemen vorstellen, die Null-Referenzen verursachen können, während ihr konzeptioneller Nutzen erhalten bleibt.

Option verwenden

Eine Variable auf None zu setzen, ist recht einfach:

let nothing: Option<u32> = Option::None;  // Variable nothing is set to None

Wenn du aber möchtest, dass der Typ Option einen Wert trägt, kannst du diesen Wert nicht direkt zuweisen. Eine Variable vom Typ Option und zum Beispiel eine Variable vom Typ i32 sind nicht gleichwertig. Du musst Some verwenden:

let wrong_way: Option<i32> = -4; // This will not work

let right_way: Option<i32> = Option::Some(-4); // This will work
let another_right_way = Option::Some(-4); // Compiler infers that this is Option<i32>

Aus demselben Grund funktioniert Folgendes nicht:

let number = 47;
let option_number = Option::Some(15);

let compile_error = number + option_number; // Cannot add an i32 and an Option<i32> - they are of different types

Um den Wert zu erhalten, den Some enthält, musst du zuerst prüfen, ob er vorhanden ist:

let mut some_words = Option::Some("choose something to say"); // some_words set to something

match some_words {
    Option::Some(str) => println!("Here, we will {}", str),
    Option::None => println!("I've got nothing to say"),
} // Prints, "Here, we will choose something to say"

some_words = Option::None; // some_words now set to None

// Exactly the same match block as above
match some_words {
    Option::Some(str) => println!("Here, we will {}", str),
    Option::None => println!("I've got nothing to say"),
} // Prints, "I've got nothing to say"

Cairo hat außer match noch andere Werkzeuge, um Werte in Option zu prüfen und auf sie zuzugreifen, aber match sollte dir inzwischen vertraut sein.

Betrachte das als Demonstration, warum Cairo Option anstelle einer Null-Referenz verwendet. Der Punkt ist, dass du prüfen musst, ob die Option-Variable Some ist (in diesem Fall kannst du den enthaltenen Wert extrahieren und verwenden) oder None. Sonst wird dein Programm nicht kompiliert; der Compiler schützt dich vor null.

Anleitung

Du arbeitest daran, ein Rollenspiel zu implementieren. Der Charakter des Spielers wird durch Folgendes dargestellt:

pub struct Player {
    health: u32,
    mana: Option<u32>,
    level: u32,
}

Spieler in diesem Spiel müssen Level 10 erreichen, bevor sie einen Mana-Pool freischalten, den sie zum Wirken von Zaubersprüchen nutzen können. Vorher ist das Mana des Spielers Option::None.

Du arbeitest in diesem Spiel an zwei Funktionen: der Wiederbelebungsmechanik und der Zaubermechanik.

Die Methode revive sollte prüfen, ob der Spieler tatsächlich tot ist (seine Gesundheit hat 0 erreicht). Wenn ja, sollte die Methode eine neue Player-Instanz mit 100 Gesundheit zurückgeben. Die Methode revive sollte das Level des Spielers beibehalten. Wenn das Level des Spielers 10 oder höher ist, sollte er mit 100 Mana wiederbelebt werden. Wenn das Level des Spielers unter 10 liegt, sollte sein Mana Option::None sein.

let dead_player = Player { health: 0, mana: Option::None, level: 2 };
dead_player.revive()
// Returns Player { health: 100, mana: Option::None, level: 2 }

Wenn die Methode revive für einen Spieler aufgerufen wird, dessen Gesundheit 1 oder höher ist, dann sollte die Methode Option::None zurückgeben.

let alive_player = Player { health: 1, mana: Option::Some(15), level: 11 };
alive_player.revive()
// Returns Option::None

Die Methode cast_spell nimmt eine veränderliche Referenz auf den Spieler sowie einen Parameter mana_cost entgegen, der angibt, wie viel Mana der Zauber kostet. Sie gibt die Menge an Schaden zurück, die der gewirkte Zauber verursacht.

  • Wenn der Spieler keinen Zugriff auf einen Mana-Pool hat, muss ein Versuch, den Zauber zu wirken, seine Gesundheit um die Manakosten des Zaubers verringern. Der zurückgegebene Schaden muss 0 sein.

    let not_a_wizard_yet = Player { health: 79, mana: Option::None, level: 9 };
    assert_eq!(not_a_wizard_yet.cast_spell(5), 0)
    assert_eq!(not_a_wizard_yet.health, 74);
    assert_eq!(not_a_wizard_yet.mana, Option::None);
    
  • Wenn der Spieler einen Mana-Pool hat, aber nicht genug Mana, sollte die Methode den Pool nicht verändern. Der zurückgegebene Schaden muss 0 sein.

    let low_mana_wizard = Player { health: 93, mana: Option::Some(3), level: 12 };
    assert_eq!(low_mana_wizard.cast_spell(10), 0);
    assert_eq!(low_mana_wizard.health, 93);
    assert_eq!(low_mana_wizard.mana, Option::Some(3));
    
  • Andernfalls wird der Zauber erfolgreich gewirkt. Die mana_cost sollte vom Mana-Pool des Spielers abgezogen werden. Der zurückgegebene Schaden muss das Zweifache der Manakosten des Zaubers betragen.

    let wizard = Player { health: 123, mana: Option::Some(30), level: 18 };
    assert_eq!(wizard.cast_spell(10), 20);
    assert_eq!(wizard.health, 123);
    assert_eq!(wizard.mana, Option::Some(20));
    

Viel Spaß!

Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Cairo Exercism

Bereit, mit Rollenspiel zu starten?

Melde dich bei Exercism an, um Cairo mit 25 Konzepte68 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.