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

В качестве домашнего задания мне дали класс карт, в котором перечислены типы для ранга и масти. Мне нужно сравнить две покерные комбинации (каждая рука представляет собой 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;
}

person Logan Serman    schedule 09.02.2009    source источник
comment
Я думаю, что ваше определение стрита не совсем правильное: en.wikipedia.org/wiki/Poker_straight# Прямо   -  person Scott W    schedule 10.02.2009


Ответы (10)


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

person shsteimer    schedule 09.02.2009

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

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)
person Austin Salonen    schedule 20.02.2009
comment
Это наименее подверженный ошибкам и читаемый ответ (учитывая, что тузы играют двойную роль) - person Amir Afghani; 19.12.2011

Хороший подход к решению покерных комбинаций в целом состоит в том, чтобы присвоить каждой карте битовое значение с установленным битом ((ранг-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. For a pair, V1 will have a single bit set, V0 will have multiple bits set, and V2 will be zero.
  2. For two-pair, V1 will have two bits set and V2 will equal zero.
  3. For a three-of-a-kind, V1 will have a single bit set, and V2 will equal V1.
  4. For a straight, V0 will either be 0x1000055 or else a power-of-two multiple of 0x155.
  5. For a flush, V2 will have precisely one bit set.
  6. For a full house, V1 will have two bits set, and V2 will be non-zero.
  7. For four-of-a-kind, either V1 will be twice v0, with both having one bit set, or V0 will have precisely two bits set and V1 will be zero.
  8. For a straight flush, conditions for straight and flush will be met.

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

person supercat    schedule 19.12.2011

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

person Rik    schedule 10.02.2009

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

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

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

person Instantsoup    schedule 09.02.2009

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

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

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

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

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

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

person Bill K    schedule 09.02.2009
comment
О, когда вы говорите 8 пробелов подряд, я думаю, это то место, где вы позволяете ему переноситься; это оно? - person Michael Myers; 10.02.2009
comment
Не лучше ли просто проверить 5 не пробелов подряд? Например, у вас не было бы 8 ячеек подряд, если бы ваши карты были 5, 6, 7, 8, 9. - person Adnan; 14.02.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

person Eric    schedule 10.02.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
person hacken    schedule 10.02.2009
comment
Переход к битам, когда массив может делать то же самое - возможно, более эффективно? (Битовые поля, как правило, требуют чтения + записи, а не только записи). Чувак, ты должен пересмотреть свои программные приоритеты. Читаемость перед всеми остальными, оптимизация в последнюю очередь и т. д. - person Bill K; 10.02.2009
comment
Битовые поля на порядки эффективнее, если вы пишете оценщик рук. Вы превращаете всю оценку рук в полдюжины просмотров стола. Я считаю, что получившийся код легче использовать в покерной программе, но ymmv. Если вы заинтересованы в этой программе, google выдаст кучу быстрых вариантов. - person hacken; 10.02.2009
comment
Странное предположение там. Источник? Я знаю, что установка одного бита менее эффективна, чем запись байта в массив, но, возможно, вы думаете о чем-то другом. Я работаю с ними постоянно (обработка видеопотоков), не то чтобы я боюсь или что-то в этом роде, просто плохое решение, если не нужно. - person Bill K; 10.02.2009
comment
Установка одного бита происходит медленнее. Но вы не устанавливаете ни единого бита. Вы устанавливаете все биты в 1 регистр для всех карт, а затем записываете этот регистр. Большая часть скорости заключается в том, чтобы избежать необходимости делать сортировку и иметь возможность определить, является ли что-то прямым с некоторой математикой, а затем 1 доступом к памяти. - person hacken; 12.02.2009
comment
В моем сердце есть слабость к битовым полям, но это довольно далеко от вашего пути, чтобы избежать сортировки пяти карт. С этими ограничениями сортировка выбором превзойдет сортировку слиянием и быструю сортировку. Если бы вы создавали игру для обслуживания тысяч пользователей, конечно, но в данном контексте это излишество. - person rtperson; 13.02.2009

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

person Apocalisp    schedule 10.02.2009

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

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

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

person Germán Rodríguez    schedule 09.02.2009