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); } } }