public int GetStrategyScore(int numHandsToPlay) { int playerChips = 0; var deck = new Deck(testConditions.NumDecks); var randomizer = new Randomizer(); Hand dealerHand = new Hand(); Hand playerHand = new Hand(); List <Hand> playerHands = new List <Hand>(); List <int> betAmountPerHand = new List <int>(); for (int handNum = 0; handNum < numHandsToPlay; handNum++) { dealerHand.Cards.Clear(); playerHand.Cards.Clear(); dealerHand.AddCard(deck.DealCard()); dealerHand.AddCard(deck.DealCard()); playerHand.AddCard(deck.DealCard()); if (StackTheDeck) { // even out the hands dealt to the player so it's proportionate to the // number of cells in the three grids var rand = randomizer.GetFloatFromZeroToOne(); if (rand < 0.33F) { // deal a pair deck.ForceNextCardToBe(playerHand.Cards[0].Rank); } if (rand >= 0.33F && rand < 0.66F) { // deal a soft hand if (playerHand.Cards[0].Rank != Card.Ranks.Ace) { deck.ForceNextCardToBe(Card.Ranks.Ace); } else { deck.EnsureNextCardIsnt(Card.Ranks.Ace); // avoid a pair of Aces } } // yes, our normal deal for hard hands may result in a pair or a hard hand, but // we don't care since we're just trying to even out the proportion of those type of hands } playerHand.AddCard(deck.DealCard()); playerHands.Clear(); playerHands.Add(playerHand); // we need to track how much bet per hand, since you can double down after a split. betAmountPerHand.Clear(); betAmountPerHand.Add(testConditions.BetSize); playerChips -= testConditions.BetSize; // 1. check for player Blackjack if (playerHand.HandValue() == 21) { // if the dealer also has 21, then it's a tie if (dealerHand.HandValue() == 21) // ##!! THIS WAS EDITED FROM != TO == ##!! { playerChips += betAmountPerHand[0]; // return the bet } else { // Blackjack typically pays 3:2, although some casinos do 5:4 playerChips += testConditions.BlackjackPayoffSize + betAmountPerHand[0]; //+betSize was EDITED IN } betAmountPerHand[0] = 0; continue; // go to next hand } // 2. if the dealer has blackjack, then simply move to the next hand, since playerChips was already decremented if (dealerHand.HandValue() == 21) { continue; } // 3. If the player has a playable hand, get a decision and play until standing or busting // If split is selected, a new hand is added to playerHands, which is why we loop like this: for (var handIndex = 0; handIndex < playerHands.Count; handIndex++) { playerHand = playerHands[handIndex]; var gameState = GameState.PlayerDrawing; while (gameState == GameState.PlayerDrawing) { // if the hand was split and resulted in Blackjack, pay off and more to the next hand if (playerHand.HandValue() == 21) { if (playerHand.Cards.Count == 2) // Blackjack { int blackjackPayoff = (testConditions.BlackjackPayoffSize + betAmountPerHand[handIndex]) / testConditions.BetSize; //testConditions.BlackjackPayoffSize * betAmountPerHand[handIndex] / testConditions.BetSize; playerChips += blackjackPayoff; betAmountPerHand[handIndex] = 0; } gameState = GameState.DealerDrawing; break; } var action = strategy.GetActionForHand(playerHand, dealerHand.Cards[0]); // if there's an attempt to double-down with more than 2 cards, turn into a hit if (action == ActionToTake.Double && playerHand.Cards.Count > 2) { action = ActionToTake.Hit; } switch (action) { case ActionToTake.Hit: playerHand.AddCard(deck.DealCard()); // if we're at 21, we automatically stand if (playerHand.HandValue() == 21) { gameState = GameState.DealerDrawing; } // did we bust? if (playerHand.HandValue() > 21) { betAmountPerHand[handIndex] = 0; gameState = GameState.PlayerBusted; } break; case ActionToTake.Stand: gameState = GameState.DealerDrawing; break; case ActionToTake.Double: // double down means bet another chip, and get one and only card card playerChips -= testConditions.BetSize; betAmountPerHand[handIndex] += testConditions.BetSize; playerHand.AddCard(deck.DealCard()); if (playerHand.HandValue() > 21) { betAmountPerHand[handIndex] = 0; gameState = GameState.PlayerBusted; } else { gameState = GameState.DealerDrawing; } break; case ActionToTake.Split: // add the new hand to our collection var newHand = new Hand(); newHand.AddCard(playerHand.Cards[1]); playerHand.Cards[1] = deck.DealCard(); newHand.AddCard(deck.DealCard()); playerHands.Add(newHand); // our extra bet playerChips -= testConditions.BetSize; betAmountPerHand.Add(testConditions.BetSize); break; } } } // 4. if there are playable hands for the player, get the dealer decisions bool playerHandsAvailable = betAmountPerHand.Sum() > 0; if (playerHandsAvailable) { var gameState = GameState.DealerDrawing; // draw until holding 17 or busting while (dealerHand.HandValue() < 17) { dealerHand.AddCard(deck.DealCard()); if (dealerHand.HandValue() > 21) { // payoff each hand that is still valid - busts and blackjacks have 0 for betAmountPerHand for (int handIndex = 0; handIndex < playerHands.Count; handIndex++) { playerChips += betAmountPerHand[handIndex] * 2; // the original bet and a matching amount } gameState = GameState.DealerBusted; break; } } // 5. and then compare the dealer hand to each player hand if (gameState != GameState.DealerBusted) { int dealerHandValue = dealerHand.HandValue(); for (int handIndex = 0; handIndex < playerHands.Count; handIndex++) { var playerHandValue = playerHands[handIndex].HandValue(); // if it's a tie, give the player his bet back if (playerHandValue == dealerHandValue) { playerChips += betAmountPerHand[handIndex]; } else { if (playerHandValue > dealerHandValue) { // player won playerChips += betAmountPerHand[handIndex] * 2; // the original bet and a matching amount } else { // player lost, nothing to do since the chips have already been decremented } } } } } } return(playerChips); }
public static void ShowPlayableHands(StrategyBase strategy, Canvas canvas, string savedImageName, string displayText) { // clear the screen canvas.Children.Clear(); Color hitColor = Colors.LightGreen, standColor = Color.FromRgb(252, 44, 44), doubleColor = Colors.Yellow, splitColor = Colors.MediumPurple; AddInformationalText(displayText, canvas); // display a grid for non-paired hands without an ace. One column for each possible dealer upcard AddColorBox(Colors.White, "", 0, 0, canvas); int x = 1, y = 0; foreach (var upcardRank in Card.ListOfRanks) { // strategy for 10, J, Q, and K are the same, so skip some of those if (upcardRank == Card.Ranks.Jack || upcardRank == Card.Ranks.Queen || upcardRank == Card.Ranks.King) { continue; } Card dealerUpcard = new Card(upcardRank, Card.Suits.Diamonds); string upcardRankName = Card.RankText(upcardRank); AddColorBox(Colors.White, upcardRankName, x, 0, canvas); y = 1; for (int hardTotal = 20; hardTotal > 4; hardTotal--) { // add a white box with the total AddColorBox(Colors.White, hardTotal.ToString(), 0, y, canvas); // build player hand Hand playerHand = new Hand(); // divide by 2 if it's even, else add one and divide by two int firstCardRank = ((hardTotal % 2) != 0) ? (hardTotal + 1) / 2 : hardTotal / 2; int secondCardRank = hardTotal - firstCardRank; if (firstCardRank == secondCardRank) { firstCardRank++; secondCardRank--; if (firstCardRank == 11) { // hard 20 needs to be three cards, so in this case 9, 4, 7 firstCardRank = 4; playerHand.AddCard(new Card(Card.Ranks.Seven, Card.Suits.Clubs)); } } playerHand.AddCard(new Card((Card.Ranks)firstCardRank, Card.Suits.Diamonds)); playerHand.AddCard(new Card((Card.Ranks)secondCardRank, Card.Suits.Hearts)); // get strategy and display var action = strategy.GetActionForHand(playerHand, dealerUpcard); switch (action) { case ActionToTake.Hit: AddColorBox(hitColor, "H", x, y, canvas); break; case ActionToTake.Stand: AddColorBox(standColor, "S", x, y, canvas); break; case ActionToTake.Double: AddColorBox(doubleColor, "D", x, y, canvas); break; } y++; } x++; } // and another for hands with an ace // display a grid for hands without an ace. One column for each possible dealer upcard const int leftColumnForAces = 12; AddColorBox(Colors.White, "", leftColumnForAces, 0, canvas); x = leftColumnForAces + 1; foreach (var upcardRank in Card.ListOfRanks) { // strategy for 10, J, Q, and K are the same, so skip some of those if (upcardRank == Card.Ranks.Jack || upcardRank == Card.Ranks.Queen || upcardRank == Card.Ranks.King) { continue; } string upcardRankName = Card.RankText(upcardRank); Card dealerUpcard = new Card(upcardRank, Card.Suits.Diamonds); AddColorBox(Colors.White, upcardRankName, x, 0, canvas); y = 1; // we don't start with Ace, because that would be AA, which is handled in the pair zone // we also don't start with 10, since that's blackjack. So 9 is our starting point // only need 2 through 9, since a-a is in the pairs table, and a-10 is blackjack for (var otherCard = Card.Ranks.Nine; otherCard >= Card.Ranks.Two; otherCard--) { // add a white box with the player hand: "A-x" string otherCardRank = Card.RankText(otherCard); AddColorBox(Colors.White, "A-" + otherCardRank, leftColumnForAces, y, canvas); // build player hand Hand playerHand = new Hand(); // first card is an ace, second card is looped over playerHand.AddCard(new Card(Card.Ranks.Ace, Card.Suits.Hearts)); // ace of hearts playerHand.AddCard(new Card(otherCard, Card.Suits.Spades)); // get strategy and display var action = strategy.GetActionForHand(playerHand, dealerUpcard); switch (action) { case ActionToTake.Hit: AddColorBox(hitColor, "H", x, y, canvas); break; case ActionToTake.Stand: AddColorBox(standColor, "S", x, y, canvas); break; case ActionToTake.Double: AddColorBox(doubleColor, "D", x, y, canvas); break; } y++; } x++; } // finally, a grid for pairs int startY = y + 1; AddColorBox(Colors.White, "", leftColumnForAces, startY, canvas); x = leftColumnForAces + 1; foreach (var upcardRank in Card.ListOfRanks) { // strategy for 10, J, Q, and K are the same, so skip some of those if (upcardRank == Card.Ranks.Jack || upcardRank == Card.Ranks.Queen || upcardRank == Card.Ranks.King) { continue; } string upcardRankName = Card.RankText(upcardRank); Card dealerUpcard = new Card(upcardRank, Card.Suits.Diamonds); AddColorBox(Colors.White, upcardRankName, x, startY, canvas); y = startY + 1; for (var pairedRank = Card.Ranks.Ace; pairedRank >= Card.Ranks.Two; pairedRank--) { // strategy for 10, J, Q, and K are the same, so skip some of those if (pairedRank == Card.Ranks.Jack || pairedRank == Card.Ranks.Queen || pairedRank == Card.Ranks.King) { continue; } // add a white box with the player hand: "x-x" string pairedCardRank = Card.RankText(pairedRank); AddColorBox(Colors.White, pairedCardRank + "-" + pairedCardRank, leftColumnForAces, y, canvas); // build player hand Hand playerHand = new Hand(); playerHand.AddCard(new Card(pairedRank, Card.Suits.Hearts)); // X of hearts playerHand.AddCard(new Card(pairedRank, Card.Suits.Spades)); // X of spades // get strategy and display var action = strategy.GetActionForHand(playerHand, dealerUpcard); switch (action) { case ActionToTake.Hit: AddColorBox(hitColor, "H", x, y, canvas); break; case ActionToTake.Stand: AddColorBox(standColor, "S", x, y, canvas); break; case ActionToTake.Double: AddColorBox(doubleColor, "D", x, y, canvas); break; case ActionToTake.Split: AddColorBox(splitColor, "P", x, y, canvas); break; } y++; } x++; } // now that's it's drawn, save an image? if (!string.IsNullOrEmpty(savedImageName)) { SaveCanvasToPng(canvas, savedImageName); } }