Blackjack Bust Calculator

12

Blackjack, also known as twenty-one, is a comparing card game between yourself and a dealer, where each player in turn competes against the dealer, but players do not play against each other.

Play goes as follows, the dealer deals you a card. The dealer then deals them-self a card, face down. The dealer then deals you another card. Then finally, the dealer deals them-self a card, face-up.

Challenge

Your challenge is to write a program (or function) that when run (or called), outputs (or returns) the probability that the next card the dealer gives you will make you bust, which means the cumulative score of cards in your hand after the dealer gives you another card is over 21.

Input

The three visible cards in play. They are the two cards you have in your hand, and the one face card you can see in the dealers hand. This can be in whatever format you find suitable for your application.

There are 52 cards in a deck(4 of each of the cards below). The value of the cards are as follows:

Symbol(Case Insensitive)  Name     Value
2                         Two      2
3                         Three    3
4                         Four     4
5                         Five     5
6                         Six      6
7                         Seven    7
8                         Eight    8
9                         Nine     9
T                         Ten      10
J                         Jack     10
Q                         Queen    10
K                         King     10
A or 1                    Ace      1 

In Blackjack, an ace can count as 1 or 11. In our challenge, only count it as a 1

Output

The probability, in a ratio or percentage format, that the next card we draw will make us bust.

You may output the percentage, the fraction, or just the numerator of the fraction.

Examples

In this example, the first two cards are in our hand, the third card is the dealers visible card

 Input          ->       Output

 A 2 Q          ->       0.00%  or  0/49 or 0
 A 2 3          ->       0.00%  or  0/49 or 0
 T T T          ->       91.84% or 45/49 or 91.84 
 T J K          ->       91.84% or 45/49 or 45
 9 7 3          ->       61.22% or 30/49 ...
 9 7 Q          ->       59.18% or 29/49 ...

Rules

Standard loopholes are not allowed.

This is , so the shortest code in bytes for each language wins!

DevelopingDeveloper

Posted 2018-05-07T15:43:30.910

Reputation: 1 415

2Are we allowed to take the ace as 1 and face cards as 10s, or would that be stretching the input format too far? – None – 2018-05-07T15:52:29.870

So, we can take face cards as 10? – wastl – 2018-05-07T15:54:23.110

@Mnemonic Taking the Ace as 1 is fine. – DevelopingDeveloper – 2018-05-07T15:55:42.657

@Mnemonic @wastl The inputs are only one character, so I am going to have to say no. Take them as QJKT. – DevelopingDeveloper – 2018-05-07T15:56:09.437

Can I take them as lowercase letters? – None – 2018-05-07T15:56:34.047

@Mnemonic Yes that is fine. – DevelopingDeveloper – 2018-05-07T15:57:02.673

1@Arnauld Thank you for the catch. I updated the ratios but not the probabilities. As for your output question yest that is fine. You do not have to add the /49 on each answer. – DevelopingDeveloper – 2018-05-07T18:03:27.483

1"T J K -> 91.84% or 45/49 or 45 or etc..." - so we may simply output the numerator? If so could you state it in the text? – Jonathan Allan – 2018-05-07T18:37:16.030

1@JonathanAllan Updated – DevelopingDeveloper – 2018-05-07T19:47:40.970

Answers

7

Jelly,  26  24 bytes

O%48«⁵µ13R«⁵ẋ4œ-+ṖS$>21S

A monadic link accepting a list of characters (using either the lower-case option OR the upper-case option with 1 for A) which returns the numerator (the number of 49ths) in [0,49].

Try it online! Or see the test-suite

How?

Note that by using lower-case the minimum of 10 and the ordinals modulo by 48 gives the card values. The same holds for upper-case T, J, Q, K and 1 for an ace, as shown on the right (but an upper-case A does not work):

     card:   a   2   3   4   5   6   7   8   9   t   j   q   k   |   1   T   J   Q   K
  ordinal:  97  50  51  52  53  54  55  56  57 116 106 113 107   |  49  84  74  81  75
   mod 48:   1   2   3   4   5   6   7   8   9  20  10  17  11   |   1  36  26  33  27
