14
\$\begingroup\$

Challenge:

Given two five-card hands, determine which one wins by the standard ranking of poker hands.

Input:

Ten cards separated by spaces from stdin or as command line arguments, whichever you prefer. The first five cards are Player 1's hand while the last five are Player 2's hand. Each card will be a two letter string of the form RS where R is rank and S is suit. The ranks range from 2-9, T for ten, and J, Q, K, and A for Jack, Queen, King, and Ace respectively. The suits are H, D, C, S for Hearts, Diamonds, Clubs, and Spades respectively. You must output the number of the player that wins: '1' or '2'.

Examples of Cards:

AS - the Ace of Spades
QD - the Queen of Diamonds
2C - the Two of Clubs
TH - the Ten of Hearts

Input to Output Examples:

5H 5C 6S 7S KD 2C 3S 8S 8D TD -> 2

Explanation: Player 1 has a Pair of Fives while Player 2 has a Pair of Eights.

5D 8C 9S JS AC 2C 5C 7D 8S QH -> 1

Explanation: Neither Player has anything special, but Player 1's high card is an Ace while Player 2's high card is a Queen.

2D 9C AS AH AC 3D 6D 7D TD QD -> 2

Explanation: Player 1 has Three Aces, Player 2 has a Flush of Diamonds.

4D 6S 9H QH QC 3D 6D 7H QD QS -> 1

Explanation: Both players have a Pair of Queens, but Player 1's second highest card is a Nine whereas Player 2's is a Seven.

Rules and Clarifications:

  • Refer to the standard ranking of poker hands for the details of comparing hands.
  • You may assume that there are no repeated cards in each pair of hands.
  • You may assume that there is a definite winner in each case.
  • Suit does not factor into the ranking of a hand. For example, two royal flushes of different suits are equal (therefore any input where both players have a royal flush is invalid by the preceding rule).
  • As this is code golf, the shortest answer wins.

Notes:

asked Mar 30, 2014 at 2:07
\$\endgroup\$
5
  • \$\begingroup\$ Apologies if there's anything I've missed! This is my first code golf question. \$\endgroup\$ Commented Mar 30, 2014 at 2:08
  • \$\begingroup\$ This is similar to this recent question codegolf.stackexchange.com/q/23743/15599 and the 5-card version referenced within it. However those questions only required to name the type of hand. A big difference here is that if both players have the same type of hand, we have to determine which is better by card rank (e.g. for two pairs, who has the best first pair, second pair, and if necessary single card.) Therefore it is not a duplicate. Always search for similar questions, link them, (i see you did) and be prepared to defend why it is not a duplicate before posting. \$\endgroup\$ Commented Mar 30, 2014 at 2:29
  • \$\begingroup\$ What if the flop and the hand are the same? \$\endgroup\$ Commented Mar 30, 2014 at 2:39
  • \$\begingroup\$ @IsmaelMiguel There is no flop in this version. There are simply two separate hands that must be evaluated against each other. \$\endgroup\$ Commented Mar 30, 2014 at 3:04
  • 1
    \$\begingroup\$ Previously solved for 10 cards here \$\endgroup\$ Commented Mar 30, 2014 at 8:05

5 Answers 5

3
\$\begingroup\$

Haskell - (削除) 352 (削除ここまで) 339 characters

import Data.List
v h=10*(sum$map(\l->l*l)g)+b g:k where
 (g,k)=unzip$reverse$sort$map(\r->(length r,head r))$group$sort$map(maybe 0 id.(`elemIndex`"23456789TJQKA").head)h
 b(1:_)=f(map(!!1)h)+t k;b _=0
f(y:z)|all(==y)z=75;f _=0
t[y,_,_,_,z]|y-z==4=70;t[12,3,2,1,0]=65;t _=0
w(a,b)|v a>v b="1\n";w _="2\n"
main=interact$w.splitAt 5.words

Runs:

& echo "5H 5C 6S 7S KD 2C 3S 8S 8D TD" | runhaskell 25056-Poker.hs 
2
& echo "5D 8C 9S JS AC 2C 5C 7D 8S QH" | runhaskell 25056-Poker.hs 
1
& echo "2D 9C AS AH AC 3D 6D 7D TD QD" | runhaskell 25056-Poker.hs 
2
& echo "4D 6S 9H QH QC 3D 6D 7H QD QS" | runhaskell 25056-Poker.hs 
1

Ungolf'd and commented, so you can see the techinque:

