Option BJPlayer::getOption(const BJHand & hand, int upCard, bool doubleDown,
                        bool split, bool surrender) {
    PlayerHand & testHand = playerHands[findHand(hand)];
    double value = testHand.valueStand[false][upCard - 1];
    Option option = BJ_STAND;
    if (value < testHand.valueHit[false][upCard - 1]) {
        value = testHand.valueHit[false][upCard - 1];
        option = BJ_HIT;
    }
    if (doubleDown) {
        if (value < testHand.valueDoubleDown[false][upCard - 1]) {
            value = testHand.valueDoubleDown[false][upCard - 1];
            option = BJ_DOUBLE_DOWN;
        }
    }
    if (split) {
        int pairCard = 1;
        while (!hand.getCards(pairCard)) {
            pairCard++;
        }
        if (value < valueSplit[pairCard - 1][upCard - 1]) {
            value = valueSplit[pairCard - 1][upCard - 1];
            option = BJ_SPLIT;
        }
    }
    if (surrender) {
        if (value < -0.5) {
            value = -0.5;
            option = BJ_SURRENDER;
        }
    }
    return option;
}
void BJPlayer::correctStandBlackjack() {
    if (shoe.getTotalCards(Card::Ace) && shoe.getTotalCards(Card::Ten)) {
        currentHand.reset();

        currentHand.deal(Card::Ace); 
		currentHand.deal(Card::Ten);

        PlayerHand & hand = playerHands[findHand(currentHand)];
        shoe.reset(currentHand);

        if (shoe.getCards(Card::Ace)) {
            shoe.deal(Card::Ace);
            hand.valueStand[false][0] = (double)3/2
                    *((double)1 - shoe.getProbability(10));
            shoe.undeal(Card::Ace);
        }
        for (int upCard = Card::Two; upCard < Card::Ten; ++upCard) {
            if (shoe.getCards(upCard)) {
                hand.valueStand[false][upCard - 1] = (double)3/2;
            }
        }
        if (shoe.getCards(Card::Ten)) {
            shoe.deal(Card::Ten);
            hand.valueStand[false][9] = (double)3/2
                    *((double)1 - shoe.getProbability(1));
            shoe.undeal(Card::Ten);
        }
    }
}
void ArmContourFinder::update() {

	//To run every frame
	for (int i = 0; i < polylines.size(); ++i)
	{
		handFound[getLabel(i)] = findHand(i);
	}
	updateHands();
}
void BJPlayer::linkHands() {
    for (int i = 0; i < numHands; i++) {
        PlayerHand & hand = playerHands[i];
        for (int card = 1; card <= 10; card++) {
            if (!hand.hitHand[card - 1]
				&& hand.cards[card-1] < shoe.getCards(card)) {
                currentHand.reset(hand.cards);
                currentHand.deal(card);
                if (record(currentHand)) {
                    hand.hitHand[card - 1] = findHand(currentHand);
                }
            }
        }
    }
}
void BJPlayer::computeSplit(BJRules & rules, BJStrategy & strategy) {
    for (int pairCard = 1; pairCard <= 10; pairCard++) {
        if (resplit[pairCard - 1] >= 2 && shoe.getTotalCards(pairCard) >= 2) {

// Compute maximum number of split hands.

            int maxSplitHands = resplit[pairCard - 1];
            if (shoe.getTotalCards(pairCard) < maxSplitHands) {
                maxSplitHands = shoe.getTotalCards(pairCard);
            }

// Compute probability of splitting exactly 2, 3, and 4 hands.

            double pSplit[5][10];
            shoe.reset();
            shoe.deal(pairCard); 
			shoe.deal(pairCard);
            for (int upCard = Card::Ace; upCard <= Card::Ten; ++upCard) {
                if (shoe.getCards(upCard)) {
                    shoe.deal(upCard);
                    double n = shoe.getCards(),
                        p = shoe.getCards(pairCard);
                    if (maxSplitHands > 2) {
                        pSplit[2][upCard - 1] = (n - p)/n*(n - 1 - p)/(n - 1);
                        if (maxSplitHands > 3) {
                            pSplit[3][upCard - 1] = pSplit[2][upCard - 1]*2
                                    *p/(n - 2)*(n - 2 - p)/(n - 3);
                            pSplit[4][upCard - 1] = (double)1
                                    - pSplit[2][upCard - 1]
                                    - pSplit[3][upCard - 1];
                        } else {
                            pSplit[3][upCard - 1] = (double)1
                                    - pSplit[2][upCard - 1];
                            pSplit[4][upCard - 1] = 0;
                        }
                    } else {
                        pSplit[2][upCard - 1] = 1;
                        pSplit[3][upCard - 1] = pSplit[4][upCard - 1] = 0;
                    }

// We only lose our initial wager if the dealer has blackjack.

                    if (upCard == 1) {
                        valueSplit[pairCard - 1][upCard - 1] = shoe.
                                getProbability(10);
                    } else if (upCard == 10) {
                        valueSplit[pairCard - 1][upCard - 1] = shoe.
                                getProbability(1);
                    } else {
                        valueSplit[pairCard - 1][upCard - 1] = 0;
                    }
                    valueSplit[pairCard - 1][upCard - 1] *=
                            pSplit[2][upCard - 1] + pSplit[3][upCard - 1]*2
                                                  + pSplit[4][upCard - 1]*3;
                    shoe.undeal(upCard);
                }
            }

// For each possible number of split hands, re-compute expected values with the
// appropriate number of pair cards removed.

            for (int splitHands = 2; splitHands <= maxSplitHands;
                    splitHands++) {
                linkHandCounts(true, pairCard, splitHands);
                computeStand(true, pairCard, splitHands);
                if (pairCard != 1) {
                    computeDoubleDown(true, pairCard, splitHands);
                    computeHit(rules, strategy, true, pairCard, splitHands);
                }
                currentHand.reset();
                currentHand.deal(pairCard);

// Remove split pair cards for weighting expected values of possible hands.

                int i = 0, j;
                shoe.reset();
                for (int split = 0; split < splitHands; ++split) {
                    shoe.deal(pairCard);
                    i = playerHands[i].hitHand[pairCard - 1];
                }
                for (int upCard = Card::Ace; upCard <= Card::Ten; ++upCard) {
                    if (shoe.getCards(upCard)) {
                        shoe.deal(upCard);
                        double valueUpCard = 0,
                            pNoPair = (double)1 - shoe.
                                    getProbability(pairCard);

// Evaluate each possible two-card split hand.

                        for (int card = 1; card <= 10; card++) {
                            if (shoe.getCards(card)) {
                                currentHand.deal(card);
                                PlayerHand & hand = playerHands[
                                        playerHands[i].hitHand[card - 1]];
                                double value, testValue;
                                if (pairCard == 1) {
                                    value = hand.valueStand[true][upCard - 1];
                                } else {
                                    bool doubleDown = rules.
                                            getDoubleAfterSplit(currentHand);
                                    switch (strategy.getOption(currentHand,
                                            upCard, doubleDown, false, false)){

// Again, use the playing option that maximizes expected value for the
// non-split hand.

                                    case BJ_MAX_VALUE :
                                        j = findHand(currentHand);
                                        testValue = playerHands[j].
                                                valueStand[false][upCard - 1];
                                        value = hand.
                                                valueStand[true][upCard - 1];
                                        if (testValue < playerHands[j].
                                                valueHit[false][upCard - 1]) {
                                            testValue = playerHands[j].
                                                   valueHit[false][upCard - 1];
                                            value = hand.
                                                    valueHit[true][upCard - 1];
                                        }
                                        if (doubleDown) {
                                            if (testValue < playerHands[j].
                                                valueDoubleDown[false]
                                                        [upCard - 1]) {
                                                value = hand.
                                                    valueDoubleDown[true]
                                                        [upCard - 1];
                                            }
                                        }
                                        break;
                                    case BJ_STAND :
                                        value = hand.
                                                valueStand[true][upCard - 1];
                                        break;
                                    case BJ_HIT :
                                        value = hand.
                                                valueHit[true][upCard - 1];
                                        break;
                                    case BJ_DOUBLE_DOWN :
                                        value = hand.
                                                valueDoubleDown[true]
                                                    [upCard - 1];
                                        break;
                                    default :
                                        value = 0;
                                    }
                                }

// If further resplitting is allowed, condition on NOT drawing an additional
// pair.

                                double p = shoe.getProbability(card);
                                if (splitHands < maxSplitHands) {
                                    p /= pNoPair;
                                }
                                if (card != pairCard
                                        || splitHands == maxSplitHands) {
                                    valueUpCard += value*p;
                                }
                                currentHand.undeal(card);
                            }
                        }
                        valueSplit[pairCard - 1][upCard - 1] += valueUpCard
                                *pSplit[splitHands][upCard - 1]*splitHands;
                        shoe.undeal(upCard);
                    }
                }
            }
        }
    }
}
void BJPlayer::computeHitCount(int count, bool soft, BJRules & rules,
                               BJStrategy & strategy, bool split, int pairCard,
                               int splitHands) {
    for (int i = playerHandCount[count][soft]; i;
            i = playerHands[i].nextHand) {
        PlayerHand & hand = playerHands[i];
        currentHand.reset(hand.cards);
        shoe.reset(currentHand);
        for (int hands = 1; hands < splitHands; ++hands) {
            currentHand.undeal(pairCard);
        }
        for (int upCard = Card::Ace; upCard <= Card::Ten; ++upCard) {
            if (shoe.getCards(upCard)) {
                shoe.deal(upCard);
                hand.valueHit[split][upCard - 1] = 0;
                for (int card = 1; card <= 10; card++) {
                    if (shoe.getCards(card)) {
                        currentHand.deal(card);
                        int j = hand.hitHand[card - 1];
                        double value, testValue;
                        if (currentHand.getCount() <= 21) {
                            PlayerHand & hitHand = playerHands[j];
                            bool doubleDown;
                            if (split) {
                                doubleDown = rules.
                                        getDoubleAfterSplit(currentHand);
                            } else {
                                doubleDown = rules.getDoubleDown(currentHand);
                            }
                            switch (strategy.getOption(currentHand, upCard,
                                    doubleDown, false, false)) {

// To be consistent with a "fixed" playing strategy, use the option maximizing
// expected value for the non-split hand.

                            case BJ_MAX_VALUE :
                                j = findHand(currentHand);
                                testValue = playerHands[j].
                                        valueStand[false][upCard - 1];
                                value = hitHand.valueStand[split][upCard - 1];
                                if (testValue < playerHands[j].
                                        valueHit[false][upCard - 1]) {
                                    testValue = playerHands[j].
                                            valueHit[false][upCard - 1];
                                    value = hitHand.
                                            valueHit[split][upCard - 1];
                                }
                                if (doubleDown) {
                                    if (testValue < playerHands[j].
                                          valueDoubleDown[false][upCard - 1]) {
                                        value = hitHand.
                                            valueDoubleDown[split][upCard - 1];
                                    }
                                }
                                break;
                            case BJ_STAND :
                                value = hitHand.valueStand[split][upCard - 1];
                                break;
                            case BJ_HIT :
                                value = hitHand.valueHit[split][upCard - 1];
                                break;
                            case BJ_DOUBLE_DOWN :
                                value = hitHand.
                                        valueDoubleDown[split][upCard - 1];
                                break;
                            default :
                                value = 0;
                            }
                        } else {
                            value = -1;
                        }
                        currentHand.undeal(card);
                        hand.valueHit[split][upCard - 1] += value
                                *shoe.getProbability(card);
                    }
                }
                shoe.undeal(upCard);
            }
        }
    }
}
double BJPlayer::getValueDoubleDown(const BJHand & hand, int upCard) const {
    return playerHands[findHand(hand)].valueDoubleDown[false][upCard - 1];
}
void BJPlayer::computeOverall(BJRules & rules, BJStrategy & strategy) {
    overallValue = 0;
    bool surrender = rules.getLateSurrender();
    shoe.reset();
    for (int upCard = Card::Ace; upCard <= Card::Ten; ++upCard) {
        overallValues[upCard - 1] = 0;
        if (shoe.getCards(upCard)) {
            shoe.deal(upCard);
            for (int card1 = Card::Ace; card1 <= Card::Ten; ++card1) {
                for (int card2 = Card::Ace; card2 <= Card::Ten; ++card2) {
                    if (shoe.getCards(card1) && shoe.getCards(card2) &&
						(card1 != card2 || shoe.getCards(card1) >= 2)) {
                        currentHand.reset();
                        double p = shoe.getProbability(card1);
                        shoe.deal(card1); currentHand.deal(card1);
                        p *= shoe.getProbability(card2);
                        shoe.deal(card2); currentHand.deal(card2);
                        PlayerHand & hand = playerHands[findHand(currentHand)];
                        double value;
                        BJHand testHand(hand.cards);
                        bool doubleDown = rules.getDoubleDown(testHand),
                            split = (card1 == card2
                                    && resplit[card1 - 1] >= 2);
                        double valueSurrender;
                        switch (strategy.getOption(testHand, upCard,
                                doubleDown, split, surrender)) {
                        case BJ_MAX_VALUE :
                            value = hand.valueStand[false][upCard - 1];
                            if (value < hand.valueHit[false][upCard - 1]) {
                                value = hand.valueHit[false][upCard - 1];
                            }
                            if (doubleDown) {
                                if (value < hand.
                                        valueDoubleDown[false][upCard - 1]) {
                                    value = hand.
                                        valueDoubleDown[false][upCard - 1];
                                }
                            }
                            if (split) {
                                if (value < valueSplit[card1 - 1]
                                        [upCard - 1]) {
                                    value = valueSplit[card1 - 1][upCard - 1];
                                }
                            }
                            if (surrender) {
                                valueSurrender = computeSurrender(upCard);
                                if (value < valueSurrender) {
                                    value = valueSurrender;
                                }
                            }
                            break;
                        case BJ_STAND :
                            value = hand.valueStand[false][upCard - 1];
                            break;
                        case BJ_HIT :
                            value = hand.valueHit[false][upCard - 1];
                            break;
                        case BJ_DOUBLE_DOWN :
                            value = hand.valueDoubleDown[false][upCard - 1];
                            break;
                        case BJ_SPLIT :
                            value = valueSplit[card1 - 1][upCard - 1];
                            break;
                        case BJ_SURRENDER :
                            value = computeSurrender(upCard);
                            break;
                        }
                        overallValues[upCard - 1] += value*p;
                        shoe.undeal(card2);
                        shoe.undeal(card1);
                    }
                }
            }
            shoe.undeal(upCard);
            overallValue += overallValues[upCard - 1]
                    *shoe.getProbability(upCard);
        }
    }
}