11
\$\begingroup\$

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!

\$\endgroup\$
  • 2
    \$\begingroup\$ Are we allowed to take the ace as 1 and face cards as 10s, or would that be stretching the input format too far? \$\endgroup\$ – Mnemonic May 7 '18 at 15:52
  • \$\begingroup\$ So, we can take face cards as 10? \$\endgroup\$ – wastl May 7 '18 at 15:54
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – DevelopingDeveloper May 7 '18 at 18:03
  • 1
    \$\begingroup\$ "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? \$\endgroup\$ – Jonathan Allan May 7 '18 at 18:37
  • 1
    \$\begingroup\$ @JonathanAllan Updated \$\endgroup\$ – DevelopingDeveloper May 7 '18 at 19:47
7
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ temptation to flat-out steal the mod-48 technology intensifies \$\endgroup\$ – Magic Octopus Urn May 9 '18 at 22:23
  • \$\begingroup\$ If I do end up making an answer using mod-48 I'm bountying you 200 for the epic observation. \$\endgroup\$ – Magic Octopus Urn May 9 '18 at 22:24
4
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ 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).. \$\endgroup\$ – Kevin Cruijssen May 8 '18 at 11:58
  • \$\begingroup\$ 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? \$\endgroup\$ – Kevin Cruijssen May 8 '18 at 12:00
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – Arnauld May 8 '18 at 12:06
  • 1
    \$\begingroup\$ @KevinCruijssen Here is some code showing what's going on. \$\endgroup\$ – Arnauld May 8 '18 at 12:22
  • \$\begingroup\$ Ah ok, now it all makes sense. Thanks! \$\endgroup\$ – Kevin Cruijssen May 8 '18 at 12:24
2
\$\begingroup\$

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.
\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.