Derivation of the basic strategy


Derivation of the basic strategy

Difficulty: 20/100

Quick run

Execute the run.sh script. It should take a minute or so:

$ ./run.sh
h20-2 (10 10) n=1000    s=0.634 (0.03)  d=-1.676 (0.03) h=-0.844 (0.02) stand
h20-3 (10 10) n=1000    s=0.66 (0.03)   d=-1.744 (0.03) h=-0.847 (0.02) stand
h20-4 (10 10) n=1000    s=0.65 (0.03)   d=-1.708 (0.03) h=-0.852 (0.02) stand
[...]
p2-T n=1000     y=-0.552 (0.05) n=-0.381 (0.03) no
p2-A n=1000     y=-0.565 (0.04) n=-0.543 (0.03) uncertain
p2-A n=10000    y=-0.6505 (0.01)        n=-0.5025 (0.008)       no

A new text file called bs.txt with the strategy should be created from scratch:

#    2  3  4  5  6  7  8  9  T  A
h20  s  s  s  s  s  s  s  s  s  s  
h19  s  s  s  s  s  s  s  s  s  s  
h18  s  s  s  s  s  s  s  s  s  s  
h17  s  s  s  s  s  s  s  s  s  s  
h16  s  s  s  s  s  h  h  h  s  h  
h15  s  s  s  s  s  h  h  h  h  h  
h14  s  s  s  s  s  h  h  h  h  h  
h13  s  s  s  s  s  h  h  h  h  h  
h12  h  h  s  s  s  h  h  h  h  h  
h11  d  d  d  d  d  d  d  d  d  h  
h10  d  d  d  d  d  d  d  d  h  d  
h9   h  d  d  d  d  h  h  h  h  h  
h8   h  h  h  h  h  h  h  h  h  h  
h7   h  h  h  h  h  h  h  h  h  h  
h6   h  h  h  h  h  h  h  h  h  h  
h5   h  h  h  h  h  h  h  h  h  h  
h4   h  h  h  h  h  h  h  h  h  h  
#    2  3  4  5  6  7  8  9  T  A
s20  s  s  s  s  s  s  s  s  s  s  
s19  s  s  s  s  d  s  s  s  s  s  
s18  d  d  d  d  d  s  s  h  h  h  
s17  h  d  d  d  d  h  h  h  h  h  
s16  h  h  d  d  d  h  h  h  h  h  
s15  h  h  d  d  d  h  h  h  h  h  
s14  h  h  h  d  d  h  h  h  h  h  
s13  h  h  h  h  d  h  h  h  h  h  
s12  h  h  h  h  d  h  h  h  h  h  
#    2  3  4  5  6  7  8  9  T  A
pA   y  y  y  y  y  y  y  y  y  y  
pT   n  n  n  n  n  n  n  n  n  n  
p9   y  y  y  y  y  n  y  y  n  n  
p8   y  y  y  y  y  y  y  y  y  y  
p7   y  y  y  y  y  y  n  n  n  n  
p6   y  y  y  y  y  n  n  n  n  n  
p5   n  n  n  n  n  n  n  n  n  n  
p4   n  n  n  y  y  n  n  n  n  n  
p3   y  y  y  y  y  y  n  n  n  n  
p2   y  y  y  y  y  y  n  n  n  n  

Full table with results

The script computes the expected value of each combination

  1. Player’s hand (hard, soft and pair)
  2. Dealer upcard
  3. Hit, soft and stand (for hards and softs) and splitting or not (for pairs)

The results are given as the expected value in percentage with the uncertainty (one standard deviation) in the last significant digit.