import Data.List
value :: [String] -> [Int]
value hand = 10 * (sum $ map (\l->l*l) groups) + bonus groups : kicker
 -- ^ Value of a hand is 10 times the sum of the squares of the group lengths
 -- plus the straight & flush bonus, followed by the kicker (to break ties)
 -- This 10 * sum-of-squares + bonus works out to put the hands in category
 -- order, and then they only need to be ordered by card ranks.
 where
 -- | The cards are sorted into groups by matching rank, then the groups
 -- sorted by length and rank: For example: "7C 7D 7H QS 2S" will becomes
 -- [(3,7),(1,Q),(1,2)]. This is like a run-length encoding. Finally, the
 -- groups lengths, and the kicker ranks are taken apart into two lists.
 -- N.B: kicker here includes the ranks of the groups, unlike the poker term.
 (groups,kicker) = unzip -- split apart
 $ reverse $ sort -- reverse sort by (length,rank)
 $ map (\r->(length r,head r)) -- turn groups into (length,rank) pairs
 $ group $ sort -- group sorted ranks
 $ map (maybe 0 id . (`elemIndex`"23456789TJQKA") . head) hand
 -- take first letter of each card in the hand, and map to [0..12]
 -- | Give a bonus for flush and straight to hands with five cards,
 -- or equivalently hands where the largest group length is just 1
 bonus (1:_ ) = flush (map (!!1) hand) -- flush takes the suits of the hand
 + straight kicker -- straight takes the ranks
 bonus _ = 0
 -- | A flush is if all suits match the first suit
 flush (y:z) | all (==y) z = 75
 | otherwise = 0
 -- | There are two kinds of straight.
 -- N.B: If there are five groups, then there are no duplicate ranks
 straight [y,_,_,_,z] | y-z == 4 = 70 -- normal, high to low
 straight [12,3,2,1,0] = 65 -- ace is low, but it sorts high
 straight _ = 0
wins :: ([String], [String]) -> String
wins (a,b) | value a > value b = "1\n"
 | otherwise = "2\n"
main = interact $ wins . splitAt 5 . words
answered Apr 1, 2014 at 7:12
\$\endgroup\$
2
\$\begingroup\$

Python - (削除) 774 (削除ここまで) (削除) 722 (削除ここまで) (削除) 707 (削除ここまで) (削除) 698 (削除ここまで) 685 chars

import sys
t,q,e,u='--23456789TJQKA','SDCH',enumerate,len
_=lambda c,i=0:chr(97+c[i])
def j(s):
 v,g,l=[0]*15,[0]*4,''
 for c in s:
 r,s=c[0],c[1];v[t.find(r)]+=1;g[q.find(s)]+=1
 c,h,k,m,f=0,0,[0,0,[],[],[]],0,0
 for x,i in e(v):
 for b in[2,3,4]:
 if i==b:k[b]+=[x]
 v[1]=v[14]
 for x,i in e(v):
 if i:
 c+=1
 if c==5:m,h=1,x
 if i==1:l+=_([x])
 else:c=0
 f,l,d=max(g)//5*2,l[::-1],'';z=f+m
 if z==3:d='z'+l
 if k[4]:d='y'+_(k[4])+l
 if k[2] and k[3]:d='x'+_(k[3])+_(k[2])
 if z==2:d='w'+l
 if z==1:d='v'+_([h])
 if k[3]:d='u'+_(k[3])+l
 if u(k[2])>1:d='t'+_(k[2],1)+_(k[2])+l
 if u(k[2])==1>u(k[3]):d='s'+_(k[2])+l
 return d or l
p=sys.argv
print(1+(j(p[1:6])<j(p[6:])))

I chose to generate a string for each hand that represents it, starting with a character for the type of hand, followed by characters describing the particular variation of the type (for example, which card did you just have 4 of?), followed by the values of the remaining cards in case of a tie (if both players have the same double pair, the 5th card will have to decide who wins). I've tested it quite extensively, but I don't actually play poker, so I hope I got it right. Also, I know it's not fully golfed yet, I can probably shave off a few dozen chars later on.

answered Mar 30, 2014 at 16:31
\$\endgroup\$
1
  • \$\begingroup\$ Kill 5 chars with _=lambda c:chr(97+c). Also, you have some unnecessary whitespace after :s and =s. Finally, use ; instead of new lines to separate statements to reduce whitespace used for indentation. \$\endgroup\$ Commented Mar 30, 2014 at 17:07
2
\$\begingroup\$

JavaScript - (削除) 526 (削除ここまで) 508

function a(b){b=b.split(" ");var c=b.splice(5,5),d=[],e=[],r=[8,9,5,6,1,2,3,10,4,7],A=14,K=13,Q=12,J=11,S={"S":1,"C":2,"H":4,"D":8};for(i=0;i<5;i++){d.push(b[i].split('')[1]);b[i]=b[i].split('')[0];e.push(c[i].split('')[1]);c[i]=c[i].split('')[0]}function p(w,m){var v,i,o,s=1<<w[0]|1<<w[1]|1<<w[2]|1<<w[3]|1<<w[4];for(i=-1,v=o=0;i<5;i++,o=Math.pow(2,w[i]*4)){v+=o*((v/o&15)+1)}v=v%15-((s/(s&-s)==31)||(s==0x403c)?3:1);v-=(m[0]==(m[1]|m[2]|m[3]|m[4]))*((s==0x7c00)?-5:1);return r[v]}alert(p(b,d)>p(c,e)?1:2)}

