Функция определения того, является ли покерная рука стритом?
-
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;
- Для пары V1 будет иметь один установленный бит, V0 будет иметь несколько битов, а V2 будет равен нулю.
- Для двух пар в V1 будут установлены два бита, а V2 будет равен нулю.
- Для тройки V1 будет иметь один установленный бит, а V2 будет равен V1.
- Для прямой V0 будет либо 0x1000055, либо кратным степени двойки 0x155.
- Для сброса V2 будет иметь ровно один установленный бит.
- Для фулл-хауса в V1 будут установлены два бита, а V2 будет ненулевым.
- Для каре либо V1 будет дважды v0, причем оба имеют один установленный бит, либо V0 будет иметь ровно два установленных бита, а V1 будет равен нулю.
- Для стрит-флеша будут соблюдены условия для стрита и флеша.
Эти тесты, необходимые для этого подхода, должны быть быстро реализованы с минимальным количеством ветвей.
Вы можете написать причудливый алгоритм, возвращающий 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
это значительно облегчит работу с картами и поиск возможных комбинаций.