Code Golf:谁拥有最好的扑克牌?

Tom*_*len 18 language-agnostic code-golf rosetta-stone

我喜欢这样的挑战,我希望很快能提交我的答案.

哪位牌手拥有最好的7张牌?

给出9张牌的无序列表(以空格分隔),找出哪个牌手有最好的扑克牌. 这是扑克手牌排名列表.输入示例:

2C 5H AS KS 2D 4D QD KH 3S
(ie: [[2C 5H] [AS KS] [2D 4D QD KH 3S]])
Run Code Online (Sandbox Code Playgroud)

阵列中的前2张牌代表牌手1的牌,阵列中的第2张牌代表牌手2的牌.最后5张牌代表社区牌,两张牌都分享.实际上,两个玩家都有7张牌,你必须确定哪个玩家拥有最好的5张扑克牌.

卡片被定义为一个字符串,第一个字符代表卡片值,第二个值代表西装.总是大写的.没有卡可能出现两次.

该函数将计算手牌是否为任何一名球员的平局或胜利.它将在输入结束时输出总数.输出格式稍后在本文中定义.

例子

2C 5H AS KS 2D 4D QD KH 3S
(ie: [[2C 5H] [AS KS] [2D 4D QD KH 3S]])
Player 2 wins this hand.  Player 1 has a pair of 2's, player 2 has a pair of kings.

5S 6S 8H 9D 7S 8S JH TS 2H
(ie: [[5S 6S] [8H 9D] [7S 8S JH TS 2H]])
Player 1 wins this hand  Player 1 has a flush, player 2 has a straight.

2S 2H AC AS 2C AH 9H TS 2D    
(ie: [[2S 2H] [AC AS] [2C AH 9H TS 2D]])
Player 1 wins this hand.  Player 1 has quads, player 2 has a full house

5S 6S 2D 4D 9S AS KD JC 9D
(ie: [[5S 6S] [2D 4D] [9S AS KD JC 9D]])
A draw.  Both players have Ace high.
Run Code Online (Sandbox Code Playgroud)

更多信息

感谢mgroves以下链接到Project Euler,它有类似的问题:http://projecteuler.net/index.php?section = problem&id = 54

测试数据

我们将使用Project Euler测试数据:

http://projecteuler.net/project/poker.txt

您的解决方案应接受该文本文件作为输入,并输出总计胜出数.

示例输出

输出必须采用以下格式:

1: 45
2: 32
D: 12
Run Code Online (Sandbox Code Playgroud)

球员1赢了45手,球员2赢了32手,并且有12个平局.(不是实际结果)

规则

  • 没有返回获胜的手牌类型,只有世界卫生组织赢了,如果有人
  • 卡列表输入没有特定的顺序
  • 输入中没有卡片出现两次
  • 输入始终为大写
  • 将Project Euler测试数据作为输入
  • 输出一个计数,其中玩家以上面给定的格式获得最多的牌局和总牌局

mob*_*mob 15

Perl,414 398 370/458 344/416 char

换行并不重要.

