Parcours
/
Cairo
Cairo
/
Exercices
/
Jeu de rôle
Jeu de rôle

Jeu de rôle

Exercice d'apprentissage

Introduction

Références nulles

Si tu as déjà utilisé un autre langage de programmation (C/C++, Python, Java, Ruby, Lisp, etc.), il est probable que tu aies déjà rencontré null ou nil. L'utilisation de null ou de nil est la manière dont ces langages indiquent qu'une variable particulière n'a pas de valeur. Cependant, cela fait de l'utilisation accidentelle d'une variable null une erreur facile (et fréquente) à commettre. Comme tu peux l'imaginer, essayer d'appeler une fonction qui n'existe pas ou d'accéder à une valeur qui n'existe pas peut mener à toutes sortes de bugs et de plantages. Le créateur de null est même allé jusqu'à l'appeler son « erreur à un milliard de dollars ».

Le type Option

Pour éviter ces problèmes, les variables Cairo peuvent utiliser l'énumération Option pour représenter l'absence de valeur en toute sécurité. Cette énumération prend deux variantes : None, l'équivalent de null en Cairo, et Some(T), où T est une valeur de n'importe quel type.

Elle ressemble à ceci :

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

Tu peux voir Option comme une couche de sécurité entre toi et les problèmes que peuvent causer les références nulles, tout en conservant leur utilité conceptuelle.

Utilise Option

Définir une variable à None est assez simple :

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

Cependant, si tu veux que le type Option porte une valeur, tu ne peux pas affecter cette valeur directement. Une variable de type Option et, disons, une variable de type i32 ne sont pas équivalentes. Tu dois utiliser Some :

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>

Pour la même raison, ce qui suit ne fonctionnera pas :

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

Pour récupérer la valeur contenue dans Some, tu dois d'abord vérifier qu'elle existe :

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 dispose d'autres outils que match pour vérifier et accéder aux valeurs contenues dans Option, mais match devrait t'être familier maintenant.

Considère ceci comme une démonstration de la raison pour laquelle Cairo utilise Option plutôt qu'une référence nulle. L'idée, c'est que tu dois vérifier si la variable Option vaut Some (auquel cas tu peux extraire et utiliser la valeur qu'elle contient) ou None. Sinon, ton programme ne compilera pas ; le compilateur te protège de null.

Instructions

Tu travailles sur l'implémentation d'un jeu de rôle. Le personnage du joueur est représenté par ce qui suit :

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

Dans ce jeu, les joueurs doivent atteindre le niveau 10 avant de débloquer une réserve de mana, qu'ils peuvent utiliser pour lancer des sorts. Avant cela, le mana du joueur vaut Option::None.

Dans ce jeu, tu travailles sur deux fonctionnalités : le mécanisme de réanimation et le mécanisme de lancement de sorts.

La méthode revive doit vérifier que le joueur est bien mort (ses points de vie ont atteint 0) et, si c'est le cas, elle doit renvoyer une nouvelle instance de Player avec 100 points de vie. La méthode revive doit préserver le niveau du joueur. Si le niveau du joueur est supérieur ou égal à 10, il doit être réanimé avec 100 points de mana. Si le niveau du joueur est inférieur à 10, son mana doit valoir Option::None.

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

Si la méthode revive est appelée sur un Player dont les points de vie sont supérieurs ou égaux à 1, elle doit renvoyer Option::None.

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

La méthode cast_spell prend une référence mutable vers le Player ainsi qu'un paramètre mana_cost indiquant combien de mana le sort coûte. Elle renvoie la quantité de dégâts que le sort lancé inflige.

  • Si le joueur n'a pas accès à une réserve de mana, tenter de lancer le sort doit diminuer ses points de vie du coût en mana du sort. Les dégâts renvoyés doivent être 0.

    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);
    
  • Si le joueur dispose d'une réserve de mana mais pas d'assez de mana, la méthode ne doit pas affecter la réserve. Les dégâts renvoyés doivent être 0.

    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));
    
  • Sinon, le sort est lancé avec succès. Le mana_cost doit être déduit de la réserve de mana du joueur. Les dégâts renvoyés doivent être égaux à deux fois le coût en mana du sort.

    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));
    

Amuse-toi bien !

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Cairo Exercism

Prêt à commencer Jeu de rôle ?

Inscris-toi sur Exercism pour apprendre et maîtriser Cairo avec 25 concepts68 exercices, et un vrai mentorat humain, le tout gratuitement.