Name the poker hand

22

3

Name the poker hand

Given five cards, output the name of the poker hand, which will be one of:

High card
One pair
Two pair
Three of a kind
Straight
Flush
Full house
Four of a kind
Straight flush
Royal Flush

If in doubt, refer to the rules at http://en.wikipedia.org/wiki/List_of_poker_hands.

Input

5 cards from either stdin or commandline arguments. A card is a two letter string on the form RS, where R is rank and S is suit. The ranks are 2 - 9 (number cards), T (ten), J (Jack), Q (Queen), K (King), A (Ace). The suits are S, D, H, C for spades, diamonds, hearts and clubs respectively.

Example of cards

5H - five of hearts
TS - ten of spades
AD - ace of diamonds

Example of input => desired output

3H 5D JS 3C 7C => One pair
JH 4C 2C JD 2H => Two pair
7H 3S 7S 7D 7C => Four of a kind
8C 3H 8S 8H 3S => Full house

Rules

Shortest code wins

Edit

Looking great so far! I can't really verify all the answers, since I don't know these languages very well and don't have compilers/interpreters for all of them, but I suspect that not everyone have thought about that Aces can be both the highest and the lowest cards of a Straight (flush).

daniero

Posted 2012-06-29T01:21:54.873

Reputation: 17 193

2

There is a vaguely related oldie on Stack Overflow.

– dmckee --- ex-moderator kitten – 2012-06-29T17:19:01.923

Are we allowed to capitalize (or not) hand names as we please? – Mr.Wizard – 2012-07-02T09:41:01.587

Mr.Wizard, sure. – daniero – 2012-07-02T14:49:41.203

Answers

3

GolfScript (209 208 207 206 200 199 197 196 chars)

3/zip:^0={10,''*"TJQKA"+?}/]:?15,{?\{=}+,,}%2,-$6,14.),++@$/):|;[!!2*^1=.&,(!+5+]or{/}*'Full house
Two pair
One pair
ThreeKFourKHigh card
Flush
Straight''K'/' of a kind
'*n/~|1$"Royal"if" "+2$+](=

I'm exploiting the offered freedom to tweak capitalisation: my Straight Flush and Royal Flush both capitalise Flush in order to reuse the word from the simple flush.

Note: some earlier versions were buggy: they only supported full house when the pair was of lower value than the pair royal. They can be corrected by replacing the space separating - 0 with a $.

Demo

Peter Taylor

Posted 2012-06-29T01:21:54.873

Reputation: 41 901

Now that's a golfed program! I've been looking for ways to shorten it, but can't come up with anything. Using .& to find the distinct chars in a string is a very useful trick. – Cristian Lupascu – 2012-07-09T12:45:32.973

@w0lf, that's a fairly standard trick. Howard uses it too in his solution. – Peter Taylor – 2012-07-09T12:50:06.100

8

Came up with an answer of my own :)

Python - 312 301 298

R,K,F,S,g=' 23456789TJQKA2345A',' of a Kind','Flush','Straight ',sorted
s,r=''.join(g(raw_input(),key=R.find)).split()
n,m=g(map(r.count,set(r)))[-2:]
print[[F,[0,'High Card','TOwnoe'[n&1::2]+' Pair',['Full House','Three'+K][n&1],'Four'+K][m]],[[S,'Royal '][r[0]=='T']+F,S]][r in R][len(set(s))>1]

Creates a 2x2 list where the indices of the two dimensions are boolean checks for flush and straight. In case of both, we check if it's a royal flush or just a straight flush. For not flush and not straight, we check for the other hands: m and n holds the highest and second highest amount of same-rank cards; the names of the hands are stored in a list with indices according to m. Sub-checks within this list's values are done with n to seperate one pair from two pair, and three of a kind from house.

Edit: Thanks Nolen Royality for a total of 20 characters saved!

daniero

Posted 2012-06-29T01:21:54.873

Reputation: 17 193

1... and beat mine. – Mr.Wizard – 2012-07-03T02:06:05.157

