From 2915d826f744612e0d975282f5bddf13270b9f3f Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 28 Oct 2026 23:19:52 +0100 Subject: v1.1.0: highlight winning symbols on the slots board --- tests/client_core.rs | 16 ++++++++++------ tests/server_core.rs | 2 +- tests/slots.rs | 43 +++++++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 21 deletions(-) (limited to 'tests') diff --git a/tests/client_core.rs b/tests/client_core.rs index 80ec587..91ddcab 100644 --- a/tests/client_core.rs +++ b/tests/client_core.rs @@ -155,12 +155,12 @@ fn spin_replaces_the_board_and_keeps_the_controls_line() { assert!(h.sent.iter().any(|line| line == "PLAY_START slots 50")); assert_eq!(h.screen.lines.len(), lines_before_spin); - h.reply("GAME_RESULT session-1 100 50 1050 CCCCLLCLODGSDGS win 1"); + h.reply("GAME_RESULT session-1 100 50 1050 CCCCLLCLODGSDGS win 1 0,3,6"); assert_eq!(h.board().len(), 9); assert!(h .board() .get(2) - .is_some_and(|line| line.contains("[ C ] [ C ] [ C ] [ D ] [ D ]"))); + .is_some_and(|line| line.contains("{ C } { C } { C } [ D ] [ D ]"))); assert!(h.board()[6].contains("Won 100 PLN")); assert!(h.board()[7].contains("Winning lines: 1")); assert!(h.board()[1].contains("Balance: 1050 PLN")); @@ -173,7 +173,7 @@ fn changing_the_bet_after_a_spin_does_not_leave_stale_lines() { let mut h = Harness::new(); h.enter_slots("50"); h.key(Key::Char(' ')); - h.reply("GAME_RESULT session-1 100 50 1050 CCCCLLCLODGSDGS win 1"); + h.reply("GAME_RESULT session-1 100 50 1050 CCCCLLCLODGSDGS win 1 0,3,6"); let lines_before_bet = h.screen.lines.len(); h.key(Key::Char('+')); @@ -183,7 +183,7 @@ fn changing_the_bet_after_a_spin_does_not_leave_stale_lines() { assert!(h .board() .get(2) - .is_some_and(|line| line.contains("[ C ] [ C ] [ C ] [ D ] [ D ]"))); + .is_some_and(|line| line.contains("{ C } { C } { C } [ D ] [ D ]"))); assert_eq!(h.screen.lines.len(), lines_before_bet); assert_eq!( h.screen @@ -206,6 +206,7 @@ fn a_losing_spin_shows_no_win_and_no_winning_lines() { assert_eq!(h.board().len(), 9); assert!(h.board()[6].contains("No win.")); assert_eq!(h.board()[7], ""); + assert!(!h.board()[2].contains('{')); } #[test] @@ -214,11 +215,12 @@ fn a_mega_win_shows_all_winning_lines() { h.enter_slots("10"); h.key(Key::Char(' ')); - h.reply(&format!("GAME_RESULT session-1 750 10 1740 {ALL_C} mega 1,2,3,4,5")); + h.reply(&format!("GAME_RESULT session-1 750 10 1740 {ALL_C} mega 1,2,3,4,5 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14")); assert_eq!(h.board().len(), 9); assert!(h.board()[6].contains("MEGA WIN! 750 PLN")); assert!(h.board()[7].contains("Winning lines: 1,2,3,4,5")); + assert_eq!(h.board()[2].matches("{ C }").count(), 5); } #[test] @@ -517,12 +519,13 @@ fn disconnect_clears_connection_state() { #[test] fn parses_a_five_by_three_result_with_winning_lines() { - let response = format!("GAME_RESULT session-1 100 50 1050 {WIN3} win 1"); + let response = format!("GAME_RESULT session-1 100 50 1050 {WIN3} win 1 0,3,6"); let result = parse_spin_response(&response).expect("valid 5x3 result"); assert_eq!(result.reels.chars().count(), 15); assert_eq!(result.win_type, "win"); assert_eq!(result.win_lines, vec![1]); + assert_eq!(result.win_cells, vec![0, 3, 6]); } #[test] @@ -533,6 +536,7 @@ fn accepts_a_legacy_three_symbol_result() { assert_eq!(result.reels, "OSS"); assert_eq!(result.win_type, "two"); assert!(result.win_lines.is_empty()); + assert!(result.win_cells.is_empty()); } #[test] diff --git a/tests/server_core.rs b/tests/server_core.rs index f3736e9..5c3c316 100644 --- a/tests/server_core.rs +++ b/tests/server_core.rs @@ -189,7 +189,7 @@ fn a_winning_spin_updates_the_balance_and_the_audit_row() { let response = core.handle_message(&mut state, "PLAY_START slots 10"); assert!(response.starts_with("GAME_RESULT"), "spin failed: {response}"); assert!(response.contains(" 20 10 1010 "), "response: {response}"); - assert!(response.ends_with(" win 1"), "response: {response}"); + assert!(response.ends_with(" win 1 0,3,6"), "response: {response}"); assert_eq!(core.balance("alice"), Some(1010)); assert_eq!(core.play_count("alice"), 1); diff --git a/tests/slots.rs b/tests/slots.rs index 5fb751a..857e607 100644 --- a/tests/slots.rs +++ b/tests/slots.rs @@ -1,6 +1,6 @@ //! Regression tests for the server-side 5x3 slots game. -use zagan_bet::server::games::slots::{SlotsGame, PAYLINES, REELS, ROWS}; +use zagan_bet::server::games::slots::{LineWin, SlotsGame, PAYLINES, REELS, ROWS}; use zagan_bet::server::games::traits::{Game, GamePhase}; /// Convert row-major test rows into the column-major wire format. @@ -15,13 +15,17 @@ fn grid(rows: [&str; 3]) -> String { result } -fn payout(rows: [&str; 3], bet: u64) -> (u64, Vec) { +fn payout(rows: [&str; 3], bet: u64) -> (u64, Vec) { let reels = grid(rows); let game = SlotsGame::with_grid(&reels); let cells: Vec = reels.chars().collect(); game.calculate_payout(&cells, bet) } +fn lines(wins: &[LineWin]) -> Vec { + wins.iter().map(|win| win.line).collect() +} + #[test] fn the_wire_grid_is_five_reels_by_three_rows() { assert_eq!(REELS, 5); @@ -37,50 +41,60 @@ fn the_wire_grid_is_five_reels_by_three_rows() { #[test] fn three_of_a_kind_on_the_top_line_pays() { - let (winnings, lines) = payout(["CCCDD", "CLLGG", "CLOSS"], 10); + let (winnings, wins) = payout(["CCCDD", "CLLGG", "CLOSS"], 10); assert_eq!(winnings, 20, "CCC on line 1 pays 2x total bet"); - assert_eq!(lines, vec![1]); + assert_eq!(lines(&wins), vec![1]); + assert_eq!(wins[0].cells, vec![0, 3, 6]); } #[test] fn four_of_a_kind_pays_more_than_three() { - let (winnings, lines) = payout(["CCCCD", "LOGDS", "OGDSL"], 10); + let (winnings, wins) = payout(["CCCCD", "LOGDS", "OGDSL"], 10); assert_eq!(winnings, 50, "CCCC pays 5x total bet"); - assert_eq!(lines, vec![1]); + assert_eq!(lines(&wins), vec![1]); + assert_eq!(wins[0].cells, vec![0, 3, 6, 9]); } #[test] fn five_of_a_kind_pays_all_lines() { - let (winnings, lines) = payout(["SSSSS", "SSSSS", "SSSSS"], 10); + let (winnings, wins) = payout(["SSSSS", "SSSSS", "SSSSS"], 10); assert_eq!(winnings, 7500, "five SSSSS lines at 150x each"); - assert_eq!(lines, vec![1, 2, 3, 4, 5]); + assert_eq!(lines(&wins), vec![1, 2, 3, 4, 5]); + assert_eq!(wins[0].cells, vec![0, 3, 6, 9, 12]); + assert_eq!(wins[3].cells, vec![0, 4, 8, 10, 12]); + assert_eq!(wins[4].cells, vec![2, 4, 6, 10, 14]); } #[test] fn the_v_payline_is_evaluated() { - let (winnings, lines) = payout(["COGDC", "LCLCG", "OGCSD"], 10); + let (winnings, wins) = payout(["COGDC", "LCLCG", "OGCSD"], 10); assert_eq!(winnings, 150, "V line with five C symbols pays 15x"); - assert_eq!(lines, vec![4]); + assert_eq!(lines(&wins), vec![4]); + assert_eq!(wins[0].cells, vec![0, 4, 8, 10, 12]); } #[test] fn no_matching_line_pays_nothing() { - let (winnings, lines) = payout(["CLOGD", "LOSGC", "DGDSC"], 100); + let (winnings, wins) = payout(["CLOGD", "LOSGC", "DGDSC"], 100); assert_eq!(winnings, 0); - assert!(lines.is_empty()); + assert!(wins.is_empty()); } #[test] fn winning_lines_are_added_together() { - let (winnings, lines) = payout(["SSSSS", "LLLLL", "OOOOO"], 10); + let (winnings, wins) = payout(["SSSSS", "LLLLL", "OOOOO"], 10); assert_eq!(winnings, (150 + 20 + 25) * 10); - assert_eq!(lines, vec![1, 2, 3]); + assert_eq!(lines(&wins), vec![1, 2, 3]); + + let mut cells: Vec = wins.iter().flat_map(|win| win.cells.clone()).collect(); + cells.sort_unstable(); + assert_eq!(cells, (0..15).collect::>()); } #[test] @@ -111,6 +125,7 @@ fn a_spin_produces_a_finished_state_and_a_result_with_win_lines() { assert_eq!(result.winnings, 20); assert_eq!(result.result_data.get("win_type").unwrap(), "win"); assert_eq!(result.result_data.get("win_lines").unwrap(), "1"); + assert_eq!(result.result_data.get("win_cells").unwrap(), "0,3,6"); } #[test] -- cgit v1.2.3