coding-horror/basic-computer-games · error

Failed to read line

Error message

Failed to read line

What it means

In 35_Even_Wins, human_play reads how many marbles the human wants to take via io::stdin().read_line(&mut num).expect("Failed to read line"). The input is parsed as u32 inside a match that already handles parse failures by printing an error and continuing the loop. The .expect() guards only the I/O layer: a stdin EOF or read failure panics, while invalid numbers are handled gracefully.

Source

Thrown at 35_Even_Wins/rust/src/main.rs:107

            println!("You are the winner! Congratulations!");
        } else {
            println!("The computer wins: all hail mighty silicon!");
        }

        println!("");
    }
}

fn human_play(game: &mut Game) {
    println!("It's your turn!");
    loop {
        let max_take = game.get_max_take();
        println!("Marbles to take? ({} - {}) --> ", game.min_take, max_take);

        let mut num = String::new();
        io::stdin()
            .read_line(&mut num)
            .expect("Failed to read line");

        let _: u32 = match num.trim().to_uppercase().parse() {
            Ok(num) => {
                if game.take(num) {
                    println!("Okay, taking {} marble ...", num);
                    break;
                };
                println!("");
                continue;
            }
            _ => {
                println!("Please enter a whole number from 1 to 4");
                println!("");
                continue;
            }
        };
    }
}

View on GitHub (pinned to 5301155192)

Solutions

  1. Replace .expect() with .unwrap_or_default() — an empty string will fail the u32 parse, triggering the existing 'Please enter a whole number' retry
  2. Use match on read_line's Result to break out of the loop and end the game on EOF
  3. Return early from human_play on I/O error, signaling the game to end

Example fix

// before
let mut num = String::new();
io::stdin()
    .read_line(&mut num)
    .expect("Failed to read line");

let _: u32 = match num.trim().to_uppercase().parse() {

// after
let mut num = String::new();
let _ = io::stdin().read_line(&mut num);

let _: u32 = match num.trim().to_uppercase().parse() {
Defensive patterns

Strategy: fallback

Try / catch

let mut num = String::new();
let _ = io::stdin().read_line(&mut num);
// empty string from I/O failure falls through to parse error,
// which the existing match handles by re-prompting

Prevention

When it happens

Trigger: The human player's turn arrives and stdin is at EOF (piped input exhausted, Ctrl+D pressed), or the read syscall fails. The game loop would handle a bad number, but cannot recover from a missing input.

Common situations: Automated testing of the Even_Wins game where the input script runs out during a human turn, or a user closing the terminal when prompted for a marble count.

Related errors


AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13). Data as JSON: /api/errors/8469531ec51a871e. Report an issue: GitHub.