min(_,10):   1   2   3   4   5   6   7   8   9  10  10  10  10   |   1  10  10  10  10

O%48«⁵µ13R«⁵ẋ4œ-+ṖS$>21S - Link: list of characters   e.g. "q3a"
O                        - ordinals (of the input list)    [113, 51, 97]
 %48                     - modulo by 48                    [17,3,1]
     ⁵                   - ten
    «                    - minimum                         [10,3,1]
      µ                  - start a new monadic chain
       13R               - range of 13                     [1,2,3,4,5,6,7,8,9,10,11,12,13]
           ⁵             - ten                             10
          «              - minimum                         [1,2,3,4,5,6,7,8,9,10,10,10,10]
            ẋ4           - repeat four times               [1,2,3,4,5,6,7,8,9,10,10,10,10,1,2,3,4,5,6,7,8,9,10,10,10,10,1,2,3,4,5,6,7,8,9,10,10,10,10,1,2,3,4,5,6,7,8,9,10,10,10,10]
              œ-         - multi-set difference            [1,2,3,4,5,6,7,8,9,10,10,10,10,1,2,3,4,5,6,7,8,9,10,10,10,10,1,2,3,4,5,6,7,8,9,10,10,10,10  ,2  ,4,5,6,7,8,9   ,10,10,10]
                   $     - last two links as a monad:
                 Ṗ       -   pop                           [10,3]
                  S      -   sum                           13
                +        - add (vectorises)                [14,15,16,17,18,19,20,21,22,23,23,23,23,14,15,16,17,18,19,20,21,22,23,23,23,23,14,15,16,17,18,19,20,21,22,23,23,23,23,15,17,18,19,20,21,22,23,23,23]
                    >21  - greater than 21?                [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1]
                       S - sum                             19

Jonathan Allan

Posted 2018-05-07T15:43:30.910

Reputation: 67 804

*temptation to flat-out steal the mod-48 technology intensifies* – Magic Octopus Urn – 2018-05-09T22:23:43.110

If I do end up making an answer using mod-48 I'm bountying you 200 for the epic observation. – Magic Octopus Urn – 2018-05-09T22:24:32.250

4

JavaScript (ES6), 73 62 bytes

Takes input as an array of 3 characters with 1 for aces. Returns the integer X representing the probability X/49 to be busted.

a=>([b,c]=a.map(v=>v*4||40)).map(n=>b-=n+b>52,b+=c-32)|b>12&&b

Try it online!

Exhaustive test

The golfed formula is not very intuitive. So, the easiest way to prove its consistency is probably to just compare all possible outputs against the ones provided by a basic ungolfed implementation:

g = a => {
  deck = [...'123456789TJQK'.repeat(4)];
  a.forEach(card => deck.splice(deck.indexOf(card), 1));

  return deck.filter(card =>
    (+a[0] || 10) +
    (+a[1] || 10) +
    (+card || 10) > 21
  ).length;
}

Try it online!

Arnauld

Posted 2018-05-07T15:43:30.910

Reputation: 111 334

What does .map(n=>b-=n+b>52,b+=c-32) do in general? I'm not too familiar with JS's .map and trying to understand what the comma does here.. Initially I though it's a shorter variant of .map(n=>{b-=n+b>52;b+=c-32}) or something.. I know a=>([b,c]=a.map(v=>v*4||40)) converts ['1','2','Q'] to [ 4, 8, 40 ], and then it loops over these three values, where b is the first value, and c is the second (if I understand correctly). But I'm a bit confused about .map(n=>b+=(n+b<53)-1,b+=c-32) (if the first b-= is changed to b+=) vs .map(n=>b+=(n+b<53)-33+c).. – Kevin Cruijssen – 2018-05-08T11:58:34.037

Hmm, or is it indeed b = first value, c = second value in [4, 8, 40], and the b-=n+b>52 modifies c as well if it's the second iteration? In which case combining both b-= and b+= into a single b+= (or b-=) won't work because of that? – Kevin Cruijssen – 2018-05-08T12:00:25.853

1

