From fdc8024a61b21314fb1ca1ab6d8adf45c9c7b063 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 24 Aug 2026 18:30:25 +0200 Subject: Balance slots payouts: EV=0.972 (2.8% house edge). Three-of-a-kind: 2-28x, two-of-a-kind: 1-3x. --- src/bin/client/games/slots.rs | 4 ++-- src/bin/server/games/slots.rs | 27 ++++++++++++++------------- tests/slots.rs | 16 ++++++++-------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/bin/client/games/slots.rs b/src/bin/client/games/slots.rs index d664dbc..bc0a9b4 100644 --- a/src/bin/client/games/slots.rs +++ b/src/bin/client/games/slots.rs @@ -50,8 +50,8 @@ impl Game for SlotsGame { Match symbols to win!\n\ \n\ Payouts:\n\ - Three of a kind: 5x-100x bet\n\ - Two of a kind: 2x-20x bet\n\ + Three of a kind: 2x-28x bet\n\ + Two of a kind: 1x-3x bet\n\ \n\ Symbols: C=Cherry, L=Lemon, O=Orange, G=Grapes, D=Diamond, S=Seven\n\ \n\ diff --git a/src/bin/server/games/slots.rs b/src/bin/server/games/slots.rs index 3d285ef..04ac175 100644 --- a/src/bin/server/games/slots.rs +++ b/src/bin/server/games/slots.rs @@ -12,19 +12,20 @@ impl SlotsGame { let symbols = vec!['C', 'L', 'O', 'G', 'D', 'S']; let mut payouts = HashMap::new(); - payouts.insert("CCC".to_string(), 5); - payouts.insert("LLL".to_string(), 10); - payouts.insert("OOO".to_string(), 15); - payouts.insert("GGG".to_string(), 20); - payouts.insert("DDD".to_string(), 50); - payouts.insert("SSS".to_string(), 100); - - payouts.insert("CC".to_string(), 2); - payouts.insert("LL".to_string(), 3); - payouts.insert("OO".to_string(), 4); - payouts.insert("GG".to_string(), 5); - payouts.insert("DD".to_string(), 10); - payouts.insert("SS".to_string(), 20); + // Balanced payouts: EV = 210/216 ≈ 0.972 (2.8% house edge) + payouts.insert("CCC".to_string(), 2); + payouts.insert("LLL".to_string(), 3); + payouts.insert("OOO".to_string(), 5); + payouts.insert("GGG".to_string(), 8); + payouts.insert("DDD".to_string(), 14); + payouts.insert("SSS".to_string(), 28); + + payouts.insert("CC".to_string(), 1); + payouts.insert("LL".to_string(), 1); + payouts.insert("OO".to_string(), 1); + payouts.insert("GG".to_string(), 2); + payouts.insert("DD".to_string(), 2); + payouts.insert("SS".to_string(), 3); Self { symbols, payouts } } diff --git a/tests/slots.rs b/tests/slots.rs index c50f425..6babd98 100644 --- a/tests/slots.rs +++ b/tests/slots.rs @@ -12,9 +12,9 @@ fn make_game() -> SlotsGame { fn three_of_a_kind_pays() { let game = make_game(); // CCC = 5x - assert_eq!(game.calculate_payout(&['C', 'C', 'C'], 100), 500); + assert_eq!(game.calculate_payout(&['C', 'C', 'C'], 100), 200); // SSS = 100x - assert_eq!(game.calculate_payout(&['S', 'S', 'S'], 10), 1000); + assert_eq!(game.calculate_payout(&['S', 'S', 'S'], 10), 280); } /// Two adjacent matching symbols pays the two-of-a-kind multiplier. @@ -22,9 +22,9 @@ fn three_of_a_kind_pays() { fn two_adjacent_pays() { let game = make_game(); // CC? = 2x - assert_eq!(game.calculate_payout(&['C', 'C', 'D'], 100), 200); + assert_eq!(game.calculate_payout(&['C', 'C', 'D'], 100), 100); // ?LL = 3x - assert_eq!(game.calculate_payout(&['D', 'L', 'L'], 50), 150); + assert_eq!(game.calculate_payout(&['D', 'L', 'L'], 50), 50); } /// Non-adjacent matching symbols (e.g. [C,D,C]) must also pay. @@ -33,11 +33,11 @@ fn two_adjacent_pays() { fn two_non_adjacent_pays() { let game = make_game(); // C,D,C — two cherries at positions 0 and 2 - assert_eq!(game.calculate_payout(&['C', 'D', 'C'], 100), 200); + assert_eq!(game.calculate_payout(&['C', 'D', 'C'], 100), 100); // S,X,S — two sevens at positions 0 and 2 - assert_eq!(game.calculate_payout(&['S', 'L', 'S'], 10), 200); + assert_eq!(game.calculate_payout(&['S', 'L', 'S'], 10), 30); // L,O,L - assert_eq!(game.calculate_payout(&['L', 'O', 'L'], 50), 150); + assert_eq!(game.calculate_payout(&['L', 'O', 'L'], 50), 50); } /// No matching symbols returns 0. @@ -80,7 +80,7 @@ fn calculate_result_on_finished_state() { let result = game.calculate_result(&state).unwrap(); assert_eq!(result.bet_amount, 100); - assert_eq!(result.winnings, 200); // CC = 2x + assert_eq!(result.winnings, 100); // CC = 1x } /// calculate_result on a non-finished state returns an error. -- cgit v1.2.3