Over-21 Game Shell and eTCL Slot Calculator Demo Example , numerical analysis

This page is under development. Comments are welcome, but please load any comments in the comments section at the bottom of the page. Please include your wiki MONIKER in your comment with the same courtesy that I will give you. Its very hard to reply intelligibly without some background of the correspondent. Thanks,gold


gold Here is some eTCL starter code converting a slot calculator into the Over-21 game shell.

Odds for successive draws in a 52 card deck can be found for Blackjack as follows. Probability of drawing successive aces would be set probability_2_aces {(4 /52)* ( 3/ 51)}, 0.004524. In blackjack, a winning hand of two cards would be "ace & face ", where ace is counted as 11 and face as 10. Probability of drawing successive 2 cards for winning hand would be would be set probability_ace_&_face {(4/52)*(16/51)}, 0.02413. The dealer wins ties, so the dealer will win, even if a dream winning hand is dealt to both player and dealer. For example, four successive cards as first ace&face to the player and second ace&face to dealer would be set double_winner {(4/52)*(16/51)*(3/50)*(15/49)}, 0.0004432 . However, some dealers use multiple 2-8 decks and alternate dealing of cards to multiple players. The probability for multiple decks was set probability_multiple_decks (N1*4-S1+1)/(N1*52-S1+1)*(F1/(N1*52-S2+1))...). For example , winning hand for 2 decks was {(8/104)*(32/103)}, 0.02389. For 8 decks, the winning hand of ace&face would be {(32/416)*(128/415)}, 0.02372.

There are differences between the Over-21 calculator and the Blackjack game on the tables. Both hands of 2 cards each for dealer and player are shown in display of Over-21 calculator. Whereas on the tables, only one card of the hand must be shown until dealer calls or payoff. Also the Over-21 calculator is using random selection on 52 card deck, not pulling cards off deck like the tables. On the tables, the order of dealt cards to dealer and more than one player might makes a difference in computed probability. On the tables, the ability to call the end of the game, knowledge of played top cards, and winning all ties are considerable advantages to dealer.

General guidelines for computer games suggest the player should win one in five times to keep interest up. Right now, the Over-21 game shell is using the first deal of two cards to estimate win for the player. The winning conditions for the Over-21 game are 1) player score greater than dealer, 2) player score greater than ~17, and 3) player score less than 22 (not busted). On the tables, the dealer could win on the second or next deal, since the dealer calls or closes the game. Most of the tables use additional decks (2-8) and pull the dealt cards, which could be implemented in the program with concat or remove list element statements. The next steps for the Over-21 game shell should be tracking the win conditions for the dealer and a button for second deal.


Blackjack Probability

Probability of drawing successive 2 cards for winning hand in Blackjack would be would be set probability_ace_&_face {(4/52)*(16/51)}, 0.02413. In a similar manner, the probability of face_&_ace would be set probability_face_&_ace{(16/51)*(4/52)}, 0.02413. The probability of winning hand on first draw would be (p(ace_&_face)+ face_&_ace ),(0.02413+0.02413), 0.04826. Converting to fraction, (1/0.04826)= 20.721094, the odds of winning a Blackjack hand on first draw was rounding 1/21. Meaning, the player has the expectation of winning one in 21 games.

For two successive cards dealt from a 52 card deck and asking an extra draw in Blackjack, the breakpoint at 50% can be estimated for the probability of going busted. Suppose a player held a 16 from the first 2 card draw, then the player asking for an extra card dealt might thrown the hand over 21. Cards 6,7,8,9,10,J,Q,K=8 cards will raise the hand over 21, so the probability of the extra card would be 8*4 suits/ 52, converting 8*4/13*4, reduction 8/13,0.615, 61.5 percent. For a hand of 15 drawing an extra card, cards 7,8,9,10,J,Q,K=7 cards will bust. The probability of 15 and extra card causing bust would be 7*4 suits/ 52, converting 7*4/13*4, reduction 7/13,53.84 percent. A hand of 14 & extra card leads to cards 8,9,10,J,Q,K=6 cards for bust. The probability of 14 and extra card would be 6*4 suits/ 52, converting 6*4/13*4, reduction 6/13,46.15 percent. While the analysis does not account for cards pulled from a 52 card deck or multiple decks, the 50 percent breakpoint is between holding a hand of 14 and a hand of 16 for the extra card leading to player bust. The 50 percent breakpoint is why a player will often stand or hold at 16, figuring 16 as a probable win .The hold of 16 for the player can be used in the Over-21 game shell.


