Визначення покерних рук


19

Я робив гру «Техаський холдем» як частину оцінки, і я роздумував над тим, як перевірити 7 доступних карт і визначити, чи існують руки.

Єдиний можливий спосіб, який я можу придумати, - це сортування карт чисельно, а потім вивчити кожну можливу групу з 5 карт і перевірити, чи вони відповідають списку кожної можливої ​​руки. Це зайняло б тривалий час, і snd було б можливим лише для визначення пар, оскільки позов не має значення.

Картки - це кожний рядок, що складається з числа / a / j / q / k, і костюм (char)3(який символізує невеликий символ лопати).

Чи є у когось якісь пропозиції, формули чи посилання, які я міг би використати для створення системи ручного аналізу?

Не турбуйтеся про те, щоб звалити руки один проти одного, це інший чайник з рибою.


1
Просто вказуючи на це, але векторний тег у його контексті стосується лінійної алгебри. Не контейнер.
Сидар

@Sidar Не соромтесь редагувати теги в майбутньому, якщо ви вважаєте, що вони не відповідають. Якщо ви наведіть курсор на теги і з'явиться опція "Редагувати теги" (принаймні для мене?), І ви можете редагувати лише теги, не редагуючи питання.
MichaelHouse

@ Byte56 У мене є ця дивна звичка думати, я не впевнений, чи я правий, тому я роблю це пасивно через коментар ... Тому я не редагував пост. Можливо, я щось пропустив у пості, тому я чекав його відповіді.
Сидар

Тут також є приємна стаття, яка з’явилася в Game Developer кілька років тому: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion

1
Я зробив реалізацію в Java для забавної деякий час назад , ви можете знайти його тут: codereview.stackexchange.com/questions/10973 / ... . Якщо ви подивитесь на PokerHand.java, ви знайдете методи для тестування кожного типу рук (наприклад, isFullHouse). Вони працюють лише в тому випадку, якщо картки розібрані спочатку.
bughi

Відповіді:


20

Я думаю, що ви можете знайти більшість рук в покер, просто склавши кілька таблиць, скільки карт у руці є в кожному ранзі та костюмі.

Іншими словами, створіть картографічну карту масивів (цифри та A / J / Q / K) для підрахунку карт цього рангу в руці. Якщо у гравця є пара або три в своєму роді, в цьому масиві буде елемент, рівний 2 або 3, і т. Д. У них є повний будинок, якщо є один елемент, який є 2, а інший, що становить 3, і прямий якщо в цьому масиві є п'ять послідовних елементів, рівних 1.

Так само ви можете скласти аналогічний масив з підрахунку карток кожного костюма та використовувати його для виявлення спалахів.

Виявивши присутність певної руки, досить просто повернутися назад і знайти конкретні картки в руці, щоб виділити їх в інтерфейсі користувача або все, що вам потрібно зробити.

У псевдокоді:

int countByRank[13] = { 0 };        // Initialize counter to zero for each rank
for (cards in hand)
    countByRank[card.rank] += 1;    // Increment counter for this card's rank
if (countByRank.find(2))
    // There's a pair
else if (countByRank.find(3))
    // There's a three-of-a-kind
// etc...

17

Це трохи хитро, тому що так багато комбінацій. На щастя, у вас є процесор, який може перевірити велику кількість комбінацій за дуже короткий час.

Вам знадобиться кілька різних стратегій для виявлення різних типів рук. На щастя, кілька різних типів можуть перекривати стратегії. Я шукав би через, за ​​рангом руки.

  1. Прямий рум'янець
  2. Чотири з роду
  3. Аншлаг
  4. Промийте
  5. Прямо
  6. Три з роду
  7. Дві пари
  8. Одна пара
  9. Висока карта

2, 3, 6, 7, 8Все простий підрахунок. Використовуючи список карток «Туз до короля», просто помістіть номер кожного значення у списку, збільшуючи для кожної додаткової знайденої картки. Потім перевірте список на 4, якщо немає 4, у вас немає 4 подібного роду. Перевірте це на 3, якщо немає 3, у вас немає 3 подібних. Якщо у вас є 3, перевірте наявність 2 (із зазначенням повного будинку). І так далі...

