summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-28 23:24:08 +0100
committersalmonik <salmonik@tuta.io>2026-10-28 23:24:08 +0100
commit33452f55afcad603f72e054d56ad7848a3d09503 (patch)
treefcef1b0e4a88284ff3fc652fbaecdb087413a17f /src
parentv1.1.0: highlight winning symbols on the slots board (diff)
downloadzagan-bet-33452f55afcad603f72e054d56ad7848a3d09503.tar.gz
zagan-bet-33452f55afcad603f72e054d56ad7848a3d09503.zip
v1.2.0: show the symbol paytable on the slots board
Diffstat (limited to 'src')
-rw-r--r--src/client/games/slots.rs8
-rw-r--r--src/lib.rs1
-rw-r--r--src/server/games/slots.rs29
-rw-r--r--src/slots.rs33
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 @@
1use super::traits::{Game, GamePhase, GameState}; 1use super::traits::{Game, GamePhase, GameState};
2use 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.
4pub const SLOT_BOARD_LINES: usize = 9; 5pub const SLOT_BOARD_LINES: usize = 9;
5pub const LINES: usize = 5;
6pub const REELS: usize = 5;
7pub const ROWS: usize = 3;
8 6
9pub struct SlotsGame; 7pub 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 )
diff --git a/src/lib.rs b/src/lib.rs
index e700173..a261ab0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,4 +8,5 @@
8pub mod client; 8pub mod client;
9pub mod protocol; 9pub mod protocol;
10pub mod server; 10pub mod server;
11pub mod slots;
11pub mod tofu; 12pub 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 @@
1use super::traits::{Game, GameError, GamePhase, GameResult, GameState}; 1use super::traits::{Game, GameError, GamePhase, GameResult, GameState};
2use crate::slots::PAYTABLE;
2use rand::Rng; 3use rand::Rng;
3use std::collections::HashMap; 4use std::collections::HashMap;
4 5
5pub const REELS: usize = 5; 6pub use crate::slots::{PAYLINES, REELS, ROWS, SYMBOLS};
6pub const ROWS: usize = 3;
7pub const SYMBOLS: [char; 6] = ['C', 'L', 'O', 'G', 'D', 'S'];
8
9/// Five paylines, each entry is the row used on reel 0..4.
10pub 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)]
19struct Payout { 9struct Payout {
@@ -37,15 +27,12 @@ pub struct SlotsGame {
37 27
38impl SlotsGame { 28impl 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
3pub const REELS: usize = 5;
4pub const ROWS: usize = 3;
5pub const SYMBOLS: [char; 6] = ['C', 'L', 'O', 'G', 'D', 'S'];
6
7/// Five paylines, each entry is the row used on reel 0..4.
8pub 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.
17pub 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.
27pub 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}