18

私はこのような挑戦が大好きです、うまくいけばすぐに私の答えを提出します。

どのプレイヤーが最高の7カードハンドを持っていますか?

9枚のカードの順序付けられていないリスト(スペースで区切られている)を前提として、どのプレーヤーが最高のポーカーハンドを持っているかを調べます。 これがポーカーハンドランキングのリストです。入力例:

2C 5H AS KS 2D 4D QD KH 3S
(ie: [[2C 5H] [AS KS] [2D 4D QD KH 3S]])

配列の最初の2枚のカードはプレーヤー1の手を表し、配列の2番目の2枚はプレーヤー2の手を表します。最後の5枚のカードはコミュニティカードを表し、両方のプレイヤーが共有するカードです。事実上、両方のプレーヤーは7枚のカードを持っており、どちらのプレーヤーが最高の5枚のカードポーカーハンドを持っているかを判断する必要があります。

カードは文字列として定義され、最初の文字はカードの値を表し、2番目の値はスーツを表します。常に大文字。カードが2回表示されることはありません。

この関数は、ハンドがどちらかのプレーヤーにとって引き分けか勝利かを計算します。入力の最後に合計が出力されます。出力形式は、この投稿の後半で定義されます。

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.

より詳しい情報

同様の問題を抱えているプロジェクトオイラーへの次のリンクを提供してくれたmgrovesに感謝します:http://projecteuler.net/index.php?section = problems&id = 54

テストデータ

プロジェクトオイラーのテストデータを使用します。

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

ソリューションは、そのテキストファイルを入力として受け入れ、勝ちと引き分けの合計を出力する必要があります。

出力例

出力は次の形式である必要があります。

1: 45
2: 32
D: 12

プレーヤー1は45ハンドを獲得し、プレーヤー2は32ハンドを獲得し、12回のドローがありました。(実際の結果ではありません)

ルール

  • 勝ち手のタイプを返す必要はありません。誰かが勝った場合にのみWHOが勝ちます。
  • カードリストの入力に特定の順序はありません
  • 入力にカードが2回表示されない
  • 入力は常に大文字です
  • プロジェクトオイラーのテストデータを入力として受け取ります
  • 上記の指定された形式で、プレーヤーが最も多くのハンドと合計ドローを獲得したカウントを出力します
4

6 に答える 6

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}

これにより、「10枚のカード」の問題が解決されます(10枚のカードが配られ、プレーヤー1には最初の5枚のカードがあり、プレーヤー2には次の5枚のカードがあります)。

最初のセクションNでは、各カードを数値に変換できるサブルーチンを定義します。非フェイスカードの場合、これは簡単なマッピング(5H ==> 5H)ですが、フェイスカードを変換します(KC => 13C、AD => 14D)。

最後のセクションでは、入力の各行をカードに解析し、カードを数値に変換し、カードを2人のプレーヤーの別々のハンドに分割し、それらのハンドを分析して比較します。すべての手はハッシュの1つの要素をインクリメントします%X。すべての入力が解析されると、%Xプレーヤー1が勝ったハンドの数、またはプレーヤー2が勝ったハンドの数が含まれます。

真ん中のセクションは、5枚のカードのセットを入力として受け取り、12桁の数字を生成するサブルーチンであり、より強いポーカーハンドはより価値の高い数字を持つという特性を備えています。仕組みは次のとおりです。

    for$m(@_){$m-$_||($s+=2,++$p[$m])for@_}

これが「ペア」検出器です。2枚のカードの数値が同じである場合は、1枚のカードのハッシュ要素をインクリメントし、「スコア」変数$sを2つ増やします。最終的に各カードをそれ自体と比較することになります。したがって$s、少なくとも10になり$p[$x]、カードごとに少なくとも1つになります$x。手札に3種類のカードが含まれている場合、それらの3枚のカードは他の2枚のカードと一致します。つまり、これら3枚のカードの間に9枚の一致があり、「スコア」は少なくとも18枚になります。

    @_=sort{$p[$b]-$p[$a]||$b-$a}@_;

カードを(1)そのカードが「ペア」の一部である回数と(2)カードの値で並べ替えます。したがって、2つの7と2つの3を持つハンドでは、2つの7が最初に表示され、次に2つの3が表示され、次にキッカーが表示されます。2つの7と3つの3を持つハンドでは、最初に3つの3が続き、次に2つの7が続きます。この順序付けの目的は、スコアが同じ2つのハンドを区別することです。8のペアを持つハンドと7のペアを持つハンドの両方に1つのペアがありますが、8のペアがあることを認識できる必要があります。優れている。

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

