Функция определения того, является ли покерная рука стритом?

StackOverflow https://stackoverflow.com/questions/530208

  •  22-08-2019
  •  | 
  •  

Вопрос

Для домашнего задания мне дали класс Card, в котором перечислены типы ранга и масти.Мне нужно сравнить две покерные руки (каждая рука представляет собой ArrayList из 5 карт) и определите победителя.

А isStraight() меня действительно беспокоит, потому что мне приходится начинать счет заново после туза.Например,

КОРОЛЯ, КОРОЛЬ, ТУЗ, ДВА, ТРИ

По-прежнему считается стритом.Как лучше всего закодировать эту функциональность?

Вот код типа перечисления ранга/масти, если это поможет.

public enum Rank
{
    TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT(8), NINE(9),
    TEN(10), JACK(11), QUEEN(12), KING(13), ACE(14);

    private final int points;

    private Rank(int points)
    {
        this.points = points;
    }

    public int points()
    {
        return this.points;
    }
}

public enum Suit
{
    DIAMONDS, CLUBS, HEARTS, SPADES;
}
Это было полезно?

Решение

Вы ведь понимаете, что по правилам любой покерной игры, в которую я когда-либо играл или слышал, стрит не может быть завернутым, верно?Туз может быть младшим [A,2,3,4,5] или старшим [10,J,Q,K,A], но он не может быть перевернутым.Согласно этим правилам (не вашим) я уже реализовал нечто подобное.По сути, вы сортируете массив и проходите по нему, проверяя, чтобы текущая карта была на одну выше предыдущей.В первой итерации, если это туз, вы явно проверяете наличие [A,2,3,4,5].Если это так, вы возвращаете true, а если нет, то продолжаете использовать обычную прямую логику.Это должно направить вас в правильном направлении.

Другие советы

Хороший подход к решению покерных комбинаций в целом состоит в том, чтобы присвоить каждой карте битовое значение с набором битов ((ранг-2)*2), а также набором битов (масть+28), (так что 2 = 1, 3 = 4 , 4=16 и т. д.до A=0x1000000).Затем сложите все карты (назовите этот результат «Сумма»).Вычислите V1=(Сумма & 0x2AAAAAA)>>1, V0=(Сумма & 0x1555555) и V2=V1 & V0.Также ИЛИ вместе значения для пяти карт и вычислите V3=OrValue & 0xF0000000;

  1. Для пары V1 будет иметь один установленный бит, V0 будет иметь несколько битов, а V2 будет равен нулю.
  2. Для двух пар в V1 будут установлены два бита, а V2 будет равен нулю.
  3. Для тройки V1 будет иметь один установленный бит, а V2 будет равен V1.
  4. Для прямой V0 будет либо 0x1000055, либо кратным степени двойки 0x155.
  5. Для сброса V2 будет иметь ровно один установленный бит.
  6. Для фулл-хауса в V1 будут установлены два бита, а V2 будет ненулевым.
  7. Для каре либо V1 будет дважды v0, причем оба имеют один установленный бит, либо V0 будет иметь ровно два установленных бита, а V1 будет равен нулю.
  8. Для стрит-флеша будут соблюдены условия для стрита и флеша.

Эти тесты, необходимые для этого подхода, должны быть быстро реализованы с минимальным количеством ветвей.

Вы можете написать причудливый алгоритм, возвращающий true, несмотря на количество возможных карт, но если вы понимаете, что в отсортированной руке есть только 10 действительных комбинаций, вы можете просто поискать следующие:

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)

Поскольку в вашем списке всего 5 карт, вы можете отсортировать его и определить разницу между двумя последовательными картами.Если в ней есть туз, ее тоже нужно рассматривать как младшую карту.если все различия равны 1 (или -1, в зависимости от порядка сортировки), у вас есть прямая.

Я бы сказал, что, учитывая такое определение РАНГА, эти стриты могут начинаться только с максимального значения ACE.points() - 4.

