using KfChatDotNetBot.Models.DbModels; using Money = KfChatDotNetBot.Services.Money; namespace KfChatDotNetBot.Models; public class BlackjackGameMetaModel { /// /// Player's hands (multiple if split) /// public required List> PlayerHands { get; set; } /// /// Dealer's hand /// public required List DealerHand { get; set; } /// /// Remaining cards in the deck /// public required List Deck { get; set; } /// /// Whether each hand has doubled down (can only hit once more) /// public required List HasDoubledDown { get; set; } /// /// Current hand being played (for split hands) /// public int CurrentHandIndex { get; set; } = 0; /// /// Original wager amount (per hand) /// public decimal OriginalWagerAmount { get; set; } } public class Card { /// /// Card rank (2-10, J, Q, K, A) /// public required string Rank { get; set; } /// /// Card suit (♠, ♥, ♦, ♣) /// public required string Suit { get; set; } /// /// Get the blackjack value of this card /// public int GetValue() { return Rank switch { "A" => 11, // Aces are handled specially in hand calculation "K" or "Q" or "J" => 10, _ => int.Parse(Rank) }; } /// /// Display card as string /// public override string ToString() { return $"{Rank}{Suit}"; } } public static class BlackjackHelper { private static readonly string[] Ranks = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" }; private static readonly string[] Suits = { "♠", "♥", "♦", "♣" }; /// /// Create a new shuffled deck /// public static List CreateDeck(GamblerDbModel gambler) { var deck = new List(); foreach (var suit in Suits) { foreach (var rank in Ranks) { deck.Add(new Card { Rank = rank, Suit = suit }); } } // Shuffle using Fisher-Yates for (int i = deck.Count - 1; i > 0; i--) { int j = Money.GetRandomNumber(gambler, 0, i + 1); (deck[i], deck[j]) = (deck[j], deck[i]); } return deck; } /// /// Calculate hand value with proper Ace handling /// public static int CalculateHandValue(List hand) { int value = 0; int aces = 0; foreach (var card in hand) { if (card.Rank == "A") { aces++; value += 11; } else { value += card.GetValue(); } } // Convert Aces from 11 to 1 if needed to avoid bust while (value > 21 && aces > 0) { value -= 10; aces--; } return value; } /// /// Check if hand is blackjack (21 with 2 cards) /// public static bool IsBlackjack(List hand) { return hand.Count == 2 && CalculateHandValue(hand) == 21; } /// /// Check if a hand can be split (two cards of same rank) /// public static bool CanSplit(List hand) { if (hand.Count != 2) return false; // Check if both cards have the same value (not rank, to allow 10/J/Q/K splits) return hand[0].GetValue() == hand[1].GetValue(); } /// /// Format hand for display /// public static string FormatHand(List hand, bool hideFirstCard = false) { if (hideFirstCard && hand.Count > 0) { return $"[HIDDEN] {string.Join(" ", hand.Skip(1).Select(c => c.ToString()))}"; } return string.Join(" ", hand.Select(c => c.ToString())); } }