Гольф кода: у Кого есть лучшая покерная комбинация?

18
задан 9 revs, 4 users 94% 31 July 2010 в 01:07
поделиться

6 ответов

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

Последний раздел разбирает каждую строку ввода в карты, преобразует карты в числовые значения, делит карты на отдельные руки для двух игроков, анализирует и сравнивает эти руки. Каждая рука увеличивает один элемент хэша %X. Когда все входные данные разобраны, %X содержит количество рук, выигранных игроком 1, выигранных игроком 2, или ничьих.

Средняя часть представляет собой подпрограмму, которая принимает на вход набор из пяти карт и выдает 12-значное число с тем свойством, что более сильные покерные руки будут иметь более высокие значения. Вот как это работает:

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

Это детектор "пары". Если две любые карты имеют одинаковое числовое значение, увеличиваем хэш-элемент для одной из карт и увеличиваем переменную "score" $s на два. Обратите внимание, что в итоге мы будем сравнивать каждую карту с самой собой, поэтому $s будет не меньше 10, а $p[$x] будет не меньше единицы для каждой карты $x. Если рука содержит три карты, то эти три карты совпадут с двумя другими картами - будет похоже, что среди этих трех карт есть 9 совпадений, и "счет" будет не менее 18.

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

Сортируйте карты по (1) количеству раз, когда эта карта входит в "пару" и (2) значению карты. Таким образом, в руке с двумя семерками и двумя тройками сначала появятся две семерки, затем две тройки, затем кикер. В руке с двумя семерками и тремя тройками первыми будут три тройки, затем две семерки. Цель этого порядка - отличить две руки с одинаковым счетом - рука с парой восьмерок и рука с парой семерок имеют по одной паре, но мы должны быть в состоянии сказать, что пара восьмерок лучше.

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

Эта линия - детектор "стрита". Стрит стоит 23 очка и возникает, когда в руке нет пар ($s<11 означает, что найдено только 5 "пар" - каждая карта совпадает сама с собой) и либо (1) значение самой старшей карты ровно на четыре больше значения самой младшей карты ($_[0]-$_[4]==4), или (2) самая старшая карта - туз, а следующая по значению карта - пятерка ($_[0]-$_[1]==9), что означает, что рука имеет стрит A-2-3-4-5. В последнем случае туз теперь является наименее ценной картой в руке, поэтому мы изменяем @_, чтобы отразить это (push@_,shift)

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

Эта линия - детектор флеша. Флеш стоит на 14 очков больше и возникает, когда последний символ одинаков для каждой карты. Первое выражение ("@_"=~/.$/) имеет побочный эффект установки $& на последний символ (масть) последней карты в руке. Итоговое выражение (4) будет истинным тогда и только тогда, когда все элементы @_ имеют одинаковый последний символ.

    $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, игроки делят следующие 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}
15
ответ дан 30 November 2019 в 07:12
поделиться

Haskell: 793 796 806 826 864 904 901 880 863


Поскольку текстовый файл несовместим с 9 картой руками, я просто читаю строчку из консоли и выводю кто выиграет.


Исправления:

  • Туз теперь считается меньше, чем 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
7
ответ дан 30 November 2019 в 07:12
поделиться

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";
3
ответ дан 30 November 2019 в 07:12
поделиться

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
4
ответ дан 30 November 2019 в 07:12
поделиться

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

Эта программа работает со входным списком из 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
7
ответ дан 30 November 2019 в 07:12
поделиться

C, 665 + 379 символов

Вот мой ответ, состоящий из двух частей.

Первый - это полный анализатор 7 карт, включая макрос «AddCard» 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 + 5 карт (без учета 10-й карты). Он использует макрос Parse, P для создания 32-битных значений, представляющих каждую карту. Представление: 0A0K0Q0J0T090807060504030200shdc . Рука хранится в виде массива из 5 единиц.

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]);}

Я уверен, что нужно обрезать еще несколько символов. Я скоро добавлю объяснение.

Оценщик работает со скоростью 17,6 миллионов раздач в секунду на моем Core2 Duo с тактовой частотой 3 ГГц. Это всего в 3,5 раза медленнее, чем оценщик PokerSource , который использует не менее 56К таблиц поиска.

3
ответ дан 30 November 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: