Escolha a última carta na mão de poker

31

As mãos de pôquer são classificadas da melhor para a pior da seguinte forma:

  1. Straight flush - cinco cartas de ordem sequencial, todas do mesmo naipe
  2. Four of a kind - quatro cartas do mesmo valor e uma carta de outro valor
  3. Full house - três cartas de um valor e duas cartas de outro valor
  4. Flush - cinco cartas do mesmo naipe
  5. Straight - cinco cartas de valor sequencial
  6. Três do mesmo tipo - três cartas do mesmo valor e duas cartas de duas outras fileiras
  7. Dois pares - duas cartas do mesmo valor, duas cartas de outro valor e uma carta de um terceiro valor
  8. Um par - duas cartas do mesmo valor e três cartas de três outras fileiras
  9. Carta alta - cinco cartas nem todas com o mesmo valor seqüencial ou do mesmo naipe e nenhuma delas com o mesmo valor

  • Rank = O número no cartão (A, K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3, 2). Você pode optar por usar T em vez de 10.
  • Naipe = copas (h), espadas (s), paus (c) e diamantes (d).

Observe que o ás, Apode ser o número mais alto e o mais baixo (1 ou 14).

Uma carta pode ser identificada por duas letras As(Ás de espadas), Jc(Valete de paus), 7h(7 de copas) e assim por diante.


Desafio:

Você recebe quatro cartas do revendedor (quatro seqüências de entrada). Encontre e produza o melhor cartão possível possível.

Se houver cartões igualmente bons, você poderá escolher qual escolher.

Os formatos de entrada e saída são opcionais, mas os cartões individuais devem ser identificados como mostrado acima Jce 2h.


Casos de teste:

Ah Kh Jh 10h
Qh

7d 8h 10c Jd
9d (or 9h, 9c, 9s)

Js 6c 10s 8h
Jc (or Jh, Jd)

Ac 4c 5d 3d
2h (or 2d, 2c, 2s)

5s 9s Js As
Ks

2h 3h 4h 5h
6h

Js Jc Ac Ah
As (or Ad)  <- Note that AAAJJ is better than AAJJJ because A is higher than J

10d 9d 5h 9c
9h (or 9s)

Ah Ac Ad As
Ks (or Kd, Kh, Kc)

4d 5h 8c Jd
Jc (or Js, Jh)

Este é um código de golfe, portanto, o menor envio em bytes vence.

Stewie Griffin
fonte

Respostas:

13

Pitão, 73 bytes

