25
\$\begingroup\$

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

\$\endgroup\$
3
  • 3
    \$\begingroup\$ There is a vaguely related oldie on Stack Overflow. \$\endgroup\$ Commented Jun 29, 2012 at 17:19
  • \$\begingroup\$ Are we allowed to capitalize (or not) hand names as we please? \$\endgroup\$
    – Mr.Wizard
    Commented Jul 2, 2012 at 9:41
  • \$\begingroup\$ Mr.Wizard, sure. \$\endgroup\$
    – daniero
    Commented Jul 2, 2012 at 14:49

10 Answers 10

10
\$\begingroup\$

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!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ ... and beat mine. \$\endgroup\$
    – Mr.Wizard
    Commented Jul 3, 2012 at 2:06
  • \$\begingroup\$ Love the new solution, 312 characters is pretty tiny. Very clever method of dealing with one vs two pairs :D \$\endgroup\$ Commented Jul 8, 2012 at 19:14
  • \$\begingroup\$ 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 ^^ \$\endgroup\$
    – daniero
    Commented Jul 8, 2012 at 19:32
  • 1
    \$\begingroup\$ 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)))? \$\endgroup\$ Commented Jul 10, 2012 at 5:22
  • \$\begingroup\$ Woah, you are darn right I could :D Don't know why that slipped my mind. Good catch, thanks! \$\endgroup\$
    – daniero
    Commented Jul 10, 2012 at 16:03
6
\$\begingroup\$

Ruby 1.9 (427 359 348 338 296 292 289)

EDIT: Fixed to work with low aces.

EDIT: Incorporated @je-je's fixes / improvements

o,p=%w(flush straight)
f=/1{5}|^1+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',/^[^1]+$/,'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
\$\endgroup\$
3
  • \$\begingroup\$ This incorrectly identifies AH 3H 4H 5H 6C as a straight. Replacing line 2 with f=/1{5}|^1+0+1$/ fixes this. The full house matching regex can be golfed to /^[^1]+$/. \$\endgroup\$
    – je je
    Commented Aug 23, 2022 at 1:12
  • \$\begingroup\$ For ease of reference: try je je's failing testcase online \$\endgroup\$ Commented Sep 26, 2022 at 21:17
  • \$\begingroup\$ Thanks, incorporated both those changes 👍🏻 10 years, how time flies! \$\endgroup\$ Commented Sep 27, 2022 at 1:30
4
\$\begingroup\$

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..
\$\endgroup\$
1
  • \$\begingroup\$ Do h>24 and u[2]>1 work as well as h==25 and u[2]==2? And why is the output of High card conditional on h? What is h if the ranks are, say, 7 6 5 4 2? \$\endgroup\$
    – Rosie F
    Commented Jul 24, 2020 at 19:39
3
\$\begingroup\$

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

\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 9, 2012 at 12:45
  • \$\begingroup\$ @w0lf, that's a fairly standard trick. Howard uses it too in his solution. \$\endgroup\$ Commented Jul 9, 2012 at 12:50
3
\$\begingroup\$

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"]]]&
\$\endgroup\$
3
  • \$\begingroup\$ Nice. You even found space to save in the pattern matching. E.g. _ instead of {_,_,_,_} \$\endgroup\$
    – DavidC
    Commented Jul 2, 2012 at 11:29
  • \$\begingroup\$ 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. \$\endgroup\$
    – daniero
    Commented Jul 2, 2012 at 21:05
  • \$\begingroup\$ @Daniero Thanks. I'll fix the name. \$\endgroup\$
    – Mr.Wizard
    Commented Jul 3, 2012 at 1:44
3
\$\begingroup\$

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

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

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.

\$\endgroup\$
0
2
\$\begingroup\$

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.

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

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:

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

Factor + poker, 16 bytes

string>hand-name

Try it online!

\$\endgroup\$

Your Answer

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

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