Выберите последнюю карту в покерной руке

31

Покерные руки ранжируются от лучших к худшим следующим образом:

  1. Стрит-флеш - пять карт последовательного ранга одной масти
  2. Четыре вида - четыре карты одного ранга и одна карта другого ранга
  3. Полный дом - три карты одного ранга и две карты другого ранга
  4. Флеш - пять карт одной масти
  5. Стрит - пять карт последовательного ранга
  6. Три в своем роде - три карты одного ранга и две карты двух других рангов
  7. Две пары - две карты одного ранга, две карты другого ранга и одна карта третьего ранга
  8. Одна пара - две карты одного ранга и три карты трех других рангов
  9. Старшая карта - пять карт не всех последовательного ранга или одной масти, и ни одна из них не имеет одинакового ранга

  • Ранг = число на карте (A, K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3, 2). Вы можете использовать T вместо 10.
  • Костюм = сердечки (h), пики (ы), булавы (c) и бриллианты (d).

Обратите внимание, что туз, Aможет быть как старшим, так и младшим числом (1 или 14).

Карту можно идентифицировать двумя буквами As(туз пик), Jc(валет треф), 7h(7 сердец) и так далее.


Вызов:

Вы получаете четыре карты от дилера (четыре строки ввода). Найдите и выведите наилучшую возможную последнюю карту, которую вы можете получить.

Если есть карты, которые одинаково хороши, тогда вы можете выбрать, какую выбрать.

Форматы ввода и вывода являются необязательными, но отдельные карты должны быть идентифицированы, как показано выше Jcи 2h.


Тестовые случаи:

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)

Это код гольфа, поэтому выигрывают самые короткие данные в байтах.

Стьюи Гриффин
источник

Ответы:

13

Pyth, 73 байта

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

Это довольно ужасно. Разбор карт, сортировка значений ... Все занимает так много символов. Но подход интересен.

Попробуйте онлайн: демонстрация или тестовый набор

Объяснение:

Я генерирую все 52 карты, удаляю четыре карты ввода, генерирую счет для каждой карты (счет руки) и печатаю карту с максимальным счетом.

Счет немного странный. Если я сравню счет двух совершенно разных рук, он может выбрать не того победителя. Например, стрит побьет 4 туза. Но это работает, если первые 4 карты одинаковы в обеих руках. И мой вычисленный счет на самом деле не значение, а список значений:

  • G: Сначала я группирую 5 карт по рангу и беру длины: 5h 5d 6c 5s Jd -> [3, 1, 1]
  • F: Затем я добавляю 4 минус количество различных наборов в этот список. Flush -> 3добавляется, not flush -> 2/1/0добавляется.
  • S: Добавить еще один номер. 0если это не прямая, 4если это прямая A2345, или 5если это более высокая прямая.

Эти списки из 4-7 номеров сортируются в порядке убывания и выбирается список с максимальным значением.

Почему это работает? Здесь вы видите возможные конфигурации для всех типов. Буква рядом с числами говорит вам, по какому правилу сгенерировано это число.

  • Стрит-флеш: [5S, 3F, 1G, 1G, 1G, 1G, 1G]или[4S, 3F, 1G, 1G, 1G, 1G, 1G]
  • Четыре вида: [4G, 1G, 0F, 0S]
  • Полный дом: [3G, 2G, 1F, 0S]или[3G, 2G, 0F, 0S]
  • Румянец: [3F, 1G, 1G, 1G, 1G, 1G, 0S]
  • Straight: [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]
  • Три вида: [3G, 1G, 1G, 1F, 0S],[3G, 1G, 1G, 0F, 0S]
  • Две пары [2G, 2G, 2F, 1G, 0S], [2G, 2G, 1F, 1G, 0S],[2G, 2G, 1G, 0F, 0S]
  • Одна пара: [2G, 2F, 1G, 1G, 1G, 0S], [2G, 1G, 1G, 1G, 1F, 0S],[2G, 1G, 1G, 1G, 0F, 0S]
  • Старшая карта: [2F, 1G, 1G, 1G, 1G, 1G, 0S], [1F, 1G, 1G, 1G, 1G, 1G, 0S],[1G, 1G, 1G, 1G, 1G, 0S, 0F]