usage:

a("5H 5C 6S 7S KD 2C 3S 8S 8D TD");

ungolfed:

function a(b) {
b = b.split(" ");
var c=b.splice(5,5),
 d=[],
 e=[],
 r=[8,9,5,6,1,2,3,10,4,7],
 A=14,
 K=13,
 Q=12,
 J=11,
 S={"S":1,"C":2,"H":4,"D":8};
 for (i=0;i<5;i++) {
 d.push(b[i].split('')[1]);
 b[i] = b[i].split('')[0];
 e.push(c[i].split('')[1]);
 c[i] = c[i].split('')[0]; 
 }
function p(w,m){
 var v, i, o, s = 1<<w[0]|1<<w[1]|1<<w[2]|1<<w[3]|1<<w[4];
 for (i=-1, v=o=0; i<5; i++, o=Math.pow(2,w[i]*4)) {v += o*((v/o&15)+1);}
 v = v % 15 - ((s/(s&-s) == 31) || (s == 0x403c) ? 3 : 1);
 v -= (m[0] == (m[1]|m[2]|m[3]|m[4])) * ((s == 0x7c00) ? -5 : 1);
 return r[v];
}
alert(p(b,d)>p(c, e)?1:2);
}

source

answered Apr 1, 2014 at 14:47
\$\endgroup\$
2
\$\begingroup\$

Python 3, 454 characters

def z(v,u):
 v.sort();o,d,w=0,{2:0,3:0},[0]+v[:-1]
 if v[4]==13 and T(w):v=w
 t,f=T(v),len(set(u))==1
 for p,c in set((p,v.count(p)) for p in v):
 if c==4:o+=2**77
 d[c]=d.get(c,0)+1;o+=2**(c*14+p)
 if f+t:o+=2**(71+f*4+t*3)
 elif d[3]:o+=2**(73+3*d[2])
 o+=2**(70+d[2]);return o
i,c,T=input().split(),'-23456789TJQKA',lambda v:all(v[i]==v[0]+i for i in range(5))
v,u=[c.find(x[0]) for x in i],[x[1] for x in i]
print(1+(z(v[:5],u[:5])<z(v[5:],u[5:])))

Function z evaluates a hand to a single integer, which is effectively serving as an ordinal using Python's arbitrary precision integers. Its parameters, v and u, are lists of the values (2-14) and suits (single-char strings). The first two lines of z sort the cards, initialize relevant structures, and check if we have a low-ace straight. We then check for a straight or flush on the next line. The internal loop iterates the counts of different cards, solves the 4-of-a-kind case, tallies, and adds the appropriate ordinal. The last 3 lines of z solve the ordinals of all the other hand ranks -- flushes, straights, and straight-flushes, followed by 3-of-a-kind and full houses, followed by two pair, pair, and high card.

In the main area, we parse the input, declare lambda v (which checks for straights), and the last line evaluate the hands and prints the result.

answered Aug 24, 2022 at 23:19
\$\endgroup\$
1
\$\begingroup\$

perl, (削除) 801 (削除ここまで) 733 chars