eo_S+*-5l@\AN}SPMJ+NZSM.:+\AT5+-4l{eMJlM.gPkJ-sM*=T+`M}2Tc4"JQKA""hscd"=Zc

Isso é bem terrível. Analisando cartões, classificando os valores, ... Tudo leva tantos caracteres. Mas a abordagem é interessante.

Experimente on-line: Demonstration or Test Suite

Explicação:

Gero todos os 52 cartões, retiro os quatro cartões da entrada, giro uma pontuação para cada cartão (pontuação da mão) e imprimo o cartão com a pontuação máxima.

A pontuação é um pouco estranha. Se eu comparar a pontuação de duas mãos completamente diferentes, pode escolher o vencedor errado. Por exemplo, uma sequência venceria 4 ases. Mas funciona, se as 4 primeiras cartas forem iguais nas duas mãos. E minha pontuação calculada não é realmente um valor, mas uma lista de valores:

  • G: Primeiro eu agrupo as 5 cartas por posição e compro: 5h 5d 6c 5s Jd -> [3, 1, 1]
  • F: Em seguida, acrescento 4 menos o número de suítes diferentes a esta lista. Flush -> 3é anexado, not flush -> 2/1/0é anexado.
  • S: adicione outro número. 0se não for uma sequência, 4se for a sequência A2345, ou 5se for uma sequência mais alta.

Essas listas de 4-7 números são classificadas em ordem decrescente e a lista com valor máximo é selecionada.

Por que isso funciona? Aqui você vê as configurações possíveis para todos os tipos. A letra ao lado dos números indica com qual regra esse número foi gerado.

  • Straight flush: [5S, 3F, 1G, 1G, 1G, 1G, 1G]ou[4S, 3F, 1G, 1G, 1G, 1G, 1G]
  • Quatro de um tipo: [4G, 1G, 0F, 0S]
  • Casa completa: [3G, 2G, 1F, 0S]ou[3G, 2G, 0F, 0S]
  • Rubor: [3F, 1G, 1G, 1G, 1G, 1G, 0S]
  • Em linha reta: [5S, 2F, 1G, 1G, 1G, 1G, 1G], [5S, 1F, 1G, 1G, 1G, 1G, 1G], [5S, 1G, 1G, 1G, 1G, 1G, 0F], [4S, 2F, 1G, 1G, 1G, 1G, 1G], [4S, 1F, 1G, 1G, 1G, 1G, 1G],[4S, 1G, 1G, 1G, 1G, 1G, 0F]
  • Três de um tipo: [3G, 1G, 1G, 1F, 0S],[3G, 1G, 1G, 0F, 0S]
  • Dois pares: [2G, 2G, 2F, 1G, 0S], [2G, 2G, 1F, 1G, 0S],[2G, 2G, 1G, 0F, 0S]
  • Um par de: [2G, 2F, 1G, 1G, 1G, 0S], [2G, 1G, 1G, 1G, 1F, 0S],[2G, 1G, 1G, 1G, 0F, 0S]
  • Alta card: [2F, 1G, 1G, 1G, 1G, 1G, 0S], [1F, 1G, 1G, 1G, 1G, 1G, 0S],[1G, 1G, 1G, 1G, 1G, 0S, 0F]

Pyth compara as listas em elementos. Portanto, é óbvio que um straight flush sempre vence quatro do mesmo tipo. A maioria das regras típicas do poker é óbvia nessas listas. Alguns parecem conflitantes.

  • Uma Straight vencerá o Four ou o Full house: Não é um problema. Se você tiver a chance de obter Four of a kind / Full house com a carta do river, não poderá chegar a uma sequência ao mesmo tempo (já que você já tem 2 ou 3 suítes diferentes na sua mão).
  • Um Straight vencerá contra um flush. Se você conseguir um flush e um straight com a carta do river, também poderá alcançar um straight. E o straight flush tem uma pontuação melhor do que o straight e o flush.
  • Um par [2G, 2F, 1G, 1G, 1G, 0S]ganhará contra algumas mãos de dois pares. Também não há problema. Se você receber dois pares com a carta do river, terá pelo menos um par antes do river. Mas isso significa que você pode melhorar para três tipos, o que é melhor. Portanto, um par de dois nunca será realmente a resposta.
  • A carta alta [2F, 1G, 1G, 1G, 1G, 1G, 0S]ganhará contra algumas mãos de um par. Se esta é a melhor pontuação que você pode alcançar, antes do river você terá 3 cartas de uma suíte e uma carta de uma suíte diferente. Mas então você pode escolher o cartão com uma dessas duas suítes e com um valor que já aparece, e você terminará com a pontuação [2F, 2G, ...], que também é melhor.

Portanto, isso escolhe o tipo correto de solução. Mas como obtenho o melhor par (de 4 possibilidades), como escolho o melhor straight, ...? Porque duas soluções diferentes de um par podem ter a mesma pontuação.

Isso é fácil. Pyth garante uma classificação estável (ao usar o máximo). Então, eu simplesmente gero os cartões na ordem 2h 2s 2c 2d 3h 3s ... Ad. Portanto, o cartão com o valor mais alto será automaticamente o máximo.

Detalhes da implementação

=Zcdivide a sequência de entrada e armazena a lista de cartões Z. =T+`M}2Tc4"JQKA"gera a lista de classificações ['2', ..., '10', 'J', 'Q', 'K', 'A']e as armazena T. -sM*T..."hscd"Zgera cada combinação de classificação com as suítes e remove os cartões de Z.

