13
\$\begingroup\$

One of the things that makes contract bridge very interesting is its highly complicated "artificial" meta game. This system of scoring hands is a small part of it.

Bridge is a trick-taking card game. Each player gets a hand of 13 cards, and the game starts with the bidding. The bidding determines how the rest of the game plays, and so is a crucial part of it. In order to ensure that you and your partner do not bid too high (or too low), this artificial scoring system was developed to tell you how good your hand is.

Scoring

Here's a sample hand:

S:KQT5
H:J72
D:965
C:AK8

The S, H, D, C represent the suits (spades, hearts, diamonds and clubs) and the rest are the cards in those suits. So this hand has a queen of spades (Q), king of spades (K), ten of spades (T), five of spades, jack of hearts, seven of hearts, etc.

The scoring system works as follows:

  • You get 4 points for every ace (A) you have, 3 points for every king (K), 2 points for every queen (Q) and 1 point for every jack (J). No other cards give points.
  • Every card after the fourth in a suit gives you 1 point. So if you have six hearts, you'd get 2 points.
  • A suit where you only have 2 cards gives you 1 point (this is a doubleton). A suit where you have just 1 card gives you 2 points (this is a singleton). If you have no cards in a certain suit, you get 3 points (this is a void). (Usually these are only counted once you've agreed on a suit with your partner, but I'm including them to make the challenge more interesting.)

So, the above hand has 13 points.

Challenge

Given a bridge hand in the format shown above, calculate how many points the hand has. The suits will always be listed in the order spades, hearts, diamonds and clubs, and the cards will always be sorted in the order A, K, Q, J, T, 9 - 2.

Sample Inputs and Outputs

S:KQT5
H:J72
D:965
C:AK8
       \-> 13

S:AKQT6
H:54
D:J83
C:732
       \-> 12

S:
H:KQT8754
D:A86
C:432
       \-> 15

S:9876
H:843
D:652
C:432
       \-> 0

S:AKQT5
H:AQJ6
D:Q3
C:AK
       \-> 28

This is , so shortest code in bytes wins.

\$\endgroup\$
4
\$\begingroup\$

Jelly, 27 25 21 bytes

Thanks @Dennis for -3 bytes!

L_5.AḞW+“JQKA”i$€Sµ€S

This takes input as a list of lines. To take input as a multiline string, precatenate a ṣ⁷µ.

Making a table of the frequency points:

Cards:    0  1  2  3  4  5  6 ... 4+k
Points:   3  2  1  0  0  1  2 ... k

we can see that they're equal to abs(c-3.5)-.5, where c is the number of cards. Since each line contains two extra characters, and the number of points is always an integer, this is floor(abs(l-5.5)) where l is the line length.

Note that Jelly's indices are 1-based, and also the behavior of vectorized functions on mismatched dimensions: the extra elements of the longer list are unaffected. So [1] + [3,2,0,0] gives [4,2,0,0].

                  µ      The program is two monadic fs applied in turn; an atop.
L_5.AW+“JQKA”i$€S       Helper function:
                 €        For €ach line:
L                         Get the line Length.
 _5.                      Subtract 5.5 (Numeric literals' decimal parts default to .5)
    A                     Apply Absolute value
     Ḟ                    Floor
      W                   Then Wrap it in an array. "S:AKQT6" gives [1].
        “JQKA”i$          Monadic function: index into the string "JQKA".
                €         Apply ^ over €ach char of the line; [3,2,0,0,0].
       +                  Add the two arrays together; [4,2,0,0,0].
                 S        Sum; 6.
                    S    Main link: Sum all results

Try it here.

\$\endgroup\$
3
\$\begingroup\$

ES6, 107 99 89 bytes

s=>(t=0,[...s].map(c=>t+="JQKA".search(c)+1),s.split`
`.map(l=>t+=(l=l.length-6)^l>>4),t)
\$\endgroup\$
2
\$\begingroup\$

Pyth, 27 25 24 bytes

sms+a5.5ldshMxL"JQKA"d.z

We calculate the values separately for each suit, then add them.

  s m                 sum of map lambda d:  (d is a line of input)
      +                 add the
        s a                 floor of the absolute difference between
            5.5               5.5
            l d               and len(d)
          s hM xL           to the sum of the indices each incremented by one
                  "JQKA"      of each char in d in the string "JQKA"
                  d
      .z

Test suite.

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

Retina, 77 59 bytes

T`AKQJTd`5-1
:(.){0,3}(.)?
$#1$#1$#2 3$0
\S
$0$*1
+`1 1

1

Explanation by lines/line pairs:

  • In the first line we convert chars AKQJT987655432 to 5432111111111. This means for every suit we have a sum. If we have 0 1 2 3 4 5 6 7 ... cards in this suit, the sum is off by +3 +1 -1 -3 -4 -4 -4 -4 ... from the correct score.
  • In lines 2 and 3 to correct this we add 3 to every line and before a space we add values which we will subtract. This subtracted value is twice the length of cards with a max of 3, and 1 more if there are at least 4 cards.
  • In lines 4 and 5 we convert digits to unary dropping everything else except the separator space.
  • In lines 6 and 7 we do unary subtraction.
  • In line 8 we count up the 1's which gives the result.

Try it online here.

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

APL (Dyalog Classic), 24 bytes

+/(⌊∘|5.5-≢¨),5|'JQKA'⍳∊

Try it online!

uses ⎕io=1

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

Stax, 18 bytes

½Γ}♣▓="pì∩û╨▐M↨}╚-

Shortest answer so far, defeated Jelly (although I expect to be defeated soon ...)

Run and debug online!

Explanation

Uses the unpacked version to explain.

LZF{"JQKA"I^+i5-:++F5+
L                         Collect input in a list (if this is not needed, we can yet save another byte)
 Z                        Put a zero under the top of the stack, used as the accumulator
  F                       Loop for every suit
   {               F      Calculate the "score" for the string describing the suit
    "JQKA"I^              Find the 1-based index of current character in "JQKA", 0 for not found
            +             Add to the accumulator
             i5-:+        Subtract 5 from the current 0-based index, and take the sign
                  +       Add to the accumulator
                    5+    Add 5 extra points for each suit

This is achieved by translating

  • Every card after the fourth in a suit gives you 1 point. So if you have six hearts, you'd get 2 points.
  • A suit where you only have 2 cards gives you 1 point (this is a doubleton). A suit where you have just 1 card gives you 2 points (this is a singleton). If you have no cards in a certain suit, you get 3 points (this is a void).

To

  • Score 3 extra points for each suit
  • Each card before the fourth in a suit gives you -1 point, each card after the fourth gives you 1 point, the fourth card scores 0.

Then we can make use of the property of the signum function.

By doing this we can avoid explicit handling of number of cards saving a few bytes.

\$\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.