Для 1, 5ви можете використовувати один і той же список і шукати послідовності , де всі карти мають одну або кілька записів в списку для послідовності 5 карт. Якщо вони теж мають однаковий костюм, це прямий флеш.

4може мати те саме налаштування списку, але цього разу ви рахуєте позов. Шукайте числа від 5 або більше.

Нарешті, у 9вас є найвища картка, яка має бути простим питанням перегляду останнього найвищого значення з одного із ваших списків вище.

Ви можете вибухнути, як тільки знайдете відповідність, якщо шукаєте в порядку. Хоча було б тривіально продовжувати пошук і знаходити всі збіги, якщо ви хочете надати всю цю інформацію користувачеві.


По суті, ви наповнюєте відра. Потім перевіряємо відра на комбінації. Проілюструвати:

введіть тут опис зображення

Починаючи з масиву, з відром для кожної карти, перейдіть через карти і порахуйте екземпляр кожної карти. Тоді ви можете легко повторити масив і перевірити певні комбінації. У цьому прикладі зрозуміло, що існує 4 подібних, оскільки одне із відра містить 4 елементи.


6

Я наткнувся на цей алгоритм один раз. Він множує прості числа, щоб визначити руки, і це дуже цікаве читання. Оцінювач рук покеру Кактуса Кева


1
Цей цікавий, але я не впевнений, що ти все це прочитав. Цей алгоритм призначений для 5 карт . Можливо, ви знайшли в пошуку Google, пов’язаному з 7 картками, оскільки автор заявляє, що має алгоритм для 7 карт, але не ділиться ним. Дивіться сірий текст у верхній частині сторінки. Тому я не впевнений, наскільки цей алгоритм корисний для набору карт 7.
MichaelHouse

1
Оскільки існує лише 21 різна карта з 5 карт, яку можна зробити з 7 карт карт, одним із варіантів є використання оцінювача по 5 карт на кожній з них, і вибрати найкраще.
Адам

@ Byte56 Ти маєш рацію, я пам'ятаю, що я використав її до 7 карт, але заздалегідь довелося визначити найкращу 5 карту, яка ніби підірвала ефективність.
petervaz

Посилання на цю відповідь з тих пір згнило, а домен зібрав спамер. Я перенаправив посилання на архів початкової сторінки, але щоб зробити цю відповідь більш надійною, було б ідеально відредагувати відповідь, щоб включити підсумок алгоритму, запропонованого в тілі самої відповіді.
DMGregory

2

Щоб доповнити чудові відповіді, які це питання вже отримало, я подумав, що було б корисно запропонувати один із найпростіших способів порівняння рук після використання базової методики класифікації. Перш за все, вам захочеться позначити руки своїм класом , як підказують численні відповіді - більшість ваших зіставлень "рука X краще, ніж рука Y?" тоді це можна зробити, просто порівнявши класи двох рук і побачивши, який клас кращий. Для решти вам потрібно буде порівнювати на основі картки за карткою, і виявиться, що трохи більше роботи з класифікацією полегшить це.

В якості базового випадку розглянемо ситуацію, коли обидві руки - це руки з високою картою; у цьому випадку ви спершу порівняєте дві найвищі карти, потім (якщо вони збігаються) наступні дві карти тощо. Якщо ви вважаєте, що кожна вхідна рука сортована від найвищої до найнижчої карти, такий підхід призводить до коду, який виглядає як це:

int CompareHandsOfSameClass(Hand h1, Hand h2) {
  for ( int i = 0; i < 5; i++ ) {
    if ( h1[i].rank > h2[i].rank ) {
      return -1;
    } else if ( h1[i].rank < h2[i].rank ) {
      return 1;
    }
  }
  return 0;
}

