11
\$\begingroup\$

Background

Brag is a card game similar in concept to, but simpler than, poker. A hand in brag consists of three cards and is ranked as follows from highest to lowest:

  • Three of a kind - all three cards the same rank. Named as "three Kings" etc.

  • Running flush aka straight flush. All three cards of same suit and of consecutive ranks. The hand is named by the three cards in ascending order followed by the words "on the bounce" to distinguish from a simple run/straight, eg "ten-jack-queen on the bounce". Note an ace is either high or low but not both - "king-ace-two" is not a run.

  • Run aka straight. As above but without the requirement to match suits. Named simply as eg "ten-jack-queen".

  • Flush - all three cards the same suit, named after the highest rank eg "Ace flush".

  • Pair - two cards the same rank together with a third of another version rank. Named as "pair of threes" etc.

  • Any other combination, named after the highest rank eg "ace high".

Challenge

Given three playing cards, output the name of the brag hand they output.

The cards will be input either as three 2-character strings or concatenated as a single 6-character string (whichever your implementation prefers), where the first of each pair is the rank (2...9, T, J, Q, K, A) and the second signifies the suit (H, C, D, S).

Standard golfing rules apply - write a program or function which accepts this input and outputs the name of the hand as detailed above.

You can assume the input will be valid (ranks and suits in the above range, no repeated card) and in whatever case you prefer, but will not be in any particular order.

Output must be either in all capitals, all lower case, or a sensible capitalisation eg title case or sentence case. Numeric ranks should be spelled out eg "tens" not 10s.

Sample inputs & outputs:

2H3C2D => "pair of twos"

TD8C9C => "eight-nine-ten"

4SKS9S => "king flush"

4D4H4S => "three fours"

5H3H2C => "five high"

2D3DAD => "ace-two-three on the bounce"

6D6C6H => "three sixes"

This is my first attempt at a challenge on this site, please do suggest improvements but be gentle :)

\$\endgroup\$
13
  • 3
    \$\begingroup\$ Related. Related. \$\endgroup\$ Mar 12, 2017 at 13:48
  • 4
    \$\begingroup\$ Welcome to PPCG! I've only skimmed the challenge so far, but it looks decent for a first challenge. That said, writing good challenges is hard and for the future I'd recommend posting ideas in the sandbox first where you can get feedback and improve details of the specification before risking downvotes, close votes and answers that might be invalidated by later changes to the challenge. \$\endgroup\$ Mar 12, 2017 at 13:49
  • \$\begingroup\$ @MartinEnder thanks! I'll certainly have been a look at the sandbox next time. \$\endgroup\$
    – IanF1
    Mar 12, 2017 at 13:50
  • \$\begingroup\$ Can we get input as arrays of tuples? Also, can we shorten output like 'king flush' to 'fk'? \$\endgroup\$ Mar 12, 2017 at 14:08
  • 1
    \$\begingroup\$ please add "6D6C6S" as a test case since six is an odd plural \$\endgroup\$ Mar 16, 2017 at 21:39

4 Answers 4

3
\$\begingroup\$

Python 2, 788, 715, 559, 556, 554, 546, 568, 522 bytes

*now passes the 'sixes' * thanks to Ben Frankel for saving 46 Bytes!


import re
d,m,n=dict(zip('JQKA',range(10,15))),'pair of %ss','%s-%s-%s'
C=lambda s:int(d.get(s[0],s[0]))
z,x,c=sorted(re.findall('..',raw_input()),key=C)
q,w,e=C(z),C(x),C(c)
A=[0,0,'two','three','four','five','six','seven','eight','nine','ten','jack','queen','king','ace']
I,O,U=A[e],A[w],A[q]
a,k='%s high'%I,e-w+q
if k==13:a=n%(I,U,O)
if k==w:a=n%(U,O,I)
if q==w or e==w or e==q:a=m%O
if k==e==w:a='three %ss'%I
if'x'in a:a=a[:-1]+'es'
if z[-1]==x[-1]==c[-1]:
 if'-'in a:a+=' on the bounce'
 else:a='%s flush'%I
print a

Try it online!

Thanks for a cool first challenge!

