File indexing completed on 2025-02-23 05:14:54
0001 // bjgc_playertableutil.cpp -*-C++-*- 0002 #include <bjgc_playertableutil.h> 0003 0004 #include <bjgb_dealercount.h> 0005 #include <bjgb_types.h> // 'Double' 0006 0007 #include <cassert> 0008 #include <iostream> // TBD TEMPORARY 0009 0010 // The player's hand is all about expected value, not just Probability. 0011 // 0012 // The question is: For a specified set of rules, shoe, and dealer up card, 0013 // what is the expected value of any given hand (assuming you play perfectly) 0014 // and what is the optimal strategy. 0015 // 0016 // The structure of the Player's table is the same as that of the Dealer's 0017 // table except that the numbers in the columns represent expected values for 0018 // each dealer up card assuming a strategy. 0019 // 0020 // We need a table for stand (pstab), hit at least once (phtab), and hit once 0021 // only (p1tab), which we will use when we double the bet. 0022 // 0023 // In the end, we will need a table that has the best way to play. 0024 // 0025 // Split applies only to certain even counts: S2, 4-20. We will get one card 0026 // to a split Ace unless we there is rule allowing multiple cards. In the end, 0027 // we will have to incorporate the probability of getting two of the same card: 0028 // P(1) * P(1), P(2) * P(2), ... P(10) * P(10). In the case of Aces, we will 0029 // typically use the 1-hit table without considering splits. In all other 0030 // cases, we'll need a table that considers the possibility of getting a pair 0031 // and doubling the resulting expected value of that single card. As a result, 0032 // the dealer table holds soft counts at the beginning and the has notion of 0033 // single cards, even for non-TEN cards, so that we can use the hit/one-hit 0034 // depending on whether it is a pair of Aces or otherwise. 0035 // 0036 // Surrender is defined precisely in terms of whether the expected value of 0037 // -0.5 is better or worse than playing normally. 0038 0039 namespace bjgc { 0040 0041 // ---------------------- 0042 // struct PlayerTableUtil 0043 // ---------------------- 0044 0045 // CLASS METHODS 0046 void PlayerTableUtil::copyPlayerRow(PlayerTable *pta, int hia, const PlayerTable& ptb, int hib) 0047 { 0048 assert(pta); 0049 assert(0 <= hia); 0050 assert(hia < bjgb::State::k_NUM_STATES); 0051 assert(0 <= hib); 0052 assert(hib < bjgb::State::k_NUM_STATES); 0053 0054 for (int i = 1; i <= 10; ++i) { 0055 pta->exp(hia, i) = ptb.exp(hib, i); 0056 } 0057 } 0058 0059 bjgb::Types::Double PlayerTableUtil::eDouble(const PlayerTable& p1t, int uc, int hv, bool sf) 0060 { 0061 std::cout << "##### eDouble: " << std::flush; 0062 std::cout << " uc = " << uc; 0063 std::cout << " hv = " << hv; 0064 std::cout << " sf = " << sf; 0065 std::cout << std::endl; 0066 0067 assert(1 <= uc); 0068 assert(uc <= 10); 0069 assert(2 <= hv); 0070 assert(hv <= 21); 0071 assert(hv >= 4 || sf); 0072 assert(hv <= 11 || !sf); 0073 0074 // The expected value is simply twice the corresponding value in the 0075 // hard/soft hand. 0076 0077 int hi = sf ? bjgb::State::soft(hv) : bjgb::State::hard(hv); // hand index 0078 0079 bjgb::Types::Double temp = p1t.exp(hi, uc); 0080 assert(bjgb::Types::isValid(temp)); 0081 0082 bjgb::Types::Double expectedValue = 2 * temp; 0083 assert(bjgb::Types::isValid(expectedValue)); 0084 0085 return expectedValue; 0086 } 0087 0088 bjgb::Types::Double PlayerTableUtil::eHit1(const PlayerTable& pst, int uc, int hv, bool sf, const bjgb::Shoe& shoe) 0089 { 0090 // Implementation note: Column values are deliberately summed in a 0091 // canonical order for numerical consistency: A, 2, ..., 9, T. 0092 0093 assert(1 <= uc); 0094 assert(uc <= 10); 0095 assert(1 <= hv); 0096 assert(hv <= 21); 0097 assert(hv > 1 || sf); 0098 assert(hv <= 11 || !sf); 0099 0100 bjgb::Types::Double sum = 0; // Accumulated expected value for each 0101 // possible hand. 0102 0103 for (int cd = 1; cd <= 10; ++cd) { // for each possible card dealt, 'cd' 0104 int soft = 1 == cd || sf; // if we get an A it is automatically soft 0105 int value = hv + cd; // hit hand with 'cd' 0106 0107 if (soft && value + 10 <= 21) { 0108 value += 10; // make soft count a hard count 0109 } 0110 0111 // Hand 'value' is hard from here on. 0112 0113 if (value <= 16) { 0114 assert(bjgb::Types::isValid(pst.exp(bjgb::State::hard(16), uc))); 0115 0116 sum += shoe.prob(cd) * pst.exp(bjgb::State::hard(16), uc); 0117 } else if (value >= 22) { 0118 assert(-1 == pst.exp(bjgb::State::e_HOV, uc)); 0119 0120 sum += shoe.prob(cd) * pst.exp(bjgb::State::e_HOV, uc); 0121 } else { 0122 assert(17 <= value); 0123 assert(value <= 21); 0124 assert(bjgb::Types::isValid(pst.exp(bjgb::State::hard(value), uc))); 0125 0126 sum += shoe.prob(cd) * pst.exp(bjgb::State::hard(value), uc); 0127 } 0128 } 0129 0130 return sum; 0131 } 0132 0133 bjgb::Types::Double 0134 PlayerTableUtil::eHitN(const PlayerTable& pht, const PlayerTable& pst, int uc, int hv, bool sf, const bjgb::Shoe& shoe) 0135 { 0136 // Implementation note: 'eHitN' is similar to 'eHit1' except that, for 0137 // each card, we choose to hit again or stand as appropriate. Since this 0138 // table depends on itself, we need to do things in order, which means hard 0139 // counts down to 11 first, then soft counts from 11 to 1, followed by hard 0140 // counts from 10 to 2. If we access an expected value that is not in the 0141 // valid range of -2 to 2, it is invalid and should be asserted as such. 0142 // Note that column values are deliberately summed in a canonical order for 0143 // numerical consistency: A, 2, ..., 9, T. 0144 0145 assert(1 <= uc); 0146 assert(uc <= 10); 0147 assert(1 <= hv); 0148 assert(hv <= 21); 0149 assert(hv > 1 || sf); 0150 assert(hv <= 11 || !sf); 0151 0152 bjgb::Types::Double sum = 0; // Accumulated expected value for each 0153 // possible hand. 0154 0155 for (int cd = 1; cd <= 10; ++cd) { // for each possible card dealt, 'cd' 0156 int minValue = hv + cd; // lowest possible cards value 0157 0158 bjgb::Types::Double expVal = -9999.99; 0159 bjgb::Types::Double shi = -999; 0160 bjgb::Types::Double hhi = -999; 0161 bjgb::Types::Double maxValue = -999999.9999; 0162 0163 bool stillSoftFlag; // unset! 0164 0165 // If minimum value is over, the expected value is exactly that of 0166 // standing with an OVER. 0167 0168 if (minValue > 21) { 0169 expVal = pst.exp(bjgb::State::e_HOV, uc); 0170 assert(-1.0 == expVal); 0171 } else { 0172 stillSoftFlag = (1 == cd || sf) && minValue <= 11; 0173 maxValue = minValue + stillSoftFlag * 10; 0174 0175 shi = bjgb::State::hard(maxValue); 0176 hhi = (stillSoftFlag ? bjgb::State::soft : bjgb::State::hard)(minValue); 0177 bjgb::Types::Double stand = pst.exp(shi, uc); 0178 assert(bjgb::Types::isValid(stand)); 0179 0180 bjgb::Types::Double hitIt = pht.exp(hhi, uc); 0181 assert(bjgb::Types::isValid(hitIt)); 0182 0183 expVal = std::max<bjgb::Types::Double>(stand, hitIt); 0184 assert(bjgb::Types::isValid(expVal)); 0185 } 0186 0187 sum += shoe.prob(cd) * expVal; 0188 assert(bjgb::Types::isValid(sum)); 0189 0190 // what follows is just double checking :) 0191 0192 if (minValue > 21) { 0193 assert(-1.0 == expVal); 0194 } else if (minValue <= 11 && stillSoftFlag) { 0195 assert(maxValue == minValue + 10); 0196 assert(maxValue <= 21); 0197 assert(bjgb::State::hard(maxValue) == shi); 0198 assert(bjgb::State::soft(minValue) == hhi); 0199 } else { // they are both hard counts and not over 21. 0200 assert(maxValue == minValue); 0201 assert(maxValue == minValue); 0202 assert(maxValue <= 21); 0203 assert(bjgb::State::hard(maxValue) == shi); 0204 assert(bjgb::State::hard(minValue) == hhi); 0205 } 0206 } 0207 0208 return sum; 0209 } 0210 0211 bjgb::Types::Double PlayerTableUtil::eSplit(const PlayerTable& pdt, 0212 const PlayerTable& pht, 0213 const PlayerTable& p1t, 0214 const PlayerTable& pst, 0215 int uc, 0216 int hv, 0217 int n, 0218 const bjgb::Shoe& shoe, 0219 const bjgb::Rules& rules) 0220 // TBD: rules: can you double after a split Ace? 0221 // TBD: rules: can you re-split after a split Ace? 0222 { 0223 std::cout << "[eSplit: n = " << n << "]" << std::flush; 0224 assert(1 <= uc); 0225 assert(uc <= 10); 0226 assert(2 <= hv); 0227 assert(hv <= 20); 0228 assert(0 == hv % 2); // only even hands can be split 0229 assert(n >= 0); 0230 0231 // The value to be returned is 2 * the expected value of every drawn card 0232 // other than the split card. Suppose the split card is 8: the expected 0233 // value of splitting two eights is twice the max of hitting or doubling 0234 // A..7, 9, and 10. But, for an eight, it is recursive, and there is 0235 // P(8) * the expected value of splitting again with decremented 'n': 0236 // 0237 // Split(8s, 10, 3) = 2 * shoe.prob( 1) * maxDHS(soft( 9)) // maybe can't 0238 // // double? 0239 // + 2 * shoe.prob( 2) * maxDHS(hard(10)) 0240 // + 2 * shoe.prob( 3) * maxDHS(hard(11)) 0241 // + ... 0242 // + 2 * shoe.prob( 7) * maxDHS(hard(15)) 0243 // + 2 * shoe.prob( 8) * Split(8s, 10, 2) 0244 // + 2 * shoe.prob( 9) * maxDHS(hard(17)) 0245 // + 2 * shoe.prob(10) * maxDHS(hard(18)) 0246 // 0247 // Split(As, 6, 1) = 2 * shoe.prob( 1) * maxDHS(soft(2)) // maybe can't 0248 // // double? 0249 // + 2 * shoe.prob( 2) * maxDHS(soft(3)) 0250 // + 2 * shoe.prob( 3) * maxDHS(hard(11)) 0251 // + ... 0252 // + 2 * shoe.prob( 7) * maxDHS(hard(15)) 0253 // + 2 * shoe.prob( 9) * maxDHS(hard(17)) 0254 // + 2 * shoe.prob(10) * maxDHS(hard(18)) 0255 // 0256 0257 if (0 == n) { // Splitting is not an option. 0258 std::cout << "[n = 0]" << std::flush; 0259 // We have recursed, and splitting is no longer an option. We need to 0260 // return the best value between hitting or standing, and possibly 0261 // doubling. 0262 0263 int hi = 2 == hv ? bjgb::State::soft(2) : bjgb::State::hard(hv); 0264 int ui = uc; // It would be nice if both 0265 // 'hi' and 'ui' were type-safe. 0266 0267 // TBD: the block below should be factored out as a separate function. 0268 0269 bjgb::Types::Double hVal = pht.exp(hi, ui); 0270 bjgb::Types::Double sVal = pst.exp(hi, ui); 0271 0272 bjgb::Types::Double expVal = std::max<bjgb::Types::Double>(hVal, sVal); 0273 0274 if (rules.playerMayDoubleOnTheseTwoCards(hv, 2 == hv)) { 0275 std::cout << "[can double]" << std::flush; 0276 bjgb::Types::Double dVal = pdt.exp(hi, ui); 0277 expVal = std::max<bjgb::Types::Double>(expVal, dVal); 0278 } 0279 0280 std::cout << "[***EARLY RETURN***]" << std::flush; 0281 0282 return expVal; // there expected value isn't doubled here 0283 } 0284 0285 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0286 // If we get to here, splitting is a viable option and the bet will be 0287 // doubled; we'll make the assumption that splitting is to be repeated 0288 // while possible. 0289 0290 bjgb::Types::Double expectedValue = 0.0; // Accumulate expected value over 0291 // 10 cards. 0292 int ui = uc; 0293 const int playerCard = hv / 2; 0294 0295 // Address splitting Aces as a special case. Note that re-splitting Aces 0296 // is handled from outside the function by passing num-splits as 1. There 0297 // is therefore no need to query 'playerMayResplitAces'. 0298 0299 if (1 == playerCard && rules.playerGetsOneCardOnlyToSplitAce()) { 0300 std::cout << "[card=A]" << std::flush; 0301 bool resplitAces = n >= 2; // set by checking rules from outside 0302 std::cout << "[A]" << std::flush; 0303 0304 if (resplitAces) { // Note that we do 'prob(1)' first! always. 0305 std::cout << "[C]" << std::flush; 0306 // TBD look into removing possibility of 'n == 0' 0307 expectedValue += shoe.prob(1) * eSplit(pdt, pht, p1t, pst, uc, hv, n - 1, shoe, rules); 0308 } 0309 0310 for (int i = 2 - !resplitAces; i <= 10; ++i) { 0311 std::cout << "[B]" << std::flush; 0312 int softHand = 1 + i; 0313 expectedValue += shoe.prob(i) * pst.exp(bjgb::State::soft(softHand), ui); 0314 } 0315 } else { // treat Aces just like any other card (split based on 'n') 0316 std::cout << "[C]" << std::flush; 0317 for (int i = 1; i <= 10; ++i) { // for each possible drawn card 0318 std::cout << "[E]" << std::flush; 0319 if (playerCard == i && n >= 2) { // this is where we recurse 0320 std::cout << "[F]" << std::flush; 0321 // 0 would mean we recursed internally 0322 // 1 would mean no further splits are allowed 0323 // TBD consider removing the duplication of '0 == n' 0324 0325 expectedValue += shoe.prob(playerCard) * eSplit(pdt, pht, p1t, pst, uc, hv, n - 1, shoe, rules); 0326 } else { // no more splitting 0327 std::cout << "[G]" << std::flush; 0328 bool sf = 1 == i || 1 == playerCard; 0329 int hand = playerCard + i; 0330 int hi = sf ? bjgb::State::soft(hand) : bjgb::State::hard(hand); 0331 0332 bjgb::Types::Double hVal = pht.exp(hi, ui); 0333 bjgb::Types::Double sVal = pst.exp(hi, ui); 0334 0335 bjgb::Types::Double expVal = std::max<bjgb::Types::Double>(hVal, sVal); 0336 0337 if (rules.playerMayDoubleOnTheseTwoCards(hv, 2 == hv)) { 0338 std::cout << "[H]" << std::flush; 0339 bjgb::Types::Double dVal = pdt.exp(hi, ui); 0340 expVal = std::max<bjgb::Types::Double>(expVal, dVal); 0341 } 0342 0343 expectedValue += shoe.prob(i) * expVal; 0344 std::cout << "\n[" << i << ": " << expectedValue << "]" << std::flush; 0345 } 0346 } 0347 } 0348 0349 std::cout << "[RETURN 2*EXP]" << std::flush; 0350 0351 return 2 * expectedValue; 0352 } 0353 0354 bjgb::Types::Double PlayerTableUtil::eStand(const DealerTable& t, int uc, int hv) 0355 { 0356 // Implementation note: Values are deliberately added in a canonical order 0357 // for numerical consistency: OVER first, then lower cards, then higher 0358 // cards. 0359 0360 assert(1 <= uc); 0361 assert(uc <= 10); 0362 assert(4 <= hv); 0363 assert(hv <= 21); 0364 0365 const int ci = hv < 17 ? -1 : hv - 17; // count index 0366 // e.g., if hv = 17, ci = 0; if hv = 21, ci = 4; bj = 5 0367 0368 bjgb::Types::Double sum = t.prob(bjgb::State::unus(uc), bjgb::DealerCount::e_COV); 0369 // you win if you stand and dealer busts 0370 0371 for (int i = 0; i < ci; ++i) { // counts that are lower than 'hv' 0372 sum += t.prob(bjgb::State::unus(uc), i); 0373 } 0374 0375 const int k_FINAL = bjgb::DealerCount::k_NUM_FINAL_COUNTS - 1; 0376 // Don't count OVER again. 0377 0378 for (int i = ci + 1; i < k_FINAL; ++i) { 0379 sum -= t.prob(bjgb::State::unus(uc), i); 0380 } 0381 0382 return sum; 0383 } 0384 0385 bjgb::Types::Double PlayerTableUtil::evalShoeImp(const bjgb::Shoe& shoe, 0386 const PlayerTable& pt, 0387 const PlayerTable& pat, 0388 const bjgb::Rules& rules) 0389 { 0390 // The idea is that we're going to calculate the probability of every 0391 // dealer card. Note that we need to pass in the adjusted player table 0392 // if we cannot lose double our bet, otherwise we need to pass in the 0393 // unadjusted table. 0394 0395 // We need to make a pass for surrender if available before we check for 0396 // blackjack. TBD 0397 0398 bjgb::Types::Double expectedValue = 0.0; 0399 0400 for (int i = 1; i <= 10; ++i) { // for each dealer card 0401 bjgb::Types::Double pi = shoe.prob(i); 0402 bjgb::Types::Double pdbj = 1 == i ? shoe.prob(10) : 10 == i ? shoe.prob(1) : 0.0; 0403 0404 for (int j = 1; j <= 10; ++j) { // for each dealer card 0405 bjgb::Types::Double pj = shoe.prob(j); 0406 bjgb::Types::Double pij = pi * pj; 0407 0408 for (int k = 1; k <= 10; ++k) { // for each dealer card 0409 bjgb::Types::Double pk = shoe.prob(k); 0410 bjgb::Types::Double pijk = pij * pk; 0411 0412 bool softFlag = j == 1 || k == 1; 0413 bool splitFlag = j == k; 0414 int v = j + k; 0415 0416 const PlayerTable& pTab = rules.playerCanLoseDouble() ? pt : pat; 0417 0418 bjgb::Types::Double best = pTab.exp(softFlag ? bjgb::State::soft(v) : bjgb::State::hard(v), i); 0419 0420 if (splitFlag) { 0421 best = std::max<bjgb::Types::Double>(best, pTab.exp(bjgb::State::pair(j), i)); 0422 } 0423 0424 // We need to handle BJ separately because of payouts and 0425 // such. We might build them directly into the expected 0426 // values for the tables, but let's just calculate them here 0427 // separately anyway: 0428 // 0429 // if player has blackjack (assume player always stands) 0430 // if dealer has blackjack 0431 // eVal = 0 0432 // else 0433 // eVal = rules.playerBlackjackPayout(); 0434 // else 0435 // if dealer has blackjack 0436 // eVal = -1.0 0437 // else 0438 // eVal = best (based on appropriate player table) 0439 0440 bool bjFlag = 11 == v && softFlag; 0441 0442 bjgb::Types::Double eVal = -99e99; // "unset" value 0443 0444 if (bjFlag) { 0445 eVal = pdbj * 0.0 + (1.0 - pdbj) * rules.playerBlackjackPayout(); 0446 } else { 0447 eVal = pdbj * -1.0 + (1.0 - pdbj) * best; 0448 } 0449 0450 if (rules.playerMaySurrender()) { 0451 // If surrender is possible, we cannot do worse than -0.5. 0452 // So if at the end of the exercise we would have a value 0453 // for this combination of less than -0.5, we simply 0454 // surrender and max out at -0.5. 0455 0456 eVal = std::max<bjgb::Types::Double>(eVal, -0.5); 0457 } 0458 0459 expectedValue += pijk * eVal; 0460 0461 } // end for k 0462 } // end for j 0463 } // end for i 0464 0465 return expectedValue; 0466 } 0467 0468 bool PlayerTableUtil::isSamePlayerRow(const PlayerTable& pta, int hia, const PlayerTable& ptb, int hib) 0469 { 0470 assert(0 <= hia); 0471 assert(hia < bjgb::State::k_NUM_STATES); 0472 assert(0 <= hib); 0473 assert(hib < bjgb::State::k_NUM_STATES); 0474 0475 for (int i = 1; i <= 10; ++i) { 0476 if (pta.exp(hia, i) != ptb.exp(hib, i)) { 0477 std::cout << "[FALSE: i = " << i << "]" << std::flush; 0478 0479 return false; // RETURN 0480 } 0481 } 0482 0483 return true; 0484 } 0485 0486 bjgb::Types::Double PlayerTableUtil::mx(int hi, int cd, const PlayerTable& t, const PlayerTable& q) 0487 { 0488 assert(0 <= hi); 0489 assert(hi < bjgb::State::k_NUM_STATES); 0490 assert(1 <= cd); 0491 assert(cd <= 10); 0492 0493 assert((bjgb::State::e_HOV == hi) != bjgb::Types::isValid(t.exp(hi, cd))); 0494 // either it is OVER in which case the entry is invalid or vice versa 0495 assert(bjgb::Types::isValid(q.exp(hi, cd))); 0496 0497 return bjgb::State::e_HOV == hi ? q.exp(hi, cd) : std::max<bjgb::Types::Double>(t.exp(hi, cd), q.exp(hi, cd)); 0498 } 0499 0500 bjgb::Types::Double 0501 PlayerTableUtil::mx3(int hi, int cd, const PlayerTable& x, const PlayerTable& y, const PlayerTable& z) 0502 { 0503 assert(0 <= hi); 0504 assert(hi < bjgb::State::k_NUM_STATES); 0505 assert(1 <= cd); 0506 assert(cd <= 10); 0507 assert(bjgb::Types::isValid(x.exp(hi, cd))); 0508 assert(bjgb::Types::isValid(y.exp(hi, cd))); 0509 assert(bjgb::Types::isValid(z.exp(hi, cd))); 0510 0511 const bjgb::Types::Double temp = std::max<bjgb::Types::Double>(x.exp(hi, cd), y.exp(hi, cd)); 0512 0513 return std::max<bjgb::Types::Double>(temp, z.exp(hi, cd)); 0514 } 0515 0516 void PlayerTableUtil::populatePlayerTable( 0517 PlayerTable *pt, const PlayerTable& pxt, const PlayerTable& pht, const PlayerTable& pst, const bjgb::Rules& rules) 0518 { 0519 // TBD this doc is not clear 0520 // The player table assumes that these are the first two cards (TBD 0521 // meaning what??). Copy the maximum from the Splits, Hits, and Stands 0522 // tables. Then transfer the split values. This table alone is sufficient 0523 // to determine the odds of the game but we will still need separate 0524 // functions for strategy. 0525 // 0526 // Note that if the dealer peeks for BJ, we need to separate out the case 0527 // where the dealer gets blackjack and the adjusted shoe where he or she 0528 // doesn't. 0529 0530 assert(pt); 0531 0532 // Just copy the split values. 0533 0534 for (int i = 1; i <= 10; ++i) { 0535 copyPlayerRow(pt, bjgb::State::pair(i), pxt, bjgb::State::pair(i)); 0536 } 0537 0538 // hard counts 0539 0540 for (int i = 4; i <= 20; ++i) { 0541 copyPlayerRow(pt, bjgb::State::hard(i), pst, bjgb::State::hard(i)); 0542 // copy the hard stand values 0543 0544 for (int j = 1; j <= 10; ++j) { 0545 pt->exp(bjgb::State::hard(i), j) = 0546 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::hard(i), j), pht.exp(bjgb::State::hard(i), j)); 0547 0548 if (rules.playerMayDoubleOnTheseTwoCards(i, false)) { 0549 std::cout << "[D: HARD i=" << i << ", j=" << j << "]\n"; 0550 pt->exp(bjgb::State::hard(i), j) = 0551 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::hard(i), j), pxt.exp(bjgb::State::hard(i), j)); 0552 } 0553 } 0554 } 0555 0556 // soft counts 0557 0558 for (int i = 2; i <= 10; ++i) { 0559 copyPlayerRow(pt, bjgb::State::soft(i), pst, bjgb::State::soft(i)); 0560 // copy the soft stand values 0561 0562 for (int j = 1; j <= 10; ++j) { 0563 pt->exp(bjgb::State::soft(i), j) = 0564 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::soft(i), j), pht.exp(bjgb::State::soft(i), j)); 0565 0566 if (rules.playerMayDoubleOnTheseTwoCards(i, true)) { 0567 std::cout << "[D: SOFT i=" << i << ", j=" << j << "]\n"; 0568 pt->exp(bjgb::State::soft(i), j) = 0569 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::soft(i), j), pxt.exp(bjgb::State::soft(i), j)); 0570 } 0571 } 0572 } 0573 0574 // blackjack 0575 0576 copyPlayerRow(pt, bjgb::State::e_SBJ, pst, bjgb::State::e_SBJ); 0577 // copy the BJ values 0578 0579 for (int j = 1; j <= 10; ++j) { 0580 pt->exp(bjgb::State::e_SBJ, j) = 0581 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::e_SBJ, j), pht.exp(bjgb::State::e_SBJ, j)); 0582 0583 if (rules.playerMayDoubleOnTheseTwoCards(11, true)) { 0584 std::cout << "[D: BJ j=" << j << "]\n"; 0585 pt->exp(bjgb::State::e_SBJ, j) = 0586 std::max<bjgb::Types::Double>(pt->exp(bjgb::State::e_SBJ, j), pxt.exp(bjgb::State::e_SBJ, j)); 0587 } 0588 } 0589 } 0590 0591 void PlayerTableUtil::populateP1tab(PlayerTable *p1, 0592 const PlayerTable& ps, 0593 const bjgb::Shoe& shoe, 0594 const bjgb::Rules& rules) 0595 { 0596 assert(p1); 0597 0598 // 53 pair(10) 0599 // 52 pair( 9) 0600 // 51 pair( 8) 0601 // 50 pair( 7) 0602 // 49 pair( 6) 0603 // 48 pair( 5) 0604 // 47 pair( 4) 0605 // 46 pair( 3) 0606 // 45 pair( 2) 0607 // 44 pair( 1) 0608 #if 0 0609 for (int j = 10; j >= 1; --j) { 0610 for (int i = 1; i <= 10; ++i) { 0611 p->exp(bjgb::State::pair(j), i) = 0612 eStand(q, i, j == 1 ? 12 : 2 * j); 0613 0614 assert(p->exp(bjgb::State::pair(j), i) == 0615 j >= 6 ? p->exp(bjgb::State::hard(2 * j), i) 0616 : p->exp(bjgb::State::hard( 16), i)); 0617 } 0618 } 0619 #endif 0620 0621 for (int j = 10; j >= 1; --j) { // card value for each split hand 0622 for (int i = 1; i <= 10; ++i) { 0623 p1->exp(bjgb::State::pair(j), i) = eHit1(ps, i, 2 * j, j == 1, shoe); 0624 } 0625 } 0626 // Checked below. 0627 0628 // --------- 0629 // 43 e_HOV // cannot hit a hand that is OVer 0630 // N.A. 0631 0632 // 42 hard(21) 0633 // 41 hard(20) 0634 // 40 hard(19) 0635 // 39 hard(18) 0636 // 38 hard(17) 0637 // 37 hard(16) 0638 // 36 hard(15) 0639 // 35 hard(14) 0640 // 34 hard(13) 0641 // 33 hard(12) 0642 // 32 hard(11) 0643 // 31 hard(10) 0644 // 30 hard( 9) 0645 // 29 hard( 8) 0646 // 28 hard( 7) 0647 // 27 hard( 6) 0648 // 26 hard( 5) 0649 // 25 hard( 4) 0650 // 24 hard( 3) // this has to be a single 3 after a split 0651 // 23 hard( 2) // this has to be a single 2 after a split 0652 0653 for (int j = 21; j >= 2; --j) { 0654 for (int i = 1; i <= 10; ++i) { 0655 p1->exp(bjgb::State::hard(j), i) = eHit1(ps, i, j, false, shoe); 0656 } 0657 } 0658 0659 // -------- 0660 // 22 unus(10) 0661 // 21 unus( 9) 0662 // 20 unus( 8) 0663 // 19 unus( 7) 0664 // 18 unus( 6) 0665 // 17 unus( 5) 0666 // 16 unus( 4) 0667 // 15 unus( 3) 0668 // 14 unus( 2) 0669 // 13 unus( 1) // this is the first card of two and it is an Ace. 0670 0671 for (int j = 10; j >= 1; --j) { 0672 for (int i = 1; i <= 10; ++i) { 0673 p1->exp(bjgb::State::unus(j), i) = eHit1(ps, i, j, 1 == j, shoe); 0674 } 0675 0676 std::cout << "[Z j = " << j << "]" << std::flush; 0677 0678 assert(isSamePlayerRow(*p1, bjgb::State::unus(j), *p1, 1 == j ? bjgb::State::unus(j) : bjgb::State::hard(j))); 0679 // check 1 case below 0680 } 0681 0682 // 12 e_HZR // cannot hit one card only on no cards 0683 // N.A. 0684 0685 // -------- 0686 // 11 e_SBJ // so treat this as an S11 (STUPID IS AS STUPID DOES) 0687 0688 for (int i = 1; i <= 10; ++i) { 0689 p1->exp(bjgb::State::e_SBJ, i) = eHit1(ps, i, 11, true, shoe); 0690 } 0691 0692 // 10 soft(11) 0693 // 9 soft(10) 0694 // 8 soft( 9) 0695 // 7 soft( 8) 0696 // 6 soft( 7) 0697 // 5 soft( 6) 0698 // 4 soft( 5) 0699 // 3 soft( 4) 0700 // 2 soft( 3) 0701 // 1 soft( 2) 0702 // 0 soft( 1) // this is after a split Ace, which you *must* hit, no BJ 0703 0704 for (int j = 11; j >= 1; --j) { 0705 for (int i = 1; i <= 10; ++i) { 0706 p1->exp(bjgb::State::soft(j), i) = eHit1(ps, i, j, true, shoe); 0707 } 0708 } 0709 0710 assert(isSamePlayerRow(*p1, bjgb::State::e_SBJ, *p1, bjgb::State::soft(11))); 0711 0712 for (int j = 10; j >= 2; --j) { // card this is split (TBD meaning??) 0713 assert(isSamePlayerRow(*p1, bjgb::State::pair(j), *p1, bjgb::State::hard(2 * j))); 0714 } 0715 0716 assert(isSamePlayerRow(*p1, bjgb::State::pair(1), *p1, bjgb::State::soft(2))); 0717 0718 assert(isSamePlayerRow(*p1, bjgb::State::unus(1), *p1, bjgb::State::soft(1))); 0719 } 0720 0721 void PlayerTableUtil::populatePdtab(PlayerTable *pd, const PlayerTable& p1) 0722 { 0723 assert(pd); 0724 assert(bjgb::Types::isValid(p1.exp(bjgb::State::hard(20), 1))); 0725 assert(bjgb::Types::isValid(p1.exp(bjgb::State::hard(4), 9))); 0726 assert(bjgb::Types::isValid(p1.exp(bjgb::State::hard(11), 2))); 0727 assert(bjgb::Types::isValid(p1.exp(bjgb::State::hard(2), 10))); 0728 0729 // 53 pair(10) 0730 // 52 pair( 9) 0731 // 51 pair( 8) 0732 // 50 pair( 7) 0733 // 49 pair( 6) 0734 // 48 pair( 5) 0735 // 47 pair( 4) 0736 // 46 pair( 3) 0737 // 45 pair( 2) 0738 // 44 pair( 1) 0739 // N.A. 0740 0741 // --------- 0742 // 43 e_HOV 0743 // N.A. 0744 0745 // 42 hard(21) // 3+ cards, not appropriate for a double 0746 // N.A. 0747 0748 // 41 hard(20) 0749 // 40 hard(19) 0750 // 39 hard(18) 0751 // 38 hard(17) 0752 // 37 hard(16) 0753 // 36 hard(15) 0754 // 35 hard(14) 0755 // 34 hard(13) 0756 // 33 hard(12) 0757 // 32 hard(11) 0758 // 31 hard(10) 0759 // 30 hard( 9) 0760 // 29 hard( 8) 0761 // 28 hard( 7) 0762 // 27 hard( 6) 0763 // 26 hard( 5) 0764 // 25 hard( 4) 0765 0766 for (int j = 20; j >= 4; --j) { 0767 std::cout << "j=" << j << std::flush; 0768 for (int i = 1; i <= 10; ++i) { 0769 pd->exp(bjgb::State::hard(j), i) = eDouble(p1, i, j, false); 0770 } 0771 } 0772 0773 // 24 hard(3) // this has to be a single 3 after a split 0774 // 23 hard(2) // this has to be a single 2 after a split 0775 // N.A. 0776 0777 // -------- 0778 // 22 unus(10) 0779 // 21 unus( 9) 0780 // 20 unus( 8) 0781 // 19 unus( 7) 0782 // 18 unus( 6) 0783 // 17 unus( 5) 0784 // 16 unus( 4) 0785 // 15 unus( 3) 0786 // 14 unus( 2) 0787 // 13 unus( 1) // This is the first card of two and it is an Ace. 0788 // N.A. 0789 0790 // 12 e_HZR // cannot hit one card only on no cards 0791 // N.A. 0792 0793 // -------- 0794 // 11 e_SBJ // so treat this as an S11 (STUPID IS AS STUPID DOES) 0795 0796 for (int i = 1; i <= 10; ++i) { 0797 pd->exp(bjgb::State::e_SBJ, i) = eDouble(p1, i, 11, true); 0798 } 0799 0800 // 10 soft(11) 0801 // 9 soft(10) 0802 // 8 soft( 9) 0803 // 7 soft( 8) 0804 // 6 soft( 7) 0805 // 5 soft( 6) 0806 // 4 soft( 5) 0807 // 3 soft( 4) 0808 // 2 soft( 3) 0809 // 1 soft( 2) 0810 0811 for (int j = 11; j >= 2; --j) { 0812 std::cout << "J=" << j << std::flush; 0813 for (int i = 1; i <= 10; ++i) { 0814 pd->exp(bjgb::State::soft(j), i) = eDouble(p1, i, j, true); 0815 } 0816 } 0817 0818 assert(isSamePlayerRow(*pd, bjgb::State::e_SBJ, *pd, bjgb::State::soft(11))); 0819 0820 // 0 soft(1) // this is after a split Ace, which you *must* hit, no BJ 0821 // N.A. 0822 } 0823 0824 void PlayerTableUtil::populatePhtab(PlayerTable *ph, 0825 const PlayerTable& ps, 0826 const bjgb::Shoe& shoe, 0827 const bjgb::Rules& rules) 0828 { 0829 assert(ph); 0830 0831 // 53 pair(10) 0832 // 52 pair( 9) 0833 // 51 pair( 8) 0834 // 50 pair( 7) 0835 // 49 pair( 6) 0836 // 48 pair( 5) 0837 // 47 pair( 4) 0838 // 46 pair( 3) 0839 // 45 pair( 2) 0840 // 44 pair( 1) 0841 // N.A. 0842 0843 // --------- 0844 // 43 e_HOV 0845 // N.A. 0846 0847 // 42 hard(21) 0848 // 41 hard(20) 0849 // 40 hard(19) 0850 // 39 hard(18) 0851 // 38 hard(17) 0852 // 37 hard(16) 0853 // 36 hard(15) 0854 // 35 hard(14) 0855 // 34 hard(13) 0856 // 33 hard(12) 0857 // 32 hard(11) 0858 0859 for (int j = 21; j >= 11; --j) { 0860 for (int i = 1; i <= 10; ++i) { 0861 ph->exp(bjgb::State::hard(j), i) = eHitN(*ph, ps, i, j, false, shoe); 0862 } 0863 } 0864 0865 // 10 soft(11) 0866 // 9 soft(10) 0867 // 8 soft( 9) 0868 // 7 soft( 8) 0869 // 6 soft( 7) 0870 // 5 soft( 6) 0871 // 4 soft( 5) 0872 // 3 soft( 4) 0873 // 2 soft( 3) 0874 // 1 soft( 2) 0875 // 0 soft( 1) // this is after a split Ace, which you *must* hit, no BJ 0876 0877 for (int j = 11; j >= 1; --j) { 0878 for (int i = 1; i <= 10; ++i) { 0879 ph->exp(bjgb::State::soft(j), i) = eHitN(*ph, ps, i, j, true, shoe); 0880 } 0881 } 0882 0883 // 31 hard(10) 0884 // 30 hard( 9) 0885 // 29 hard( 8) 0886 // 28 hard( 7) 0887 // 27 hard( 6) 0888 // 26 hard( 5) 0889 // 25 hard( 4) 0890 // 24 hard( 3) // this has to be a single 3 after a split 0891 // 23 hard( 2) // this has to be a single 2 after a split 0892 0893 for (int j = 10; j >= 2; --j) { 0894 for (int i = 1; i <= 10; ++i) { 0895 ph->exp(bjgb::State::hard(j), i) = eHitN(*ph, ps, i, j, false, shoe); 0896 } 0897 } 0898 0899 // -------- 0900 // 22 unus(10) 0901 // 21 unus( 9) 0902 // 20 unus( 8) 0903 // 19 unus( 7) 0904 // 18 unus( 6) 0905 // 17 unus( 5) 0906 // 16 unus( 4) 0907 // 15 unus( 3) 0908 // 14 unus( 2) 0909 // 13 unus( 1) // This is the first card of two and it is an Ace. 0910 0911 for (int j = 10; j >= 1; --j) { 0912 for (int i = 1; i <= 10; ++i) { 0913 ph->exp(bjgb::State::unus(j), i) = eHitN(*ph, ps, i, j, 1 == j, shoe); 0914 } 0915 0916 assert(isSamePlayerRow(*ph, bjgb::State::unus(j), *ph, 1 == j ? bjgb::State::soft(j) : bjgb::State::hard(j))); 0917 } 0918 0919 // 12 e_HZR // cannot hit one card only on no cards 0920 // N.A. 0921 0922 // -------- 0923 // 11 e_SBJ // so treat this as an S11 (STUPID IS AS STUPID DOES) 0924 0925 for (int i = 1; i <= 10; ++i) { 0926 ph->exp(bjgb::State::e_SBJ, i) = eHitN(*ph, ps, i, 11, true, shoe); 0927 } 0928 0929 assert(isSamePlayerRow(*ph, bjgb::State::e_SBJ, *ph, bjgb::State::soft(11))); 0930 0931 // 53 pair(10) 0932 // 52 pair( 9) 0933 // 51 pair( 8) 0934 // 50 pair( 7) 0935 // 49 pair( 6) 0936 // 48 pair( 5) 0937 // 47 pair( 4) 0938 // 46 pair( 3) 0939 // 45 pair( 2) 0940 // 44 pair( 1) 0941 0942 for (int j = 10; j >= 1; --j) { // card value for each split hand 0943 for (int i = 1; i <= 10; ++i) { 0944 ph->exp(bjgb::State::pair(j), i) = eHitN(*ph, ps, i, 2 * j, 1 == j, shoe); 0945 } 0946 } 0947 0948 for (int j = 10; j >= 2; --j) { // card this is split (TBD meaning??) 0949 assert(isSamePlayerRow(*ph, bjgb::State::pair(j), *ph, bjgb::State::hard(2 * j))); 0950 } 0951 0952 assert(isSamePlayerRow(*ph, bjgb::State::pair(1), *ph, bjgb::State::soft(2))); 0953 } 0954 0955 void PlayerTableUtil::populatePstab(PlayerTable *ps, 0956 const DealerTable& dt, 0957 const bjgb::Shoe& shoe, 0958 const bjgb::Rules& rules) 0959 { 0960 assert(ps); 0961 0962 // 53 pair(10) 0963 // 52 pair( 9) 0964 // 51 pair( 8) 0965 // 50 pair( 7) 0966 // 49 pair( 6) 0967 // 48 pair( 5) 0968 // 47 pair( 4) 0969 // 46 pair( 3) 0970 // 45 pair( 2) 0971 // 44 pair( 1) 0972 0973 for (int j = 10; j >= 1; --j) { 0974 for (int i = 1; i <= 10; ++i) { 0975 ps->exp(bjgb::State::pair(j), i) = eStand(dt, i, 1 == j ? 12 : 2 * j); 0976 0977 assert(ps->exp(bjgb::State::pair(j), i) == j >= 6 ? ps->exp(bjgb::State::hard(2 * j), i) 0978 : ps->exp(bjgb::State::hard(16), i)); 0979 } 0980 } 0981 0982 // --------- 0983 // 43 e_HOV 0984 0985 ps->setRow(bjgb::State::e_HOV, -1.0); // set all entries to simple loss 0986 0987 // 42 hard(21) 0988 // 41 hard(20) 0989 // 40 hard(19) 0990 // 39 hard(18) 0991 // 38 hard(17) 0992 // 37 hard(16) 0993 // 36 hard(15) 0994 // 35 hard(14) 0995 // 34 hard(13) 0996 // 33 hard(12) 0997 // 32 hard(11) 0998 // 31 hard(10) 0999 // 30 hard( 9) 1000 // 29 hard( 8) 1001 // 28 hard( 7) 1002 // 27 hard( 6) 1003 // 26 hard( 5) 1004 // 25 hard( 4) 1005 1006 for (int j = 21; j >= 4; --j) { 1007 for (int i = 1; i <= 10; ++i) { 1008 ps->exp(bjgb::State::hard(j), i) = eStand(dt, i, j); 1009 } 1010 } 1011 1012 // 24 hard(3) // this has to be a 3 card after a split 1013 // 23 hard(2) // this has to be a 2 card after a split 1014 // N.A. 1015 1016 // -------- 1017 // 22 unus(10) 1018 // 21 unus( 9) 1019 // 20 unus( 8) 1020 // 19 unus( 7) 1021 // 18 unus( 6) 1022 // 17 unus( 5) 1023 // 16 unus( 4) 1024 // 15 unus( 3) 1025 // 14 unus( 2) 1026 // 13 unus( 1) // This is the first card of two and it is an Ace. 1027 // N.A. 1028 1029 // 12 e_HZR // cannot stand on no cards 1030 1031 // -------- 1032 // 11 e_SBJ 1033 1034 ps->setRow(bjgb::State::e_SBJ, rules.playerBlackjackPayout()); 1035 // set all entries blackjack 1036 1037 ps->exp(bjgb::State::e_SBJ, 1) -= shoe.prob(10) * rules.playerBlackjackPayout(); 1038 ps->exp(bjgb::State::e_SBJ, 10) -= shoe.prob(1) * rules.playerBlackjackPayout(); 1039 1040 // 10 soft(11) 1041 // 9 soft(10) 1042 // 8 soft( 9) 1043 // 7 soft( 8) 1044 // 6 soft( 7) 1045 // 5 soft( 6) 1046 // 4 soft( 5) 1047 // 3 soft( 4) 1048 // 2 soft( 3) 1049 // 1 soft( 2) 1050 1051 for (int j = 11; j >= 2; --j) { 1052 for (int i = 1; i <= 10; ++i) { 1053 ps->exp(bjgb::State::soft(j), i) = eStand(dt, i, j + 10); 1054 } 1055 } 1056 1057 // 0 soft(1) // this is after a split Ace, which you *must* hit, no BJ 1058 // N.A. 1059 } 1060 1061 void PlayerTableUtil::populatePxtab(PlayerTable *pxt, 1062 const PlayerTable& pdt, 1063 const PlayerTable& pht, 1064 const PlayerTable& p1t, 1065 const PlayerTable& pst, 1066 const bjgb::Shoe& shoe, 1067 const bjgb::Rules& rules) 1068 { 1069 assert(pxt); 1070 1071 // Copy over the values from the double table. 1072 1073 for (int i = 4; i <= 20; ++i) { // there is no hard 2-card 21 1074 copyPlayerRow(pxt, bjgb::State::hard(i), pdt, bjgb::State::hard(i)); 1075 } 1076 1077 for (int i = 2; i <= 11; ++i) { // A+A, A+2, ... A+T (after a split Ace) 1078 copyPlayerRow(pxt, bjgb::State::soft(i), pdt, bjgb::State::soft(i)); 1079 } 1080 1081 copyPlayerRow(pxt, bjgb::State::e_SBJ, pdt, bjgb::State::e_SBJ); 1082 // This is a natural A + 10. 1083 1084 for (int i = 2; i <= 20; i += 2) { 1085 int splitCard = i / 2; 1086 int maxSplits = rules.playerMaxNumHands() - 1; // typically 3 1087 1088 for (int j = 1; j <= 10; ++j) { 1089 pxt->exp(bjgb::State::pair(splitCard), j) = eSplit(pdt, pht, p1t, pst, j, i, maxSplits, shoe, rules); 1090 } 1091 } 1092 } 1093 1094 } // namespace bjgc