Тепер хороша новина: виявляється, що це лексикографічне впорядкування , відповідним чином підроблене, працює для порівняння двох рук у будь-якійкласів, якщо їх клас однаковий. Наприклад, оскільки спосіб порівняння пар полягає в тому, щоб спершу порівняти пари, то з іншими трьома картами ви можете відсортувати руку, щоб спочатку поставити пару (або навіть одну карту пари спочатку!) Та запустити це те саме порівняння. (Так, наприклад, рука, схожа на A9772, зберігатиметься як 77A92 або, ще краще, 7A927; рука A9972 зберігатиметься як 9A729, і порівнюючи з наведеним вище кодом, ви почали б, поставивши 7 проти 9, і виявите, що A9972 виграв). Рука з двох пар буде зберігатися спочатку з вищою з двох пар, потім з нижньою, потім з «кікеркою» (так, наприклад, A9977 зберігатиметься як 97A97); три види зберігатимуться з однією картою з трьох перших, потім кикерів, потім інших карт (наприклад, A7772 буде 7A277); повний будинок зберігався б з одним із трьох, а потім одним із двох (наприклад, 99777 зберігався б як 79779); і прямі, і рум'янці можуть бути збережені в прямому лексикографічному порядку, оскільки вони обидва порівнюються так само, як і руки з високою картою. Це призводить до прямої функції зовнішнього компаратора, яка працює для всіх класів рук з уже заданою функцією:

// Compare two hands, returning -1/0/+1 as hand 1 is less than, equal to,
// or greater than hand 2. Note that this function assumes the hands have
// already been classified and sorted!
int CompareHands(Hand h1, Hand h2) {
  if ( h1.handClass > h2.handClass ) {
    return -1;
  } else if ( h1.handClass < h2.handClass ) {
    return 1;
  } else {
    return CompareHandsOfSameClass(h1, h2);
  }
}

Сподіваємось, це допоможе!


1

Можливі деякі паралелізації, використовуючи відповідні представлення карт та подвійне скручування. Наприклад, цей код Java оцінює 7-картних жорсткостей, повертаючи ціле число, яке можна використовувати для порівняння двох рук. Це може бути адаптоване, щоб повідомляти про тип руки більш зручним для користувача способом. Основні ідеї походять зі сторінки Кактуса Кева, на яку йдеться у попередній відповіді.

Якщо вас цікавлять лише можливі реалізації для іменування руки на різних мовах, а не ефективність та чіткість коду, ви також можете ознайомитись з назвою Назва покеру на покер на codegolf.SE.


1

По-перше, вам потрібно знати ранг та маску всіх карт; тривіально, але необхідно.

Потім прокрутіть ці 7 карт і створіть дві гістограми; один за рангом (використовуючи масив з 13 індексами, всі ініціалізовані до нуля та збільшуються на 1, якщо і коли буде знайдена карта в руці з цим рангом) та один за мастом (використовуючи масив з чотирьох елементів, побудованих аналогічно як для ранжу) . Це лінійні операції, і ви можете робити обидві операції для кожної картки лише для одного набору обходів.

Потім можна визначити, чи існує будь-яка з наведених нижче груп, просто вивчивши кожну гістограму на відра, що відповідають критеріям, та / або простий наступний тест:

  • Пара: Чи рівно одне відра має значення рівно 2, причому жодне інше відро не має значення вище 1 і не має змиву?
  • Дві пари: Чи мають два чи більше ранги з величиною рівно 2, причому жодне відро не має більше 2 і не має промивання? (очевидно, три пари - це не рука, але це можливість, даючи сім карт; найсильніша дві пари - рука гравця)
  • TOAK: Чи рівно одне відро має значення рівно 3, причому жодне інше відро не має значення більше 1 і не має промивання?
  • Прямо: Чи мають п’ять послідовних відра значення 1 або більше, без залишків? (Не забувайте, що тузи є високими та низькими; ви можете використовувати гістограму ранжу з 14 елементів та порахувати тузи у двох відрах, якщо хочете)
  • Flush: Чи має якесь відро для костюмів 5 або більше карт? (якщо так, скануйте руку на картки цього костюма і виберіть топ 5)
  • Full House: чи будь-яке відро для одного рейтингу має значення 3, а будь-яке інше відро має значення 2 (при 7 картках флеш неможливий у повному будинку, якщо ви не граєте з колодою Pinochle)
  • Four of a Kind: Чи має один ранг значення 4? (жодна інша комбінація не повинна бути можливою)
  • Прямий флеш: Чи є і прямі, і рум'яна, зазначені в гістограмах? Якщо так, чи є принаймні одна картка у вказаному флеш-костюмі з рангом, що відповідає кожному рангу вказаної прямої? (це, мабуть, найдорожче обчислювально, але слід просто порахувати, скільки є послідовних рангів, і вам слід сканувати руку лише один раз на 5 умовних рангів, двічі на 6 і три рази на 7)