\$\endgroup\$
14
  • 1
    \$\begingroup\$ Some whitespace golfing suggestions: TIO \$\endgroup\$ Mar 16, 2017 at 12:35
  • \$\begingroup\$ Thanks! I knew the white space was adding a lot of bytes but I thought it required 4 spaces. Edited! @math_junkie \$\endgroup\$
    – Stephen
    Mar 16, 2017 at 12:38
  • \$\begingroup\$ @user7686415 Or you could use actual tabs instead. \$\endgroup\$
    – mbomb007
    Mar 16, 2017 at 13:33
  • 1
    \$\begingroup\$ @NotthatCharles fixed it! \$\endgroup\$
    – Stephen
    Mar 17, 2017 at 1:40
  • 1
    \$\begingroup\$ @Stephen, Sure. D.get(a, b) means access the value in the dict D at key a, with default value b if the key is not found. It's the same as writing D[a] if a in D else b, which is the same as writing D[a] if a in D.keys() else b. \$\endgroup\$ Mar 17, 2017 at 4:50
2
\$\begingroup\$

Ruby, 384, 320

Accepts an array of two-char strings.

Translates the pip values into hex values and identifies hands based on how many distinct pip values there are.

->*d{u=d.map{|x|*u=x[1]}==u*3
g=d.map{|x|(x[0].tr'TJQKA','ABCDE').hex}.sort
g=1,2,3if[2,3,14]==g
_,l,h=a=g.map{|x|%w{king queen jack ten nine eight seven six five four three two ace}[-x%13]}
[*g[0]..2+g[0]]==g ?a*?-+(u ?' on the bounce':''):u ?h+' flush':[h+' high','pair of '+l+=l[?x]?'es':?s,'three '+l][-g.uniq.size]}

Annotated:

->*d{
    # u is "Is this a flush?"" (see if you have more than one suit)
    u=d.map{|x|u=x[1]}==[u]*3

    # g is the sorted card values in integer (convert to base 16)
    g=d.map{|x|x[0].tr('TJQKA','ABCDE').hex}.sort

    # use Ace == 1 if we have a low straight
    g=[1,2,3]if[2,3,14]==g

    # a is the names of all the cards
    a=g.map{|x|%w{ace two three four five six seven eight nine ten jack queen king ace}[x-1]}

    # l is for "plural" - just choose the middle card because we
    #                     only care about plurals for 2s or 3s
    l=a[1].sub(?x,'xe')+?s

    # if [g[0],g[0]+1,g[0]+2] == g, we have a run
    # possibly "on the bounce"
    ([*g[0]..g[0]+2]==g) ? (a * ?-) + (u ? ' on the bounce' : '') :

    # if we have a flush, we can't have three-of-a-kind, so try that first
    u ? a[2]+' flush' :

    # otherwise, dedupe your hand. if there's: 
    # 3 values, x high; 2 values, pair; 1 value, three
    [a[2]+' high','pair of '+l,'three '+l][-g.uniq.size]
}
\$\endgroup\$
2
\$\begingroup\$

PHP, 413 405 398 409 408 406 398 bytes

Unfortunately, PHP does not support nested array referencing inside strings;
that would have saved another 6 5 bytes.

for(;$a=$argn[$i++];)$i&1?$v[strpos(_3456789TJQKA,$a)]++:$c[$a]++;$k=array_keys($v);sort($k);$n=[two,three,four,five,six,seven,eight,nine,ten,jack,queen,king,ace];echo($m=max($v))<2?($k[!$d=count($c)]+2-($h=$k[2])?$k[1]>1|$h<12?"$n[$h] ".[flush,high][$d++/2]:"ace-two-three":$n[$k[0]]."-".$n[$k[1]]."-$n[$h]").[" on the bounce"][$d^1]:($m<3?"pair of ":"three ").$n[$v=array_flip($v)[$m]].e[$v^4].s;

Run with echo <hand> | php -nR '<code> or test it online.

breakdown

for(;$a=$argn[$i++];)$i&1?      # loop through input
    $v[strpos(_3456789TJQKA,$a)]++  # count values on even positions [0,2,4]
    :$c[$a]++;                      # count colors on odd positions [1,3,5]