@KevinCruijssen b+=c-32 is an (unused) parameter of map() and is evaluated only once before the first iteration. n=>b-=n+b>52 is the callback function (the 1st parameter of map()) and is called on each iteration. Technically, map() does accept a 2nd parameter (called thisArg), but this is irrelevant here: we just want this piece of code to be executed before the loop begins.

– Arnauld – 2018-05-08T12:06:52.797

1

@KevinCruijssen Here is some code showing what's going on.

– Arnauld – 2018-05-08T12:22:21.693

Ah ok, now it all makes sense. Thanks! – Kevin Cruijssen – 2018-05-08T12:24:47.467

2

Pyth, 35 bytes

Jm?}dGTsdQclf>T-21sPJ.-*4+ST*3]TJ49

Takes input as a list of characters (or as a string).
Try it here

Explanation

Jm?}dGTsdQclf>T-21sPJ.-*4+ST*3]TJ49
Jm?}dGTsdQ                            Convert each input to the appropriate number.
                     .-*4+ST*3]TJ     Remove each from the deck.
           lf>T-21sPJ                 Count how many remaining cards bust.
          c                      49   Get the probability.

user48543

Posted 2018-05-07T15:43:30.910

Reputation:

1

Perl 5, 115 bytes

map{//;$k{$_}=4-grep$' eq$_,@F}1..9,T,J,Q,K;map{s/\D/10/}@F;$_=grep{$F[0]+$F[1]+$_>21}map{(s/\D/10/r)x$k{$_}}keys%k

Try it online!

Xcali

Posted 2018-05-07T15:43:30.910

Reputation: 7 671

1

Python 2, 97 96 bytes

def f(s):C=[min(int(c,36),10)for c in s];D=C[0]+C[1];return(4*D-35+sum(v+D<22for v in C))*(D>11)

Try it online!

Takes a 3-character string as input, with '1' being used as Ace. Returns the numerator.

Chas Brown

Posted 2018-05-07T15:43:30.910

Reputation: 8 959

1

Java 8, 109 bytes

a->{int r=3;for(;r-->0;a[r]=a[r]<59?a[r]*4-192:40);r=a[0]+a[1]-32;for(int v:a)r-=v+r>52?1:0;return r>12?r:0;}

Port of @Arnauld's JavaScript (ES6) answer.
Input as character-array with three values, Aces as '1'; output is the probability p in p/49.

Try it online.

Explanation:

a->{                   // Method with integer-array as parameter and integer return-type
  int r=3;for(;r-->0;  //  Loop over the array
    a[r]=a[r]<59?      //   If the current item is a digit:
          a[r]*4-192   //    Multiply it by 4
         :             //   Else:
          40);         //    Change it to 40
  r=a[0]+a[1]-32;      //  Set `r` to the first value, plus the second value, minus 32
  for(int v:a)         //  Loop over the now modified array again
    r-=v+r>52?         //   If the current value plus `r` is larger than 52
        1              //    Decrease the result-integer by 1
       :0;             //   Else: Leave the result-integer the same
  return r>12?         //  If the result-integer is larger than 12
          r            //   Return the result-integer
         :             //  Else:
          0;}          //   Return 0

Kevin Cruijssen

Posted 2018-05-07T15:43:30.910

Reputation: 67 575

1

05AB1E, 46 bytes

Y9ŸJ.•§®т•«Á4שsð.;#S|UεX‚˜ε®sk>T‚W}O21›}DOsg/

Try it online!

This can be done better, working on it.

Magic Octopus Urn

Posted 2018-05-07T15:43:30.910

Reputation: 19 422

1

05AB1E, 23 22 21 bytes

AST:4-D¨OÐ4@*4*Š+T@O-

Try it online!

AST:                   # replace all letters in the input with 10
    4-                 # subtract 4 from each card value
      D                # duplicate
       ¨               # drop the last element
        O              # sum (hand value of the player - 8)
         Ð             # triplicate that
          4@*          # set to 0 if it's less than 4
             4*        # multiply by 4
               Š       # 3-way swap
                +      # add the player's hand value to each card value
                 T@O   # count how many are >= 10
                    -  # subtract

Grimmy

Posted 2018-05-07T15:43:30.910

Reputation: 12 521