Love the new solution, 312 characters is pretty tiny. Very clever method of dealing with one vs two pairs :D – Nolen Royalty – 2012-07-08T19:14:25.603

Thanks :) You're welcome to try it if you want. But you're maybe not using any similar variable as mine m and n. Checking this and watching your code again, I just realized I can shave off some more on the original one ^^ – daniero – 2012-07-08T19:32:07.777

1Couldn't you lose another 8 chars by switching m,n=g([c.count(x)for x in set(r)]) to m,n=g(map(c.count,set(r)))? – Nolen Royalty – 2012-07-10T05:22:47.607

Woah, you are darn right I could :D Don't know why that slipped my mind. Good catch, thanks! – daniero – 2012-07-10T16:03:28.137

5

Ruby 1.9 (427 359 348 338 296 292)

EDIT: Fixed to work with low aces.

o,p=%w(flush straight)
f=/1{5}|1{4}0+1$/
s=[0]*13
puts Hash[*$*.map{|c|s['23456789TJQKA'.index c[0]]+=1;c[1]}.uniq[1]?[f,p,?4,'four'+a=' of a kind',/3.*2|2.*3/,'full house',?3,'three'+a,/2.*2/,'two pair',?2,'one pair',0,'high card']:[/1{5}$/,'royal '+o,f,p+' '+o,0,o]].find{|r,y|s.join[r]}[1]

The basic idea is to build up an array of the quantity of card in each rank, concatenate the digits into a string, and then run regular expressions to see which hand shape fits. We count the number of distinct suits to determine whether to check it against the different flushes (flush, straight flush, royal flush) or to the other shapes (everything else).

Takes the cards as separate command-line args, like so:

>ruby poker-hand-golf.rb 3H 5D JS 3C 7C
one pair

Paul Prestidge

Posted 2012-06-29T01:21:54.873

Reputation: 2 390

4

C, 454 characters

#define L for(a=1;a<6;a++)for(b=0;b<13;b++)
#define U u[b+6]
#define R(x,y) if(x)puts(#y);else
b,f,r,h=0,s=0,u[20]={0};main(int a,char**v){L U+=v[a][0]=="23456789TJQKA"[b];f=v[1][1];L{if(v[a][1]!=f)f=0;u[a]+=a==U;if(b>7)h+=U;if(a*13+b<64||!U)r=0;else if(++r==5)s=1;}R(f&&h==25,Royal flush)R(f&&s,Straight flush)R(u[4],Four of a kind)R(u[3]&&u[2],Full house)R(f,Flush)R(s,Straight)R(u[3],Three of a kind)R(u[2]==2,Two pair)R(u[2],One pair)R(h,High card);}

Run from command line with cards as arguments, e.g. ./a.out 8C 3H 8S 8H 3S

Expanded version, with comments:

#define L for(a=1;a<6;a++)for(b=0;b<13;b++)
#define R(x,y) if(x)puts(#y);else
#define U u[b+6]
b,f,r,h=0,s=0,u[20]={0};
main(int a,char**v){
    // card usage - u[6..]
    L U+=v[a][0]=="23456789TJQKA"[b];
    // NOTE: lets expand the inner body of the loop in the answer so this looks more sane:
    // flush
    f=v[1][1];L if(v[a][1]!=f)f=0;
    // count of usages - u[0..5] 
    L u[a]+=a==U;
    // high cards x5
    L if(b>7)h+=U;
    // straights
    L if(a*13+b<64||!U)r=0;else if(++r==5)s=1;        
    // display
    R(f&&h==25,Royal flush)
    R(f&&s,Straight flush)
    R(u[4],Four of a kind)
    R(u[3]&&u[2],Full house)
    R(f,Flush)
    R(s,Straight)
    R(u[3],Three of a kind)
    R(u[2]==2,Two pair)
    R(u[2],One pair)
    R(h,High card);    
}

Edits:

  1. Saved 12 chars by combining and reusing loops.
  2. Saved 9 chars by inlining string constant.
  3. Saved 19 chars by using stringification in macro, nasty..

baby-rabbit

Posted 2012-06-29T01:21:54.873

Reputation: 1 623

3

