summaryrefslogtreecommitdiffstats
path: root/src/client/games/slots.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/client/games/slots.rs87
1 files changed, 62 insertions, 25 deletions
diff --git a/src/client/games/slots.rs b/src/client/games/slots.rs
index 5eed34d..39c43b2 100644
--- a/src/client/games/slots.rs
+++ b/src/client/games/slots.rs
@@ -1,8 +1,10 @@
1use super::traits::{Game, GamePhase, GameState}; 1use super::traits::{Game, GamePhase, GameState};
2 2
3/// Height of the game board. It must never depend on the spin result, or an 3/// Height of the game board. It must never depend on the spin result.
4/// in-place redraw would move to the wrong line. 4pub const SLOT_BOARD_LINES: usize = 9;
5pub const SLOT_BOARD_LINES: usize = 7; 5pub const LINES: usize = 5;
6pub const REELS: usize = 5;
7pub const ROWS: usize = 3;
6 8
7pub struct SlotsGame; 9pub struct SlotsGame;
8 10
@@ -11,17 +13,27 @@ impl SlotsGame {
11 Self 13 Self
12 } 14 }
13 15
14 fn render_reels(&self, reels: &str) -> String { 16 fn cell(chars: &[char], row: usize, col: usize) -> char {
15 let mut chars = reels.chars(); 17 if chars.len() == REELS * ROWS {
16 format!( 18 chars.get(col * ROWS + row).copied().unwrap_or('?')
17 "[ {} ] [ {} ] [ {} ]", 19 } else if chars.len() == 3 && row == 0 {
18 chars.next().unwrap_or('?'), 20 // Legacy 3-symbol server: degrade to the first row.
19 chars.next().unwrap_or('?'), 21 chars.get(col).copied().unwrap_or('?')
20 chars.next().unwrap_or('?') 22 } else {
21 ) 23 '?'
24 }
25 }
26
27 fn render_grid(&self, reels: &str) -> [String; ROWS] {
28 let chars: Vec<char> = reels.chars().collect();
29 std::array::from_fn(|row| {
30 (0..REELS)
31 .map(|col| format!("[ {} ]", Self::cell(&chars, row, col)))
32 .collect::<Vec<_>>()
33 .join(" ")
34 })
22 } 35 }
23 36
24 /// The fifth board line: current status, result, or error.
25 fn render_status(&self, state: &GameState) -> String { 37 fn render_status(&self, state: &GameState) -> String {
26 if let Some(error) = state.data.get("error") { 38 if let Some(error) = state.data.get("error") {
27 return format!("ERROR: {error}"); 39 return format!("ERROR: {error}");
@@ -35,14 +47,29 @@ impl SlotsGame {
35 .get("winnings") 47 .get("winnings")
36 .map(String::as_str) 48 .map(String::as_str)
37 .unwrap_or("0"); 49 .unwrap_or("0");
38 return match state.data.get("win_type").map(String::as_str) { 50 if winnings != "0" {
39 Some("jackpot") => format!("JACKPOT! Winnings: {winnings} PLN"), 51 return match state.data.get("win_type").map(String::as_str) {
40 Some("two") => format!("Two of a kind! Winnings: {winnings} PLN"), 52 Some("mega") => format!("MEGA WIN! {winnings} PLN"),
41 _ => "No win.".to_string(), 53 Some("big") => format!("BIG WIN! {winnings} PLN"),
42 }; 54 _ => format!("Won {winnings} PLN"),
55 };
56 }
57 return "No win.".to_string();
43 } 58 }
44 "Press [SPACE] to spin!".to_string() 59 "Press [SPACE] to spin!".to_string()
45 } 60 }
61
62 fn render_win_lines(&self, state: &GameState) -> String {
63 if state.phase != GamePhase::Finished {
64 return String::new();
65 }
66 match state.data.get("win_lines").map(String::as_str) {
67 Some(lines) if !lines.is_empty() && lines != "-" => {
68 format!("Winning lines: {lines}")
69 }
70 _ => String::new(),
71 }
72 }
46} 73}
47 74
48impl Game for SlotsGame { 75impl Game for SlotsGame {
@@ -57,13 +84,18 @@ impl Game for SlotsGame {
57 .get("balance") 84 .get("balance")
58 .map(String::as_str) 85 .map(String::as_str)
59 .unwrap_or("?"); 86 .unwrap_or("?");
87 let grid = self.render_grid(&reels);
60 88
61 format!( 89 format!(
62 "=== SLOTS ===\r\nBet: {} PLN Balance: {} PLN\r\n{}\r\n\r\n{}\r\n\r\n[+/-] Adjust Bet [Q] Quit", 90 "=== SLOTS ===\r\nBet: {} PLN Lines: {} Balance: {} PLN\r\n{}\r\n{}\r\n{}\r\n\r\n{}\r\n{}\r\n[+/-] Bet [SPACE] Spin [Q] Quit",
63 state.bet_amount, 91 state.bet_amount,
92 LINES,
64 balance, 93 balance,
65 self.render_reels(&reels), 94 grid[0],
66 self.render_status(state) 95 grid[1],
96 grid[2],
97 self.render_status(state),
98 self.render_win_lines(state)
67 ) 99 )
68 } 100 }
69 101
@@ -74,17 +106,22 @@ impl Game for SlotsGame {
74 fn get_help(&self) -> String { 106 fn get_help(&self) -> String {
75 "SLOTS GAME\n\ 107 "SLOTS GAME\n\
76 =========\n\ 108 =========\n\
77 Match symbols to win!\n\ 109 5 reels x 3 rows, 5 paylines.\n\
110 Match 3, 4 or 5 symbols from the left on a payline.\n\
78 \n\ 111 \n\
79 Payouts:\n\ 112 Payouts (x total bet, 3/4/5 of a kind):\n\
80 Three of a kind: 2x-28x bet\n\ 113 C: 2 / 5 / 15\n\
81 Two of a kind: 1x-3x bet\n\ 114 L: 3 / 7 / 20\n\
115 O: 3 / 8 / 25\n\
116 G: 4 / 12 / 40\n\
117 D: 6 / 18 / 70\n\
118 S: 9 / 30 / 150\n\
82 \n\ 119 \n\
83 Symbols: C=Cherry, L=Lemon, O=Orange, G=Grapes, D=Diamond, S=Seven\n\ 120 Symbols: C=Cherry, L=Lemon, O=Orange, G=Grapes, D=Diamond, S=Seven\n\
84 \n\ 121 \n\
85 Controls:\n\ 122 Controls:\n\
86 SPACE - Spin the reels\n\ 123 SPACE - Spin the reels\n\
87 +/- - Adjust bet amount\n\ 124 +/- - Adjust total bet\n\
88 Q - Exit the game" 125 Q - Exit the game"
89 .to_string() 126 .to_string()
90 } 127 }