# include # include # include # define DECKS 6 # define HANDS 1000000 # define DEBUG_LEVEL 1 // DEBUG_LEVEL description // 9 banker draws; hard + soft decision generator // 7 player draws; hard + soft decision generator // 5 banker draws; soft decision generator // 3 player draws; soft decision generator // 0 quiet static int BankerDecision (int, int) ; static int PlayerDecision (int, int, int) ; static double EvalDecision (int, int, int, int, int) ; static int HandValue (int, int) ; static int showdown (int, int, int, int) ; static int DealCard () ; static int HardDecision[23][11], SoftDecision[23][11] ; static int Double11Decision[11], Double12Decision[11] ; void main () { int i,j,k ; int PlayerStart, PlayerSoft ; int BankerTotal, BankerUp ; double HitEV, StayEV, DoubleEV, NormalEV, PlayerHit ; double DiffHardDecision[23][11], DiffSoftDecision[23][11] ; double HardTotalEV[23][11], SoftTotalEV[23][11] ; double Double11EV[11], Double12EV[11] ; FILE *fp ; for (i=0; i<22; i++) { for (j=0; j<11; j++) { HardDecision[i][j] = 1 ; SoftDecision[i][j] = 1 ; DiffHardDecision[i][j] = .0 ; DiffSoftDecision[i][j] = .0 ; HardTotalEV[i][j] = .0 ; SoftTotalEV[i][j] = .0 ; } } // determine the HardDecision table PlayerSoft = 0 ; for (PlayerStart = 19; PlayerStart >= 13; PlayerStart--) { for (BankerUp = 1; BankerUp <= 10; BankerUp++) { PlayerHit = 0 ; StayEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; PlayerHit = 1 ; HitEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; if (DEBUG_LEVEL > 0) { printf("playerStart: %2d bankerUp: %2d HitEV: %+f StayEV: %+f\n", PlayerStart, BankerUp, HitEV, StayEV) ; } HardDecision[PlayerStart][BankerUp] = (HitEV > StayEV) ; DiffHardDecision[PlayerStart][BankerUp] = -1. * fabs(HitEV - StayEV) ; HardTotalEV[PlayerStart][BankerUp] = (HitEV > StayEV) ? HitEV : StayEV ; } if (DEBUG_LEVEL > 0) printf("\n") ; } // determine the SoftDecision table PlayerSoft = 1 ; for (PlayerStart = 10; PlayerStart >= 3; PlayerStart--) { // for A9 downto A2 for (BankerUp = 1; BankerUp <= 10; BankerUp++) { PlayerHit = 0 ; StayEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; PlayerHit = 1 ; HitEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; if (DEBUG_LEVEL > 0) { printf("playerStart: (%2d) bankerUp: %2d HitEV: %+f StayEV: %+f\n", PlayerStart+10, BankerUp, HitEV, StayEV) ; } SoftDecision[PlayerStart][BankerUp] = (HitEV > StayEV) ; DiffSoftDecision[PlayerStart][BankerUp] = -1. * fabs(HitEV - StayEV) ; SoftTotalEV[PlayerStart][BankerUp] = (HitEV > StayEV) ? HitEV : StayEV ; } if (DEBUG_LEVEL > 0) printf("\n") ; } // evaluate double-down option PlayerSoft = 0 ; PlayerStart = 11 ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { PlayerHit = HardDecision[11][BankerUp] ; NormalEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; PlayerHit = 1 ; DoubleEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 2) ; Double11Decision[BankerUp] = (2.*DoubleEV > NormalEV) ; if (DEBUG_LEVEL > 0) { printf("double down 11 vs %2d: 2*DoubleEV = %+f NormalEV = %+f\n", BankerUp,2.*DoubleEV,NormalEV) ; } Double11EV[BankerUp] = (2.*DoubleEV > NormalEV) ? 2.*DoubleEV : NormalEV ; } PlayerStart = 12 ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { PlayerHit = HardDecision[12][BankerUp] ; NormalEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 40) ; PlayerHit = 1 ; DoubleEV = EvalDecision (PlayerStart, PlayerSoft, PlayerHit, BankerUp, 2) ; Double12Decision[BankerUp] = (2.*DoubleEV > NormalEV) ; if (DEBUG_LEVEL > 0) { printf("double down 12 vs %2d: 2*DoubleEV = %+f NormalEV = %+f\n", BankerUp,2.*DoubleEV,NormalEV) ; } Double12EV[BankerUp] = (2.*DoubleEV > NormalEV) ? 2.*DoubleEV : NormalEV ; } // output decision tables fp = fopen("HardDecision.tbl","w") ; for (PlayerStart=19; PlayerStart >= 13; PlayerStart--) { for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%d ",HardDecision[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fclose(fp) ; fp = fopen("SoftDecision.tbl","w") ; for (PlayerStart=10; PlayerStart >= 3; PlayerStart--) { for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%d ",SoftDecision[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fclose(fp) ; fp = fopen("Double11Decision.tbl","w") ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%d ",Double11Decision[BankerUp]) ; } fclose(fp) ; fp = fopen("Double12Decision.tbl","w") ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%d ",Double12Decision[BankerUp]) ; } fclose(fp) ; fp = fopen("HardDecisionMistakes.txt","w") ; fprintf(fp,"EV cost vs. Basic Strategy Mistake (Hard Totals)\n\n") ; fprintf(fp," dealer upcard\n"); fprintf(fp," A 2 3 4 5 6 7 8 9 T\n") ; fprintf(fp,"___________________________________________________________________________\n") ; fprintf(fp,"\n") ; for (PlayerStart=19; PlayerStart >= 13; PlayerStart--) { fprintf(fp,"%2d ",PlayerStart) ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%5.3f ",DiffHardDecision[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fp = fopen("SoftDecisionMistakes.txt","w") ; fprintf(fp,"EV cost vs. Basic Strategy Mistake (Soft Totals)\n\n") ; fprintf(fp," dealer upcard\n"); fprintf(fp," A 2 3 4 5 6 7 8 9 T\n") ; fprintf(fp,"\n") ; fprintf(fp,"___________________________________________________________________________\n") ; for (PlayerStart=10; PlayerStart >= 3; PlayerStart--) { fprintf(fp,"(%2d) ",PlayerStart+10) ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%5.3f ",DiffSoftDecision[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fclose(fp) ; fp = fopen("HardTotalEV.txt","w") ; fprintf(fp,"EV for Hard Total vs. Dealer Up Card following Basic Strategy\n\n") ; fprintf(fp," dealer upcard\n"); fprintf(fp,"total A 2 3 4 5 6 7 8 9 T\n") ; fprintf(fp,"____________________________________________________________________________\n") ; for (PlayerStart=19; PlayerStart >= 13; PlayerStart--) { fprintf(fp,"%2d ",PlayerStart) ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%+5.3f ",HardTotalEV[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fclose(fp) ; fp = fopen("SoftTotalEV.txt","w") ; fprintf(fp,"EV for Soft Total vs. Dealer Up Card following Basic Strategy\n\n") ; fprintf(fp,"soft dealer upcard\n"); fprintf(fp,"total A 2 3 4 5 6 7 8 9 T\n") ; fprintf(fp,"____________________________________________________________________________\n") ; for (PlayerStart=10; PlayerStart >= 3; PlayerStart--) { fprintf(fp,"(%2d) ",PlayerStart+10) ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%+5.3f ",SoftTotalEV[PlayerStart][BankerUp]) ; } fprintf(fp,"\n") ; } fclose(fp) ; fp = fopen("DoubleDownEV.txt","w") ; fprintf(fp,"EV for 11 or 12 Two Card Total vs. Dealer Up Card following Basic Strategy\n\n") ; fprintf(fp," dealer upcard\n"); fprintf(fp,"total A 2 3 4 5 6 7 8 9 T\n") ; fprintf(fp,"____________________________________________________________________________\n") ; fprintf(fp,"12 ") ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%+5.3f ",Double12EV[BankerUp]) ; } fprintf(fp,"\n") ; fprintf(fp,"11 ") ; for (BankerUp = 1; BankerUp <= 10; BankerUp++) { fprintf(fp,"%+5.3f ",Double11EV[BankerUp]) ; } fprintf(fp,"\n") ; fclose(fp) ; } // Monte Carlo evaluation of hit/stay decision of PlayerStart vs BankerUp static double EvalDecision (int PlayerTotal, int PlayerSoft, int PlayerHit, int BankerUp, int MaxPlayerDraws) { int i,j,k ; int game, net, card, outcome ; int playerSum, playerAce, bankerSum, bankerAce ; int bankerCardCnt, playerCardCnt, bankerNatural ; double EV ; net = 0 ; for (i=0; i 5) printf("game %d\n",i) ; bankerAce = (BankerUp == 1) ; playerAce = PlayerSoft ; playerSum = PlayerTotal ; bankerSum = BankerUp ; if (DEBUG_LEVEL >= 7) { if (PlayerSoft) printf("player start: (%d)\n",playerSum+10) ; else printf("player start: %d\n",playerSum) ; } playerCardCnt = 2 ; if (PlayerHit) { while( PlayerDecision(playerSum,playerAce,BankerUp) && ((playerCardCnt - 2) < MaxPlayerDraws) ) { playerCardCnt++ ; card = DealCard() ; if (card == -1) { playerSum = 22 ; } else { playerSum += card ; playerAce |= (card == 1) ; } if (DEBUG_LEVEL >= 7) { if (playerAce && (playerSum <= 12)) printf("player draw: %d total: %d (%d)\n", card,playerSum,(playerSum+10)) ; else printf("player draw: %d total: %d\n",card,playerSum) ; } } } bankerCardCnt = 1 ; bankerNatural = 0 ; if (DEBUG_LEVEL >= 9) printf("banker upcard: %d\n",BankerUp) ; while (BankerDecision(bankerSum,bankerAce)) { card = DealCard() ; if (card == -1) { // joker bankerNatural = (bankerCardCnt == 1) && ((BankerUp == 1) || (BankerUp == 10)) ; bankerSum = 22 ; } else { bankerSum += card ; bankerAce |= (card == 1) ; } if (DEBUG_LEVEL >= 9) { if (bankerAce && (bankerSum <= 12)) printf("banker draw: %d total: %d (%d)\n", card,bankerSum,(bankerSum+10)) ; else printf("banker draw: %d total: %d\n",card,bankerSum) ; } } // if ((playerAce && playerSum <= 12)) playerSum += 10 ; // if ((bankerAce && bankerSum <= 12)) bankerSum += 10 ; // determine outcome (no playerNatural in this search) if (bankerNatural) { outcome = - 1 ; } else { outcome = showdown(playerSum,playerAce,bankerSum,bankerAce) ; } net += outcome ; if (DEBUG_LEVEL > 5) printf("outcome: %d net: %d\n",outcome,net) ; if (DEBUG_LEVEL > 5) printf("\n") ; } EV = (double)(net)/(double)HANDS ; return (EV) ; } static int PlayerDecision (int total, int soft, int upcard) { int hit ; if (soft) { if ((total == 11) || (total == 12)) { // soft 21, 22 hit = 0 ; } else if (total < 11) { hit = SoftDecision[total][upcard] ; } else if (total < 20) { hit = HardDecision[total][upcard] ; } else { hit = 0 ; } } else { if (total <= 12) { hit = 1 ; } else if ((total > 12) && (total < 20)) { hit = HardDecision[total][upcard] ; } else { hit = 0 ; } } return (hit) ; } static int BankerDecision (int total, int soft) { int hit ; if (soft) { hit = (total <= 8) || ((total > 12) && (total < 18)) ; } else { hit = (total < 18) ; } return (hit) ; } static int showdown (int PlayerTotal, int PlayerSoft, int BankerTotal, int BankerSoft) { // this subroutine does not cover banker nor player naturals int outcome ; // -1 = player loses; 0 = push; +1 = player wins if (BankerTotal > 22) { if (PlayerTotal <= 22) { outcome = 1 ; } else { outcome = (PlayerTotal < BankerTotal) ? 0 : -1 ; } } else if (PlayerTotal > 22) { outcome = -1 ; } else if ( HandValue(PlayerTotal,PlayerSoft) == HandValue(BankerTotal,BankerSoft) ) { outcome = 0 ; if (DEBUG_LEVEL >=9 ) { printf( "player: %d banker: %d\n", HandValue(PlayerTotal,PlayerSoft), HandValue(BankerTotal,BankerSoft) ) ; } } else { outcome = ( HandValue(PlayerTotal,PlayerSoft) > HandValue(BankerTotal,BankerSoft) ) ? 1 : -1 ; if (DEBUG_LEVEL >=9 ) { printf( "player: %d banker: %d\n", HandValue(PlayerTotal,PlayerSoft), HandValue(BankerTotal,BankerSoft) ) ; } } return (outcome) ; } static int DealCard () { int i,j, card ; i = (int)(drand48() * 53.) ; if (i == 52) { card = -1 ; // joker } else { j = (i%13) ; card = (j < 9) ? (j+1) : 10 ; // ace = 1 } return (card) ; } static int HandValue (int total, int soft) { int value ; value = (soft && (total <= 12)) ? (total +10) : total ; return (value) ; }