K, 294 295

d:{F:"Flush";S:"Straight ";P:" Pair";K:" of a kind";$[(f:1=#?,/-1#'c)&("AJKQT")~a@<a:,/j:1#'c:" "\:x;"Royal ",F;f&s:(4#1)~1_-':a@<a:,/(("A23456789TJQKA")!1+!14)@j;S,F;4=p:|/#:'=j;"Four",K;(2;3)~u:a@<a:,/#:'=j;"Full House";f;F;s;S;3=p;"Three",K;(1;2;2)~u;"Two",P;(1;1;1;2)~u;"One",P;"High Card"]}

.

k)d'("TS JS QS KS AS";"3S 4S 5S 7S 6S";"JC JH KS JD JS";"JC JH 2S JD 2C";"2C 9C TC QC 6C";"8C 5D 9H 6C 7D";"8C 8D 9H 8S 7D";"8C 8D 9H 2S 9D";"8C 8D 4H 2S 9D";"3C 8D 4H 2S 9D")
"Royal Flush"
"Straight Flush"
"Four of a kind"
"Full House"
"Flush"
"Straight "
"Three of a kind"
"Two Pair"
"One Pair"
"High Card"

edit: Added 1 char for Ace-low straights

tmartin

Posted 2012-06-29T01:21:54.873

Reputation: 3 917

3

Mathematica, 365

Here is my take on David Carraher's answer.

Shown with white space for some readability.

If[
  a = Characters;
  x = Thread;
  r = Range;
  d = Sort[a@StringSplit@# /. x[a@"23456789TJQKA" -> 2~r~14]];
  {t, u} = Sort[Last /@ Tally@#] & /@ x@d;
  c = First /@ d;
  f = u == {5};
  S = "Straight";
  c == r[b = d[[1, 1]], b + 4],
  If[f,
   If[c == 10~r~14, "Royal Flush", S <> " flush"], S],
  If[f, "Flush",
   Switch[t,
    {_, 4},    "Four of a kind",
    {2, 3},    "Full house",
    {__, 3},   "Three of a kind",
    {_, 2, 2}, "Two pair",
    {__, 2},   "One pair",
    _,         "High card"]
  ]
] &

One line version:

If[a=Characters;x=Thread;r=Range;d=Sort[a@StringSplit@#/.x[a@"23456789TJQKA"->2~r~14]];{t,u}=Sort[Last/@Tally@#]&/@x@d;c=First/@d;f=u=={5};S="Straight";c==r[b=d[[1,1]],b+4],If[f,If[c==10~r~14,"Royal Flush",S<>" flush"],S],If[f,"Flush",Switch[t,{_,4},"Four of a kind",{2,3},"Full house",{__,3},"Three of a kind",{_,2,2},"Two pair",{__,2},"One pair",_,"High card"]]]&

Mr.Wizard

Posted 2012-06-29T01:21:54.873

Reputation: 2 481

Nice. You even found space to save in the pattern matching. E.g. _ instead of {_,_,_,_} – DavidC – 2012-07-02T11:29:34.423

Nice solutions, both of you. For the sake of character count, I think the "Pair" should be named "One Pair", even though it sounds a bit bad, since that is what I posted and others have implemented. – daniero – 2012-07-02T21:05:30.677

@Daniero Thanks. I'll fix the name. – Mr.Wizard – 2012-07-03T01:44:20.800

3

Python 334, 326 322 Characters

p,f,l,t,o=" pair"," of a kind"," Flush","Straight","A23456789TJQK"
v,u=zip(*raw_input().split())
s=''.join(sorted(v,key=o.find))
print{5:"High card",7:"One"+p,9:"Two"+p,11:"Three"+f,13:"Full house",17:"Four"+f,23:t,24:l[1:],25:t,42:t+l,44:"Royal"+l}[(sum(map(v.count,v)),24)[len(set(u))<2]+((0,20)[s=="ATJQK"],18)[s in o]]

I know that last one liner is getting pretty unreadable, I'll put up a non-golfed version when I'm happy with with my solution.

Nolen Royalty

Posted 2012-06-29T01:21:54.873

Reputation: 330

2

Mathematica - 500 494 465 chars

This solution is based on a poker demonstration by Ed Pegg, Jr. In this version, the cards are treated internally as numbers in Range[2,14]

v[x_] := Block[{d, t, c, f, s},
 d = Sort@ToExpression[Characters[ImportString[x, "Table"][[1]]] /. {"T" -> 10, "J" -> 11, "Q" -> 12, "K" -> 13, "A" -> 14}];t = Sort /@ Map[Length, Split /@ Sort /@ Transpose@d, {2}];c = d[[All, 1]];f = (t[[2]] == {5});s = c == Range[b = d[[1, 1]], b + 4];
If[s,
 If[f, If[c == 10~Range~14, "royal flush", "straight flush"],"straight"],
 If[ f, "flush",
Switch[t[[1]],
 {1, 4}, "four of a kind",
 {2, 3}, "full house",
 {1, 1, 3}, "three of a kind",
 {1, 2, 2}, "two pair",
 {1, 1, 1, 2}, "one pair",
 {1, 1, 1, 1, 1}, "high card"]]]]

Sample inputs, outputs:

data

Notes:

f: flush

c: cards (without suit)

s: straight

t: {cards, suites}

d:

DavidC

Posted 2012-06-29T01:21:54.873

Reputation: 24 524

Nice, but how do you get two pair out of JH 4C 2C JD TH? – daniero – 2012-06-29T17:28:21.917

You are correct. There is an error that arose when I joined some components together into a pure function. I'll track it down. – DavidC – 2012-06-29T18:23:34.180

@Daniero The issue you raised has been addressed. – DavidC – 2012-06-30T18:37:41.513

David, there is a lot of room to compress this. May I? – Mr.Wizard – 2012-07-01T12:06:05.553

@Mr.Wizard Be my guest. I'll watch and learn. – DavidC – 2012-07-01T13:55:17.133

Answer posted. Thanks for letting me use your method; it's a good deal shorter than the one I started with. – Mr.Wizard – 2012-07-02T09:33:57.307

David, I just re-read my comment above and it sounds like I was asking to compress your answer, not post another one. I'm happy to do that instead! Let me know which you prefer. – Mr.Wizard – 2012-07-02T09:36:54.087

You may post another one or compress mine. Chances are, your rewrite will introduce new routines, in which case you may wish to post separately. – DavidC – 2012-07-02T11:01:45.653

@Mr.Wizard And if you want to borrow ideas from my post for your solution, go right ahead. – DavidC – 2012-07-02T11:03:51.563

2

GolfScript, 258 250 characters

3/zip~;.&,(!\{"23456789TJQKA"?}%$.(\{.@- 8%}%\;"\1"-!\.1/.&{1$\-,}%1.$?)"Four"" of a kind":k+{.,2="Full house"{.2\?)"Three"k+{.3-,({.3\?)"One pair"{;"Straight":?;2$2$&{(8="Royal"?if" flush"+}{;?{"Flush""High card"if}if}if}if}"Two pair"if}if}if}if])\;

The program expects input on STDIN as given above and outputs to STDOUT. You may test the code yourself.

> 8C 3H 8S 8H 3S
Full house

> 8C 7H 6S TH 9S
Straight

> AH 3H 4S 2H 6S
High card

Edit: Incorporated w0lf's suggestions.

Howard

Posted 2012-06-29T01:21:54.873

Reputation: 23 109

Nice solution! You can save 3 chars by putting " of a kind" in a variable, because it's used twice. – Cristian Lupascu – 2012-07-07T19:49:31.817

it also works with "Straight" – Cristian Lupascu – 2012-07-07T19:54:36.040

@w0lf Thank you. I added your suggestions to the code. – Howard – 2012-07-07T20:19:36.407

I think there's a subtle bug with the detection of Straights: AH KH 2C 3H 4H is considered a Straight, but should be High card. – Cristian Lupascu – 2012-07-09T20:04:02.847

@w0lf Hmmm, I have to think about that one... – Howard – 2012-07-10T05:23:50.630