Hand 2 3 4 5 6 7 8 9 T A
pA
yes
no
+44(5)
+6(3)
+46(5)
+13(3)
+61(5)
+11(3)
+60(5)
+14(3)
+76(5)
+8(6)
+46(5)
+20(3)
+40(5)
+12(3)
+20(5)
+1(3)
-2(5)
-19(3)
-27(4)
-36(3)
pT
yes
no
+52(5)
+61(2)
+42(5)
+67(2)
+55(5)
+66(2)
+49(5)
+70(2)
+59(5)
+66(2)
+48(5)
+77(2)
+38(5)
+81(2)
+25(4)
+75(2)
+4(5)
+43(2)
-24(4)
+9(3)
p9
yes
no
+17(2)
+10.7(9)
+29(6)
+13(3)
+28(2)
+16.6(9)
+42(6)
+16(3)
+36(6)
+21(3)
+37.7(5)
+39.9(3)
+23(5)
+7(2)
-10(2)
-16.5(9)
-43(5)
-26(3)
-47.9(4)
-46.3(3)
p8
yes
no
-3(7)
-22(3)
+10(7)
-28(3)
+19(7)
-20(3)
+19(7)
-14(3)
+26(7)
-12(3)
+26(6)
-41(3)
-6(6)
-46(3)
-39(2)
-51.4(8)
-51(5)
-60(3)
-68.13(1)
-68.40(1)
p7
yes
no
-11(7)
-34(3)
-11(8)
-25(3)
-0(8)
-20(3)
+13(8)
-23(3)
+5(8)
-17(3)
-17(6)
-33(3)
-39.02(1)
-37.11(1)
-58(6)
-43(3)
-73(5)
-49(3)
-78(4)
-67(2)
p6
yes
no
-21.3(7)
-25.4(3)
-12(2)
-23.9(9)
-9(8)
-25(3)
-2(8)
-16(3)
+17(8)
-11(3)
-26(2)
-21.6(9)
-35(5)
-25(3)
-59(5)
-31(3)
-59(5)
-42(3)
-80(4)
-54(3)
p5
yes
no
-8(7)
+41(6)
-19(7)
+38(6)
-7(8)
+45(6)
-2(8)
+55(6)
+10(8)
+59(6)
-19(5)
+52(6)
-23(6)
+33(6)
-60(5)
+10(6)
-70(5)
-6(3)
-79(4)
-37(5)
p4
yes
no
-20(6)
-2(3)
-14(7)
+1(3)
-2(2)
+3(1)
+23(8)
+6(3)
+15(2)
+8(1)
-18(6)
+10(3)
-30(6)
-3(3)
-58(5)
-25(3)
-53(5)
-28(3)
-76(4)
-51(3)
p3
yes
no
-12(2)
-16(1)
+1(7)
-16(3)
+3(2)
-6(1)
+9(2)
-3(1)
+21(8)
-1(3)
-5(2)
-16.5(9)
-24(2)
-21.1(9)
-42(6)
-24(3)
-56(5)
-41(3)
-72(4)
-49(3)
p2
yes
no
-8.6(6)
-11.2(3)
-3(2)
-9(1)
+2(2)
-3(1)
+10(2)
-1(1)
+21(8)
-2(3)
+2(2)
-9(1)
-17.56(1)
-15.99(1)
-36(2)
-24.2(9)
-52(5)
-31(3)
-60(4)
-48(3)
Hand 2 3 4 5 6 7 8 9 T A
s20
stand
hit
double
+65(6)
+22(3)
+31(6)
+68(6)
+18(3)
+34(6)
+64(6)
+21(3)
+44(6)
+66(2)
+24.6(9)
+54(2)
+69(6)
+28(3)
+52(6)
+75(6)
+30(3)
+49(6)
+78(6)
+23(3)
+27(6)
+73(6)
+14(3)
+10(6)
+44(6)
-6(3)
-4(6)
+7(5)
-27(3)
-34(5)
s19
stand
hit
double
+39(6)
+9(3)
+26(6)
+39(2)
+14.6(9)
+32(2)
+41(2)
+18.2(9)
+33(2)
+43.5(6)
+20.0(3)
+39.8(6)
+45.35(1)
+23.15(1)
+46.06(1)
+63(6)
+23(3)
+37(6)
+59(6)
+12(3)
+19(6)
+30(6)
-1(3)
-12(6)
-3(6)
-18(3)
-40(6)
-13(5)
-33(3)
-48(5)
s18
stand
hit
double
+10.99(1)
+5.88(1)
+11.78(1)
+13(2)
+10(1)
+21(2)
+16(2)
+13(1)
+25(2)
+20(6)
+14(3)
+34(6)
+22(2)
+18.9(9)
+38(2)
+40(2)
+16.9(9)
+20(2)
+11(2)
+4.5(9)
-4(2)
-17(2)
-9.4(9)
-28(2)
-24(2)
-20.4(9)
-39(2)
-49(5)
-40(3)
-66(5)
s17
stand
hit
double
-15.59(1)
-0.66(1)
-1.22(1)
-11(6)
-1(3)
+10(6)
-6(6)
+2(3)
+11(6)
-0(6)
+7(3)
+31(6)
-2(6)
+11(3)
+25(6)
-9(6)
+6(3)
-4(6)
-35(6)
-6(3)
-23(6)
-41(6)
-21(3)
-33(6)
-46(6)
-21(3)
-51(6)
-65(5)
-48(3)
-65(5)
s16
stand
hit
double
-26(6)
+0(3)
-16(6)
-26(2)
+1(1)
-4(2)
-16(6)
-4(3)
+7(6)
-16(2)
+6(1)
+13(2)
-12(2)
+9(1)
+18(2)
-48(6)
+3(3)
-19(6)
-56(6)
-6(3)
-35(6)
-55(6)
-10(3)
-48(6)
-56(6)
-27(3)
-47(6)
-72(5)
-47(3)
-68(5)
s15
stand
hit
double
-27(2)
-0(1)
-4(2)
-24.6(6)
+2.2(3)
-1.3(6)
-21(2)
+5(1)
+8(2)
-16(2)
+8(1)
+14(2)
-9(6)
+11(3)
+23(6)
-48(2)
+4(1)
-17(2)
-54(6)
-4(3)
-34(6)
-55(6)
-9(3)
-40(6)
-58(6)
-24(3)
-63(6)
-71(5)
-45(3)
-66(5)
s14
stand
hit
double
-26(6)
+3(3)
-13(6)
-22(2)
+6(1)
+0(2)
-20.5(6)
+7.8(3)
+5.5(6)
-15(2)
+10(1)
+14(2)
-14(6)
+12(3)
+23(6)
-49(6)
+9(3)
-28(6)
-49(6)
-3(3)
-36(6)
-56(6)
-10(3)
-39(6)
-56(6)
-19(3)
-62(6)
-71(5)
-40(3)
-65(5)
s13
stand
hit
double
-26(6)
+8(3)
-19(6)
-25(2)
+6(1)
-2(2)
-21(2)
+9(1)
+6(2)
-16.38(1)
+13.06(1)
+12.78(1)
-11.5(6)
+13.5(3)
+18.7(6)
-43(6)
+12(3)
-23(6)
-49(6)
+3(3)
-30(6)
-55(6)
-1(3)
-47(6)
-61(6)
-18(3)
-61(6)
-73(5)
-34(3)
-70(5)
s12
stand
hit
double
-29(2)
+9(1)
-7(2)
-18(6)
+12(3)
-2(6)
-24(6)
+21(3)
+4(6)
-18(2)
+16(1)
+11(2)
-12(2)
+16(1)
+21(2)
-48(6)
+11(3)
-21(6)
-52(6)
+8(3)
-32(6)
-55(6)
-4(3)
-42(6)
-60(6)
-22(3)
-51(6)
-66(5)
-36(3)
-75(5)
Hand 2 3 4 5 6 7 8 9 T A
h20
stand
hit
double
+63(3)
-84(2)
-172(3)
+62(3)
-87(2)
-171(3)
+65(3)
-90(1)
-172(3)
+67(3)
-87(2)
-172(3)
+68(3)
-86(2)
-172(3)
+76(3)
-84(2)
-170(3)
+76(3)
-85(2)
-169(3)
+76(3)
-83(2)
-170(3)
+48(3)
-85(2)
-162(3)
+3(3)
-89(1)
-152(3)
h19
stand
hit
double
+38(4)
-74(2)
-143(4)
+43(4)
-70(2)
-147(4)
+43(4)
-76(2)
-144(4)
+44(4)
-72(2)
-141(4)
+44(4)
-73(2)
-139(4)
+61(4)
-73(2)
-142(4)
+67(5)
-73(2)
-138(5)
+30(4)
-70(2)
-149(4)
-2(4)
-76(2)
-141(4)
-16(4)
-82(2)
-134(4)
h18
stand
hit
double
+9(5)
-65(2)
-128(5)
+17(5)
-62(2)
-127(5)
+16(5)
-63(2)
-123(5)
+17(5)
-60(2)
-127(5)
+22(5)
-63(2)
-120(5)
+40(5)
-57(3)
-121(5)
+12(5)
-63(2)
-119(5)
-20(5)
-58(2)
-124(5)
-24(5)
-73(2)
-122(5)
-45(4)
-75(2)
-114(4)
h17
stand
hit
double
-16(5)
-57(3)
-99(5)
-16(5)
-56(3)
-106(5)
-9(5)
-55(3)
-107(5)
-2(5)
-53(3)
-106(5)
+4(5)
-53(3)
-105(5)
-12(5)
-49(3)
-103(5)
-38(5)
-57(3)
-105(5)
-40(5)
-52(3)
-114(5)
-49(5)
-62(2)
-121(5)
-65(4)
-72(2)
-109(4)
h16
stand
hit
double
-28(5)
-44(3)
-101(5)
-24(5)
-51(3)
-99(5)
-20(5)
-47(3)
-98(5)
-22(6)
-42(3)
-87(6)
-11(5)
-47(3)
-98(5)
-52(6)
-41(3)
-79(6)
-52(5)
-43(3)
-93(5)
-55(2)
-49.0(8)
-103(2)
-57.55(1)
-57.58(1)
-107.30(1)
-73(1)
-68.9(7)
-104(1)
h15
stand
hit
double
-30(5)
-42(3)
-96(5)
-19(5)
-35(3)
-88(5)
-18(6)
-38(3)
-70(6)
-15(6)
-37(3)
-68(6)
-17(6)
-35(3)
-73(6)
-52(6)
-38(3)
-78(6)
-51(2)
-41.7(9)
-84(2)
-60(5)
-42(3)
-94(5)
-57.9(5)
-54.4(3)
-101.4(5)
-72(4)
-66(2)
-103(4)
h14
stand
hit
double
-30(2)
-36.8(9)
-75(2)
-25(2)
-34.2(9)
-68(2)
-22(6)
-38(3)
-69(6)
-13(6)
-27(3)
-73(6)
-13(2)
-31.6(9)
-62(2)
-49(6)
-32(3)
-62(6)
-54(6)
-37(3)
-83(6)
-54(5)
-41(3)
-92(5)
-58(2)
-51.4(8)
-92(2)
-72(4)
-58(2)
-90(4)
h13
stand
hit
double
-28.3(6)
-30.4(3)
-62.7(6)
-25(2)
-28.6(9)
-55(2)
-21(6)
-32(3)
-58(6)
-18(6)
-28(3)
-42(6)
-7(6)
-22(3)
-52(6)
-48(6)
-22(3)
-60(6)
-51(6)
-33(3)
-71(6)
-52(6)
-39(3)
-75(6)
-60(5)
-50(3)
-95(5)
-73(4)
-62(2)
-99(4)
h12
stand
hit
double
-28.5(6)
-24.9(3)
-50.7(6)
-24.6(6)
-23.5(3)
-46.3(6)
-20.3(6)
-21.5(3)
-43.6(6)
-16(2)
-19(1)
-44(2)
-12(2)
-17(1)
-34(2)
-46(6)
-26(3)
-54(6)
-53(6)
-28(3)
-55(6)
-54(6)
-37(3)
-71(6)
-56(5)
-43(3)
-74(5)
-73(5)
-54(3)
-84(5)
h11
stand
hit
double
-32(6)
+25(3)
+48(6)
-20(6)
+29(3)
+57(6)
-22(6)
+30(3)
+64(6)
-19(6)
+29(3)
+62(6)
-14(6)
+28(3)
+63(6)
-52(6)
+27(3)
+46(6)
-49(6)
+19(3)
+34(6)
-53(2)
+18.4(9)
+28(2)
-58(2)
+3(1)
+8(2)
-72.4(5)
-23.5(3)
-24.5(5)
h10
stand
hit
double
-32(6)
+12(3)
+39(6)
-23(6)
+15(3)
+47(6)
-21(6)
+24(3)
+58(6)
-18(6)
+28(3)
+45(6)
-12(6)
+31(3)
+59(6)
-46(6)
+27(3)
+51(6)
-52(2)
+19.6(9)
+28(2)
-55(6)
+13(3)
+22(6)
-59(2)
-5.9(9)
-11(2)
-70(5)
-29(3)
-21(5)
h9
stand
hit
double
-25(6)
+9(3)
-1(6)
-26(2)
+9(1)
+13(2)
-20(2)
+12(1)
+19(2)
-18(6)
+17(3)
+27(6)
-11(2)
+19.4(9)
+29(2)
-47(2)
+16.7(9)
+7(2)
-52(6)
+9(3)
-2(6)
-54(6)
-7(3)
-30(6)
-62(6)
-19(3)
-53(6)
-71(5)
-38(3)
-65(5)
h8
stand
hit
double
-29(6)
-4(3)
-18(6)
-23(6)
-9(3)
-20(6)
-22(6)
+8(3)
-17(6)
-16(2)
+6(1)
+2(2)
-12.0(6)
+10.5(3)
+8.2(6)
-54(6)
+9(3)
-21(6)
-52(6)
+0(3)
-46(6)
-55(6)
-20(3)
-67(6)
-61(5)
-32(3)
-77(5)
-75(5)
-46(3)
-88(5)
h7
stand
hit
double
-33(6)
-7(3)
-41(6)
-21(6)
-8(3)
-35(6)
-21(6)
-2(3)
-36(6)
-13(6)
+8(3)
-13(6)
-12(6)
+8(3)
-13(6)
-45(6)
-7(3)
-49(6)
-52(5)
-20(3)
-89(5)
-56(5)
-28(3)
-99(5)
-57(5)
-35(3)
-92(5)
-72(4)
-55(3)
-108(4)
h6
stand
hit
double
-25(6)
-13(3)
-47(6)
-24(2)
-11(1)
-47(2)
-19(6)
-4(3)
-40(6)
-22(6)
-10(3)
-32(6)
-12(6)
-1(3)
-18(6)
-49(5)
-15(3)
-94(5)
-54(5)
-22(3)
-100(5)
-54(5)
-31(3)
-106(5)
-58(5)
-41(3)
-113(5)
-71(4)
-58(2)
-111(4)
h5
stand
hit
double
-28(6)
-11(3)
-58(6)
-22(6)
-13(3)
-44(6)
-23(6)
-6(3)
-50(6)
-17(6)
-2(3)
-22(6)
-13(6)
-2(3)
-25(6)
-45(6)
-17(3)
-96(6)
-54(5)
-24(3)
-109(5)
-56(5)
-32(3)
-108(5)
-53(5)
-39(3)
-111(5)
-74(4)
-52(3)
-110(4)
h4
stand
hit
double
-29(6)
-18(3)
-51(6)
-25(6)
-14(3)
-50(6)
-21(6)
-5(3)
-35(6)
-16(6)
-1(3)
-30(6)
-10(6)
+2(3)
-18(6)
-48(6)
-14(3)
-94(6)
-53(5)
-19(3)
-111(5)
-53(5)
-28(3)
-108(5)
-61(5)
-40(3)
-107(5)
-74(4)
-56(3)
-108(4)

