Compare duas mãos de poker

14

Desafio:

Dadas duas mãos de cinco cartas, determine qual delas vence pelo ranking padrão das mãos de pôquer .

Entrada:

Dez cartões separados por espaços do stdin ou como argumentos da linha de comando, o que você preferir. As cinco primeiras cartas são a mão do jogador 1, enquanto as últimas cinco são a mão do jogador 2. Cada cartão será uma sequência de duas letras no formato RS, onde R é o rank e S é o naipe. As classificações variam de 2-9, T para dez e J, Q, K e A para Jack, Queen, King e Ace, respectivamente. Os naipes são H, D, C, S para Copas, Diamantes, Paus e Espadas, respectivamente. Você deve gerar o número do jogador que vence: '1' ou '2'.

Exemplos de cartões:

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

Exemplos de entrada para saída:

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

Explicação: O Jogador 1 tem um Par de Cincos enquanto o Jogador 2 tem um Par de Oito.

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

Explicação: Nenhum dos jogadores tem nada de especial, mas a carta alta do jogador 1 é um ás, enquanto a carta alta do jogador 2 é uma rainha.

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

Explicação: O jogador 1 possui três ases, o jogador 2 possui um Flush of Diamonds.

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

Explicação: Ambos os jogadores têm um par de rainhas, mas a segunda carta mais alta do jogador 1 é nove, enquanto o jogador 2 é sete.

Regras e esclarecimentos:

  • Consulte a classificação padrão das mãos de pôquer para obter detalhes sobre a comparação de mãos.
  • Você pode assumir que não há cartas repetidas em cada par de mãos.
  • Você pode assumir que existe um vencedor definitivo em cada caso.
  • O naipe não leva em consideração o ranking de uma mão. Por exemplo, dois royal flushes de naipes diferentes são iguais (portanto, qualquer entrada em que ambos os jogadores tenham um royal flush é inválida pela regra anterior).
  • Como se trata de código de golfe, a resposta mais curta vence.

Notas:

comando
fonte
Desculpas se há algo que eu perdi! Esta é a minha primeira pergunta de código de golfe.
comando
Isso é semelhante a esta pergunta recente codegolf.stackexchange.com/q/23743/15599 e a versão de 5 cartões mencionada nela. No entanto, essas perguntas são necessárias apenas para nomear o tipo de mão. Uma grande diferença aqui é que, se os dois jogadores tiverem o mesmo tipo de mão, precisamos determinar qual é o melhor por ordem de cartas (por exemplo, para dois pares, quem tem o melhor primeiro par, segundo par e, se necessário, uma carta única). não é uma duplicata. Sempre procure por perguntas semelhantes, vincule-as (veja o que você fez) e esteja preparado para defender por que não é uma duplicata antes de postar.
Level River St
E se o flop e a mão forem iguais?
Ismael Miguel
@IsmaelMiguel Não há flop nesta versão. Existem simplesmente duas mãos separadas que devem ser avaliadas uma contra a outra.
comando
1
Resolvido anteriormente para 10 cartões aqui
Hasturkun 30/03

Respostas:

2

Haskell - 352 339 caracteres

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

Corre:

& 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 e comentou, para que você possa ver o 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
MtnViewMark
fonte
2

Pitão - 774 722 707 698 685 caracteres

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:])))

Eu escolhi gerar uma string para cada mão que a represente, começando com um caractere para o tipo de mão, seguido por caracteres que descrevem a variação específica do tipo (por exemplo, qual cartão você tinha apenas 4 de?), Seguido por os valores das cartas restantes em caso de empate (se ambos os jogadores tiverem o mesmo par duplo, a quinta carta terá que decidir quem ganha). Eu testei bastante, mas na verdade não jogo poker, então espero ter acertado. Além disso, eu sei que ainda não está totalmente jogado, provavelmente poderei raspar algumas dezenas de caracteres mais tarde.

Tal
fonte
Mate 5 caracteres com _=lambda c:chr(97+c). Além disso, você tem algum espaço em branco desnecessário após :s e =s. Por fim, use em ;vez de novas linhas para separar instruções para reduzir o espaço em branco usado para indentação.
user12205
Agradável com a lambda, obrigado!
Tal
2

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

uso:

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

fonte

Alex
fonte
1

perl, 801 733 caracteres

Eu acredito que esta é uma implementação bastante direta. Basicamente, para cada mão, classificamos os naipes e os rostos separadamente. Em seguida, fazemos outra cópia dos rostos com ases com contagem baixa, para que possamos verificar retas com ases baixos. Depois, determinamos se temos um flush ou straight e qual é a carta mais alta. Depois, verificamos as partidas em ordem de pontuação (primeiro, verificamos os straight flushes, depois os quatro tipos, etc.). A pontuação real é apenas a concatenação do tipo de mão seguida pelos valores de face das cartas na ordem em que elas importam (isso é _s () na versão não-golfada, u () na versão do golfe). Aqui está:

@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

E aqui está o equivalente a menos golfe:

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;
skibrianski
fonte
AH 2C 3S 4S 5D 6C 7S 7C 7D TDproduz um resultado de 2, mas acho que uma sequência bate três do mesmo tipo
ossifrage melindroso 30/03/14