diff options
Diffstat (limited to 'src/client/games/slots.rs')
| -rw-r--r-- | src/client/games/slots.rs | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/src/client/games/slots.rs b/src/client/games/slots.rs index 6e2ebbe..5eed34d 100644 --- a/src/client/games/slots.rs +++ b/src/client/games/slots.rs | |||
| @@ -1,4 +1,8 @@ | |||
| 1 | use super::traits::{Game, GameState}; | 1 | use super::traits::{Game, GamePhase, GameState}; |
| 2 | |||
| 3 | /// Height of the game board. It must never depend on the spin result, or an | ||
| 4 | /// in-place redraw would move to the wrong line. | ||
| 5 | pub const SLOT_BOARD_LINES: usize = 7; | ||
| 2 | 6 | ||
| 3 | pub struct SlotsGame; | 7 | pub struct SlotsGame; |
| 4 | 8 | ||
| @@ -8,17 +12,36 @@ impl SlotsGame { | |||
| 8 | } | 12 | } |
| 9 | 13 | ||
| 10 | fn render_reels(&self, reels: &str) -> String { | 14 | fn render_reels(&self, reels: &str) -> String { |
| 11 | if reels.is_empty() { | 15 | let mut chars = reels.chars(); |
| 12 | "[ ? ] [ ? ] [ ? ]".to_string() | 16 | format!( |
| 13 | } else { | 17 | "[ {} ] [ {} ] [ {} ]", |
| 14 | let chars: Vec<char> = reels.chars().collect(); | 18 | chars.next().unwrap_or('?'), |
| 15 | format!( | 19 | chars.next().unwrap_or('?'), |
| 16 | "[ {} ] [ {} ] [ {} ]\r", | 20 | chars.next().unwrap_or('?') |
| 17 | chars.get(0).unwrap_or(&'?'), | 21 | ) |
| 18 | chars.get(1).unwrap_or(&'?'), | 22 | } |
| 19 | chars.get(2).unwrap_or(&'?') | 23 | |
| 20 | ) | 24 | /// The fifth board line: current status, result, or error. |
| 25 | fn render_status(&self, state: &GameState) -> String { | ||
| 26 | if let Some(error) = state.data.get("error") { | ||
| 27 | return format!("ERROR: {error}"); | ||
| 28 | } | ||
| 29 | if state.phase == GamePhase::Playing { | ||
| 30 | return "Spinning...".to_string(); | ||
| 31 | } | ||
| 32 | if state.phase == GamePhase::Finished { | ||
| 33 | let winnings = state | ||
| 34 | .data | ||
| 35 | .get("winnings") | ||
| 36 | .map(String::as_str) | ||
| 37 | .unwrap_or("0"); | ||
| 38 | return match state.data.get("win_type").map(String::as_str) { | ||
| 39 | Some("jackpot") => format!("JACKPOT! Winnings: {winnings} PLN"), | ||
| 40 | Some("two") => format!("Two of a kind! Winnings: {winnings} PLN"), | ||
| 41 | _ => "No win.".to_string(), | ||
| 42 | }; | ||
| 21 | } | 43 | } |
| 44 | "Press [SPACE] to spin!".to_string() | ||
| 22 | } | 45 | } |
| 23 | } | 46 | } |
| 24 | 47 | ||
| @@ -29,16 +52,23 @@ impl Game for SlotsGame { | |||
| 29 | 52 | ||
| 30 | fn render(&self, state: &GameState) -> String { | 53 | fn render(&self, state: &GameState) -> String { |
| 31 | let reels = state.data.get("reels").cloned().unwrap_or_default(); | 54 | let reels = state.data.get("reels").cloned().unwrap_or_default(); |
| 55 | let balance = state | ||
| 56 | .data | ||
| 57 | .get("balance") | ||
| 58 | .map(String::as_str) | ||
| 59 | .unwrap_or("?"); | ||
| 32 | 60 | ||
| 33 | format!( | 61 | format!( |
| 34 | "=== SLOTS ===\r\nBet: {} PLN\r\n{}\r\n\r\nPress [SPACE] to spin!\r\n\r\nControls: [+/-] Adjust Bet [Q] Quit", | 62 | "=== SLOTS ===\r\nBet: {} PLN Balance: {} PLN\r\n{}\r\n\r\n{}\r\n\r\n[+/-] Adjust Bet [Q] Quit", |
| 35 | state.bet_amount, | 63 | state.bet_amount, |
| 36 | self.render_reels(&reels) | 64 | balance, |
| 65 | self.render_reels(&reels), | ||
| 66 | self.render_status(state) | ||
| 37 | ) | 67 | ) |
| 38 | } | 68 | } |
| 39 | 69 | ||
| 40 | fn render_lines(&self, _state: &GameState) -> usize { | 70 | fn render_lines(&self, _state: &GameState) -> usize { |
| 41 | 6 | 71 | SLOT_BOARD_LINES |
| 42 | } | 72 | } |
| 43 | 73 | ||
| 44 | fn get_help(&self) -> String { | 74 | fn get_help(&self) -> String { |