Detailed explanation

We want to derive the basic strategy from scratch, i.e. without assuming anything. What we are going to do is to play a large (more on what large means below) number of hands by fixing our first two cards and the dealer upcard and sequentially standing, doubling or hitting the first card. Then we will compare the results for the three cases and select as the proper strategy the better one.

Standing and doubling are easy plays, because after we stand or double the dealer plays accordingly to the rules. She hits until seventeen (either soft or hard). But if we hit on our hand, we might need to make another decision wether to stand or hit again. As we do not want to assume anything, we have to play in such an order that if we do need to make another decision, we already know which is the better one.

Hard hands

So we start by arranging the shoe so that the user gets hard twenty (i.e. two faces) and the dealer gets succesively upcards of two to ace. So we play each combination of dealer upcard (ten) three times each playing either

  1. always standing
  2. always doubling
  3. always hitting

In general the first two plays are easy, because the game stops either after standing or after receiving only one card. The last one might lead to further hitting, but since we are starting with a hard twenty, that would either give the player twenty one or a bust. In any case, the game also ends. So we play a certain number of hands (say one thousand hands) each of these three plays for each of the ten upcard faces and record the outcome. The correct play for hard twenty against each of the ten upcards is the play that gave the better result, which is of course standing.

Next, we do the same for a hard nineteen. In this case, the hitting play might not end after one card is drawn. But if that is the case, i.e. receiving an ace for a total of hard twenty, we already know what the best play is from the previous step so we play accordingly and we stand. Repeating this procedure down to hard four we can build the basic strategy table for any hard total against any dealer upcard.

