Виберіть останню карту в покерній руці


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.
  • Костюм = сердечка (год), лопати (-ла), клубочки (в) та діаманти (г).

Зауважте, що туз, 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 - число "A" s у картці), _Sсортує список за зменшенням.

e виберіть максимум та роздрукуйте.


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: помилковий, якщо рука рум'яна
  • c: бітмаска клубів
  • d: бітмаска Diamonds
  • h: бітмаска серця
  • s: бітова маска піків
  • x = c | d: бітмаска Clubs OR Diamonds
  • y = h | s: бітмаска Hearts OR Spades
  • 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: Нам не потрібно дбати про Two-Pair, який, можливо, не може бути найкращим варіантом. (Якщо у нас вже є одна пара, ми можемо перетворити її на «Третього роду». І якщо у нас вже є дві пари, ми можемо перетворити їх на повний дім.)

Тестові справи


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>


Смішно бачити, що обидва наші підходи, схоже, сходяться до дуже схожих розмірів. :-) Ефективність, але ви, безумовно, швидші.
Арнольд

@Arnauld мені вдалося поголити ще 4 байти. Ваша черга
edc65
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.