Новое в игре Rust: Hangman

Oct 11 2020

Я решил попробовать свои силы в игре «Палач», чтобы немного познакомиться с языком.

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_guessСлово зашито, и есть неограниченное количество догадок.

Чтобы сохранить уже угаданные буквы, я использую u128и отмечаю соответствующий бит. Это должно быть нормально, поскольку все буквы ASCII представлены как u8<128.

Можете ли вы помочь мне просмотреть код, есть ли что-то о Rust, которое я пропустил?

Ответы

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

Добро пожаловать в Rust. Вот несколько советов, которые помогут вам начать:

Создание идиоматических деклараций использования

В Rust не принято переносить функцию в область видимости напрямую через объявление использования. Вместо этого io::stdinи io::stdoutпредпочтительнее. См. Раздел « Создание идиоматических путей использования» в книге для получения дополнительной информации.

Использование структур для самодокументирования кода

Вы включили это предложение в свое объяснение кода:

Чтобы сохранить уже угаданные буквы, я использую u128и отмечаю соответствующий бит. Это должно быть нормально, поскольку все буквы ASCII представлены как u8<128.

Желательно включать эту информацию в сам код. В этом случае мы можем ввести 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
    }
}

и соответствующим образом измените код:

let mut letters = AsciiSet::new();

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

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

Проверка на ASCII

letter as u8обрезает символ, если !letter.is_ascii(). Проверьте этот случай и попросите пользователя соответственно.