Shopping cart

0

Cart

  • 0 item

Nessun prodotto nel carrello.

All categories
 Corso Gratuito di Programmazione Rust Lezione 007 – Programmazione di un Gioco ad Indovinelli – Parte 3

SE VUOI PRENDERE LA CERTIFICAZIONE PER QUESTO CORSO CLICCA QUI

Consentire più tentativi con il looping

La parola chiave loop crea un ciclo infinito. Aggiungeremo un ciclo per dare agli utenti più possibilità di indovinare il numero:

Nome file: src/main.rs

rust

// --snip-- println!("Il numero segreto è: {secret_number}"); loop {
println!("Per favore inserisci il tuo tentativo."); // --snip--

match guess.cmp(&secret_number) {
Ordering::Less => println!("Troppo piccolo!"),
Ordering::Greater => println!("Troppo grande!"),
Ordering::Equal => println!("Hai vinto!"),
}
}

Come puoi vedere, abbiamo spostato tutto dall’input del tentativo in avanti in un ciclo. Assicurati di indentare le righe all’interno del ciclo di altri quattro spazi ciascuna e esegui di nuovo il programma. Il programma chiederà ora un altro tentativo all’infinito, il che in realtà introduce un nuovo problema. Non sembra che l’utente possa uscire!

L’utente potrebbe interrompere sempre il programma utilizzando la scorciatoia da tastiera ctrl-c. Ma c’è un altro modo per uscire da questo mostro insaziabile, come menzionato nella discussione sul parsing in “Confronto del Tentativo col Numero Segreto”: se l’utente inserisce una risposta non numerica, il programma si blocca. Possiamo approfittarne per consentire all’utente di uscire, come mostrato qui:

less

$ cargo run
Compilazione di guessing_game v0.1.0 (file:///projects/guessing_game)
Finito dev [non ottimizzato + informazioni di debug] target(s) in 1.50s
Running `target/debug/guessing_game`
Indovina il numero!
Il numero segreto è: 59
Per favore inserisci il tuo tentativo.
45
Hai indovinato: 45
Troppo piccolo!
Per favore inserisci il tuo tentativo.
60
Hai indovinato: 60
Troppo grande!
Per favore inserisci il tuo tentativo.
59
Hai indovinato: 59
Hai vinto!
Per favore inserisci il tuo tentativo.
quit
thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/main.rs:28:47
note: esegui con `RUST_BACKTRACE=1` variabile d'ambiente per visualizzare un traceback

Digitando quit, il gioco si interromperà, ma come noterai, lo farà anche inserendo qualsiasi altro input non numerico. Questo è subottimale, per non dire altro; vogliamo che il gioco si interrompa anche quando viene indovinato il numero corretto. Uscire dopo un Indovinamento Corretto

Programmiamo il gioco per uscire quando l’utente vince aggiungendo una istruzione break:

Nome file: src/main.rs

rust

// --snip--

match guess.cmp(&secret_number) {
Ordering::Less => println!("Troppo piccolo!"),
Ordering::Greater => println!("Troppo grande!"),
Ordering::Equal => {
println!("Hai vinto!");
break;
}
}
}

Aggiungendo la linea break dopo Hai vinto!, il programma esce dal ciclo quando l’utente indovina correttamente il numero segreto. Uscire dal ciclo significa anche uscire dal programma, perché il ciclo è l’ultima parte di main. Gestione dell’Input non Valido

Per raffinare ulteriormente il comportamento del gioco, anziché bloccare il programma quando l’utente inserisce un non numero, facciamo in modo che il gioco ignori un non numero in modo che l’utente possa continuare a indovinare. Possiamo farlo modificando la riga in cui il tentativo viene convertito da una stringa a un u32, come mostrato nel Listato 2-5.

Nome file: src/main.rs

rust

// --snip-- io::stdin()
.read_line(&mut guess)
.expect("Impossibile leggere la riga"); let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
}; println!("Hai indovinato: {guess}");