Soft hands

We can now switch to analyze soft hands. Starting from soft twenty (i.e. an ace and a nine) we do the same we did for the hard case. The only difference is that wehn hitting, we might end either in another soft hand which we would already analyzed because we start from twenty and go down, or in a hard hand, which we also already analyzed se we can play accordingly.

Pairs

When dealing with pairs, we have to decide wether to split or not. When we do not split, we end up in one of the already-analyzed cases: either a soft twelve of any even hard hand. When we split, we might end in a hard or soft hand (already analyzed) or in a new pair. But since the new pair can be only the same pair we are analyzing, we have to treat it like we treated the first pair: either to split it or not, so we know how to deal with it.

Number of hands

The output is the expected value e of the bankroll, which is a random variable with an associated uncertainty \Delta e (i.e. a certain numbers of standard deviations). For example, if we received only blackjacks, the expected value would be 1.5 (provided blackjacks pay 3 to 2). If we busted all of our hands without doubling or splitting, the expected value would be -1. In order to say that the best strategy is, let’s say stand and not hitting or doubling, we have to make sure that e_h-\Delta e_h > e_s+\Delta e_s and e_h-\Delta e_h > e_d+\Delta e_d. If there is no play that can give a better expected value than the other two taking into account the uncertainties, then we have to play more hands in order to reduce the random uncertainty.