o...ordena essas cartas restantes por: lM.gPkJo comprimento dos grupos das fileiras, +-4l{eMJlManexa 4 comprimentos (suítes), +*-5l@\AN}SPMJ+NZSM.:+\AT5acrescenta 0/4/5, dependendo da suíte (gere cada substring de comprimento 5 de "A" + T, verifique se a mão um deles (requer classificar a mão e classificar todos os subconjuntos), multiplicar por 5 - número de "A" s no cartão), _Sclassifica a lista diminuindo.

e escolha o máximo e imprima.

Jakube
fonte
2
Muito criativa e ótima explicação!
9788 Gregory Martin
4

JavaScript (ES6), 329 324 317 312 309 bytes

H=>[..."cdhs"].map(Y=>[...L="AKQJT98765432"].map(X=>~H.indexOf(X+=Y)||([...H,X].map(([R,S])=>a|=eval(S+'|=1<<L.search(R)',F|=S!=H[0][1]),F=a=c=d=h=s=0),x=c|d,y=h|s,c&=d,h&=s,p=c|x&y|h,t=c&y|h&x,(S=a-7681?((j=a/31)&-j)-j?F?c&h?2e4+a:t?t^p?3e4+t:7e4:p?8e4+p:M:4e4+a:F?5e4+a:a:F?6e4:1e4)<M&&(R=X,M=S))),M=1/0)&&R

Como funciona

Para cada carta restante no baralho, calculamos a pontuação da mão S. Quanto menor a pontuação, melhor a mão.

Variáveis ​​usadas para calcular a pontuação

  • F: falsy se a mão é um flush
  • c: bitmask de clubes
  • d: bitmask de diamantes
  • h: bitmask de Copas
  • s: bitmask de espadas
  • x = c | d: bitmask de clubes ou diamantes
  • y = h | s: bitmask de copas ou espadas
  • a: máscara de bit de todos os fatos combinados
  • p = c & d | x & y | h & s: par de máscara de bit (1)
  • t = c & d & y | h & s & x: três de um tipo máscara de bit (1)

(1) Eu escrevi essas fórmulas alguns anos atrás e as usei em vários mecanismos de pôquer. Eles trabalham. :-)

Outras fórmulas

  • c & d & h & s: quatro de um tipo de máscara
  • a == 7681: teste para a reta especial "A, 2, 3, 4, 5" (0b1111000000001)
  • ((j = a / 31) & -j) == j: teste para todas as outras retas

Gráfico de pontuação

Value    | Hand
---------+--------------------------------------------
0   + a  | Standard Straight Flush
1e4      | Special Straight Flush "A, 2, 3, 4, 5"
2e4 + a  | Four of a Kind
3e4 + t  | Full House
4e4 + a  | Flush
5e4 + a  | Standard Straight
6e4      | Special Straight "A, 2, 3, 4, 5"
7e4      | Three of a Kind
8e4 + p  | Pair
Max.     | Everything else

NB: Não precisamos nos preocupar com dois pares, o que não pode ser nossa melhor opção. (Se já temos um par, podemos transformá-lo em um Três. E se já temos dois pares, podemos transformá-los em um Full House.)

Casos de teste

Arnauld
fonte
3

JavaScript (ES6), 307 349

Isso é bastante volumoso e não tenho certeza de que é a melhor abordagem. Ainda um pouco de golfe, talvez.

h=>(r='_23456789TJQKAT',R=x=>r.search(x[0]),M=i=>[...'hcds'].some(s=>h.indexOf(j=h[i][0]+s)<0)&&j,[u,v,w,y]=h.sort((a,b)=>R(a)-R(b)).map(x=>R(x)),[,,d,e,f,g,k]=[...new Set(h+h)].sort(),q=10-u-v-w,s=(z=y>12)&q>0?q:y-u<5&&u*5+q-y,d>r?z?'Kh':'Ah':f>r?M((e>r?v<w:u<v)+1):s?r[s]+g:k?M(3):r[13-z-(w>11)-(v>10)]+g)