%M=map{$_,$Z++}0..9,T,J,Q,K,A;sub N{/.$/;$M{$`}.$&}

sub B{$s=@p=();
for$m(@_){$m-$_||($s+=2,++$p[$m])for@_}
@_=sort{$p[$b]-$p[$a]||$b-$a}@_;
$s=23 if$s<11&&($_[0]-$_[4]<5||$_[0]-$_[1]>8&&push@_,shift);
"@_"=~/.$/;$s+=14*(4<grep/$&/,@_);
$s=100*$s+$_ for@_;$s}

++$X{B((@c=map{N}split)[0..4])<=>B(@c[5..9])}for<>;
printf"1: %d\n2: %d\nD: %d\n",@X{1,-1,0}
Run Code Online (Sandbox Code Playgroud)

这解决了"10张牌"的问题(发出了10张牌,玩家1有前5张牌而玩家2有第2张牌).

第一部分定义了一个子程序N,它可以转换每张卡,使其具有数值.对于非面部卡,这是一个简单的映射(5H ==> 5H),但它确实转换了面部卡(KC => 13C,AD => 14D).

最后一部分将每行输入解析为卡片,将卡片转换为包含数值,将卡片划分为两个玩家的单独手中,并分析和比较这些牌.每只手递增哈希的一个元素%X.当解析所有输入时,%X包含玩家1赢得的牌数,玩家2赢得的牌数或关系.

中间部分是一个子程序,它采用一组五张牌作为输入并产生一个12位数的数字,其特点是较强的扑克牌将具有较高值的​​数字.以下是它的工作原理:

    for$m(@_){$m-$_||($s+=2,++$p[$m])for@_}
Run Code Online (Sandbox Code Playgroud)

这是"配对"探测器.如果任何两张牌具有相同的数值,则增加其中一张牌的哈希元素,并将"得分"变量$s增加2.请注意,我们最终将每张卡与自身进行比较,因此$s至少为10 $p[$x]张,每张卡至少一张$x.如果手牌中包含三张牌,则这三张牌将与其他两张牌相匹配 - 就像这三张牌中有9场比赛一样,"得分"至少为18.

    @_=sort{$p[$b]-$p[$a]||$b-$a}@_;
Run Code Online (Sandbox Code Playgroud)

通过以下方式对卡进行排序:(1)该卡是"对"的一部分的次数和(2)卡的值.因此,在有两个7和两个3的手中,两个7将首先出现,然后是两个3,然后是踢球者.在拥有两个7和三个3的手中,三个3将首先跟随两个7的.这个排序的目的是区分具有相同分数的两只手 - 一只手拿着一对8并且一只手拿着一对7都有一对,但我们需要能够分辨出一对8的更好.

    $s=23 if$s<11&&($_[0]-$_[4]<5||$_[0]-$_[1]>8&&push@_,shift);
Run Code Online (Sandbox Code Playgroud)

这条线是"直"探测器.直线值得23分,并且当手中没有对时($s<11意味着只有5对" - 每张卡与自身匹配 - 被发现)并且(1)最高卡的值正好比4最低牌($_[0]-$_[4]==4)的值,或(2)最高值牌是Ace,而下一张最高牌是5($_[0]-$_[1]==9),这意味着牌有A-2-3-4-5直牌.在后一种情况下,Ace现在是手中最不值钱的牌,所以我们操纵@_反映(push@_,shift)

    "@_"=~/.$/;$s+=14*(4<grep/$&/,@_);
Run Code Online (Sandbox Code Playgroud)

这条线是冲洗检测器.刷新值多14点,并且当每张卡的最后一个字符相同时发生.第一个表达式("@_"=~/.$/)具有设置$&为手中最后一张牌的最后一个字符(套装)的副作用.4<grep/$&/,@_当且仅当所有元素@_具有相同的最后一个字符时,最终的表达式()才为真.

    $s=100*$s+$_ for@_;$s}
Run Code Online (Sandbox Code Playgroud)

创建并返回以手牌得分开头的值,然后按照卡片的重要性顺序包含卡片的值.各种牌局的得分将是

Hand           Score
----------    ------
High card       10     (each card matches itself for two points)
One pair        14     (2 additional matches)
Two pair        18     (4 additional matches)
Three of a kind 22     (6 additional matches)
Straight        23     (no pair, but 23 points for straight)
Flush           24     (no pair, but 14 additional points for the flush)
Full house      26     (8 additional matches)
4 of a kind     34     (12 additional matches)
Straight flush  37     (23 + 14 points)
Run Code Online (Sandbox Code Playgroud)

这符合扑克规则.具有相同分数的手可以通过手牌的值来区分,按照对手的重要性的顺序,一直到手中最不重要的牌.

9卡问题的解决方案(两个卡到玩家1,两个卡到玩家2,玩家共享接下来的5张牌并构建他们最好的5张牌)需要大约70个笔画才能选出最好的5张牌.每位玩家可获得7张牌:

%M=map{$_,$Z++}0..9,T,J,Q,K,A;sub N{/./;$M{$&}.$'}

sub A{my$I;
for$k(0..41){@d=@_;splice@d,$_,1for$k%7,$k/7;$s=@p=();
for$m(grep$_=N,@d){$m-$_||($s+=2,$p[$m]++)for@d}
@d=sort{$p[$b]-$p[$a]||$b-$a}@d;
$s=23 if$s<11&&($d[0]-$d[4]<5||$d[0]-$d[1]>8&&push@d,shift@d);
"@d"=~/.$/;$s+=14*(4<grep/$&/,@d);
$s=100*$s+$_ for@d;
$I=$s if$s>$I}$I}

++$X{A((@c=split)[0,1,4..8])<=>A(@c[2..8])}for<>;
printf"1: %d\n2: %d\nD: %d\n",@X{1,-1,0}
Run Code Online (Sandbox Code Playgroud)

  • 对我来说都是极客:D (2认同)

Tho*_*ing 7

Haskell:793 796 806 826 864 904 901 880 863


由于文本文件与9张牌不一致,我只是从控制台读取一行并输出谁获胜.


Bug修复:

  • 现在Ace在ace-low跑中的数量低于2.
  • 比较全屋固定(再次:D).
  • 保证选择给定手型的最佳版本.例如,如果玩家可以在2-6跑和3-7跑之间进行选择,则选择3-7跑(冲到一边).
  • 现在比PHP解决方案更短!

Golfed:

import Data.List
(%)=mod
m=map
y=foldr1
t=0<1
z=13
w=[0,1,2,3,12]
n&x|length x<n=[]|t=take n x
b?x|b=x|t=[]
n!k= \c->e(n&m(%k)c)?(n&c)
e[]=1<1
e(x:y)=all(x==)y
k q c|any null[q c,p$c\\q c]=[]|t=q c
f=5!4
s c=(sort(m(%z)c)`elem`w:[[n..n+4]|n<-[0..8]])?c
r=3!z
p=2!z
g x y|c x y<2=x|t=y
q x(_,[])=x
q _ y=y
b h=y q$m($h)$zipWith(\t f->(,)t.y g.m(f.take 5).permutations)[1..][1!1,p,k p,r,s,f,k r,4!z,s.f]
h=reverse.a.m(%z)
a v|w\\v==[]=[-1..3]|t=sort v
c x y=o(h x)$h y
o[](_:_)=2
o[]_=0
o _[]=1
o(a:b)(k:d)|a>k=1|a<k=2|t=o b d
d n(a,k)|a==[]=0|n<1=0|r>s=1|r<s=2|f/=0=f|t=d(n-length o)(a\\o,k\\u)where(r,o)=b a;(s,u)=b k;f=c o u
i x=head.findIndices(x==)
u(n:k)c@[r,s]|n%z==i r"23456789TJQKA"&&n%4==i s"HDSC"=n|t=u k c
l c=(2&c++snd(splitAt 4c),drop 2c)
main=getLine>>=print.d 5.l.m(u[0..]).words
Run Code Online (Sandbox Code Playgroud)

Ungolfed:

import Control.Exception (assert)
import Data.List (permutations, sort, intersect, findIndices, (\\))
import Data.Function (on)

(%) = mod

aceLowRun = [0,1,2,3,12]

tryTake n xs
  | length xs < n = []
  | otherwise = take n xs

cond ? xs
  | cond = xs
  | otherwise = []

eqOn n f cards = allEq (tryTake n $ map f cards) ? tryTake n cards

allEq [] = False
allEq (x:xs) = all (== x) xs

combWithPair pokerHand cards
  | any null [picked1, picked2] = []
  | otherwise = pokerHand cards
  where
    picked1 = pokerHand cards
    picked2 = pair $ cards \\ picked1

straightFlush = straight . flush

quads = eqOn 4 (% 13)

fullHouse = combWithPair triples

flush = eqOn 5 (% 4)

straight cards = (sort (map (% 13) cards) `elem` runs) ? cards
  where
    runs = aceLowRun : [[n..n+4] | n <- [0..8]]

triples = eqOn 3 (% 13)

twoPair = combWithPair pair

pair = eqOn 2 (% 13)

single = eqOn 1 id

bestVersionOfHand [] ys = ys
bestVersionOfHand xs [] = xs
bestVersionOfHand xs ys
  | compareSameRankedHands xs ys < 2 = xs
  | otherwise = ys

rate rating pokerHand cards = (rating, handResult)
  where
    handResult = foldr1 bestVersionOfHand
                        (map (pokerHand . take 5) $ permutations cards)

pokerHands = zipWith rate [1..] [
    single
  , pair
  , twoPair
  , triples
  , straight
  , flush
  , fullHouse
  , quads
  , straightFlush
  ]

bestHand hand = foldr1 (\xs ys -> if null (snd ys) then xs else ys)
                       (map ($ hand) pokerHands)

highestVals = reverse . arrangeVals . map (% 13)
  where
    arrangeVals vals = if vals `intersect` aceLowRun == aceLowRun
      then [-1..3]
      else sort vals

compareSameRankedHands = compareSameRankedHands' `on` highestVals

compareSameRankedHands' [] [] = 0
compareSameRankedHands' (card1:cards1) (card2:cards2)
  | card1 > card2 = 1
  | card1 < card2 = 2
  | otherwise = compareSameRankedHands' cards1 cards2

decideWinner n cards1 cards2
  | null cards1 = assert (null cards2) 0
  | n < 1 = 0
  | rating1 > rating2 = 1
  | rating1 < rating2 = 2
  | cmpRes /= 0 = cmpRes
  | otherwise = decideWinner
                  (n - assert (length bests1 == length bests2) (length bests1))
                  (cards1 \\ bests1)
                  (cards2 \\ bests2)
  where
    (rating1, bests1) = bestHand cards1
    (rating2, bests2) = bestHand cards2
    cmpRes = compareSameRankedHands bests1 bests2

indexOf x = head . findIndices (x==)

toNum = toNum' [0..]

toNum' (n:ns) [rank, suit]
  | n % 13 == indexOf rank "23456789TJQKA" && n % 4 == indexOf suit "HDSC" = n
  | otherwise = toNum' ns [rank, suit]

cluster cards = (take 2 cards ++ snd (splitAt 4 cards), drop 2 cards)

main = getLine >>= print
  . uncurry (decideWinner 5)
  . cluster
  . map toNum
  . words
Run Code Online (Sandbox Code Playgroud)


Nab*_*abb 7

GolfScript - 151/187字符

该程序在每行10张卡的输入列表上工作,即两张5张牌.

n%0.@{3/5/{[zip~;.&,(!15*\[{n),*"TJQKA"+?}/]:|$),-4>=14*+1|{.2\?|@-,5\-.49?@*@+\.+@+\}/.16445=13*@+\]}%.~={0):0;;}{~>.!@+\@+\}if}/"1: "@@n"2: "@n"D: "0
Run Code Online (Sandbox Code Playgroud)

该程序适用于每行9张卡的输入列表,其格式在规范中描述.

n%0.@{3/.4>:D;2/2<{D+.{3/1$^.{3/1$^[zip~;.&,(!15*\[{n),*"TJQKA"+?}/]$:|),-4>=14*+1|{.2\?|@-,5\-.49?@*@+\.+@+\}/.16445=13*@+\]}%\;~}%$-1=\;}%.~={0):0;\(\}*~>.!@+\@+\}/"1: "@@n"2: "@n"D: "0
Run Code Online (Sandbox Code Playgroud)