Implementation

The steps above can be written in a Bash script that

  • loops over hands and upcards,
  • creates a strategy file for each possible play hit, double or stand (or split or not),
  • runs Libreblackjack,
  • checks the results and picks the best play,
  • updates the strategy file
#!/bin/bash

for i in grep cut bc awk; do
 if [ -z "`which $i`" ]; then
  echo "error: $i not installed"
  exit 1
 fi
done

debug=0

declare -A strategy
declare -A ev

declare -A min
min["hard"]=4   # from 20 to 4 in hards
min["soft"]=12  # from 20 to 12 in softs

rm -f hard.html soft.html pair.html

# --------------------------------------------------------------
# start with standing
cp hard-stand.txt hard.txt
cp soft-stand.txt soft.txt

cat << EOF > table.md
| Hand | \$n\$ | Stand | Double | Hit |
| ---- | ----- | ----- | ------ | --- |
EOF


for type in hard soft; do
 for hand in `seq 20 -1 ${min[${type}]}`; do
 
  # choose two random cards that make up the player's assumed total
  if [ ${type} = "hard" ]; then
   t="h"
   card1=11
   card2=11
   while test $card1 -gt 10 -o $card2 -gt 10; do
    card1=$((${RANDOM} % (${hand}-3) + 2))
    card2=$((${hand} - ${card1}))
   done
  elif [ ${type} = "soft" ]; then
   t="s"
   # one card is an ace
   card1=1
   card2=$((${hand} - 10 - ${card1}))
  fi

  cat << EOF >> ${type}.html
 <tr>
  <td>${t}${hand}</td>
  <td>
   <div class="text-right">s<span class="d-none d-lg-inline">tand</span></div>
   <div class="text-right">h<span class="d-none d-lg-inline">it</span></div>
   <div class="text-right">d<span class="d-none d-lg-inline">ouble</span></div>
  </td>