Pushbutton Operation

For testcases in a computer session, the eTCL calculator increments a new testcase number internally, eg. TC(1), TC(2) , TC(3) , TC(N). The testcase number is internal to the calculator and will not be printed until the report button is pushed for the current result numbers. The current result numbers will be cleared on the next Deal button. The command { calculate; reportx } or { calculate ; reportx; clearx } can be added or changed to report automatically

For the push buttons in the Over-21 game shell, the recommended procedure is push Testcase and fill frame to initialize the display, then push Deal. Deal displays the first 2 card hands for dealer and player, estimating the state of the game. The cards in Over-21 are picked randomly from a list of 52 cards, not pulled from the multiple decks like the tables. The face cards are counted as 10, the ace cards are counted as 11, and other cards 2-10 at face value. Where both hands total less than 16, the winner of the Over-21 game is unresolved or undeclared. If a player is 16 or higher integer over the other player (dealer), that is considered a probable win, until resolved in the next round. A clear winner is a player that scores 21 or watches the other player bust, go over 21. The internal logic is set so that dealer wins all ties.

If additional deals are necessary, push Extra_Deal to give each player one card. The extra cards are initialized at zero in the first deal and are not picked or reported until the Extra-Deal button is pushed for the Nth time. Holds are implemented foe the player only. Without hold, it is possible for both players to go over 21 on a deal. Normally at the tables, the dealer would hold ( no extra card ) on the near underside of 21 and not go out of the game with the player. Recommend pushing Report after Deal or Extra_Deal to preserve a game history, especially when multiple rounds of extra deals are played. Report allows copy and paste from console to a texteditor.

The Hold_Extra command places an experimental and one time hold of >16 on the extra deal for the player. The hold of 16 effects players hands of 16 and higher, standing or holding for one deal. Hold_Extra will have no effect on hands lower than 16 and is not used for the first deal (hold of logic 0). The hold is withdrawn on the player with the execution of the extra deal and the rule is one push, one time of hold. Just for grins, the card picked during the player hold is filed in the Report, but not added to player score. Placing simultaneous experimental holds on both dealer and player was tried, but the program logic kept locking up (and not sure how to evaluate a round where both parties pass).

The Clear command essentially nulls the Over-21 display to zeros and resets the initial variables, mostly to zero. Pushing a testcase refreshs the display with some new cards, but does not reset the internal testcase series etc.

Though rare, some Over-21 games lasted 4 or 5 deals in the testing, where small cards were picked often in the early deals. Some tables honor a special rule that a player staying in the game for 5 deals is declared a winner. Additional Nth Extra-Deals are possible until both the dealer and player exceed 21, causing end of game reported as game state 505. Since this program is under test, after the end of game (505) recommend push Report, Clear, Testcase, and Deal to be sure all variables are saved and then cleared to restart the sequence. The best hint is that if the player is a probable winner on the first deal or reaches 21, take the money and run...staying at the tables for extra deals will not make you rich.


value Over-21 game_status
0 unresolved game or no winner declared.
1 player is probable winner, lacking extra deal.
2 dealer is busted, player is declared winner.
3 player has 21, player is declared winner.
4 dealer probable winner, lacking extra deal.
5 player is busted, dealer is declared winner.
6 dealer has 21, dealer is declared winner.
505 game over, both dealer and player busted.

Pseudocode and Equations

dealer and player dealt two initial cards
dealer wins all ties
ace card is 1 or 11
all face cards are 10
all ten cards are 10
sum of cards > 21 set lose condition (bust)
sum of dealer >sum of player =< 21, player in winner state  
sum of player = >sum of dealer =< 21, dealer in winner state  
player or dealer may sit turn, called hold condition 
player has 5 cards not over 21 is winner (rare)
Player and dealer must show one card only, until close or payout.
Normally dealer holds at 16 and above
Normally player wants extra deal if hand <16
Double down, optional if player dealt two cards of same number, but not same suit.
Player on double down must put double money up for two  hands. 

