| flat_bet = 1 | flat_bet = 1 | ||||
| no_insurance = true | no_insurance = true | ||||
| delay = 0 | delay = 0 | ||||
| ; arranged_cards = 2,1,11 | ; arranged_cards = 2,1,11 | ||||
| ; rng_seed = 1 | ; rng_seed = 1 |
| # 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 |
| *.yaml | |||||
| *.str | |||||
| *.log | |||||
| hard.txt | |||||
| soft.txt | |||||
| pair.txt | |||||
| bs.txt | |||||
| *.html | |||||
| table.md | |||||
| blackjack.conf |
| 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 s s s s s | |||||
| h15 s s s s s s s s s s | |||||
| h14 s s s s s s s s s s | |||||
| h13 s s s s s s s s s s | |||||
| h12 s s s s s s s s s s | |||||
| h11 s s s s s s s s s s | |||||
| h10 s s s s s s s s s s | |||||
| h9 s s s s s s s s s s | |||||
| h8 s s s s s s s s s s | |||||
| h7 s s s s s s s s s s | |||||
| h6 s s s s s s s s s s | |||||
| h5 s s s s s s s s s s | |||||
| h4 s s s s s s s s s s |
| decks = -1 | |||||
| flat_bet = 1 | |||||
| no_insurance = true | |||||
| ; hit_soft_17 = 0 | |||||
| ; rng_seed = 1 |
| pA n n n n n n n n n n | |||||
| pT n n n n n n n n n n | |||||
| p9 n n n n n n n n n n | |||||
| p8 n n n n n n n n n n | |||||
| p7 n n n n n n n n n n | |||||
| p6 n n n n n n n n n n | |||||
| p5 n n n n n n n n n n | |||||
| p4 n n n n n n n n n n | |||||
| p3 n n n n n n n n n n | |||||
| p2 n n n n n n n n n n |
| #!/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 [ "x$upcard" = "xT" ]; then | |||||
| upcard_n=10 | |||||
| elif [ "x$upcard" = "xA" ]; then | |||||
| upcard_n=1 | |||||
| else | |||||
| upcard_n=$(($upcard)) | |||||
| fi | |||||
| n=10000 # 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.conf as a template and add some custom stuff | |||||
| cp options.conf blackjack.conf | |||||
| cat << EOF >> blackjack.conf | |||||
| hands = ${n} | |||||
| player = internal | |||||
| arranged_cards = ${card1}, $((${upcard_n} + 13)), $((${card2} + 26)) | |||||
| 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! | |||||
| blackjack | |||||
| # evaluate the results | |||||
| ev[${t}${hand},${upcard},${play}]=$(grep mean ${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 9999999 ]; 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 | |||||
| exit | |||||
| 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.conf as a template and add some custom stuff | |||||
| cp options.conf blackjack.conf | |||||
| cat << EOF >> blackjack.conf | |||||
| 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! | |||||
| blackjack > /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 | |||||
| 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 | |||||
| s20 s s s s s s s s s s | |||||
| s19 s s s s s s s s s s | |||||
| s18 s s s s s s s s s s | |||||
| s17 s s s s s s s s s s | |||||
| s16 s s s s s s s s s s | |||||
| s15 s s s s s s s s s s | |||||
| s14 s s s s s s s s s s | |||||
| s13 s s s s s s s s s s | |||||
| s12 s s s s s s s s s s | |||||
| #include <random> | #include <random> | ||||
| #include <cmath> | #include <cmath> | ||||
| #include "conf.h" | |||||
| namespace Libreblackjack { | namespace Libreblackjack { | ||||
| void shortversion(void); | void shortversion(void); | ||||
| void help(const char *); | void help(const char *); | ||||
| double variance = 0; | double variance = 0; | ||||
| } playerStats; | } playerStats; | ||||
| std::string report_file_path; | |||||
| int report_verbosity = 3; | |||||
| void updateMeanAndVariance(void); | void updateMeanAndVariance(void); | ||||
| private: | private: | ||||
| bool done = false; | bool done = false; | ||||
| std::list<reportItem> report; | std::list<reportItem> report; | ||||
| int reportVerbosity = 3; | |||||
| }; | }; | ||||
| Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(1, 52) { | Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(1, 52) { | ||||
| conf.set(&n_hands, {"n_hands", "hands"}); | |||||
| conf.set(&n_hands, {"n_hands", "hands"}); | |||||
| conf.set(&n_decks, {"decks", "n_decks"}); | conf.set(&n_decks, {"decks", "n_decks"}); | ||||
| conf.set(&max_bet, {"max_bet", "maxbet"}); | conf.set(&max_bet, {"max_bet", "maxbet"}); | ||||
| conf.set(&double_after_split, {"das", "double_after_split"}); | conf.set(&double_after_split, {"das", "double_after_split"}); | ||||
| conf.set(&blackjack_pays, {"blackjack_pays"}); | conf.set(&blackjack_pays, {"blackjack_pays"}); | ||||
| conf.set(&playerStats.bankroll, {"bankroll"}); | |||||
| conf.set(&playerStats.bankroll, {"bankroll", "initial_bankroll"}); | |||||
| // TODO: these should be go in the parent dealer class | |||||
| conf.set(&error_standard_deviations, {"error_standard_deviations"}); | |||||
| conf.set(report_file_path, {"report_file_path", "report"}); | |||||
| conf.set(&report_verbosity, {"report_verbosity", "report_level"}); | |||||
| conf.set(&number_of_burnt_cards, {"number_of_burnt_cards", "n_burnt_cards", "burnt_cards"}); | conf.set(&number_of_burnt_cards, {"number_of_burnt_cards", "n_burnt_cards", "burnt_cards"}); | ||||
| conf.set(&penetration, {"penetration"}); | conf.set(&penetration, {"penetration"}); |
| show_version = true; | show_version = true; | ||||
| break; | break; | ||||
| case 'c': | case 'c': | ||||
| std::cout << "custom conf " << optarg << std::endl; | |||||
| configFilePath = std::move(std::string(optarg)); | configFilePath = std::move(std::string(optarg)); | ||||
| explicitConfigFile = true; | explicitConfigFile = true; | ||||
| break; | break; | ||||
| // common settings to all dealers and players | // common settings to all dealers and players | ||||
| set(&max_incorrect_commands, {"max_incorrect_commands"}); | set(&max_incorrect_commands, {"max_incorrect_commands"}); | ||||
| set(&error_standard_deviations, {"error_standard_deviations"}); | |||||
| set(yaml_report_path, {"yaml_report", "yaml_report_path"}); | |||||
| return; | return; | ||||
| std::string getPlayerName(void) { return player; }; | std::string getPlayerName(void) { return player; }; | ||||
| unsigned int max_incorrect_commands = 10; | unsigned int max_incorrect_commands = 10; | ||||
| std::string yaml_report_path; | |||||
| std::string report_file_path; | |||||
| // TODO: | |||||
| unsigned int hands_per_char = false; | unsigned int hands_per_char = false; | ||||
| double error_standard_deviations; | |||||
| bool show_help = false; | bool show_help = false; | ||||
| bool show_version = false; | bool show_version = false; | ||||
| Internal::Internal(Configuration &conf) { | Internal::Internal(Configuration &conf) { | ||||
| hard.resize(21); // 4--20 | |||||
| soft.resize(21); // 12--20 | |||||
| pair.resize(21); // 2*(2--10) + 11 | |||||
| // fill everything with "none" | |||||
| hard.resize(21); | |||||
| soft.resize(21); | |||||
| pair.resize(21); | |||||
| for (int value = 0; value < 21; value++) { | for (int value = 0; value < 21; value++) { | ||||
| hard[value].resize(12); | hard[value].resize(12); | ||||
| pair[value][upcard] = Libreblackjack::PlayerActionTaken::None; | pair[value][upcard] = Libreblackjack::PlayerActionTaken::None; | ||||
| } | } | ||||
| } | } | ||||
| // TODO: read a default basic strategy | |||||
| // read in a skeleton of the basic strategy | |||||
| std::vector<std::string> default_hard(21); | |||||
| std::vector<std::string> default_soft(21); | |||||
| std::vector<std::string> default_pair(21); | |||||
| default_hard[20] = " ssssssssss"; | |||||
| default_hard[19] = " ssssssssss"; | |||||
| default_hard[18] = " ssssssssss"; | |||||
| default_hard[17] = " ssssssssss"; | |||||
| default_hard[16] = " ssssshhhsh"; | |||||
| default_hard[15] = " ssssshhhhh"; | |||||
| default_hard[14] = " ssssshhhhh"; | |||||
| default_hard[13] = " ssssshhhhh"; | |||||
| default_hard[12] = " hhssshhhhh"; | |||||
| default_hard[11] = " dddddddddh"; | |||||
| default_hard[10] = " ddddddddhd"; | |||||
| default_hard[9] = " hddddhhhhh"; | |||||
| default_hard[8] = " hhhhhhhhhh"; | |||||
| default_hard[7] = " hhhhhhhhhh"; | |||||
| default_hard[6] = " hhhhhhhhhh"; | |||||
| default_hard[5] = " hhhhhhhhhh"; | |||||
| default_hard[4] = " hhhhhhhhhh"; | |||||
| default_soft[20] = " ssssssssss"; | |||||
| default_soft[19] = " ssssdsssss"; | |||||
| default_soft[18] = " dddddsshhh"; | |||||
| default_soft[17] = " hddddhhhhh"; | |||||
| default_soft[16] = " hhdddhhhhh"; | |||||
| default_soft[15] = " hhdddhhhhh"; | |||||
| default_soft[14] = " hhhddhhhhh"; | |||||
| default_soft[13] = " hhhhdhhhhh"; | |||||
| default_soft[12] = " hhhhdhhhhh"; | |||||
| default_pair[20] = " nnnnnnnnnn"; | |||||
| default_pair[18] = " yyyyynyynn"; | |||||
| default_pair[16] = " yyyyyyyyyy"; | |||||
| default_pair[14] = " yyyyyynnnn"; | |||||
| default_pair[12] = " yyyyynnnnn"; | |||||
| default_pair[11] = " yyyyyyyyyy"; | |||||
| default_pair[10] = " nnnnnnnnnn"; | |||||
| default_pair[8] = " nnnyynnnnn"; | |||||
| default_pair[6] = " yyyyyynnnn"; | |||||
| default_pair[4] = " yyyyyynnnn"; | |||||
| for (int value = 4; value < 21; value++) { | |||||
| for (int upcard = 2; upcard < 12; upcard++) { | |||||
| if (default_hard[value] != "") { | |||||
| switch (default_hard[value][upcard]) { | |||||
| case 'h': | |||||
| hard[value][upcard] = Libreblackjack::PlayerActionTaken::Hit; | |||||
| break; | |||||
| case 's': | |||||
| hard[value][upcard] = Libreblackjack::PlayerActionTaken::Stand; | |||||
| break; | |||||
| case 'd': | |||||
| hard[value][upcard] = Libreblackjack::PlayerActionTaken::Double; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (default_soft[value] != "") { | |||||
| switch (default_soft[value][upcard]) { | |||||
| case 'h': | |||||
| soft[value][upcard] = Libreblackjack::PlayerActionTaken::Hit; | |||||
| break; | |||||
| case 's': | |||||
| soft[value][upcard] = Libreblackjack::PlayerActionTaken::Stand; | |||||
| break; | |||||
| case 'd': | |||||
| soft[value][upcard] = Libreblackjack::PlayerActionTaken::Double; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (default_pair[value] != "" && default_pair[value][upcard] == 'y') { | |||||
| pair[value][upcard] = Libreblackjack::PlayerActionTaken::Split; | |||||
| } | |||||
| } | |||||
| } | |||||
| // read the actual file | |||||
| conf.set(strategy_file_path, {"strategy_file_path", "strategy_file", "strategy"}); | |||||
| // std::ifstream is RAII, i.e. no need to call close | // std::ifstream is RAII, i.e. no need to call close | ||||
| std::ifstream fileStream("bs.txt"); | |||||
| std::ifstream fileStream(strategy_file_path); | |||||
| std::string line; | std::string line; | ||||
| std::string token; | std::string token; | ||||
| if (fileStream.is_open()) { | if (fileStream.is_open()) { | ||||
| while (getline(fileStream, line)) { | while (getline(fileStream, line)) { | ||||
| if (line[0] == '#' || line[0] == ';' || line.empty()) { | |||||
| if (line[0] == '#' || line[0] == ';' || line.empty() || line.find_first_not_of(" \t\r\n") == line.npos) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| private: | private: | ||||
| std::string strategy_file_path{"bs.txt"}; | |||||
| std::vector<std::vector<Libreblackjack::PlayerActionTaken>> pair; | std::vector<std::vector<Libreblackjack::PlayerActionTaken>> pair; | ||||
| std::vector<std::vector<Libreblackjack::PlayerActionTaken>> soft; | std::vector<std::vector<Libreblackjack::PlayerActionTaken>> soft; | ||||
| std::vector<std::vector<Libreblackjack::PlayerActionTaken>> hard; | std::vector<std::vector<Libreblackjack::PlayerActionTaken>> hard; |
| #include <iostream> | #include <iostream> | ||||
| #include "base.h" | |||||
| #include "conf.h" | #include "conf.h" | ||||
| #include "base.h" | |||||
| #include "blackjack.h" | #include "blackjack.h" | ||||
| #include "tty.h" | #include "tty.h" | ||||
| #include "stdinout.h" | #include "stdinout.h" |
| } | } | ||||
| int Dealer::writeReportYAML(void) { | int Dealer::writeReportYAML(void) { | ||||
| // FILE *file; | |||||
| // struct rusage usage; | |||||
| // double wall; | |||||
| // double ev, error; | |||||
| // int precision; | |||||
| // char format[32]; | |||||
| // if ((file = blackjack_conf.yaml_report) == NULL) { | |||||
| // file = stderr; | |||||
| // } | |||||
| FILE *out; | |||||
| if (report_file_path != "") { | |||||
| out = fopen(report_file_path.c_str(), "w"); | |||||
| } else { | |||||
| out = stderr; | |||||
| } | |||||
| // TODO: choose if comments with explanations are to be added | // TODO: choose if comments with explanations are to be added | ||||
| // TODO: choose verbosity level | |||||
| std::cerr << "---" << std::endl; | |||||
| fprintf(out, "---\n"); | |||||
| for (auto item : report) { | for (auto item : report) { | ||||
| if (item.level <= reportVerbosity) { | |||||
| std::cerr << item.key << ": "; | |||||
| fprintf(stderr, item.format.c_str(), item.value); | |||||
| std::cerr << std::endl; | |||||
| if (item.level <= report_verbosity) { | |||||
| fprintf(out, "%s: ", item.key.c_str()); | |||||
| fprintf(out, item.format.c_str(), item.value); | |||||
| fprintf(out, "\n"); | |||||
| } | } | ||||
| } | } | ||||
| fprintf(out, "...\n"); | |||||
| // std::cerr << "rules:" << std::endl; | |||||
| // std::cerr << " decks: " << decks << std::endl; | |||||
| // std::cerr << " hands: " << n_hands << std::endl; | |||||
| // std::cerr << " hit_soft_17: %d\n", | |||||
| // blackjack_conf.hit_soft_17); | |||||
| // std::cerr << " double_after_split: %d\n", | |||||
| // blackjack_conf.double_after_split); | |||||
| // std::cerr << " blackjack_pays: %g\n", | |||||
| // blackjack_conf.blackjack_pays); | |||||
| // std::cerr << " rng_seed: %d\n", blackjack_conf.rng_seed); | |||||
| // std::cerr << " number_of_burnt_cards: %d\n", | |||||
| // blackjack_conf.number_of_burnt_cards); | |||||
| // std::cerr << " no_negative_bankroll: %d\n", | |||||
| // blackjack_conf.no_negative_bankroll); | |||||
| // std::cerr << " max_bet: %d\n", blackjack_conf.max_bet); | |||||
| // if (blackjack_conf.decks > 0) | |||||
| // { | |||||
| // std::cerr << " penetration: %g\n", | |||||
| // blackjack_conf.penetration); | |||||
| // std::cerr << " penetration_sigma: %g\n", | |||||
| // blackjack_conf.penetration_sigma); | |||||
| // } | |||||
| // TODO | |||||
| // if (getrusage (RUSAGE_SELF, &usage) == 0) { | |||||
| // std::cerr << "cpu:" << std::endl; | |||||
| // std::cerr << " user: " + (usage.ru_utime.tv_sec + 1e-6 * usage.ru_utime.tv_usec) << std::endl; | |||||
| // std::cerr << " system: " + (usage.ru_stime.tv_sec + 1e-6 * usage.ru_stime.tv_usec) << std::endl; | |||||
| // measue final wall time | |||||
| // TODO: chrono | |||||
| // gettimeofday (&wall_time_final, NULL); | |||||
| // wall = (blackjack.wall_time_final.tv_sec - | |||||
| // blackjack.wall_time_initial.tv_sec) + | |||||
| // 1e-6 * (blackjack.wall_time_final.tv_usec - | |||||
| // blackjack.wall_time_initial.tv_usec); | |||||
| // std::cerr << " wall: %g\n", wall); | |||||
| // speed | |||||
| // std::cerr << " second_per_hand: %.1e\n", wall / blackjack.hand); | |||||
| // std::cerr << " hands_per_second: %.1e\n", blackjack.hand / wall); | |||||
| // } | |||||
| // std::cerr << "player: " << std::endl; | |||||
| // std::cerr << " wins: " ((double) player->wins / (double) player->number_of_hands)) << std::endl; | |||||
| // std::cerr << " pushes: %g\n", | |||||
| // (double) player->pushes / (double) player->number_of_hands); | |||||
| // std::cerr << " losses: %g\n", | |||||
| // (double) player->losses / (double) player->number_of_hands); | |||||
| // std::cerr << " dealer_blackjacks: %g\n", | |||||
| // (double) player->dealer_blackjacks / | |||||
| // (double) player->number_of_hands); | |||||
| // std::cerr << " player_blackjacks: %g\n", | |||||
| // (double) player->player_blackjacks / | |||||
| // (double) player->number_of_hands); | |||||
| // std::cerr << " dealer_busts: %g\n", | |||||
| // (double) player->dealer_busts / (double) player->number_of_hands); | |||||
| // std::cerr << " player_busts: %g\n", | |||||
| // (double) player->player_busts / (double) player->number_of_hands); | |||||
| // std::cerr << " doubled_hands: %g\n", | |||||
| // (double) player->doubled_hands / (double) player->number_of_hands); | |||||
| // std::cerr << " doubled_wins: %g\n", | |||||
| // (double) player->doubled_wins / (double) player->number_of_hands); | |||||
| // std::cerr << " insured_hands: %g\n", | |||||
| // (double) player->insured_hands / (double) player->number_of_hands); | |||||
| // std::cerr << " insured_wins: %g\n", | |||||
| // (double) player->insured_wins / (double) player->number_of_hands); | |||||
| // std::cerr << " number_of_hands: %g\n", | |||||
| // (double) player->number_of_hands); | |||||
| // std::cerr << " number_of_shuffles: %g\n", (double) blackjack.shuffles); | |||||
| // std::cerr << " total_money_waged: %g\n", | |||||
| // (double) player->total_money_waged); | |||||
| // std::cerr << " worst_bankroll: %g\n", | |||||
| // (double) player->worst_bankroll); | |||||
| // std::cerr << " final_bankroll: %g\n", (double) player->bankroll); | |||||
| // return is a keyword! | |||||
| // precision = (int) (ceil (-log10 (error))) - 2; | |||||
| // if (precision >= 0) { | |||||
| // snprintf (format, 32, ("%%+.%df ± %%.%df"), precision, precision); | |||||
| // } else { | |||||
| // snprintf (format, 32, ("%%+.0f ± %%.0f")); | |||||
| // } | |||||
| // std::cerr << " variance: % g\n", player->variance); | |||||
| // std::cerr << " deviation: % g\n", sqrt (player->variance)); | |||||
| // std::cerr << " error: % g\n", | |||||
| // sqrt (player->variance / (double) (blackjack.hand))); | |||||
| // std::cerr << " result: \"("), std::cerr << format, | |||||
| // 100.0 * ev, | |||||
| // 100 * error); | |||||
| // std::cerr << ") %%\"" << std::endl; | |||||
| std::cerr << "..." << std::endl; | |||||
| if (report_file_path != "") { | |||||
| fclose(out); | |||||
| } | |||||
| return 0; | return 0; | ||||
| } | } |