EOF
  
  for upcard in `seq 2 9` T A; do
  
   if [ "$upcard" = "T" ]; then
     upcard_n=10
   elif [ "$upcard" = "A" ]; then
     upcard_n=1
   else
     upcard_n=$(($upcard))
   fi
 
   n=1000    # start with n hands
   best="x"  # x means don't know what to so, so play
   
   while [ "${best}" = "x" ]; do
    # tell the user which combination we are trying and how many we will play
    echo -n ${t}${hand}-${upcard} \($card1 $card2\) "n="${n}
   
    for play in s d h; do
     
     # start with options.ini as a template and add some custom stuff
     cp options.ini libreblackjack.ini
     cat << EOF >> libreblackjack.ini
hands = ${n}
dealer2player = internal
arranged_cards = ${card1} $((${upcard_n} + 13)) $((${card2} + 26))
yaml_report = ${t}${hand}-${upcard}-${play}.yaml
#log = ${t}${hand}-${upcard}-${play}.log
EOF
 
     # read the current strategy
     while read w p2 p3 p4 p5 p6 p7 p8 p9 pT pA; do
      # w already has the "h" or the "s"
      strategy[${w},2]=$p2   
      strategy[${w},3]=$p3
      strategy[${w},4]=$p4    
      strategy[${w},5]=$p5    
      strategy[${w},6]=$p6    
      strategy[${w},7]=$p7    
      strategy[${w},8]=$p8    
      strategy[${w},9]=$p9    
      strategy[${w},T]=$pT    
      strategy[${w},A]=$pA    
     done < ${type}.txt
     
     # override the read strategy with the explicit play: s, d or h
     strategy[${t}${hand},${upcard}]=${play}
     
     # save the new (temporary) strategy
     rm -f ${type}.txt
     for h in `seq 20 -1 ${min[${type}]}`; do
      echo -n "${t}${h}  " >> ${type}.txt
      
      # extra space if h < 10
      if [ ${h} -lt 10 ]; then
       echo -n " " >> ${type}.txt
      fi 
      
      for u in `seq 2 9` T A; do
       echo -n "${strategy[${t}${h},${u}]}  " >> ${type}.txt
      done
      echo >> ${type}.txt
     done
     
     # debug, comment for production
     if [ "${debug}" != "0" ]; then
      cp ${type}.txt ${t}${hand}-${upcard}-${play}.str
     fi
    
     # ensamble the full bs.txt with no pairing
     cat hard.txt soft.txt pair-no.txt > bs.txt
    
     # play!
     ../../libreblackjack > /dev/null
    
     # evaluate the results
     ev[${t}${hand},${upcard},${play}]=`grep return ${t}${hand}-${upcard}-${play}.yaml | awk '{printf("%+g", $2)}'`
     error[${t}${hand},${upcard},${play}]=`grep error ${t}${hand}-${upcard}-${play}.yaml | awk '{printf("%.1g", $2)}'`
     
    done
   
    # choose the best one
    ev_s=`printf %g ${ev[${t}${hand},${upcard},s]}`
    ev_d=`printf %g ${ev[${t}${hand},${upcard},d]}`
    ev_h=`printf %g ${ev[${t}${hand},${upcard},h]}`
   
    
    if [ $n -le 999999 ]; then 
     # if we still have room, take into account errors
     error_s=${error[${t}${hand},${upcard},s]}
     error_d=${error[${t}${hand},${upcard},d]}
     error_h=${error[${t}${hand},${upcard},h]}
    else
     # instead of running infinite hands, above a threshold asume errors are zero
     error_s=0
     error_d=0
     error_h=0
    fi  
 
    echo -ne "\ts=${ev_s} (${error_s})"
    echo -ne "\td=${ev_d} (${error_d})"
    echo -ne "\th=${ev_h} (${error_h})"
   
    if   (( $(echo "${ev_s}-${error_s} > ${ev_d}+${error_d}" | bc -l) )) &&
         (( $(echo "${ev_s}-${error_s} > ${ev_h}+${error_h}" | bc -l) )); then
     best="s"
     echo -e "\tstand"
    elif (( $(echo "${ev_d}-${error_d} > ${ev_s}+${error_s}" | bc -l) )) &&
         (( $(echo "${ev_d}-${error_d} > ${ev_h}+${error_h}" | bc -l) )); then
     best="d"
     echo -e "\tdouble"
    elif (( $(echo "${ev_h}-${error_h} > ${ev_s}+${error_s}" | bc -l) )) &&
         (( $(echo "${ev_h}-${error_h} > ${ev_d}+${error_d}" | bc -l) )); then
     best="h"
     echo -e "\thit"
    else
     best="x"
     n=$((${n} * 10))
     echo -e "\tuncertain"
    fi
   done

   strategy[${t}${hand},${upcard}]=${best}
   
   
   
   echo "| ${t}${hand}-${upcard} | ${n} | ${ev_s} (${error_s}) | ${ev_h} (${error_h}) | ${ev_d} (${error_d}) |" >> table.md
   
   echo " <!-- ${upcard} -->" >> ${type}.html
   echo " <td>" >> ${type}.html
   echo ${ev_s} ${error_s} | awk -f cell.awk >> ${type}.html
   echo ${ev_h} ${error_h} | awk -f cell.awk >> ${type}.html
   echo ${ev_d} ${error_d} | awk -f cell.awk >> ${type}.html
   echo " </td>" >> ${type}.html
   
   
   # save the strategy again with the best strategy
   rm -f ${type}.txt
   for h in `seq 20 -1 ${min[${type}]}`; do
    echo -n "${t}${h}  " >> ${type}.txt
    
    # extra space if h < 10
    if [ ${h} -lt 10 ]; then
     echo -n " " >> ${type}.txt
    fi 
    
    for u in `seq 2 9` T A; do
     echo -n "${strategy[${t}${h},${u}]}  " >> ${type}.txt
    done
    
    echo >> ${type}.txt
    
   done
  done
  
  echo "</tr>" >> ${type}.html
  
 done
