Nowość w grze Rust: Hangman

Oct 11 2020

Postanowiłem spróbować swoich sił w grze w Wisielca, aby trochę oswoić się z językiem.

use std::io::{stdin, stdout, Write};

fn main() {
    let stdin = stdin();
    let mut stdout = stdout();

    let to_guess = String::from("BENEDICT");

    let mut letters: u128 = 0;

    loop {
        // Replace unguessed letters of to_guess by underscores
        let current = to_guess.chars().map(|x| {
            if x <= 127 as char && letters & (1 << x as u8) > 0 {
                x
            } else {
                '_'
            }
        });
        // Add spaces between letters
        let current = current
            .map(|x| x.to_string() + &' '.to_string())
            .collect::<Vec<String>>()
            .join(" ");

        println!("Current word: {}", current.trim_end());

        if !current.contains('_') {
            println!("Congratulations!");
            break;
        }

        print!("Enter new letter: ");
        stdout.flush().unwrap();

        let mut letter = String::new();
        stdin.read_line(&mut letter).expect("Invalid letter");

        if letter.trim().len() != 1 {
            println!("Use only one ASCII letter");
            continue;
        }

        let letter = letter.to_uppercase().chars().next().unwrap();

        letters |= 1 << letter as u8
    }
}

to_guessSłowo jest ustalony i nie ma nieograniczoną liczbę prób.

Aby zapisać odgadnięte litery, używam u128i oznaczam odpowiedni bit. Powinno być ok, ponieważ wszystkie litery ASCII są reprezentowane przez u8<128.

Czy możesz mi pomóc przejrzeć kod, czy są rzeczy, które przeoczyłem?

Odpowiedzi

2 L.F. Oct 17 2020 at 10:06

Witamy w Rust. Oto kilka sugestii, które pomogą Ci zacząć:

Tworzenie idiomatycznych deklaracji użycia

W Rust nie jest powszechne przenoszenie funkcji bezpośrednio do zakresu poprzez deklarację użycia. Zamiast tego io::stdini io::stdoutsą preferowane. Więcej informacji znajdziesz w rozdziale Tworzenie ścieżek użycia idiomatycznego .

Używanie struktur do samodzielnego tworzenia kodu

W objaśnieniu kodu zawarłeś to zdanie:

Aby zapisać odgadnięte litery, używam u128i oznaczam odpowiedni bit. Powinno być ok, ponieważ wszystkie litery ASCII są reprezentowane przez u8<128.

Zaleca się umieszczenie tych informacji w samym kodzie. W takim przypadku możemy wprowadzić struct:

#[derive(Clone, Copy, Debug, Default)]
struct AsciiSet {
    flag: u128,
}

impl AsciiSet {
    fn new() -> Self {
        Self { flag: 0 }
    }

    fn push(&mut self, letter: u8) {
        self.flag |= (1 << letter);
    }

    fn contains(&self, letter: u8) -> bool {
        (self.flag & (1 << letter)) != 0
    }
}

i odpowiednio zmodyfikuj kod:

let mut letters = AsciiSet::new();

loop {
    // ...
    if letters.contains(letter) { /* ... /* }

    // ...
    letters.push(letter);
}

Sprawdzam ASCII

letter as u8obcina znak, jeśli !letter.is_ascii(). Sprawdź ten przypadek i odpowiednio monituj użytkownika.