この線は「まっすぐな」検出器です。ストレートは23ポイントの価値があり、手札にペアがない場合($s<11つまり、各カードがそれ自体と一致する5つの「ペア」のみが見つかった場合)に発生し、(1)最も高いカードの値が最も低いカードの値($_[0]-$_[4]==4)、または(2)最も高い値のカードはエースであり、次に高いカードは5($_[0]-$_[1]==9)であり、これはハンドがA-2-3-4-5ストレートを持っていることを意味します。後者の場合、エースは手札の中で最も@_価値の低いカードであるため、それを反映するように操作します(push@_,shift

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

このラインはフラッシュ検出器です。フラッシュはさらに14ポイントの価値があり、最後のキャラクターが各カードで同じ場合に発生します。最初の式( )には、手札の最後のカードの最後のキャラクター(スーツ)に"@_"=~/.$/設定するという副作用があります。$&最終式( )は、のすべての要素の最後の文字が同じ4<grep/$&/,@_である場合にのみ真になります。@_

    $s=100*$s+$_ for@_;$s}

手のスコアで始まり、カードの重要度の順にカードの値を含む値を作成して返します。さまざまな手のスコアは

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)

これはポーカーのルールと一致しています。同じスコアのハンドは、ハンドの重要度の高い順に、ハンドの中で最も価値の低いカードに至るまで、ハンドのカードの値によって区別できます。

9枚のカードの問題(プレーヤー1に2枚のカード、プレーヤー2に2枚のカード、プレーヤーは次の5枚のカードを共有し、最高の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}
于 2010-07-31T05:50:21.643 に答える
7

Haskell:793 796 806 826 864 904 901 880 863


テキストファイルは9枚のカードハンドと矛盾しているため、コンソールから1行を読み取り、誰が勝ったかを出力しています。


バグの修正:

  • エースは、エースローランで2よりも少なくカウントされるようになりました。
  • 固定された完全な家の比較(ここでも:D)。
  • 与えられた手のタイプの最良のバージョンが選択されることを保証します。たとえば、プレーヤーが2〜6ランと3〜7ランのどちらかを選択できる場合、3〜7ランが選択されます(フラッシュは脇に置きます)。
  • PHPソリューションよりも短くなりました!

ゴルフ:

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

ゴルフなし:

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
于 2010-07-30T06:50:27.110 に答える
7

GolfScript-151/187文字

このプログラムは、1行あたり10枚のカード、つまり2枚の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

このプログラムは、仕様に記載されている形式の1行あたり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
于 2010-08-03T10:45:18.677 に答える
4

GolfScript 258 241 247/341 217/299 char

10カードの問題の解決策。最後の数行の改行だけが重要です。

10:T):J):Q):K):A;0:a;0:b;0:d;"\r\n"%{' '/5/{.{)\;}/4*-+++!:f;{);~}%{$0:z(%{.z-
!99*+:z}%}5*.{+}*99/:P!{..)\(@4+-!2*\;\.2<~9+-!\;+}and:s;[s f*6P=4P=f s P 6$]\;}
%.~={;;d):d;}{~>{a):a;}{b):b;}if}if}/
'1: 'a'
2: 'b'
D: 'd n

9枚のカードの問題は現在約80文字以上必要です。

10:T):J):Q):K):A;0:a;0:b;0:d;"\r\n"%{' '/);{('Z'%+}2*[0$2>\7<]
{:H;7,{H=:x;H{x=!},:I;6,{I=:x;I{x=!},}/}%{.{)\;}/4*-+++!:f;
{);~}%{$0:z(%{.z-!99*+:z}%}5*.{+}*99/:P!{..)\(@4+-!2*\;\.2<~9+-!\;+}and:s;[
s f*6P=4P=f s P 6$]\;}%{[\].~>{~;}{~\;}if}*}%.~={;;d):d;}{~>{a):a;}{b):b;}if}if}/
'1: 'a'
2: 'b'
D: 'd n

10枚のカードの問題のあまりゴルフバージョン。

10:T;11:J;12:Q;13:K;14:A;              # map for face cards
0:a;0:b;0:d;                           # other initialization

"\r\n"%                                # split input on \n
{                                      # on each line of input
    ' '/                               #  divide line into ten cards
    5/                                 #  split into five card hands

    {.                                 #  on each of the two hands

         {)\;}%                        #   chop last character of each card
         .(5*\;\{+}*=                  #   check sum of elem == 5*1st elem
         :f;                           #   this is the flush flag

         {);~}%$                       #   reduce cards to numerical values

         0:z;{.z- 20%{}                
             {;z 20+}if:z}%{-1*}$      #   detect pairs

         .(:h;;                        #   extract value of highest card


         20h>{..)\(@4+-!2*\;\          # detect straight
             .2<~9+-!\;+}and:s;        # s=2 for regular straight, s=1 for A-5 straight

                                       # result of this mapping - 6 elem array
         [ 0$                          #   #6 - cards in the hand
           .{20/}%{+}*:P               #   #5 - number of pairs
           s                           #   #4 - is this a straight?
           f                           #   #3 - is this a flush?
           4P=                         #   #2b - is this a full house?
           h 59>                       #   #2 - is this 4 of a kind?
           s f *                       #   #1 - is this a straight flush?
         ]-1% 

    \;
    }/

    \.@.@                             # put [hand1 hand2 hand1 hand2] on stack

    =                                 # check hand1==hand2

    {;;d):d;}                         # if equal, increment d (draw)
       {>{a):a;}                      # if >, increment a (player 1 wins)
       {b):b;}if                      # if <, increment b (player 2 wins)
     }if
}/

                                      # output results    