done


cat << EOF >> table.md
| ---- | ----- | ----- | ------ | --- |



| Hand | \$n\$ |  Yes  |  No  |
| ---- | ----- | ----- | ---- |
EOF

# --------------------------------------------------------------------
# pairs
type="pair"
t="p"
cp pair-no.txt pair.txt

for hand in A T `seq 9 -1 2`; do
 if [ "${hand}" = "A" ]; then
  pair=1
 elif [ "${hand}" = "T" ]; then
  pair=10
 else
  pair=$((${hand}))
 fi
  
 cat << EOF >> ${type}.html
 <tr>
  <td>${t}${hand}</td>
  <td>
   <div class="text-right">y<span class="d-none d-lg-inline">es</span></div>
   <div class="text-right">n<span class="d-none d-lg-inline">o</span></div>
  </td>
EOF
  
 for upcard in `seq 2 9` T A; do
  if [ "$upcard" = "T" ]; then
    upcard_n=10
  elif [ "$upcard" = "A" ]; then
    upcard_n=1
  else
    upcard_n=$(($upcard))
  fi
 
  n=1000    # start with n hands
  best="x"  # x means don't know what to so, so play
   
  while [ "${best}" = "x" ]; do
   # tell the user which combination we are trying and how many we will play
   echo -n ${t}${hand}-${upcard} "n="${n}
   
   for play in y n; do
     
    # start with options.ini as a template and add some custom stuff
    cp options.ini libreblackjack.ini
    cat << EOF >> libreblackjack.ini