Testcases Section

In planning any software, it is advisable to gather a number of testcases to check the results of the program. The math for the testcases can be checked by pasting statements in the TCL console. Aside from the TCL calculator display, when one presses the report button on the calculator, one will have console show access to the capacity functions (subroutines).

Testcase 1

table 1printed in tcl wiki format
quantitydealer first card value comment, if any
testcase number1
2 :dealer first card
7 :dealer second card
10 :player first card
11 :player second card
9.0 :dealer score
21.0 :player score
0.0 :player need card dealt? <0 or 1 >
1. :winner declared <0 or 1 >

Testcase 2

table 2printed in tcl wiki format
quantitydealer first card value comment, if any
testcase number2
7 :dealer first card
10 :dealer second card
5 :player first card
6 :player second card
17.0 :dealer score
11.0 :player score
1.0 :player need card dealt? <0 or 1 >
0. :winner declared <0 or 1 >

Testcase 3

table 3printed in tcl wiki format
quantitydealer first card value comment, if any
testcase number3
J :dealer first card
5 :dealer second card
8 :player first card
9 :player second card
15.0 :dealer score
17.0 :player score
0.0 :player need card dealt? <0 or 1 >
0. :winner declared <0 or 1 >

Testcase 4

For a system of dealing 2 cards from a 52 card deck, the sample space would be factorial(52)/((factorial(2)*factorial(52-2)) or 52!/(2!*50!), reduction 1326. Some generic expressions can be developed for the Over-21 coding. The factorial procedure used below was posted by Suchenworth. Most of these TCL expressions can be pasted into the console window and square brackets may be text substituted from wiki format.

If one uses a reference to probability of getting Blackjack on a single deck, then the advantage to the house of multiple decks can be estimated for two card draw. Using the prob_win_21 formula, the win probability for a series of multiple decks ( 2 3 4 5 6 7 8 9 10 ... infinity) can be subtracted from the probability using a single deck. A small console program can be written using the foreach statement.

  % proc f n { expr {$n < 2 ? 1 : $n * [f [incr n -1]]} } #RS
  % set space [ expr {  [f 52]/[f 2]/[f 50]} ] ;# generic TCL
  answer% 1326
  % set space_ace [ expr {  [f 4]/[f 1]/[f 3]} ] ;# generic TCL
  answer%  4
  set space_face [ expr {  [f 16]/[f 1]/[f 15]} ] ;# generic TCL
  answer% 16
  set prob_win_21 [ expr { (4./1326.)+(16./1326.)  } ] # using expr
  answer% 0.04826
  set prob_win_21   [+ [/ 4. 1326.] [/ 16. 1326.]   ] #using mathops
  answer% 0.04826
  set prob_win_21   [+ [/ $space_ace $space] [/ $space_face $space]   ]
  answer% 0.04826
  if {sum of cards == 21}{ set winner state (blackjack) }
  if {16 > sum of cards < 21} {set probable winner state} 
trial black box flow.
player> Testcase> Deal> Hold_Extra>Extra_Deal>Report>Hold_Extra>Extra_Deal>Report>End (505)>cut&paste game for later study>Clearx  
Pop routine on flow list should automate button commands.
player> game> multiple game states> cashier> states are multiple during game, cashier  pays one time > list of payouts and collection
cashier's list < {0.001 unresolved} {2 +$pay} {3.001 +$pay} {4 no_pay }{5  -$pay} {6  -$pay} {7 wash_out} {8 wash_out}>

Screenshots Section

figure 1.


References:

  • Blackjack Game Project Report - Andrew Thomas BSc (Hons)
  • New Blackjack Odds By Jeff Haney, article discussion of 6/5 payoffs

Appendix Code

appendix TCL programs and scripts

        # pretty print from autoindent and ased editor
        # Over-21 Game Shell calculator
        # written on Windows XP on eTCL
        # working under TCL version 8.5.6 and eTCL 1.0.1
        # gold on TCL WIKI, 15oct2014
        package require Tk
        namespace path {::tcl::mathop ::tcl::mathfunc}
        frame .frame -relief flat -bg aquamarine4
        pack .frame -side top -fill y -anchor center
        global hold_status hold_keeper deal_number
        global stake1 stake2 payout1 payout2
        set names {{} {dealer first card:} }
        lappend names {dealer second card:}
        lappend names {player first card: }
        lappend names {player second card :}
        lappend names {dealer score :}
        lappend names {player score : }
        lappend names {player need card dealt? < 0 or 1 > : }
        lappend names {game status < unr=0,1,2,3,4,5,6,end=505 >:}
        foreach i {1 2 3 4 5 6 7 8} {
            label .frame.label$i -text [lindex $names $i] -anchor e
            entry .frame.entry$i -width 35 -textvariable side$i
            grid .frame.label$i .frame.entry$i -sticky ew -pady 2 -padx 1 }
        proc about {} {
            set msg "Calculator for Over 21 Game Shell
            from TCL WIKI,
            written on eTCL 
            value > game_status
            0 >unresolved game or no winner declared.
            1 >player is probable winner, lacking extra deal.
            2 >dealer is busted, player is declared winner.
            3 >player has 21, player is declared winner.
            4 >dealer probable winner, lacking extra deal.
            5 >player is busted, dealer is declared winner.
            6 >dealer has 21, dealer is declared winner.
          505 >game over, previous deal had declared winner or
              both dealer and player over 21 value , both busted.
              Note: Normally both players receive one card on extra deal.
              Extra_Hold is pushed for one time hold >16 on player.
              Player can be probable winner on first deal
              and player can lose on extra deal, like tables. " 
            tk_messageBox -title "About" -message $msg }       
        proc lpick L {lindex $L [expr int(rand()*[llength $L])];}
        proc swapx { text } {
            #set text [string map [list $item $replacewith] $text] #RS
             set text [string map [list "A" "11.0"] $text] 
             set text [string map [list "J" "10.0"] $text] 
             set text [string map [list "Q" "10.0"] $text] 
             set text [string map [list "K" "10.0"] $text]
             return $text    }              
        proc cashier { } {
             global side1 side2 side3 side4 side5
             global side6 side7 side8  
             global stake1 stake2 payout1 payout2 fired1 fired2
             global testcase_number  deal_number
             puts " &|test payout for status | $side8 | | need 6 iffys |&" 
             puts " &| original stake |  1000 solar credits| | |& "
             set bet_norm 100.
             set payout1  0.
             set payout2 0.
             if { $side8 == 505.  ||  $side8 > 500. }  { return $payout2 }
             if { $fired1 == 1  ||  $fired2 == 1 }  { return $payout2 }
             if { $side8 == 2. ||  $side8 == 3. }  { set payout1 [* $bet_norm [/ 3. 2.  ] 1. ]  }
             if { $side8 == 2. ||  $side8 == 3. }  { set payout2 [* $bet_norm [/ 6. 5.  ] 1. ]  }
             if { $side8 == 5. ||  $side8 == 6. }  { set payout1 [*  $bet_norm -1. ] }
             if { $side8 == 5. ||  $side8 == 6. }  { set payout2 [*  $bet_norm -1. ] }
             if { $side8 == 2. ||  $side8 == 3. }  { set fired1 1 }
             if { $side8 == 5. ||  $side8 == 6. }  { set fired2 1 }
             set stake1 [+ $stake1 $payout1 ]
             set stake2 [+ $stake2 $payout2 ]
             puts " &|test payout1 | $payout1 | | |& "
             puts " &|test payout2 | $payout2 | | |& "
             puts " &|test stake1 at 3/2 table| $stake1 | current payout | $payout1 |& "
             puts " &|test stake2 at 6/5 table| $stake2 | current payout | $payout2 |& "
             return $payout2
             }            
         proc winner_judge {  } {  
            global side1 side2 side3 side4 side5
            global side6 side7 side8 
            global stake1 stake2 payout1 payout2 
            global testcase_number  deal_number           
            puts " dealer $side5 against player $side6 "
            puts "logic values p>16 [ expr { $side6 > 16. } ]"
            puts "logic values  p<16  [ expr { $side6 < 16. } ]  "
            puts "logic values p>d [ expr { $side6 > $side5 } ] "
            puts "logic values p>17 [ expr { $side6 > 17. } ] "
            puts "logic values p<22  [ expr { $side6 < 22. } ]  "
            if { $side6 > 16. }  { set side7 0. } 
            if { $side6 < 16. }  { set side7 1. }              
            if { $side6 > $side5 && $side6 < 22. &&  $side6 > 17. }  { set side8 1. } 
            if { $side6 < 22.  &&  $side5 > 21. }  { set side8 2. }
            if { $side6 == 21.  &&  $side6 > $side5 }  { set side8 3. }
            if { $side5 > 16.  &&  $side5 > $side6 &&  $side5 < 22. }  { set side8 4. }
            if { $side6 > 21.  &&  $side5 < 22. }  { set side8 5. }
            if { $side5 == 21.  &&  $side5 > $side6 }  { set side8 6. }
            if { $side5 == 21.  &&  $side6 == 21. }  { set side8 6. }
            if { $side6 > 21.  &&  $side5 > 21. }  { set side8 505. }
            if { $side6 > 35.  ||  $side5 > 35. }  { set side8 505. }
            set stake5 [ cashier ]
            return  5. } 
        proc calculate {     } {
            global answer2
            global side1 side2 side3 side4 side5
            global side6 side7 side8
            global  list_cards list_values
            global dealer_1extra_card player_1extra_card
            global stake1 stake2 payout1 payout2 fired1 fired2
            global hold_status hold_keeper
            global testcase_number deal_number
            incr testcase_number 
            set deal_number 0
            incr deal_number
            set cards { 2 3 4 5 6 7 8 9 10 J Q K A } 
            set list_values { 2 3 4 5 6 7 8 9 10 10 10 10 11 }
            set list_cards [ concat $cards $cards $cards $cards ]
            set dealer_1extra_card 0
            set player_1extra_card 0 
            set hold_status 0
            set hold_keeper 0
            if { $testcase_number == 1  &&  $deal_number == 1 }  { set stake1 1000. }
            if { $testcase_number == 1  &&  $deal_number == 1 }  { set stake2 1000. }
            set payout1 0.
            set payout2 0.
            set fired1 0.
            set fired2 0. 
            puts "lists cards in current deck"
            puts "$list_cards"
            set side7 0.0
            set side8 0.0
            set side1  [ lpick $list_cards ]
            set side2  [ lpick $list_cards ]
            set side3  [ lpick $list_cards ]
            set side4  [ lpick $list_cards ]
            set side5 [+  [swapx $side1 ] [swapx $side2 ] ]
            set side6 [+  [swapx $side3 ] [swapx $side4 ] ]
            set side5 [* $side5 1. ]
            set side6 [* $side6 1. ]
            set winner [ winner_judge  ] 
            puts "  first deal activated " 
                                       }
            proc second_deal {     } {
            global side1 side2 side3 side4 side5
            global side6 side7 side8
            global dealer_1extra_card player_1extra_card
            global stake1 stake2 payout1 payout2
            global hold_status hold_keeper deal_number
            global list_cards list_values
            global testcase_number
            #incr testcase_number
            incr deal_number
            set dealer_1extra_card  [ lpick $list_cards ]
            set player_1extra_card  [ lpick $list_cards ] 
            set side5 [+ $side5 [ swapx $dealer_1extra_card ] ]
            if { $hold_status < 1 || $side5 < $hold_status } { 
            set side6 [+ $side6 [ swapx $player_1extra_card ] ] }
            set winner  [ winner_judge  ] 
            puts " second or extra deal activated, dealing one extra card "
            puts " for dealer,  $dealer_1extra_card valued at [ swapx $dealer_1extra_card ]  "
            puts " for player,  $player_1extra_card valued at [ swapx $player_1extra_card ]  "
             }
             proc fillup {aa bb cc dd ee ff gg hh} {
            .frame.entry1 insert 0 "$aa"
            .frame.entry2 insert 0 "$bb"
            .frame.entry3 insert 0 "$cc"
            .frame.entry4 insert 0 "$dd"
            .frame.entry5 insert 0 "$ee"
            .frame.entry6 insert 0 "$ff" 
            .frame.entry7 insert 0 "$gg"
            .frame.entry8 insert 0 "$hh" 
             }
        proc clearx {} {
             global side1 side2 side3 side4 side5
             global side6 side7 side8  
             global stake1 stake2 payout1 payout2 fired1 fired2
             global testcase_number  deal_number
             global hold_status hold_keeper
             global dealer_1extra_card player_1extra_card
             set payout1 0.
             set payout2 0.
             set testcase_number 0
             set deal_number 0
             set fired1 0
             set fired2 0
             set dealer_1extra_card 0
             set player_1extra_card 0
             set hold_status 0
             set hold_keeper 0
            foreach i {1 2 3 4 5 6 7 8 } {
                .frame.entry$i delete 0 end } 
                       }
        proc reportx {} {
            global side1 side2 side3 side4 side5
            global side6 side7 side8 
            global dealer_1extra_card player_1extra_card
            global hold_status hold_keeper
            global stake1 stake2 payout1 payout2
            global testcase_number deal_number
            console show;
            puts "%|table $testcase_number|printed in| tcl wiki format|% "
            puts "&|value| quanity | comment, if any|& "
            puts "&|$testcase_number|testcase number| |&"
            puts "&| $deal_number :|deal_number |&"           
            puts "&| $side1 :|dealer first card|   |&"
            puts "&| $side2 :|dealer second card| |& "
            puts "&| $dealer_1extra_card :|dealer extra card| if any Nth round|& "
            puts "&| $side3 :|player first card| |& "
            puts "&| $side4 :|player second card  |  |&"
            puts "&| $player_1extra_card :|player extra card  | if any Nth round, not added under hold|&"
            puts "&| $hold_keeper :|hold status >16 on player| one time hold,if any Nth round |& "
            puts "&| $side5 :|dealer score |  |&"
            puts "&| $side6 :|player score |  |&"
            puts "&| $payout1 :|table payout at 3:2 | if dealer calls|&"
            puts "&| $payout2 :|table payout at 6:5  | if dealer calls|&"
            puts "&| $side7 :|player need card dealt? <0 or 1 >|  |&"
            puts "&| $side8 :|game status < unr=0,1,2,3,4,5,6,end=505 > |  |&"
         }
        frame .buttons -bg aquamarine4
        ::ttk::button .calculator -text "Deal" -command { fillup 0 0 0 0 0 0 0 0 ;calculate   }
        ::ttk::button .calculator2 -text "Extra_Deal" -command { second_deal ; 
                set hold_keeper $hold_status; set hold_status 0 ; }
        ::ttk::button .calculator3 -text "Hold_Extra" -command { set hold_status 16  }
        ::ttk::button .test2 -text "Testcase1" -command {clearx;fillup 1.0 7.0 10.0 10.0   8.  20.0 0. 0.}
        ::ttk::button .test3 -text "Testcase2" -command {clearx;fillup 5.0 10.0 2.0 8.0   15.  10. 1. 0. }
        ::ttk::button .test4 -text "Testcase3" -command {clearx;fillup 4.00 5.0 5.0 6.0   9.0  11.0  1.0 0. }
        ::ttk::button .clearallx -text clear -command {clearx;  fillup 0 0 0 0 0 0 0 0 }
        ::ttk::button .about -text about -command about
        ::ttk::button .cons -text report -command { reportx }
        ::ttk::button .exit -text exit -command {exit}
        pack .calculator  -in .buttons -side top -padx 10 -pady 5
        pack  .clearallx .cons .about .exit .test4 .test3 .test2  .calculator3 .calculator2  -side bottom -in .buttons
        grid .frame .buttons -sticky ns -pady {0 10}
        . configure -background aquamarine4 -highlightcolor brown -relief raised -border 30
        wm title . "Over-21 Game Shell Calculator "
 

Console program for list of cards


gold This page is copyrighted under the TCL/TK license terms, this license .

Comments Section

Please place any comments here, Thanks.