{"record":{"id":"6b2a376c1949b1db","repo":"coding-horror/basic-computer-games","slug":"ai-ran-out-of-options","errorCode":null,"errorMessage":"AI RAN OUT OF OPTIONS!","messagePattern":"AI RAN OUT OF OPTIONS!","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"11_Bombardment/rust/src/main.rs","lineNumber":95,"sourceCode":"            );\n        } else {\n            println!(\n                \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!\\n\\n\"\n            );\n            return false;\n        }\n    } else {\n        println!(\"HA, HA YOU MISSED. MY TURN NOW\\n\");\n    }\n    true\n}\n\nfn ai_turn(all_positions: &mut Vec<u8>, player_positions: &mut Vec<u8>) -> bool {\n    std::thread::sleep(Duration::from_secs(1));\n\n    let ai_missile = *all_positions\n        .choose(&mut rand::thread_rng())\n        .expect(\"AI RAN OUT OF OPTIONS!\");\n\n    let index = all_positions\n        .iter()\n        .position(|p| p == &ai_missile)\n        .expect(\"AI CHOOSE AN INVALID POSITION!\");\n\n    all_positions.remove(index);\n\n    if let Some(index) = player_positions.iter().position(|p| p == &ai_missile) {\n        player_positions.remove(index);\n\n        let remaining = player_positions.len();\n\n        if remaining > 0 {\n            println!(\"I GOT YOU. IT WON'T BE LONG NOW. POST {ai_missile} WAS HIT.\");\n            println!(\n                \"YOU HAVE ONLY {} OUTPOST LEFT.\\n\",\n                get_text_from_number(remaining)","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/11_Bombardment/rust/src/main.rs#L77-L113","documentation":"A panic via .expect(\"AI RAN OUT OF OPTIONS!\") on Iterator::choose() over all_positions in ai_turn() of the Bombardment Rust port. choose() returns None only when the slice is empty, so this fires when the AI has no remaining board positions to target. all_positions is meant to track every not-yet-fired cell; reaching an empty vector before the game is won indicates a logic/state bug (the AI firing loop is being entered after the position pool was exhausted).","triggerScenarios":"Calling ai_turn() when all_positions is empty (every cell already consumed); a turn-order bug that lets the AI take extra turns; a victory/loss check that fails to stop the loop before the AI runs out of targets.","commonSituations":"Miscalibrated board size vs number of turns; a draw/stalemate condition not detected; the game loop not breaking after player_positions hits zero, letting ai_turn run again on an empty pool.","solutions":["Guard ai_turn() with `if all_positions.is_empty() { return false; }` before calling choose.","Verify the main game loop breaks immediately when either side has no positions left.","Ensure all_positions is sized to the full board and only one entry is removed per AI turn."],"exampleFix":"// before\nlet ai_missile = *all_positions\n    .choose(&mut rand::thread_rng())\n    .expect(\"AI RAN OUT OF OPTIONS!\");\n\n// after\nif all_positions.is_empty() {\n    return false; // no targets left, end game\n}\nlet ai_missile = *all_positions\n    .choose(&mut rand::thread_rng())\n    .expect(\"AI RAN OUT OF OPTIONS!\");","handlingStrategy":"validation","validationCode":"// Guard ai_turn before calling choose\nfn ai_turn(all_positions: &mut Vec<u8>, player_positions: &mut Vec<u8>) -> bool {\n    if all_positions.is_empty() { return false; }\n    // ... existing logic","typeGuard":"// Rust: empty check is the idiomatic guard\nlet has_targets = !all_positions.is_empty();","tryCatchPattern":"// Replace .expect with a match on Option\nlet ai_missile = match all_positions.choose(&mut rand::thread_rng()) {\n    Some(&p) => p,\n    None => return false, // no targets left; end game\n};","preventionTips":["Always check is_empty() before choose()/unwrap() on a Vec.","Ensure the game loop stops as soon as either side has zero positions.","Remove exactly one position per AI turn and size all_positions to the full board."],"tags":["rust","game-logic","panic","expect","empty-collection","ai"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}