Pyth сравнивает списки поэлементно. Таким образом, очевидно, что стрит-флеш всегда побеждает четверых в своем роде. Большинство типичных правил покера очевидны с этими списками. Некоторые кажутся противоречивыми.

  • Стрит выиграет у четверки или фулл-хауса: не проблема. Если у вас есть шанс получить четверку вида / фулл-хаус с картой ривера, то вы не можете достичь стрита одновременно (поскольку у вас уже есть 2 или 3 разных люкса в руке).
  • Стрит победит против флеша. Если вы можете достичь флеша и стрита с речной картой, то вы также можете достичь стрит-флеша. И стрит-флеш имеет лучший результат, чем стрит и флеш.
  • Одна пара [2G, 2F, 1G, 1G, 1G, 0S]выиграет против двух парных рук. Тоже нет проблем. Если вы получите две пары с речной картой, то у вас была хотя бы одна пара до ривера. Но это означает, что вы можете улучшить до трех в своем роде, что лучше. Таким образом, две пары на самом деле никогда не будут ответом.
  • Старшая карта [2F, 1G, 1G, 1G, 1G, 1G, 0S]выиграет против одной пары рук. Если это лучший результат, который вы можете получить, до ривера у вас будет 3 карты одного набора и одна карта другого набора. Но затем вы можете выбрать карту с одним из этих двух наборов и с уже появившимся значением, и в итоге вы получите результат [2F, 2G, ...], что тоже лучше.

Таким образом, это выбирает правильный тип решения. Но как мне получить лучшую пару (из 4 возможных), как выбрать лучшую стрит, ...? Потому что два разных однопарных решения могут иметь одинаковый счет.

Это легко. Pyth гарантирует стабильную сортировку (при взятии максимума). Поэтому я просто генерирую карты в порядке 2h 2s 2c 2d 3h 3s ... Ad. Таким образом, карта с самым высоким значением автоматически будет максимальной.

Детали реализации

=Zcразбивает входную строку и сохраняет список карт в Z. =T+`M}2Tc4"JQKA"генерирует список рангов ['2', ..., '10', 'J', 'Q', 'K', 'A']и сохраняет их в T. -sM*T..."hscd"Zгенерирует каждую комбинацию ранга с комплектами и удаляет карты Z.

o...упорядочивает эти оставшиеся карты по: lM.gPkJдлине групп рангов, +-4l{eMJlMдобавляет 4 - длину (сюиты), +*-5l@\AN}SPMJ+NZSM.:+\AT5добавляет 0/4/5 в зависимости от сюиты (сгенерируйте каждую подстроку длины 5 из «A» + T, проверьте, если рука один из них (требует сортировки руки и сортировки всех подмножеств), умножения на 5 (число «А» в карте), _Sсортирует список по убыванию.

e выберите максимум и распечатайте.

Jakube
источник
2
Очень креативное и отличное объяснение!
Грег Мартин
4

JavaScript (ES6), 329 324 317 312 309 байт

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

Как это работает

Для каждой оставшейся карты в колоде мы вычисляем счет руки S. Чем ниже оценка, тем лучше рука.

Переменные, используемые для вычисления балла

  • F: falsy, если рука флеш
  • c: битмаск клубов
  • d: Битовая маска бриллиантов
  • h: битовая маска сердец
  • s: Пиковая маска
  • x = c | d: битмаск клубов или бриллиантов
  • y = h | s: битовая маска сердец или пики
  • a: битмаск всех комбинированных костюмов
  • p = c & d | x & y | h & s: пара битовых масок (1)
  • t = c & d & y | h & s & x: три в своем роде битовая маска (1)

(1) Я написал эти формулы несколько лет назад и использовал их в нескольких покерных движках. Они работают. :-)

Другие формулы

  • c & d & h & s: четвёртая битмаск
  • a == 7681: тест для специальной прямой "A, 2, 3, 4, 5" (0b1111000000001)
  • ((j = a / 31) & -j) == j: тест для всех других стритов

Счётная таблица

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: Нам не нужно заботиться о двух парах, которые не могут быть нашим лучшим вариантом. (Если у нас уже есть одна пара, мы можем превратить ее в тройку. А если у нас уже есть две пары, мы можем превратить их в фулл-хаус.)

Контрольные примеры

Arnauld
источник
3

JavaScript (ES6), 307 349

Это довольно громоздко, и я не уверен, что это лучший подход. Все еще немного пригодный для игры в гольф возможно.

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)

Меньше гольфа

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
)

Тест

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
источник
Забавно видеть, что оба наших подхода, похоже, сходятся к очень схожим размерам. :-) Производительность мудрая, вы определенно быстрее, хотя.
Арно
@Arnauld Мне удалось побрить еще 4 байта. Твоя очередь
edc65