Можна, цілком природно, комбінувати кілька таких перевірок:

  • Чи є рум'янець?
  • Є прямий?
    • Якщо є обидва, це прямий флеш?
    • Якщо це прямий флеш, чи є у нього і туз, і король?
  • Чи є чотири в своєму роді?
  • Скільки існує трьох видів? (Два, це повний будинок. Один, перевіряємо пари)
  • Скільки пар є? (З двома і більше, це дві пари. З однією, якщо є і три, це повний будинок, інакше це пара)
  • Нічого з перерахованого вище (висока карта).

В основному, якщо відповіді на ці результати дають будь-яку руку, встановіть отримане значення "міцність руки" на міцність знайденої руки, якщо значення вже не вище. Наприклад, якщо у вас є повний дім, сила 7 з 9, то ви також маєте трійку в роді, сила 4 і пару, сила 2.

Є кілька ярликів і швидкі виходи, але в цілому це на самому ділі не що дорого , щоб просто запустити всі перевірки.


0

Руками в покер можна відносно легко за допомогою простого ітеративного підходу.

Для кожної картки перевірте, чи є один чи два-три інші з одним і тим же обличчям, щоб перевірити, чи є пара чи три / чотири подібних.

Повні будинки схожі. Або якщо ви знайдете як пару, так і трьох таких, що не однакове обличчя, позначте повний будинок, як знайдено.

Для залишків перевірте кожен костюм, щоб побачити, чи є п’ять однакових костюмів.

Перевірити пряму легко, навіть якщо це не перекреслено. Для кожної картки перевірте, чи є одна вища, і повторіть, поки не знайдеться чи ні п’ять карт поспіль.

Королівські рум'яна та прямі рум'яна можна знайти аналогічно прямим. Королівські флеши мають деякі додаткові умови, завдяки яким картки з нижчою вартістю можуть ігноруватися.

Так, такий підхід є неефективним, але для більшості ігор у покер це не має значення. Ви перевіряєте крихітну жменю гравців кожні півхвилини, а не перевіряєте тисячі рук в секунду.

Існують кращі методи, але це може зайняти більше часу для кодування, і, ймовірно, у вас є більш важливі речі, щоб витратити час / гроші на те, що дозволить зробити кращу гру з точки зору гравців, окрім кмітливості та ефективності алгоритму.


0

простий спосіб знайти пари, подвійні пари, токи, аншлаги, покер тощо:

порівняйте кожну карту між собою у вкладеному циклі, як цей:

int matches=0;
for (int i=0;i<5;i++)
   for (int j=0;j<5;j++)
      if (i!=j && cardvalue(card[j])==cardvalue(card[i])) matches++;

матчі будуть проводити наступне:
2 для пари
4, дві пари
6 для тока
8 для фуллфауса
12 для покеру

щоб прискорити оптимізацію цього: не потрібно запускати j-цикл до 5, він може бути запущений до i-1. порівняння "i! = j" може бути видалено, значення відповідності потім зменшуються вдвічі (1 = пара, 2 = 2 пара і т.д.)

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