Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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

share|improve this question
2  
There is a vaguely related oldie on Stack Overflow. –  dmckee Jun 29 '12 at 17:19
    
Are we allowed to capitalize (or not) hand names as we please? –  Mr.Wizard Jul 2 '12 at 9:41
    
Mr.Wizard, sure. –  daniero Jul 2 '12 at 14:49

9 Answers 9

up vote 3 down vote accepted

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

share|improve this answer
    
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. –  w0lf Jul 9 '12 at 12:45
    
@w0lf, that's a fairly standard trick. Howard uses it too in his solution. –  Peter Taylor Jul 9 '12 at 12:50

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!

share|improve this answer
1  
... and beat mine. –  Mr.Wizard Jul 3 '12 at 2:06
    
Love the new solution, 312 characters is pretty tiny. Very clever method of dealing with one vs two pairs :D –  Nolen Royalty Jul 8 '12 at 19:14
    
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 Jul 8 '12 at 19:32
1  
Couldn'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 Jul 10 '12 at 5:22
    
Woah, you are darn right I could :D Don't know why that slipped my mind. Good catch, thanks! –  daniero Jul 10 '12 at 16:03

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
share|improve this answer
    
Curses, I was just getting close..! –  daniero Jul 4 '12 at 13:07

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..
share|improve this answer

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"]]]&
share|improve this answer
    
Nice. You even found space to save in the pattern matching. E.g. _ instead of {_,_,_,_} –  David Carraher Jul 2 '12 at 11:29
    
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 Jul 2 '12 at 21:05
    
@Daniero Thanks. I'll fix the name. –  Mr.Wizard Jul 3 '12 at 1:44

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

share|improve this answer

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.

share|improve this answer
    
+1. Stole your zip trick ;) –  daniero Jul 8 '12 at 19:07

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.

share|improve this answer
    
Nice solution! You can save 3 chars by putting " of a kind" in a variable, because it's used twice. –  w0lf Jul 7 '12 at 19:49
    
it also works with "Straight" –  w0lf Jul 7 '12 at 19:54
    
@w0lf Thank you. I added your suggestions to the code. –  Howard Jul 7 '12 at 20:19
    
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. –  w0lf Jul 9 '12 at 20:04
    
@w0lf Hmmm, I have to think about that one... –  Howard Jul 10 '12 at 5:23

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:

share|improve this answer
    
Nice, but how do you get two pair out of JH 4C 2C JD TH? –  daniero Jun 29 '12 at 17:28
    
You are correct. There is an error that arose when I joined some components together into a pure function. I'll track it down. –  David Carraher Jun 29 '12 at 18:23
    
@Daniero The issue you raised has been addressed. –  David Carraher Jun 30 '12 at 18:37
    
David, there is a lot of room to compress this. May I? –  Mr.Wizard Jul 1 '12 at 12:06
    
@Mr.Wizard Be my guest. I'll watch and learn. –  David Carraher Jul 1 '12 at 13:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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