'1: 'a'
2: 'b'
D: 'd n
于 2010-08-03T03:43:08.357 に答える
3

PHP、799文字

改行は重要ではありません。これは、リンクされたURLから入力を受け取ります。これは、入力例とは異なります(コミュニティカードは処理しません)。処理はmobruleのperl回答に似ていますが、スコアリング方法が異なります。

<?php
function s($i){$o=array_map('intval',$i);$f=(count(array_unique(str_replace($o,'',$i)))==1);
sort($o);$v=array_count_values($o);arsort($v);$u=array_keys($v);$h=max($u);$m=$u[0];$c=reset($v);
$p=count($v);$e=$c==1&&$o[4]==14&&$o[3]==5;$r=$o==range($o[0],$o[0]+4)||$e;$q=$e?5:$h;
$s=($f&&$r&&($h==12)?2<<11:($f&&$r?(2<<10)+$q:0))+($c==4?(2<<9)+$m:0)+($c==3&&$p==2?(2<<8)+$m:0)+($f?(2<<7)+$h:0)+
($r?(2<<6)+$q:0)+($c==3?(2<<5)+$m:0)+($c==2&&$p==3?(2<<4)+$m:0)+($p==4?(2<<3)+$m:0);$s+=!$s?$h:0;return array($s,$u);}

foreach(file($argv[1]) as $d){
list($y,$z)=array_chunk(explode(' ',trim(strtr($d,array('T'=>10,'J'=>11,'Q'=>12,'K'=>13,'A'=>14)))),5);
$y=s($y);$z=s($z);$w=$y[0]-$z[0];$x=1;while(!$w&&$x<5){$w=$y[1][$x]-$z[1][$x++];}if(!$w)@$t++;elseif($w<0)@$l++;else @$k++;}
@print "1: $k\n2: $l\nD: $t";
于 2010-07-31T23:29:41.770 に答える
3

C、665+379文字

これが私の答えです。

1つ目は、「AddCard」マクロを含む完全な7枚のカード評価ツールAです。ハンドをランク​​付けする32ビットの数値を返します。ハイニブルはタイプであり、ビット13..25はハイカードを示し、ビット0..12はキッカーを示します。結果を比較するとき、より良いハンドは常により大きな値を持ちます。

#define U unsigned
#define c(a)X=a;i=C=0;while(X){C|=(X&1)<<i++;X/=4;}
#define A(h,c)h[c&7]+=c,h[3]|=c
U C,i,X;
U E(U h[]){
U a=h[0]+h[1]+h[2]+h[4]-(h[3]&-16),t,v,k,e=a&0x55555540,o=a&0xAAAAAA80;
if(v=e&o/2){t=7;k=h[3]^v;i=0;while(k/=4)i++;k=1<<2*i;}
else if(v=o&o-1){t=6;v/=2;k=o/2^v;}
else if(e>1&o>1){t=6;v=o/2;k=(i=e&e-1)?i:e;}
else{a=h[3];
if(t=h[i=1]-(a&1)&4||h[i=2]-(a&2)&8||h[i=4]-(a&4)&16||h[i=0]-(a&8)&32)a=h[i];
a&=-64;v=a|a>>26&16;t*=5;
if(v=v&v<<2&v<<4&v<<6&v<<8){t+=4;a=v&=~(v/2);}
else if(t)for(i=(h[i]&63)/(i?i:8),v=a;i-->5;)a&=a-1;
else if(v=o/2)t=3;
else if (e){o=e&e-1;v=(i=o&o-1)?o:e;t=1+(o>0);}
k=a^v;k&=k-1;k&=k-(i==0);}
c(v);v=C/8;c(k);
return t<<28|v<<13|C/8;}

2番目は入力プロセッサです。プロジェクトオイラーファイルを2+2 + 5カードとして解析します(10枚目のカードは無視します)。Parseマクロを使用して、P各カードを表す32ビット値を作成します。表現は0A0K0Q0J0T090807060504030200shdcです。手は5つのintの配列として格納されます。

char*gets(char*);char*strchr(char*,char);
#define P(c)X=strchr(R,*c++)-R;C=1<<strchr(S,*c++)-S|64<<X*2;c++;
#define L(n)for(i=0;i<n;i++)
U g[5],h[5];
char*c,b[32];
char*S="CDHS";
char*R="23456789TJQKA";
int d,r[3]={0};
main(q){while(c=gets(b)){
L(2){P(c)A(g,C);}
L(2){P(c)A(h,C);}
L(5){P(c)A(g,C);A(h,C);}
d=E(g)-E(h);
r[d>0?0:d<0?1:2]++;
L(7)g[i]=h[i]=0;
}L(3)printf("%c:%d\n","12D"[i],r[i]);}

トリミングする文字があと数個あると思います。すぐに説明を追加します。

評価者は私の3GhzCore2Duoで@1760万ハンド/秒を実行します。これは、少なくとも56Kのルックアップテーブルを使用するPokerSourceエバリュエーターよりも3.5倍遅いだけです。

于 2010-08-02T21:42:11.003 に答える