1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::io::{stdin, stdout, Write};

use console::{style, Term};

use crate::{games::*, Play};

pub struct GameCenter;

impl GameCenter {
    /// returns a list of all games that are available in the game center
    pub fn games() -> [Box<dyn Play>; 5] {
        [
            Box::new(GuessTheWord),
            Box::new(GuessTheNumber),
            Box::new(WordType),
            Box::new(FourInALine),
            Box::new(TowerOfHanoi),
        ]
    }

    /// call this function to start the console game application
    pub fn enter() {
        let term = Term::stdout();
        term.clear_screen().expect("Failed to clear screen");

        println!("{}\n", style("press ctrl + c to exit").red());

        let mut games = Self::games();

        loop {
            term.set_title("Console Games");
            let (game_idx_err_msg, game_idx) = match Self::select_game(&games) {
                Some(value) => value,
                None => continue,
            };
            println!();

            match games.get_mut(game_idx) {
                Some(game) => {
                    term.set_title(game.name());
                    term.clear_screen().expect("Failed to clear screen");

                    game.print_intro();
                    game.start();
                }
                None => println!("{}", &game_idx_err_msg),
            };
        }
    }

    fn select_game(games: &[Box<dyn Play>]) -> Option<(String, usize)> {
        println!("{}", style("Select your game").cyan());
        for (i, game) in games.iter().enumerate() {
            println!("{}: {}", i, game.name())
        }
        print!("Game number: ");
        stdout().flush().expect("Flush failed");

        let mut game_idx = String::new();
        stdin()
            .read_line(&mut game_idx)
            .expect("Cannot read game number");
        let game_idx_err_msg = format!(
            "Game number must be an integer between {} to {}",
            0,
            games.len() - 1,
        );
        let game_idx: usize = match game_idx.trim_end().parse() {
            Ok(idx) => idx,
            Err(_) => {
                println!("{}", &game_idx_err_msg);
                return None;
            }
        };

        Some((game_idx_err_msg, game_idx))
    }
}