Le nombre magique
Vous devrez trouver un nombre que le programme a choisi au hasard

Dans cet exemple nous allons coder un petit programme en Rust qui consiste à rechercher un nombre “magique”.
Rust: 1.93.0
Niveau: Intermédiaire facile
Notions abordées: générateur random de nombres et traitement de l’input clavier utilisateur
Prérequis: Les bases Rust (les principes de programmations commun, l’ownership et borrowing, et les deux concepts Option et Result)

Repo: https://github.com/CODEheures/rust-guessing-game
Générer le nombre magique
Dans un premier temps, nous créons le projet cargo new guessing_game et importons la crate rand dans la configuration.
[dependencies]
rand = "0.9.2"
Nous allons générer un nombre aléatoire dans une plage donnée.
fn main() {
let range = 1..=15;
let number = rand::random_range(range.clone());
println!("Trouvez le nombre magique entre {} et {}.", range.start(), range.end());
println!("Le nombre magique est {}", number);
}
rand contient un raccourci random_range qui reçois une range en paramètre (ex: 1..=15) et qui fournit un nombre compris dans ce range en sortie.
ℹ️ Notez l’utilisation de .clone() pour ne pas transférer la propriété de range et pouvoir l’utiliser sur la ligne suivante.
Récuperer l’entrée clavier de l’utilisateur
use std::io::stdin;
fn main() {
let mut line = String::new();
let input = stdin().read_line(&mut line);
let guess: Option<u32> = input.ok().map_or(None, |_| line.trim().parse::<u32>().ok() );
println!("vous avez choisi {:?}", guess);
}
La fonction read_line de stdin permet de lire une ligne entrée au clavier et la stocker dans une String (la variable mutable line dans notre cas)
La variable input resultante est un Result(Ok/Err).
La ligne qui suit est la plus compliquée du programme:let guess: Option<u32> = input.ok().map_or(None, |_| line.trim().parse::<u32>().ok() ); 🤯
Pas de panique, décortiquons-la:
input.ok(), transformeinputqui est unResult(Ok/Err)enOption(Some/None)Ensuite en appliquant
.map_or()nous renvoyonssoit
Nonesi input est enErr(et doncinput.ok()estNone)soit la valeur de la closure
|_| line.trim().parse::<u32>().ok()
line.trim().parse::<u32>()trim la valeur de la Stringlineet la parse en u32. Comme pour input, le resultat de parse est unResult<u32>(Ok/Err)que l’on transforme enOption<u32>(Some/None)avec la fonction.ok().
Voilà, guess est donc un Option<u32> (Some<u32>/None)
Comparer l’entrée clavier au nombre magique
Il ne reste plus qu’à regarder ce que vaut la variable guess en la comparant à la variable number. Et pour ça il suffit d’employer match en utilisant une condition (match guard).
use std::io::stdin;
fn main() {
let range = 1..=15;
let number = rand::random_range(range.clone());
println!("Trouvez le nombre magique entre {} et {}.", range.start(), range.end());
let mut line = String::new();
let input = stdin().read_line(&mut line);
let guess: Option<u32> = input.ok().map_or(None, |_| line.trim().parse::<u32>().ok() );
match guess {
None => println!("Entrez un nombre"),
Some(n) if n == number => { println!("Bravo! Vous avez trouvé le nombre magique: {}", number); },
Some(n) if n < number => println!("Trop petit"),
Some(n) if n > number => println!("Trop grand"),
Some(_) => panic!("Ce cas est impossible"),
};
}
Les cas de figures traités dans le match sont donc les suivants:
None: On a juste fait “enter” au clavier (input=Err=>None) ou mis des lettres (line.trim().parse()=Err=>None)
Soit un nombre Some(n) égal ou inférieur ou supérieur à number
soit un dernier cas impossible qui n’arrivera jamais mais que le compilateur impose car les 3 cas au dessus sont impossible à determiné comme une complétude pour le compilateur.
Ajoutons les boucles pour laisser le joueur jouer indéfiniment
use std::io::stdin;
fn main() {
loop {
let range = 1..=15;
let number = rand::random_range(range.clone());
println!("Trouvez le nombre magique entre {} et {}. CTRL+c pour arreter.", range.start(), range.end());
'inner : loop {
let mut line = String::new();
let input = stdin().read_line(&mut line);
let guess: Option<u32> = input.ok().map_or(None, |_| line.trim().parse::<u32>().ok() );
match guess {
None => println!("Entrez un nombre"),
Some(n) if n == number => { println!("Bravo! Vous avez trouvé le nombre magique: {}", number); break 'inner },
Some(n) if n < number => println!("Trop petit"),
Some(n) if n > number => println!("Trop grand"),
Some(_) => panic!("Ce cas est impossible"),
};
}
}
}
La boucle principale reboucle sur un nouveau jeu quand le jeu est fini.
La boucle nommée ‘inner laisse le joueur retenter un nombre jusqu’à ce que celui-ci trouve la solution.
ℹ️ Notez l’utilisation de break ‘inner dans le match qui permet de sortir de la boucle secondaire quand le joueur a trouvé le nombre magique.
Conclusion
Ce programme est un classique (tellement classique que la doc rust en a fait un exemple ici), mais il concentre bon nombres de concepts différents que l’on retrouve dans tous les programmes en Rust.