Функция для определения того, является ли покерная комбинация стритом? - PullRequest
6 голосов
/ 10 февраля 2009

Для выполнения домашнего задания мне дали класс 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;
}

Ответы [ 10 ]

9 голосов
/ 10 февраля 2009

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

3 голосов
/ 19 декабря 2011

Хороший подход для разрешения покерных комбинаций в целом состоит в том, чтобы назначать каждой карте значение бита с установленным битом ((rank-2) * 2), а также с установленным битом (масти + 28) (так 2 = 1, 3 = 4, 4 = 16 и т. Д. До A = 0x1000000). Затем сложите все карты (назовите этот результат «Сумма». Вычислите V1 = (Sum & 0x2AAAAAA) >> 1, V0 = (Sum & 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. Для стрит-флеша будут выполнены условия для стрит-флеша.

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

3 голосов
/ 20 февраля 2009

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

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)
2 голосов
/ 10 февраля 2009

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

0 голосов
/ 10 февраля 2009

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

0 голосов
/ 10 февраля 2009

Я рекомендую использовать битовый вектор для представления карт. Это позволяет избежать необходимости сортировки. Вы можете добавить туза дважды (один раз как 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
0 голосов
/ 10 февраля 2009

Я не часто использую enum, я предпочитаю именованные константы, но я предполагаю, что переход от "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

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

Изменить: После перечитывания вашего вопроса мое решение не может работать из коробки. Вы должны изменить порядок своих перечислений так, чтобы TWO == 0

0 голосов
/ 10 февраля 2009

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

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

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

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

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

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

0 голосов
/ 10 февраля 2009

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

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

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

0 голосов
/ 10 февраля 2009

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

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

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

...