hands = ${n}
dealer2player = internal
arranged_cards = ${pair} $((${upcard_n} + 13)) $((${pair} + 26))
yaml_report = ${t}${hand}-${upcard}-${play}.yaml
log = ${t}${hand}-${upcard}-${play}.log
EOF
 
    # read the current strategy
    while read w p2 p3 p4 p5 p6 p7 p8 p9 pT pA; do
     # w already has the "p"
     strategy[${w},2]=$p2   
     strategy[${w},3]=$p3
     strategy[${w},4]=$p4    
     strategy[${w},5]=$p5    
     strategy[${w},6]=$p6    
     strategy[${w},7]=$p7    
     strategy[${w},8]=$p8    
     strategy[${w},9]=$p9    
     strategy[${w},T]=$pT    
     strategy[${w},A]=$pA    
    done < ${type}.txt
     
    # override the read strategy with the explicit play: y or n
    strategy[${t}${hand},${upcard}]=${play}
     
    # save the new (temporary) strategy
    rm -f ${type}.txt
    for h in A T `seq 9 -1 2`; do
     echo -n "${t}${h}   " >> ${type}.txt
     for u in `seq 2 9` T A; do
      echo -n "${strategy[${t}${h},${u}]}  " >> ${type}.txt
     done
     echo >> ${type}.txt
    done
     
    if [ "${debug}" != "0" ]; then
     cp ${type}.txt ${t}${hand}-${upcard}-${play}.str
    fi  
    
    # ensamble the full bs.txt
    cat hard.txt soft.txt pair.txt > bs.txt
    
    # play!
    ../../libreblackjack > /dev/null
    
    # evaluate the results
    ev[${t}${hand},${upcard},${play}]=`grep return ${t}${hand}-${upcard}-${play}.yaml | awk '{printf("%+g", $2)}'`
    error[${t}${hand},${upcard},${play}]=`grep error ${t}${hand}-${upcard}-${play}.yaml | awk '{printf("%.1g", $2)}'`
    
   done
   
   # choose the best one
   ev_y=`printf %g ${ev[${t}${hand},${upcard},y]}`
   ev_n=`printf %g ${ev[${t}${hand},${upcard},n]}`
   
   if [ $n -le 999999 ]; then 
    # if we still have room, take into account errors
    error_y=${error[${t}${hand},${upcard},y]}
    error_n=${error[${t}${hand},${upcard},n]}
   else
    # instead of running infinite hands, above a threshold asume errors are zero
    error_y=0
    error_n=0
   fi  
 
   echo -ne "\ty=${ev_y} (${error_y})"
   echo -ne "\tn=${ev_n} (${error_n})"
   
   if   (( $(echo "${ev_y}-${error_y} > ${ev_n}+${error_n}" | bc -l) )); then
    best="y"
    echo -e "\tyes"
   elif (( $(echo "${ev_n}-${error_n} > ${ev_y}+${error_y}" | bc -l) )); then
    best="n"
    echo -e "\tno"
   else
    best="x"
    n=$((${n} * 10))
    echo -e "\tuncertain"
   fi
  done

  echo "| ${t}${hand}-${upcard} | ${n} | ${ev_y} (${error_y}) | ${ev_n} (${error_n}) |" >> table.md
  
  echo " <!-- ${upcard} -->" >> ${type}.html
  echo " <td>" >> ${type}.html
  echo ${ev_y} ${error_y} | awk -f cell.awk >> ${type}.html
  echo ${ev_n} ${error_n} | awk -f cell.awk >> ${type}.html
  echo " </td>" >> ${type}.html
  
  
  strategy[${t}${hand},${upcard}]=${best}
   
  # save the strategy again with the best strategy
  rm -f ${type}.txt
  for h in A T `seq 9 -1 2`; do
   echo -n "${t}${h}   " >> ${type}.txt
   for u in `seq 2 9` T A; do
    echo -n "${strategy[${t}${h},${u}]}  " >> ${type}.txt
   done
   echo >> ${type}.txt
  done
 done
done

echo "| ---- | ----- | ----- | ---- |" >> table.md

 
cat header.txt hard.txt header.txt soft.txt header.txt pair.txt > bs.txt
if [ "${debug}" == "0" ]; then
 rm -f *.yaml
 rm -f *.str
 rm -f *.log
fi