summaryrefslogtreecommitdiffstats
path: root/src/bin/client/games/manager.rs
blob: 6959214536e01032de33626d63b48fb4bc107443 (plain) (blame)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::games::slots::SlotsGame;
use crate::games::traits::{Game, GameError, GamePhase, GameState};
use std::collections::HashMap;
use std::io::Write;

pub struct GameManager {
    current_session: Option<GameState>,
    pending_game_type: Option<String>,
    games: HashMap<String, Box<dyn Game>>,
}

impl GameManager {
    pub fn new() -> Self {
        let mut games: HashMap<String, Box<dyn Game>> = HashMap::new();
        games.insert("slots".to_string(), Box::new(SlotsGame::new()));

        Self {
            current_session: None,
            pending_game_type: None,
            games,
        }
    }

    pub fn get_available_games(&self) -> Vec<(&str, &str)> {
        self.games
            .iter()
            .map(|(k, v)| (k.as_str(), v.get_name()))
            .collect()
    }

    pub fn enter_game(&mut self, game_type: &str) -> Result<(), GameError> {
        if self.current_session.is_some() {
            return Err(GameError::InvalidAction);
        }

        if !self.games.contains_key(game_type) {
            return Err(GameError::InvalidAction);
        }

        self.pending_game_type = Some(game_type.to_string());

        self.current_session = Some(GameState {
            game_type: game_type.to_string(),
            bet_amount: 10,
            phase: GamePhase::WaitingToStart,
            data: HashMap::new(),
        });

        Ok(())
    }

    pub fn start_game(
        &mut self,
        stream: &mut crate::connection::TlsStream,
    ) -> Result<(), GameError> {
        let game_type = self
            .pending_game_type
            .take()
            .ok_or(GameError::InvalidAction)?;

        let state = self
            .current_session
            .as_mut()
            .ok_or(GameError::InvalidAction)?;

        if state.phase != GamePhase::WaitingToStart {
            return Err(GameError::InvalidAction);
        }

        let bet_amount = state.bet_amount;

        let writer = stream;
        writeln!(writer, "PLAY_START {} {}", game_type, bet_amount)
            .map_err(|_| GameError::NetworkError)?;

        Ok(())
    }

    pub fn get_current_game(&self) -> Option<&dyn Game> {
        self.current_session
            .as_ref()
            .and_then(|session| self.games.get(&session.game_type).map(|game| game.as_ref()))
    }

    pub fn get_current_state(&self) -> Option<&GameState> {
        self.current_session.as_ref()
    }

    pub fn get_current_render_lines(&self) -> Option<usize> {
        let session = self.current_session.as_ref()?;
        let game = self.games.get(&session.game_type)?;
        Some(game.render_lines(session))
    }

    pub fn is_in_game(&self) -> bool {
        self.current_session.is_some()
    }

    pub fn is_game_started(&self) -> bool {
        self.current_session
            .as_ref()
            .map(|s| s.phase != GamePhase::WaitingToStart)
            .unwrap_or(false)
    }

    pub fn end_game(&mut self) {
        self.current_session = None;
        self.pending_game_type = None;
    }

    pub fn adjust_bet(&mut self, delta: i64) -> Result<u64, GameError> {
        if let Some(ref session) = self.current_session {
            if session.phase != GamePhase::WaitingToStart {
                return Err(GameError::InvalidAction);
            }
        }

        if let Some(ref mut session) = self.current_session {
            let current_bet = session.bet_amount as i64;
            let new_bet = (current_bet + delta).max(10) as u64;
            session.bet_amount = new_bet;
            Ok(new_bet)
        } else {
            Err(GameError::InvalidAction)
        }
    }
}