I believe this is a pretty straight-forward implementation. Basically, for each hand, we sort the suits and the faces separately. Then we make another copy of the faces with aces counting low so we can check for straights with low aces. Then we determine if we have a flush or straight, and what the high card is. Then we just check for matches in order of score (first we check for straight flushes, then four of a kinds, etc.). The actual score is just the concatenation of the type of hand followed by the face values of the cards in the order they matter (that's _s() in the ungolfed version, u() in the golfed version). Here it is:

@l{2..9,qw(T J Q K A)}=2..14;sub u{join"",map{$_>9?$_:"0$_"}shift,ref$_[0]?$$_[0]:map{$h[$_]}@_}sub e{$p[$_[0]-1]-1==$p[$_[0]]}sub f{@p=@_;e(1)&&e(2)&&e(3)&&e 4}sub h{$h[$_[0]]==$h[$_[1]]}sub i{h(@_[0,1])&&h @_[2,3]}sub t{@s=sort map{substr($_,1)}@_;$f=$s[0]eq$s[4];@l=@h=sort{$b<=>$a}map{$l{substr($_,0,1)}}@_;@l=(@l[1..4],1)while$l[0]==14;$s=0;if(f@l){$s=1;$h=$l[0]}else{$h=$h[0];$s=1 if f@h}$f&&$s?u 9,\$h:h(4,1)?u 7,4,0:h(3,0)?u 7,3,4:i(4,3,2,0)?u 6,0,4:i(4,2,1,0)?u 6,4,0:$f?u 5,0:$s?u 4,\$h:h(4,2)?u 3,4,0,1:h(3,1)?u 3,3,0,4:h(2,0)?u 3,2..4:i(4,3,2,1)?u 2,2,4,0:i(4,3,1,0)?u 2,1,4,2:i(3,2,1,0)?u 2,1,3,4:h(4,3)?u 1,4,0,1,2:h(3,2)?u 1,3,0,1,4:h(2,1)?u 1,2,0,3,4:h(1,0)?u 1,1..4:u 0,0..4}print t(@ARGV[0..4])gt t(@ARGV[5..9])?1:2

And here's the less-golfed equivalent:

use strict;
use warnings;
# ace high or low in straights, otherwise high
# T = ten, J = jack, Q = queen, K = king, A = ace
# 0 high card
# 1 one pair
# 2 two pair
# 3 3 of a kind
# 4 straight
# 5 flush
# 6 full house
# 7 four of a kind
# 9 straight flush (royal flush a subclass of straight flush)
my %l;@l{2..9,qw(T J Q K A)}=2..14;
sub score {
 my @suits = sort map { substr($_,1) } @_;
 my @faces_h = sort { $b <=> $a } map { $l{substr($_,0,1)} } @_;
 my @faces_l = @faces_h;
 @faces_l = (@faces_l[1..4], 1) while $faces_l[0] eq 14;
 my $is_flush = $suits[0] eq $suits[4];
 my ($is_straight, $high_card);
 if($faces_l[0]-1==$faces_l[1] &&
 $faces_l[1]-1==$faces_l[2] &&
 $faces_l[2]-1==$faces_l[3] &&
 $faces_l[3]-1==$faces_l[4]) {
 $is_straight=1;
 $high_card = $faces_l[0];
 } else {
 $high_card = $faces_h[0];
 if($faces_h[0]-1==$faces_h[1] &&
 $faces_h[1]-1==$faces_h[2] &&
 $faces_h[2]-1==$faces_h[3] &&
 $faces_h[3]-1==$faces_h[4]) {
 $is_straight=1;
 }
 }
 return _s(9, \$high_card) if $is_flush && $is_straight;
 return _s(7, 4,0) if $faces_h[4] == $faces_h[1];
 return _s(7, 3,4) if $faces_h[3] == $faces_h[0];
 return _s(6, 0,4) if $faces_h[4] == $faces_h[3] && $faces_h[2] == $faces_h[0];
 return _s(6, 4,0) if $faces_h[4] == $faces_h[2] && $faces_h[1] == $faces_h[0];
 return _s(5, 0) if $is_flush;
 return _s(4, \$high_card) if $is_straight;
 return _s(3, 4,0,1) if $faces_h[4] == $faces_h[2];
 return _s(3, 3,0,4) if $faces_h[3] == $faces_h[1];
 return _s(3, 2,3,4) if $faces_h[2] == $faces_h[0];
 return _s(2, 2,4,0) if $faces_h[4] == $faces_h[3] && $faces_h[2] == $faces_h[1];
 return _s(2, 1,4,2) if $faces_h[4] == $faces_h[3] && $faces_h[1] == $faces_h[0];
 return _s(2, 1,3,4) if $faces_h[3] == $faces_h[2] && $faces_h[1] == $faces_h[0];
 return _s(1, 4,0,1,2) if $faces_h[4] == $faces_h[3];
 return _s(1, 3,0,1,4) if $faces_h[3] == $faces_h[2];
 return _s(1, 2,0,3,4) if $faces_h[2] == $faces_h[1];
 return _s(1, 1,2,3,4) if $faces_h[1] == $faces_h[0];
 return _s(0, 0..4);
}
sub _s {
 join "", map { $_ > 9 ? $_ : "0$_" } shift,
 ref $_[0] ? $$_[0] : map { $faces_h[$_] } @_
 # my @a=@_;
 # if(ref $a[1]) {
 # $a[1]=${$a[1]};
 # } else {
 # $a[$_]=$faces_h[$a[$_]] for 1..$#a;
 # }
 # join "", map { $_ < 10 ? "0$_" : $_ } @a;
}
my @p1 = @ARGV[0..4];
my @p2 = @ARGV[5..9];
my $s1 = score(@p1);
my $s2 = score(@p2);
print $s1 gt $s2 ? 1 : 2;
answered Mar 30, 2014 at 6:01
\$\endgroup\$
1
  • \$\begingroup\$ AH 2C 3S 4S 5D 6C 7S 7C 7D TD produces a result of 2, but I think a straight beats three of a kind \$\endgroup\$ Commented Mar 30, 2014 at 10:05

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.