use zagan_bet::blackjack::{ card_label, card_value, fresh_shoe, hand_total, is_blackjack, BlackjackState, }; use zagan_bet::server::games::blackjack::BlackjackGame; fn hand(deck: &[&str], bet: u64) -> zagan_bet::server::games::blackjack::BlackjackHand { let deck = deck.iter().map(|card| card.to_string()).collect(); BlackjackGame::with_deck(deck).deal(bet) } #[test] fn card_values_and_soft_totals_are_correct() { assert_eq!(card_value("AS"), 11); assert_eq!(card_value("10H"), 10); assert_eq!(card_value("KD"), 10); assert_eq!(card_label("AS"), "A♠"); assert_eq!(card_label("10H"), "10♥"); let cards = |values: &[&str]| values.iter().map(|card| card.to_string()).collect::>(); assert_eq!(hand_total(&cards(&["AS", "10H"])), 21); assert_eq!(hand_total(&cards(&["AS", "9H"])), 20); assert_eq!(hand_total(&cards(&["AS", "AS", "9H"])), 21); assert!(is_blackjack(&cards(&["AS", "KH"]))); assert!(!is_blackjack(&cards(&["AS", "9H"]))); } #[test] fn a_six_deck_shoe_has_312_cards() { let shoe = fresh_shoe(); assert_eq!(shoe.len(), 312); assert_eq!(shoe.iter().filter(|card| card.as_str() == "AS").count(), 6); } #[test] fn a_natural_blackjack_settles_immediately() { let hand = hand(&["AS", "9D", "KH", "8C"], 10); assert!(hand.is_done()); assert_eq!(hand.result, "blackjack"); assert_eq!(hand.winnings, 25); // 10 + 15 assert_eq!(hand.player_total(), 21); } #[test] fn a_player_hand_can_hit_to_21() { let mut hand = hand(&["10S", "9D", "6H", "8C", "5D"], 10); assert_eq!(hand.player_total(), 16); assert_eq!(hand.dealer_total(), 17); hand.hit().unwrap(); assert!(hand.is_done()); assert_eq!(hand.player_total(), 21); assert_eq!(hand.result, "win"); assert_eq!(hand.winnings, 20); } #[test] fn hitting_over_21_busts() { let mut hand = hand(&["10S", "9D", "6H", "8C", "KD"], 10); hand.hit().unwrap(); assert!(hand.is_done()); assert_eq!(hand.result, "bust"); assert_eq!(hand.winnings, 0); } #[test] fn doubling_adds_the_base_bet_and_draws_one_card() { let mut hand = hand(&["5S", "9D", "5H", "8C", "10D"], 10); assert_eq!(hand.player_total(), 10); hand.double().unwrap(); assert_eq!(hand.player.len(), 3); assert_eq!(hand.bet, 20); assert_eq!(hand.player_total(), 20); assert_eq!(hand.result, "win"); assert_eq!(hand.winnings, 40); } #[test] fn the_dealer_busts_and_the_player_wins() { let mut hand = hand(&["10S", "7H", "8H", "9C", "10H"], 10); assert_eq!(hand.player_total(), 18); assert_eq!(hand.dealer_total(), 16); hand.stand(); assert_eq!(hand.dealer_total(), 26); assert_eq!(hand.result, "win"); assert_eq!(hand.winnings, 20); } #[test] fn the_dealer_stands_on_soft_17() { let mut hand = hand(&["10S", "AD", "8H", "6C"], 10); assert_eq!(hand.dealer_total(), 17); hand.stand(); assert_eq!(hand.dealer.len(), 2, "dealer must stand on soft 17"); assert_eq!(hand.result, "win"); assert_eq!(hand.winnings, 20); } #[test] fn equal_totals_push() { let mut hand = hand(&["10S", "10D", "8H", "8C"], 10); hand.stand(); assert_eq!(hand.result, "push"); assert_eq!(hand.winnings, 10); } #[test] fn dealer_blackjack_wins_unless_player_also_has_it() { let dealer_blackjack = hand(&["10S", "AS", "8H", "KD"], 10); assert_eq!(dealer_blackjack.result, "lose"); assert_eq!(dealer_blackjack.winnings, 0); let both = hand(&["AS", "AD", "KH", "KC"], 10); assert_eq!(both.result, "push"); assert_eq!(both.winnings, 10); } #[test] fn the_player_state_hides_the_hole_card() { let hand = hand(&["10S", "9D", "6H", "8C"], 10); let state: BlackjackState = hand.state("session-1", 990); assert_eq!(state.phase, "player"); assert_eq!(state.dealer, vec!["9D".to_string(), "?".to_string()]); assert_eq!(state.dealer_total, 9); assert_eq!(state.player_total, 16); assert_eq!(state.actions, vec!["hit", "stand", "double"]); assert_eq!(state.bet, 10); assert_eq!(state.balance, 990); }