Kurzusok
/
Rust
Rust
/
Feladatok
/
Szerepjáték
Szerepjáték

Szerepjáték

Tanulófeladat

Bevezetés

Null-referenciák

Ha valaha használtál más programozási nyelvet (C/C++, Python, Java, Ruby, Lisp stb.), valószínűleg már találkoztál a null vagy a nil értékkel. Ezekben a nyelvekben a null vagy a nil jelzi, hogy egy adott változónak nincs értéke. Ez viszont könnyűvé (és gyakorivá) teszi azt a hibát, hogy véletlenül olyan változót használunk, amely null-ra mutat. Ahogy sejtheted, ha megpróbálunk meghívni egy nem létező függvényt, vagy hozzáférni egy nem létező értékhez, abból mindenféle bug és összeomlás származhat. A null megalkotója odáig ment, hogy „egymilliárd dolláros tévedésének”. nevezte.

Az Option típus

Ezen problémák elkerülésére a Rust nem használ null-referenciákat. Mégis szüksége van egy biztonságos módra annak jelzésére, hogy egy adott változónak nincs értéke. Itt jön képbe az Option. Ahelyett, hogy olyan változónk lenne, amelynek nincs értéke, a Rust változói használhatják az Option enumot. Ennek az enumnak két változata van: a None, a Rust null-megfelelője; és a Some(T), ahol a T bármilyen típusú érték.

Így néz ki:

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

Az Option-ra úgy gondolhatsz, mint egy biztonsági rétegre közted és a null-referenciák okozta problémák között, miközben megőrzi azok fogalmi hasznosságát.

Az Option használata

Egy változót None-ra állítani meglehetősen egyszerű:

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

Ha viszont szeretnéd, hogy az Option típus értéket hordozzon, nem rendelhetsz hozzá értéket közvetlenül. Egy Option típusú változó és mondjuk egy i32 típusú változó nem egyenértékű. A Some-ot kell használnod:

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

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

Ugyanezen okból a következő sem fog működni:

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

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

Ha szeretnéd megkapni a Some által tartalmazott értéket, először ellenőrizned kell, hogy létezik-e:

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

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

some_words = None; // some_words now set to None

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

A match mellett a Rust más eszközöket is kínál az Option-ban tárolt értékek ellenőrzésére és elérésére, de a match-et addigra már ismerned kell.

Mellékesen ezt tekintsd annak bemutatásaként, hogy a Rust miért használ Option-t null-referencia helyett. A lényeg, hogy ellenőrizned kell, hogy az Option változó Some-e (amely esetben nyugodtan kinyerheted és felhasználhatod a benne tárolt értéket), vagy None. Minden más esetben a programod nem fog lefordulni; a fordító megvéd a null-tól.

Utasítások

Azon dolgozol, hogy megvalósíts egy szerepjátékot. A játékos karakterét a következő reprezentálja:

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

A játékban a játékosoknak el kell érniük a 10. szintet, hogy feloldhassák a manapoolt, és elkezdhessenek varázslatokat használni. Addig a Player manája None.

Két funkción dolgozol ebben a játékban: a feltámasztási mechanikán és a varázslási mechanikán.

A revive metódusnak ellenőriznie kell, hogy a Player valóban halott-e (az életereje elérte a 0-t), és ha igen, a metódusnak egy új Player példányt kell visszaadnia 100 életerővel. Ha a Player szintje 10 vagy magasabb, akkor 100 manával kell feltámasztani. Ha a Player szintje 10 alatt van, a manája None kell legyen. A revive metódusnak meg kell őriznie a Player szintjét.

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

Ha a revive metódust egy olyan Player példányon hívják meg, amelynek az életereje 1 vagy annál több, akkor a metódusnak None-t kell visszaadnia.

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

A cast_spell metódus egy módosítható referenciát vár a Playerre, valamint egy mana_cost paramétert, amely megadja, mennyi manába kerül a varázslat. Visszaadja a varázslat által okozott sebzés mértékét, ami mindig a varázslat manaköltségének kétszerese, ha a varázslat sikeresen létrejön.

  • Ha a játékosnak nincs hozzáférése manapoolhoz, a varázslat megkísérlésének csökkentenie kell az életerejét a varázslat manaköltségével. A visszaadott sebzésnek 0-nak kell lennie.

    let not_a_wizard_yet = Player { health: 79, mana: 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, None);
    
  • Ha a játékosnak van manapoolja, de nincs elég manája, a metódus ne befolyásolja a poolt, hanem adjon vissza 0-t.

    let low_mana_wizard = Player { health: 93, mana: 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, Some(3));
    
  • Egyébként a mana_cost-ot le kell vonni a Player manapooljából, és a megfelelő mennyiségű sebzést kell visszaadni.

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

Jó szórakozást!

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Rust Exercism

Készen állsz elkezdeni a(z) Szerepjáték feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Rust nyelvet 99 feladat segítségével, valódi emberi mentorálással, mindez ingyen.