Итак, если вы сортируете свою руку и самый низкий РАНГ равен > ACE.points() - 4, то у вас не может быть стрита, в противном случае вы просто перебираете руку, чтобы увидеть, что каждая карта имеет предыдущий РАНГ + 1.

Если ACE может быть высоким или низким, тогда следуйте тому, что ответил SHS.

С внутренним циклом это довольно тривиально, задача состоит в том, чтобы сделать это без внутреннего цикла...

Кроме того, это зависит от того, поняли ли вы своего учителя или ваш учитель неправильно понял (или исказил) правила игры.

Я думаю, у меня возникнет соблазн просто создать массив [2..14] и разместить карты в местах, соответствующих их рангу.Если вы нажмете дубликат, это не прямой, и когда вы закончите, у вас должно быть 8 пробелов подряд.Если у вас меньше 8 мест подряд, это не стрит.

Все другие решения, которые я могу придумать, требуют внутреннего цикла, а внутренние циклы — это одна из тех небрежных вещей в программировании, которых следует избегать, когда это возможно, если вы собираетесь когда-либо стать уважаемым программистом.

редактировать:Также, если вы неправильно поняли учителя и единственным условием переноса является «10,j,q,k,a» (как в реальных правилах), то вам понадобится дополнительный тест, который, если установлены все 2, 13 и 14, это тоже провал (обход 2-а-к).

(Снова отредактировано, чтобы заменить 1 для туза на 14 после перечитывания вопроса)

Я не часто использую перечисления, предпочитаю именованные константы, но предполагаю, что переход от «ACE» к «14» тривиален.

мне слишком лень писать настоящий Java-код (кроме того, тебе действительно нужно делать домашнюю работу ^^)

check if the list has 5 cards
convert card names to a card number list named array
sort the list array
for i=1 to 4
if not (array[i] + 1) % 13 == (array[i+1]) % 13
then it is not a straight

Оператор % называется modulo so (15 % 13) == 2 Я использую этот оператор всякий раз, когда сталкиваюсь с проблемой "завернуть"

Редактировать :После перечитывания вашего вопроса мое решение не может работать «из коробки».Вам следует изменить порядок перечисления так, чтобы ДВА == 0

Я рекомендую использовать битовый вектор для представления карт.Это позволяет избежать сортировки.Вы можете добавить туз дважды (один раз в виде 1, другой раз в виде короля) или можете выделить стартовую ситуацию, проверив, установлен ли бит туза, прежде чем проверять, установлена ​​ли 2).Если скорость имеет значение, вы можете создать большую справочную таблицу.Этот подход также очищает весы для поиска остальных рук (флеши, 2 пары, фулл-хаусы, трипсы и т. д.).Это также позволяет легко определить, является ли данный стрит старше другого.И он полностью расширяется до оценщика 7 карт.

В псевдокоде это выглядит примерно так для очень общего случая (карточек можно иметь любое количество.Возвращает первую прямую)

 long cardBitMask
 for each card in hand
   setBit in cardBitMask

 hearts = mask(cardBitMask)
 diamonds = mask(cardBitMask)
 clubs = mask(cardBitMask)
 spades = mask(cardBitMask)

 // find straight
 uniqueCards = hearts|diamonds|clubs|spades
 int cardsInaRow = 0
 if uniqueCards&AceCardMask:
    cardsInaRow = 1
 for card = 2...King
   if uniqueCards&(1<<card)
      cardsInARow++
   else 
      if cardsInARow == 5
         break
      cardsInARow = 0
 if cardsInARow==5:
     return true
 return false

Дважды добавьте все ранги в список по порядку.Затем, чтобы проверить, является ли рука стритом, отсортируйте ее по рангу, а затем проверьте, является ли рука подсписком этого списка.

вы могли бы написать класс, который преобразует каждую карту в определенное значение карты

Джокер = 11 Королева = 12 Король = 13 Туз = 0 или 14

это значительно облегчит работу с картами и поиск возможных комбинаций.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top