Menos golfe

h=>(
  // card rank, 1 to 13, 0 unused
  // fake rank 14 is T, to complete a straight JQKA?
  // as I always try to complete a straight going up
  r = '_23456789TJQKAT', 

  // R: rank a card
  R = x => r.search(x[0]),  

  // M: find a missing card (to complete a same-rank set like a poker)
  // look for a card with the same rank of the card at position i
  // but with a suit not present in the hand
  M = i => [...'hcds'].some(s => h.indexOf(j=h[i][0]+s) < 0) && j,
  h.sort((a, b) => R(a)-R(b) ), // sort hand by rank
  [u,v,w,y] = h.map(x=>R(x)),   // rank of cards 0..3 in u,v,w,y

  // Purpose: look for duplicate rank and/or duplicate suits
  // Put values and suits in d,e,f,g,k, with no duplicates and sorted
  // suits are lowercase and will be at right end
  [,,d,e,f,g,k] = [...new Set(h+h)].sort(),

  // Only if all ranks are different: find the missing value to get a straight
  // or 0 if a straight cannot be obtained
  // The first part manages the A before a 2
  q = 10-u-v-w, s = y>12&q>0 ? q : y - u < 5 && u * 5 + q - y,

  d > r // d is lowercase -> all cards have the same rank
    ? u < 13 ? 'Ah' : 'Kh' // add a K to a poker of A, else add an A
    : e > r // e is lowercase -> 2 distinct ranks
      ? M(v<w ? 2 : 1) // go for a poker or a full house
      : f > r // f is lowercase -> 3 distinct ranks, we have a pair
        ? M(u<v ? 2 : 1) // find the pair and go for 3 of a kind
        : s // all different ranks, could it become a straight?
          ? r[s] + g // if there is only a suit, it will be a flush straight too
          : k // if there are 2 or more different suits
            ? M(3) // go for a pair with the max rank
            : r[13-(y>12)-(w>11)-(v>10)]+g // flush, find the max missing card
)

Teste

F=
h=>(r='_23456789TJQKAT',R=x=>r.search(x[0]),M=i=>[...'hcds'].some(s=>h.indexOf(j=h[i][0]+s)<0)&&j,[u,v,w,y]=h.sort((a,b)=>R(a)-R(b)).map(x=>R(x)),[,,d,e,f,g,k]=[...new Set(h+h)].sort(),q=10-u-v-w,s=(z=y>12)&q>0?q:y-u<5&&u*5+q-y,d>r?z?'Kh':'Ah':f>r?M((e>r?v<w:u<v)+1):s?r[s]+g:k?M(3):r[13-z-(w>11)-(v>10)]+g)

output=x=>O.textContent+=x+'\n'

;`Ah Kh Jh Th -> Qh
7d 8h Tc Jd -> 9d 9h 9c 9s
Js 6c Ts 8h -> Jc Jh Jd
Ac 4c 5d 3d -> 2h 2d 2c 2s
5s 9s Js As -> Ks
2h 3h 4h 5h -> 6h
Js Jc Ac Ah -> As Ad
Td 9d 5h 9c -> 9h 9s
Ah Ac Ad As -> Ks Kd Kh Kc
4d 5h 8c Jd -> Jc Js Jh`
.split('\n')
.forEach(s=>{
  var o = s.match(/\w+/g) // input and output
  var h = o.splice(0,4) // input in h, output in o
  var hs = h+''
  var r = F(h)
  var ok = o.some(x => x==r)
  
  output((ok?'OK ':'KO ')+ hs + ' -> ' + r)
})
<pre id=O></pre>

edc65
fonte
É engraçado ver que nossas duas abordagens parecem convergir para tamanhos muito semelhantes. :-) Em termos de desempenho, você é definitivamente mais rápido.
Arnauld
@ Arnauld Eu consegui raspar mais alguns 4 bytes. Sua vez
edc65 17/11