Name the Brag Hand

11

1

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 :)

IanF1

Posted 2017-03-12T13:46:48.133

Reputation: 212

3Related. Related. – Martin Ender – 2017-03-12T13:48:01.380

4

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.

– Martin Ender – 2017-03-12T13:49:53.387

@MartinEnder thanks! I'll certainly have been a look at the sandbox next time. – IanF1 – 2017-03-12T13:50:49.137

Can we get input as arrays of tuples? Also, can we shorten output like 'king flush' to 'fk'? – Matthew Roh – 2017-03-12T14:08:40.013

@MatthewRoh input as tuples, yes. Shortened output, no - the challenge isn't called "give a cryptic abbreviation of the brag hand" :) – IanF1 – 2017-03-12T14:20:44.243

@IanF1 Many languages seem to suffer the lack of compressing strings into shorter code- unless Jelly, of course – Matthew Roh – 2017-03-12T14:28:11.273

@MatthewRoh I'm not anticipating 6-byte answers :) – IanF1 – 2017-03-12T14:29:04.447

BTW, this doesn't look much different from other related challenges Martin posted. But I don't know if I should flag as a dupe. – Matthew Roh – 2017-03-12T15:31:46.253

@MatthewRoh Thanks for the feedback. I see it as a different balance between the two tasks involved - the calculation (what hand is this) and the efficient returning of strings, as the hands in this case are simpler than in poker. – IanF1 – 2017-03-12T15:35:14.853

@MatthewRoh btw if the community consensus is that it is a dupe, I'll understand. – IanF1 – 2017-03-12T15:39:01.080

@IanF1 The community consensus is, if it is easily solvable by editing an answer from another challenge, it's a dupe. But seeing those two 'Related' posts are not dupe hammered each other, I'm confused if I should dupe flag or not. – Matthew Roh – 2017-03-12T15:41:39.503

1please add "6D6C6S" as a test case since six is an odd plural – Not that Charles – 2017-03-16T21:39:17.490

@NotthatCharles Great shout - adding this now! – IanF1 – 2017-03-16T22:08:35.620

Answers

2

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]
}

Not that Charles

Posted 2017-03-12T13:46:48.133

Reputation: 1 905

3

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!

Stephen

Posted 2017-03-12T13:46:48.133

Reputation: 51

1

Some whitespace golfing suggestions: TIO

– math junkie – 2017-03-16T12:35:16.843

Thanks! I knew the white space was adding a lot of bytes but I thought it required 4 spaces. Edited! @math_junkie – Stephen – 2017-03-16T12:38:56.590

@user7686415 Or you could use actual tabs instead. – mbomb007 – 2017-03-16T13:33:56.983

@mbomb007 I did the whole thing on an iPad, idk how to tab or if it's even possible to do so – Stephen – 2017-03-16T14:21:19.167

Hey, welcome to the site! Hope you stick around! – Rɪᴋᴇʀ – 2017-03-16T15:01:50.373

@user7686415 http://apple.stackexchange.com/q/83302

– mbomb007 – 2017-03-16T15:51:58.120

this may fail "sixes" – Not that Charles – 2017-03-16T22:25:35.800

Golfing suggestion: d=dict(zip(['A23456789TJQKHDSC',values])) where values is the list [['ace',14],['two',2],...]. That saves 37 characters on quotes and colons. You can also save another 5 characters by defining f with a lambda, i.e., f=lambda s:d[s[0]][1]. – Ben Frankel – 2017-03-16T22:46:59.327

@BenFrankel I decided to get rid of the large dict completely, and managed to chop off well over 100 bytes. I want to use lambda somehow but I cannot for the life of me think of how to implement it now(or if i even should) Thanks for your comment! – Stephen – 2017-03-17T00:28:34.953

1@NotthatCharles fixed it! – Stephen – 2017-03-17T01:40:42.943

@Stephen, you can still shave off 5 bytes by using dict(zip('...',range(10,15))), and you can shave off some more by defining C with a lambda, C=lambda s:int(d.get(s[0],s[0])) – Ben Frankel – 2017-03-17T02:12:22.633

@BenFrankel can you explain the C function? I'm a bit confused as to how it works. How does it work when an s gets passed through that isn't in the d dict? Thanks for the help! – Stephen – 2017-03-17T04:46:55.500

1@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. – Ben Frankel – 2017-03-17T04:50:21.177

@BenFrankel thank you for the explanation! I tried for the better part of 2 hours to try and figure out how I could reduce that part. I did not know Python had a dict.get() function that allowed for a default value, I can see so many uses for this haha. I kept trying to find a way to have an if statement in a lambda function because I kept getting an error with the key not existing. Thank You! – Stephen – 2017-03-17T05:06:04.050

2

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[...])

Titus

Posted 2017-03-12T13:46:48.133

Reputation: 13 814

1this may fail "sixes" – Not that Charles – 2017-03-16T22:25:11.257

1@NotthatCharles: That cost me 11 bytes ... but I golfed them back. :) – Titus – 2017-03-17T18:03:06.153

1

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

Dead Possum

Posted 2017-03-12T13:46:48.133

Reputation: 3 256

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 – Dead Possum – 2017-03-16T17:56:56.050

1this may fail "sixes" – Not that Charles – 2017-03-16T22:24:44.270

1@NotthatCharles Yeah, thank you for noticing. I've added fix – Dead Possum – 2017-03-17T09:16:06.037