$k=array_keys($v);sort($k);     # $k=ascending values
$n=[two,three,four,five,six,seven,eight,nine,ten,jack,queen,king,ace];
echo($m=max($v))<2              # three different values:
?($k[!$d=count($c)]+2-($h=$k[2])    # test normal straight ($d=color count, $h=high card)
    ?$k[1]>1|$h<12                      # test special straight
        ?"$n[$h] ".[flush,high][$d++/2]     # flush if one color, high card if not
                                            #   ($d++ to avoid " on the bounce")
        :"ace-two-three"                    # special straight
    :$n[$k[0]]."-".$n[$k[1]]."-$n[$h]"  # normal straight
).[" on the bounce"][$d^1]          # if straight: straight flush if one color
:($m<3?"pair of ":"three ")     # pair or triplet
    .$n[$v=array_flip($v)[$m]]      # card name
    .e[$v^4].s                      # plural suffix
;

Requires PHP>=5.6 (for e[...])

\$\endgroup\$
2
  • 1
    \$\begingroup\$ this may fail "sixes" \$\endgroup\$ Mar 16, 2017 at 22:25
  • 1
    \$\begingroup\$ @NotthatCharles: That cost me 11 bytes ... but I golfed them back. :) \$\endgroup\$
    – Titus
    Mar 17, 2017 at 18:03
1
\$\begingroup\$

Python 2 - 583 bytes

I'm too new to be able to comment posts, so I just post my version of python solusion.

Fixed issue with 'es' for pair and three of sixes. Thanks to Not that Charles

d={'A':['ace',14],'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',11],'Q':['queen',12],'K':['king',13]}
r=input()
j=1
i=lambda x:d[x][j]
v=sorted(r[::2],key=i)
z,y,x=v
s=r[1::2]
e='es'if i(y)==6else's'
j=0
a=i(x)
if z==y or y==x:r="pair of %s"%i(y)+e
if s[0]*3==s:r="%s flush"%a
t="%s-%s"%(i(z),i(y))
j=1
u=" on the bounce"if r[-1]=='h'else ""
if i(z)+i(x)==2*i(y):r=t+"-%s"%a+u
if ''.join(v)=="23A":r="%s-"%a+t+u
if [z]*3==v:r="three %s"%d[z][0]+e
if len(r)==6:r="%s high"%a
print r

A bit more readable with some comments

# first of all we don't need to keep suits
d={'A':['ace',14],'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',11],'Q':['queen',12],'K':['king',13]}
r=input()                           # input placed in r, to safely check r[-1] later in code
j=1                                 # j toggles reading from dictionary: 0-string, 1-value
i=lambda x:d[x][j]                  # lambda used to access dictionary
v=sorted(r[::2],key=i)              # take values from input and sort
z,y,x=v                             # variables to compact code
s=r[1::2]                           # take suits from input
e='es'if i(y)==6else's'             # choose ending 'es' for six and 's' for others (for pair and three)
j=0                                 # toggle reading from dictionary to string
a=i(x)                              # get string of top most value
if z==y or y==x:                    # check only two pairs as values are sorted
    r="pair of %s"%i(y)+e
if s[0]*3==s:                       # compact check if all string characters are equal to detect flush
    r="%s flush"%a
t="%s-%s"%(i(z),i(y))               # part of straight output - first two values
j=1                                 # toggle reading from dictionary to values
u=" on the bounce"\                 # addon to output in case of possible straight flush
if r[-1]=='h'else ""                # detected by checking last character in r
                                    # which would be 'h' if flush was detected
if i(z)+i(x)==2*i(y):               # check straight - three sorted numbers a,b,c would be in line if a+c == 2*b
    r=t+"-%s"%a+u                   
if ''.join(v)=="23A":               # check special case with straight, started from Ace
    r="%s-"%a+t+u  
j=0                                 # toggle reading from dictionary to string
if [z]*3==v:                        # check three equal values (almost the same as flush check)
    r="three %s"%d[z][0]+e
if len(r)==6:                       # if r was never modified, then it's just one high card
    r="%s high"%a
print r                             # output r
\$\endgroup\$
3
  • \$\begingroup\$ Also may change in last rows j=0; if [z]*3==v:r="three %ss"%i(z) to if [z]*3==v:r="three %ss"%d[z][0] But it saves just 1 byte \$\endgroup\$ Mar 16, 2017 at 17:56
  • 1
    \$\begingroup\$ this may fail "sixes" \$\endgroup\$ Mar 16, 2017 at 22:24
  • 1
    \$\begingroup\$ @NotthatCharles Yeah, thank you for noticing. I've added fix \$\endgroup\$ Mar 17, 2017 at 9:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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