console_games/games/
tower_of_hanoi.rs

1use self::internal::PromptDiskMoveResult;
2use crate::Play;
3use console::Term;
4use std::io::{stdin, stdout, Write};
5mod internal;
6
7pub struct TowerOfHanoi;
8
9impl TowerOfHanoi {
10    fn prompt_disk_count(&self) -> usize {
11        let default: usize = 3;
12        loop {
13            print!("Enter disk count (left empty for default of {default}): ");
14            stdout().flush().expect("Failed to flush stdout");
15            let mut input = String::new();
16            stdin().read_line(&mut input).expect("Failed to read line");
17            if input.trim().is_empty() {
18                break default;
19            }
20            let Ok(count) = input.trim().parse() else { continue };
21            break count;
22        }
23    }
24}
25
26impl Play for TowerOfHanoi {
27    fn name(&self) -> &'static str {
28        "Tower of Hanoi"
29    }
30
31    fn instructions(&self) -> Option<&'static str> {
32        Some(
33            "The objective of the game is to move all the disks from the leftmost tower to the rightmost tower.\nA larger disk cannot be placed on top of a smaller disk."
34        )
35    }
36
37    fn start(&self) {
38        let term = Term::stdout();
39        let disk_count = self.prompt_disk_count();
40        let mut game = internal::TowerOfHanoi::new(disk_count);
41
42        loop {
43            term.clear_screen().expect("Failed to clear screen");
44            game.render();
45
46            if let Ok(PromptDiskMoveResult { from, to }) = game.prompt_disk_move() {
47                if game.move_disk(from, to).is_err() {
48                    term.clear_screen().expect("Failed to clear screen");
49                    continue;
50                }
51            } else {
52                term.clear_screen().expect("Failed to clear screen");
53                continue;
54            }
55
56            if game.win() {
57                term.clear_screen().expect("Failed to clear screen");
58                game.render();
59                println!("You win!\n");
60                break;
61            }
62        }
63    }
64}