diff options
Diffstat (limited to '')
| -rw-r--r-- | src/client/games/slots.rs | 8 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/server/games/slots.rs | 29 | ||||
| -rw-r--r-- | src/slots.rs | 33 |
4 files changed, 45 insertions, 26 deletions
diff --git a/src/client/games/slots.rs b/src/client/games/slots.rs index c367fcb..7e59919 100644 --- a/src/client/games/slots.rs +++ b/src/client/games/slots.rs | |||
| @@ -1,10 +1,8 @@ | |||
| 1 | use super::traits::{Game, GamePhase, GameState}; | 1 | use super::traits::{Game, GamePhase, GameState}; |
| 2 | use crate::slots::{paytable_line, REELS, ROWS}; | ||
| 2 | 3 | ||
| 3 | /// Height of the game board. It must never depend on the spin result. | 4 | /// Height of the game board. It must never depend on the spin result. |
| 4 | pub const SLOT_BOARD_LINES: usize = 9; | 5 | pub const SLOT_BOARD_LINES: usize = 9; |
| 5 | pub const LINES: usize = 5; | ||
| 6 | pub const REELS: usize = 5; | ||
| 7 | pub const ROWS: usize = 3; | ||
| 8 | 6 | ||
| 9 | pub struct SlotsGame; | 7 | pub struct SlotsGame; |
| 10 | 8 | ||
| @@ -106,13 +104,13 @@ impl Game for SlotsGame { | |||
| 106 | let grid = self.render_grid(&reels, &winning); | 104 | let grid = self.render_grid(&reels, &winning); |
| 107 | 105 | ||
| 108 | format!( | 106 | format!( |
| 109 | "=== 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", | 107 | "=== SLOTS ===\r\nBet: {} PLN Balance: {} PLN\r\n{}\r\n{}\r\n{}\r\n{}\r\n{}\r\n{}\r\n[+/-] Bet [SPACE] Spin [Q] Quit", |
| 110 | state.bet_amount, | 108 | state.bet_amount, |
| 111 | LINES, | ||
| 112 | balance, | 109 | balance, |
| 113 | grid[0], | 110 | grid[0], |
| 114 | grid[1], | 111 | grid[1], |
| 115 | grid[2], | 112 | grid[2], |
| 113 | paytable_line(), | ||
| 116 | self.render_status(state), | 114 | self.render_status(state), |
| 117 | self.render_win_lines(state) | 115 | self.render_win_lines(state) |
| 118 | ) | 116 | ) |
| @@ -8,4 +8,5 @@ | |||
| 8 | pub mod client; | 8 | pub mod client; |
| 9 | pub mod protocol; | 9 | pub mod protocol; |
| 10 | pub mod server; | 10 | pub mod server; |
| 11 | pub mod slots; | ||
| 11 | pub mod tofu; | 12 | pub mod tofu; |
diff --git a/src/server/games/slots.rs b/src/server/games/slots.rs index 1d71c9d..e9f58b1 100644 --- a/src/server/games/slots.rs +++ b/src/server/games/slots.rs | |||
| @@ -1,19 +1,9 @@ | |||
| 1 | use super::traits::{Game, GameError, GamePhase, GameResult, GameState}; | 1 | use super::traits::{Game, GameError, GamePhase, GameResult, GameState}; |
| 2 | use crate::slots::PAYTABLE; | ||
| 2 | use rand::Rng; | 3 | use rand::Rng; |
| 3 | use std::collections::HashMap; | 4 | use std::collections::HashMap; |
| 4 | 5 | ||
| 5 | pub const REELS: usize = 5; | 6 | pub use crate::slots::{PAYLINES, REELS, ROWS, SYMBOLS}; |
| 6 | pub const ROWS: usize = 3; | ||
| 7 | pub const SYMBOLS: [char; 6] = ['C', 'L', 'O', 'G', 'D', 'S']; | ||
| 8 | |||
| 9 | /// Five paylines, each entry is the row used on reel 0..4. | ||
| 10 | pub const PAYLINES: [[usize; REELS]; 5] = [ | ||
| 11 | [0, 0, 0, 0, 0], // line 1: top | ||
| 12 | [1, 1, 1, 1, 1], // line 2: middle | ||
| 13 | [2, 2, 2, 2, 2], // line 3: bottom | ||
| 14 | [0, 1, 2, 1, 0], // line 4: V | ||
| 15 | [2, 1, 0, 1, 2], // line 5: inverted V | ||
| 16 | ]; | ||
| 17 | 7 | ||
| 18 | #[derive(Clone, Copy)] | 8 | #[derive(Clone, Copy)] |
| 19 | struct Payout { | 9 | struct Payout { |
| @@ -37,15 +27,12 @@ pub struct SlotsGame { | |||
| 37 | 27 | ||
| 38 | impl SlotsGame { | 28 | impl SlotsGame { |
| 39 | pub fn new() -> Self { | 29 | pub fn new() -> Self { |
| 40 | let mut payouts = HashMap::new(); | 30 | let payouts = PAYTABLE |
| 41 | 31 | .iter() | |
| 42 | // RTP = 425/432 = 0.9838 (1.62% house edge) with five paylines. | 32 | .map(|&(symbol, three, four, five)| { |
| 43 | payouts.insert('C', Payout { three: 2, four: 5, five: 15 }); | 33 | (symbol, Payout { three, four, five }) |
| 44 | payouts.insert('L', Payout { three: 3, four: 7, five: 20 }); | 34 | }) |
| 45 | payouts.insert('O', Payout { three: 3, four: 8, five: 25 }); | 35 | .collect(); |
| 46 | payouts.insert('G', Payout { three: 4, four: 12, five: 40 }); | ||
| 47 | payouts.insert('D', Payout { three: 6, four: 18, five: 70 }); | ||
| 48 | payouts.insert('S', Payout { three: 9, four: 30, five: 150 }); | ||
| 49 | 36 | ||
| 50 | Self { | 37 | Self { |
| 51 | payouts, | 38 | payouts, |
diff --git a/src/slots.rs b/src/slots.rs new file mode 100644 index 0000000..561c449 --- /dev/null +++ b/src/slots.rs | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | //! Shared slots rules used by both the server engine and the client board. | ||
| 2 | |||
| 3 | pub const REELS: usize = 5; | ||
| 4 | pub const ROWS: usize = 3; | ||
| 5 | pub const SYMBOLS: [char; 6] = ['C', 'L', 'O', 'G', 'D', 'S']; | ||
| 6 | |||
| 7 | /// Five paylines, each entry is the row used on reel 0..4. | ||
| 8 | pub const PAYLINES: [[usize; REELS]; 5] = [ | ||
| 9 | [0, 0, 0, 0, 0], // line 1: top | ||
| 10 | [1, 1, 1, 1, 1], // line 2: middle | ||
| 11 | [2, 2, 2, 2, 2], // line 3: bottom | ||
| 12 | [0, 1, 2, 1, 0], // line 4: V | ||
| 13 | [2, 1, 0, 1, 2], // line 5: inverted V | ||
| 14 | ]; | ||
| 15 | |||
| 16 | /// (symbol, 3-of-a-kind, 4-of-a-kind, 5-of-a-kind) multipliers of total bet. | ||
| 17 | pub const PAYTABLE: [(char, u64, u64, u64); 6] = [ | ||
| 18 | ('C', 2, 5, 15), | ||
| 19 | ('L', 3, 7, 20), | ||
| 20 | ('O', 3, 8, 25), | ||
| 21 | ('G', 4, 12, 40), | ||
| 22 | ('D', 6, 18, 70), | ||
| 23 | ('S', 9, 30, 150), | ||
| 24 | ]; | ||
| 25 | |||
| 26 | /// One-line paytable rendered under the reels. | ||
| 27 | pub fn paytable_line() -> String { | ||
| 28 | let entries: Vec<String> = PAYTABLE | ||
| 29 | .iter() | ||
| 30 | .map(|(symbol, three, four, five)| format!("{symbol} {three}/{four}/{five}")) | ||
| 31 | .collect(); | ||
| 32 | format!("Pays 3/4/5 x bet: {}", entries.join(" ")) | ||
| 33 | } | ||
