public void InitialDealDealer(CardShoe shoe) { List<int> upCard = shoe.DealCard(1); List<int> holeCard = shoe.DealCard(1, false); Cards.AddRange(upCard); Cards.AddRange(holeCard); }
public BetHandResult BetHand(double betSize, CardShoe shoe) { // save the True Count before bet int trueCountBeforeBet = 0; if (shoe.Count != null) { trueCountBeforeBet = shoe.Count.TrueCount; } // initial deal Hand handPlayer = new Hand(); handPlayer.InitialDealPlayer(shoe); Hand handDealer = new Hand(); handDealer.InitialDealDealer(shoe); int numberOfSplits = 0; // play hand var betHandResult = new BetHandResult(); betHandResult.TrueCountBeforeBet = trueCountBeforeBet; betHandResult.BetSize = betSize; PlayHandOutcome playHandOutcome = PlayHand(handPlayer, handDealer, betSize, shoe, ref numberOfSplits); // update bet hand results betHandResult.NumberOfSplits = numberOfSplits; betHandResult.BetTotal = playHandOutcome.BetTotal; var payoff = PayoffHand(playHandOutcome, handDealer, shoe); betHandResult.Payoff = payoff; // update count with the hole card revealed shoe.Count.Update(handDealer.Cards[1], shoe.LeftPacksCount); return betHandResult; }
public static void CreateShoe() { var sampleConfiguration = new Configuration { GameRules = new GameRules { DoubleAfterSplit = true, MaxNumberOfSplits = 10 }, SimulationParameters = new SimulationParameters { UnitBetSizeBase = 5, TotalPacksCount = 4, InitialWealth = 10000, BetSizeTrueCountScale = new List<TrueCountBet> { new TrueCountBet { BetRatio = 0.2, TrueCount = 10 }, new TrueCountBet { BetRatio = 0.1, TrueCount = 20 }, new TrueCountBet { BetRatio = 0.3, TrueCount = 30 } }, CountSystem = new List<CountSystemBit> { new CountSystemBit { Card = 1, Count = -1 }, new CountSystemBit { Card = 2, Count = 1 }, new CountSystemBit { Card = 3, Count = 1 }, new CountSystemBit { Card = 4, Count = 1 }, new CountSystemBit { Card = 5, Count = 1 }, new CountSystemBit { Card = 6, Count = 1 }, new CountSystemBit { Card = 7, Count = 0 }, new CountSystemBit { Card = 8, Count = 0 }, new CountSystemBit { Card = 9, Count = 0 }, new CountSystemBit { Card = 10, Count = -1 }, new CountSystemBit { Card = 11, Count = 1 }, new CountSystemBit { Card = 12, Count = 1 }, new CountSystemBit { Card = 13, Count = 1 } } } }; CardShoe shoe = new CardShoe(sampleConfiguration, new Random()); var cards = shoe.DealCard(2); }
public void InitialDealPlayer(CardShoe shoe) { List<int> hitCards = shoe.DealCard(2); Cards.AddRange(hitCards); }
public void Hit(CardShoe shoe) { List<int> hitCards = shoe.DealCard(1); Cards.AddRange(hitCards); }
public List<Hand> Split(CardShoe shoe) { if (!IsPair()) { return null; } var splitHands = new List<Hand>(); var hand = new Hand(Cards[0], BetSize); hand.Hit(shoe); splitHands.Add(hand); hand = new Hand(Cards[1], BetSize); hand.Hit(shoe); splitHands.Add(hand); return splitHands; }
public void Run(ProgressBarSetValue progressBarSetValue = null) { var simulationCount = Configuration.SimulationParameters.SimulationCount; var shoe = new CardShoe(Configuration, Random); double betSize; BetHandResult betHandResult; int indexFinished = 0; int ratioFinishedPrevious = 0; int ratioFinishedRound; double ratioFinished; double wealth; var stopwatch = Stopwatch.StartNew(); var resultsUtils = new ResultsUtils(Configuration); var message = String.Format("Simulating {0} of played hands...", simulationCount); TraceWrapper.LogInformation(message); var penetrationThreshold = Configuration.SimulationParameters.PenetrationThreshold; for (long i = 0; i < simulationCount; i++) { wealth = resultsUtils.Statistics.WealthStatistics.WealthValue; betSize = GetBetSize(wealth, shoe); betHandResult = BetHand(betSize, shoe); resultsUtils.Update(betHandResult); if (shoe.Penetration > penetrationThreshold) { shoe.Reinitiate(); } ratioFinished = (double)i / (double)simulationCount * 100; ratioFinishedRound = (int)Math.Round(ratioFinished); if (progressBarSetValue != null && ratioFinishedRound > ratioFinishedPrevious) { progressBarSetValue(ratioFinishedRound); ratioFinishedPrevious = ratioFinishedRound; } if ((int)Math.Truncate(ratioFinished / 5.0) > indexFinished) { indexFinished++; TraceWrapper.LogInformation("Blackjack simulation: Finished {0}% in {1}.", ratioFinished, stopwatch.Elapsed); } } resultsUtils.FinalizeAll(); stopwatch.Stop(); TraceWrapper.LogInformation("Blackjack simulation: FINISHED in {0}.", stopwatch.Elapsed); var outputFolder = Configuration.SimulationParameters.OutputFolderSpecific; var filePath = Path.Combine(outputFolder, "BlackjackSim_Configuration.xml"); XmlUtils.SerializeToFile<Configuration>(Configuration, filePath); }
public PlayHandOutcome PlayHand(Hand handPlayer, Hand handDealer, double betSize, CardShoe shoe, ref int numberOfSplits) { int trueCount = 0; if (shoe.Count != null) { trueCount = shoe.Count.TrueCount; } bool surrenderDone = false; bool splitDone = numberOfSplits > 0; var playHandOutcome = new PlayHandOutcome(); handPlayer.BetSize = betSize; // consider insurance first double insuranceBet = 0; if (Configuration.GameRules.InsuranceAllowed && handDealer.IsAce(0) && !splitDone) { bool takeInsurance = Strategy.GetInsuranceDecision(handDealer, trueCount); if (takeInsurance) { insuranceBet = 0.5 * betSize; } } // player's hand play bool continuePlay = true; while (handPlayer.Value() < 21 && !surrenderDone && !handDealer.IsBlackjack() && continuePlay) { Permits permits = new Permits(handPlayer, Configuration, numberOfSplits); if (shoe.Count != null) { trueCount = shoe.Count.TrueCount; } StrategyDecisionType decision = Strategy.GetDecision(handPlayer, handDealer, trueCount, permits, Random); switch (decision) { case StrategyDecisionType.STAND: continuePlay = false; break; case StrategyDecisionType.HIT: handPlayer.Hit(shoe); break; case StrategyDecisionType.DOUBLE: handPlayer.DoubleDone = true; betSize *= 2; handPlayer.Hit(shoe); continuePlay = false; break; case StrategyDecisionType.SPLIT: var splitHands = handPlayer.Split(shoe); numberOfSplits++; var playHandOutcomeSplit1 = PlayHand(splitHands[1], handDealer, betSize, shoe, ref numberOfSplits); var playHandOutcomeSplit2 = PlayHand(splitHands[0], handDealer, betSize, shoe, ref numberOfSplits); playHandOutcome.AddHands(playHandOutcomeSplit1.HandsPlayed); playHandOutcome.AddHands(playHandOutcomeSplit2.HandsPlayed); double betTotal = playHandOutcomeSplit1.BetTotal + playHandOutcomeSplit2.BetTotal + insuranceBet; playHandOutcome.BetTotal = betTotal; playHandOutcome.InsuranceBet = insuranceBet; return playHandOutcome; case StrategyDecisionType.SURRENDER: surrenderDone = true; break; case StrategyDecisionType.NA: throw new Exception("Strategy decision was not determined!"); } } // return outcome playHandOutcome.HandsPlayed.Add(handPlayer); playHandOutcome.BetTotal = betSize + insuranceBet; playHandOutcome.InsuranceBet = insuranceBet; playHandOutcome.SurrenderDone = surrenderDone; return playHandOutcome; }
public double PayoffHand(PlayHandOutcome playHandOutcome, Hand handDealer, CardShoe shoe) { var insurancePayoff = PayoffInsurance(handDealer, playHandOutcome.InsuranceBet); int handsTotal = playHandOutcome.HandsPlayed.Count; bool splitDone = handsTotal > 1; if (playHandOutcome.SurrenderDone) { if (handsTotal > 1) { throw new Exception("Surrender done while hand has been split - should not happen!"); } var betSize = playHandOutcome.HandsPlayed[0].BetSize; return -0.5 * betSize + insurancePayoff; } // dealer's hand play while (((handDealer.Value() <= 16) || (handDealer.Value() == 17 && handDealer.IsSoft() && !Configuration.GameRules.DealerStandsSoft17)) && !playHandOutcome.AllHandBust()) { handDealer.Hit(shoe); } int dealerTotal = handDealer.Value(); double payoff = 0; foreach (var handPlayed in playHandOutcome.HandsPlayed) { var betSize = handPlayed.BetSize; if (handPlayed.DoubleDone) { betSize *= 2; } int playerTotal = handPlayed.Value(); if (handPlayed.IsBlackjack() && !handDealer.IsBlackjack() && !splitDone) { // blackjack won payoff += 1.5 * betSize; } else if (playerTotal > 21) { // player bust payoff -= betSize; } else if (dealerTotal > 21) { // dealer bust payoff += betSize; } else if (playerTotal > dealerTotal) { // player won payoff += betSize; } else if (dealerTotal > playerTotal) { // dealer won payoff -= betSize; } else { // push payoff += 0; } } return payoff + insurancePayoff; }
public double GetBetSize(double wealth, CardShoe shoe) { double betSize = 0; switch (Configuration.SimulationParameters.BetSizeCalculationType) { case BetSizeCalculationType.FIXED: betSize = Math.Round(GetBetSizeUnit(wealth)); break; case BetSizeCalculationType.TRUE_COUNT_VARIABLE: if (shoe.Count == null) { throw new Exception("Count not initiated, cannot scale bet size conditionally on True Count!"); } else { var trueCount = shoe.Count.TrueCount; var riskAversionCoefficient = Configuration.SimulationParameters.RiskAversionCoefficient; var betSizeTrueCountScale = Configuration.SimulationParameters.BetSizeTrueCountScale; var trueCountBet = betSizeTrueCountScale.GetTrueCountBet(trueCount); betSize = wealth * trueCountBet.BetRatio * (1.0 / riskAversionCoefficient); betSize = Math.Round(betSize); betSize = Math.Min(Math.Max(betSize, Configuration.SimulationParameters.BetSizeMin), Configuration.SimulationParameters.BetSizeMax); break; } case BetSizeCalculationType.TRUE_COUNT_BET_SPREAD: if (shoe.Count == null) { throw new Exception("Count not initiated, cannot scale bet size conditionally on True Count!"); } else { var trueCount = shoe.Count.TrueCount; var betSizeTrueCountScale = Configuration.SimulationParameters.BetSizeTrueCountScale; var trueCountBet = betSizeTrueCountScale.GetTrueCountBet(trueCount); var betInUnits = trueCountBet.BetInUnits; var unitBet = GetBetSizeUnit(wealth); betSize = Math.Round(betInUnits * unitBet); betSize = Math.Min(Math.Max(betSize, Configuration.SimulationParameters.BetSizeMin), Configuration.SimulationParameters.BetSizeMax); break; } } return betSize; }