public virtual void Hit(Dealer dealer, BettingBehavior betting)
        {
            if (IsBlackJack || IsBust)
            {
                return;
            }

            // just take a card and let the logic set the IsBust property as needed
            dealer.DealCard(this);

            // additional logic to hit again will be in derived classes
        }
        // this method will play a series of hands, using a specific behavior
        public override void PlayHands(int iterations, StatisticsMgr stats)
        {
            Dealer          dlr     = new Dealer(stats);
            BettingBehavior betting = new BettingBehavior();

            // this is done like this to avoid re-allocating hands
            ModifiedBettingHand bettingHand = new ModifiedBettingHand();

            // doing this here to avoid allocations
            Hand[] playerHands = new Hand[2];

            while (--iterations >= 0)
            {
                betting.DetermineBet(stats);

                bettingHand.Reset();

                dlr.DealHands(bettingHand);

                // tweak the stats before the doubledown bet
                foreach (Card playerCard in dlr.PlayerHand.Cards)
                {
                    // this records the card displayed, emulating a user that is
                    // counting the last 12 cards or so.  Counting more cards would
                    // result in better performance.
                    stats.DiscardCard(playerCard);
                }
                stats.DiscardCard(dlr.DealerHand.Cards[1]);
                stats.BlackJacks += (dlr.PlayerHand.IsBlackJack) ? 1 : 0;

                // apply the hit logic to the player's hand.  This will also
                // split if necessary
                dlr.PlayerHand.Hit(dlr, betting);

                // dealer only hits if the player doesn't go bust
                if (!dlr.PlayerHand.IsBust ||
                    (dlr.PlayerSplitHand != null && !dlr.PlayerSplitHand.IsBust))
                {
                    dlr.DealerHand.Hit(dlr);
                }

                if (iterations % 1000000 == 0)
                {
                    Debug.WriteLine("\tProfits:  {0}  Bet: {1}", stats.Profit, betting.Bet);
                }


                playerHands[0] = dlr.PlayerHand;
                if (null != dlr.PlayerSplitHand)
                {
                    // if the hand was split, add the split hand results as well
                    playerHands[1] = dlr.PlayerSplitHand;
                }
                else
                {
                    playerHands[1] = null;
                }

                foreach (var playerHand in playerHands)
                {
                    if (null == playerHand)
                    {
                        continue;
                    }

                    // keep track of the total amount bet since it's dynamic
                    stats.CumulativeBet += playerHand.Bet;

                    if (playerHand.IsBust)
                    {
                        stats.Profit -= playerHand.Bet;
                        stats.RecordLoss();
                        stats.LossesByBust++;
                        if (playerHand.IsDoubledDown)
                        {
                            stats.LossesByDoubleDown++;
                        }
                        if (playerHand.IsSplit)
                        {
                            stats.LossesBySplit++;
                        }
                    }
                    else if (playerHand.IsBlackJack && !dlr.DealerHand.IsBlackJack)
                    {
                        //  blackjack pays 3 to 2
                        stats.Profit += (int)(1.5 * playerHand.Bet);
                        stats.RecordWin(iterations);
                        if (playerHand.IsSplit)
                        {
                            stats.WinsBySplit++;
                        }
                    }
                    else if (!playerHand.IsBlackJack && dlr.DealerHand.IsBlackJack)
                    {
                        stats.Profit -= playerHand.Bet;
                        stats.RecordLoss();
                        if (playerHand.IsDoubledDown)
                        {
                            stats.LossesByDoubleDown++;
                        }
                        if (playerHand.IsSplit)
                        {
                            stats.LossesBySplit++;
                        }
                    }
                    else if (dlr.DealerHand.IsBust)
                    {
                        stats.Profit += playerHand.Bet;
                        stats.RecordWin(iterations);
                        stats.WinsByBust++;
                        if (playerHand.IsDoubledDown)
                        {
                            stats.WinsByDoubleDown++;
                        }
                        if (playerHand.IsSplit)
                        {
                            stats.WinsBySplit++;
                        }
                    }
                    else if (playerHand.SumCards > dlr.DealerHand.SumCards)
                    {
                        stats.Profit += playerHand.Bet;
                        stats.RecordWin(iterations);
                        if (playerHand.IsDoubledDown)
                        {
                            stats.WinsByDoubleDown++;
                        }
                        if (playerHand.IsSplit)
                        {
                            stats.WinsBySplit++;
                        }
                    }
                    else if (dlr.DealerHand.SumCards > playerHand.SumCards)
                    {
                        stats.Profit -= playerHand.Bet;
                        stats.RecordLoss();
                        if (playerHand.IsDoubledDown)
                        {
                            stats.LossesByDoubleDown++;
                        }
                        if (playerHand.IsSplit)
                        {
                            stats.LossesBySplit++;
                        }
                    }
                }

                // now keep track of the last few discarded cards from both players
                int index = 0;
                foreach (Card dlrCard in dlr.DealerHand.Cards)
                {
                    // skip the card that was initially shown because it was counted
                    // earlier
                    if (index++ == 1)
                    {
                        continue;
                    }

                    stats.DiscardCard(dlrCard);
                }
            }
        }
            // this is how to play, with this type of behavior
            public override void Hit(Dealer dealer, BettingBehavior betting)
            {
                if (IsBlackJack || IsBust)
                {
                    return;
                }

                if (betting.DetermineSplit(dealer.DealerHand, this, dealer.Statistics))
                {
                    HandleSplit(dealer, betting);

                    // at this point, the two bets were set, and the cards have been
                    // dealt.  The dealer knows about the hands
                    return;
                }

                // set the default bet
                Bet = betting.Bet;

                // modify the bet based on the last few cards (~12)
                {
                    float[] tensFactor =
                    {
                        0.7176587594f,
                        0.7482172244f,
                        1.008457417f,
                        0.8508591232f,
                        0.8222382664f,
                        0.8221459353f,
                        0.8482251933f,
                        0.9152756165f,
                        1.034960453f,
                        1.161035422f,
                        1.577427822f,
                        2.4375f,
                        2.0f
                    };

                    if (dealer.Statistics.TensIndex > 7)
                    {
                        int newbet = Bet;
                        newbet *= 1000;
                        Bet     = newbet;
                    }
                }

                // Intentionally not adding Insurance, because it's not material

                // determine if the bet should be modified
                if (betting.DetermineDoubleDown(dealer.DealerHand, this, dealer.Statistics))
                {
                    IsDoubledDown = true;

                    // okay to double the bet
                    Bet = betting.Bet * 2;

                    // deal one card only
                    // let the logic set the IsBust property as needed
                    Card cardDealt = dealer.DealCard(this);
                    dealer.Statistics.DiscardCard(cardDealt);
                }
                else
                {
                    // we'll keep hitting till the sum is at least 16
                    while ((SumCards < 16 && (dealer.Statistics.TensIndex > 1)) ||

                           // increase the threshold to 18 if player has an ace showing
                           (HasAce && _cards.Count < 3 && SumCards < 18) ||

                           // always hit if we're at 11 or below
                           SumCards < 12)
                    {
                        // let the logic set the IsBust property as needed
                        Card cardDealt = dealer.DealCard(this);
                        dealer.Statistics.DiscardCard(cardDealt);

                        if (IsBust)
                        {
                            break;
                        }
                    }
                }
            }
            public virtual Hand HandleSplit(Dealer dealer, BettingBehavior betting)
            {
                // create an additional hand, using one of the cards from this hand
                Hand secondHand = new Hand();

                secondHand.IsSplit = true;

                dealer.PlayerSplitHand = secondHand;

                Card secondHandFirstCard = PrepareForSplit();

                secondHand.AddCardShowing(secondHandFirstCard);

                // let the logic set the IsBust property as needed
                Card cardDealt = dealer.DealCard(this);

                dealer.Statistics.DiscardCard(cardDealt);

                // replace the second card for the primary hand
                cardDealt = dealer.DealCard(secondHand);
                dealer.Statistics.DiscardCard(cardDealt);

                // split on split is not allowed
                secondHand.IsSplittable = false;

                // set the default bet
                Bet            = betting.Bet;
                secondHand.Bet = betting.Bet;

                // now apply the hit logic
                // determine if the bet should be modified
                if (betting.DetermineDoubleDown(dealer.DealerHand, this, dealer.Statistics))
                {
                    IsDoubledDown = true;

                    // okay to double the bet
                    Bet = betting.Bet * 2;

                    // deal one card only
                    // let the logic set the IsBust property as needed
                    cardDealt = dealer.DealCard(this);
                    dealer.Statistics.DiscardCard(cardDealt);
                }
                else
                {
                    // we'll keep hitting till the sum is at least X
                    while ((SumCards < 16 &&
                            (dealer.Statistics.TensIndex > 4)) ||
                           (SumCards < 12))
                    {
                        // break from the loop if the proportion of >= 10 cards is too low
                        if (SumCards > 11 && dealer.Statistics.TensIndex < 2)
                        {
                            break;
                        }

                        // don't try if we have a run of small cards
                        if (_cards.Count > 4 && SumCards > 11)
                        {
                            break;
                        }

                        // let the logic set the IsBust property as needed
                        cardDealt = dealer.DealCard(this);
                        dealer.Statistics.DiscardCard(cardDealt);

                        if (IsBust)
                        {
                            break;
                        }
                    }
                }

                // determine if the bet should be modified for the second hand
                if (betting.DetermineDoubleDown(dealer.DealerHand, this, dealer.Statistics))
                {
                    secondHand.IsDoubledDown = true;

                    // okay to double the bet
                    secondHand.Bet = betting.Bet * 2;

                    // deal one card only
                    // let the logic set the IsBust property as needed
                    cardDealt = dealer.DealCard(secondHand);
                    dealer.Statistics.DiscardCard(cardDealt);
                }
                else
                {
                    // we'll keep hitting till the sum is at least X
                    while ((secondHand.SumCards < 15 && dealer.DealerHand.CardShowing.Face > 6) ||
                           (secondHand.SumCards < 12))
                    {
                        // break from the loop if the proportion of >= 10 cards is too low
                        if (secondHand.SumCards > 11 && dealer.Statistics.TensIndex < 3)
                        {
                            break;
                        }

                        // don't try if we have a run of small cards
                        if (secondHand.Cards.Count > 4 && secondHand.SumCards > 11)
                        {
                            break;
                        }

                        // let the logic set the IsBust property as needed
                        cardDealt = dealer.DealCard(secondHand);
                        dealer.Statistics.DiscardCard(cardDealt);

                        if (secondHand.IsBust)
                        {
                            break;
                        }
                    }
                }

                return(secondHand);
            }