// --snip--

Passiamo da una chiamata expect a un’espressione match per passare dal blocco su un errore alla gestione dell’errore. Ricorda che parse restituisce un tipo Result e Result è un enum che ha le varianti Ok e Err. Stiamo usando un’espressione match qui, come abbiamo fatto con il risultato Ordering del metodo cmp.

Se parse è in grado di trasformare con successo la stringa in un numero, restituirà un valore Ok che contiene il numero risultante. Quel valore Ok corrisponderà al modello del primo braccio, e l’espressione match restituirà semplicemente il valore num che parse ha prodotto e inserito all’interno del valore Ok. Quel numero finirà proprio dove lo vogliamo nella nuova variabile tentativo che stiamo creando.

Se parse non è in grado di trasformare la stringa in un numero, restituirà un valore Err che contiene più informazioni sull’errore. Il valore Err non corrisponde al modello Ok(num) nel primo braccio di match, ma corrisponde al modello Err(_) nel secondo braccio. L’underscore, _, è un valore generale; in questo esempio, stiamo dicendo che vogliamo corrispondere a tutti i valori Err, indipendentemente dalle informazioni che contengono al loro interno. Quindi il programma eseguirà il codice del secondo braccio, continue, che dice al programma di passare alla prossima iterazione del ciclo e chiedere un altro tentativo. Quindi, efficacemente, il programma ignora tutti gli errori che parse potrebbe incontrare!

Ora tutto nel programma dovrebbe funzionare come previsto. Proviamolo:

less

$ cargo run
Compilazione di guessing_game v0.1.0 (file:///projects/guessing_game)
Finito dev [non ottimizzato + informazioni di debug] target(s) in 4.45s
Running `target/debug/guessing_game`
Indovina il numero!
Il numero segreto è: 61
Per favore inserisci il tuo tentativo.
10
Hai indovinato: 10
Troppo piccolo!
Per favore inserisci il tuo tentativo.
99
Hai indovinato: 99
Troppo grande!
Per favore inserisci il tuo tentativo.
foo
Per favore inserisci il tuo tentativo.
61
Hai indovinato: 61
Hai vinto!

Fantastico! Con un piccolo aggiustamento finale, completeremo il gioco. Ricordati che il programma sta ancora stampando il numero segreto. Questo è stato utile per il test, ma rovina il gioco. Eliminiamo il println! che stampa il numero segreto. Il Listato 2-6 mostra il codice finale.

Nome file: src/main.rs

rust

use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Indovina il numero!"); let secret_number = rand::thread_rng().gen_range(1..=100); loop {
println!("Per favore inserisci il tuo tentativo."); let mut guess = String::new(); io::stdin()
.read_line(&mut guess)
.expect("Impossibile leggere la riga"); let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
}; println!("Hai indovinato: {guess}");

match guess.cmp(&secret_number) {
Ordering::Less => println!("Troppo piccolo!"),
Ordering::Greater => println!("Troppo grande!"),
Ordering::Equal => {
println!("Hai vinto!");
break;
}
}
}
}

A questo punto, hai costruito con successo il gioco dell’indovinello. Congratulazioni! Riassunto

Questo progetto è stato un modo pratico per introdurti a molti nuovi concetti di Rust: let, match, funzioni, l’uso di crate esterne e altro ancora. Nei prossimi capitoli, imparerai su questi concetti in dettaglio. Il Capitolo 3 tratta concetti che la maggior parte dei linguaggi di programmazione ha, come variabili, tipi di dati e funzioni, e mostra come usarli in Rust. Il Capitolo 4 esplora la proprietà, una caratteristica che rende Rust diverso dagli altri linguaggi. Il Capitolo 5 discute strutture e sintassi dei metodi, e il Capitolo 6 spiega come funzionano gli enum.

Leave a Reply

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *