判断扑克牌是否为顺子的函数?

发布于 2024-07-13 13:50:27 字数 659 浏览 8 评论 0原文

在一项家庭作业中,我得到了一个 Card 类,其中枚举了 Rank 和 Suit 的类型。 我需要比较两手扑克牌(每手牌都是 5 张牌的 ArrayList)并决定获胜者。

isStraight() 函数确实让我很困扰,因为我必须在 Ace 之后重新开始计数。 例如,

QUEEN、KING、ACE、TWO、THREE

仍被视为顺子。 编写此功能的最佳方法是什么?

这是排名/花色枚举类型代码,如果有帮助的话。

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;
}

For a homework assignment I was given a Card class that has enumerated types for the Rank and Suit. I am required to compare two poker hands (each hand is an ArrayList of 5 cards) and decide the winner.

The isStraight() function is really bothering me, because I have to start over the count after the Ace. For example,

QUEEN, KING, ACE, TWO, THREE

Is still considered a straight. What is the best way to code this functionality?

Here is the Rank/Suit enumerated type code, if that helps.

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

迷迭香的记忆 2024-07-20 13:50:27

你确实意识到,根据我玩过或听说过的任何扑克游戏的规则,顺子不能换行,对吗? A 可以是低值 [A,2,3,4,5] 或高值 [10,J,Q,K,A],但不能换行。 根据这些规则(不是你的)我之前已经实现过类似的东西。 基本上,您对数组进行排序并遍历它,确保当前的卡比前一张高。 在第一次迭代中,如果它是 A,则显式检查 [A,2,3,4,5]。 如果是,则返回 true,如果不是,则继续正常的直接逻辑。 这应该会让你走上正确的方向。

You do realize that by the rules of any poker game I've ever played or heard of a straight cannot wrap right? Ace can be low [A,2,3,4,5] or high [10,J,Q,K,A] but it can't wrap. According to those rules (not yours) I've implemented something similar before. Basically you sort the array and walk it, making sure the current card is one higher than the previous. In the first iteration, if it is an ace, then you explicitly check for [A,2,3,4,5]. If it is you return true and if it isn't you continue with the normal straight logic. This should set you in the right direction.

梦醒时光 2024-07-20 13:50:27

您可以编写一个奇特的算法来返回 true,不管可能的牌数有多少,但如果您意识到排序的手牌上只有 10 个有效组合,您可以只查找这些:

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

You could write a fancy algorithm to return true despite the number of possible cards but if you realize there are only 10 valid combinations on a sorted hand, you could just look for these:

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)
落墨 2024-07-20 13:50:27

一般来说,解决扑克牌局的一个好方法是为每张牌分配一个位值,其中位 ((rank-2)*2) 位集和位 (suit+28) 位集,(因此 2=1, 3=4 、4=16 等,直到 A=​​0x1000000)。 然后将所有卡片加在一起(将该结果称为“Sum”。计算 V1=(Sum & 0x2AAAAAA)>>1、V0=(Sum & 0x1555555) 和 V2=V1 & V0。同时将计算五张卡的值,并计算 V3=OrValue & 0xF0000000;

  1. 对于一对,V1 将具有单个位设置,V0 将具有多个位设置,并且 V2 将为零。
  2. 对于两对,V1 将设置两个位,V2 将等于 0。
  3. 对于三类,V1 将设置一个位,并且 V2 将等于 V1。
  4. 对于顺子,V0 要么是 0x1000055,要么是 0x155 的 2 的幂倍数。
  5. 对于刷新,V2 将精确地设置一位。
  6. 对于葫芦,V1 将设置两个位,V2 将非零。
  7. 对于四类,要么 V1 是 v0 的两倍,两者都设置了一位,要么 V0 将精确地设置了两位,而 V1 将为零。
  8. 对于同花,将满足同花和同花的条件。

这种方法所需的测试应该可以用最少的分支快速实现。

A nice approach for resolving poker hands in general is to assign each card a bit value with bit ((rank-2)*2) bit set as well as bit (suit+28) set, (so 2=1, 3=4, 4=16, etc. up to A=0x1000000). Then add together all the cards (call that result 'Sum'. Compute V1=(Sum & 0x2AAAAAA)>>1, V0=(Sum & 0x1555555), and V2=V1 & V0. Also OR together the values for the five cards, and compute 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.

This tests required for this approach should be implementable quickly with a minimal amount of branching.

那伤。 2024-07-20 13:50:27

由于您的列表中只有 5 张卡片,因此您可以对其进行排序并确定 2 个连续卡片之间的差异。 如果它包含一张 A,您也需要将其视为低牌。 如果所有差异均为 1(或 -1,具体取决于排序顺序),则您获得顺子。

Since there's only 5 cards in you list, you could sort it and determine the difference between 2 consecutive cards. If it contains an ace, you need to consider it as a low card too. if all the differences are 1 (or -1, depending on the sort order), you have your straight.

∞觅青森が 2024-07-20 13:50:27

我认为,考虑到 RANK 的定义,顺子只能以 ACE.points() - 4 的最大值开始。

因此,如果您对手牌进行排序,最低的 RANK 是 > ACE.points() - 4 那么你不能有顺子,否则你只需迭代手牌以查看每张牌之前的 RANK + 1。

如果 ACE 可以高或低,则按照 SHS 的回答进行。

I'd argue that given that definition of RANK, that straights can only start with a max of ACE.points() - 4.

So if you sort your hand and the lowest RANK is > ACE.points() - 4 then you can't have a straight, otherwise you just iterate over the hand to see that each card is previous RANK + 1.

If ACE can be high or low then go with what SHS answered.

云淡月浅 2024-07-20 13:50:27

对于内部循环来说,这是非常微不足道的,挑战是在没有内部循环的情况下做到这一点......

此外,这取决于您是否理解您的老师或您的老师误解(或歪曲)游戏规则。

我想我会想创建一个数组 [2..14] 并将卡片放置在与其等级相对应的位置。 如果你击中了重复的,那么它就不是顺子,当你完成后,你应该有 8 个连续的空格。 如果连续的空格少于 8 个,则不是顺子。

我能想到的所有其他解决方案都需要一个内部循环——如果您想成为一名受人尊敬的程序员,那么内部循环是您需要尽可能避免的草率编程事物之一。

编辑:另外,如果你误解了老师,唯一的包装条件是“10,j,q,k,a”(就像在真正的规则中一样),那么你需要一个额外的测试,如果 2、13 和 14 都满足设置,这也是一个失败(2-ak 环绕)。

(重新阅读问题后再次编辑,将 ace 的 1 替换为 14)

With an inner loop it's pretty trivial, the challenge would be to do it without an inner loop...

Also, it depends on if you understood your teacher or your teacher misunderstood (or misrepresented) the rules of the game.

I think I'd be tempted to just create an array [2..14] and place the cards in the location that corresponds to their rank. If you hit a duplicate, it's not a straight, and when you are done, you should have 8 spaces in a row. If you have less than 8 spaces in a row, it's not a straight.

All the other solutions I can come up with require an inner loop--and inner loops are one of those sloppy programming things you need to avoid whenever you can if you're going to ever be a respectable programmer.

edit: Also, if you misunderstood the teacher and the only wrapping condition is "10,j,q,k,a" (like in the real rules), then you need an additional test that if all of 2, 13 and 14 are set, it's also a failure (2-a-k wraparound).

(Edited again to replace 1 for ace with 14 after re-reading the question)

似最初 2024-07-20 13:50:27

我不太使用枚举,我更喜欢命名常量,但我假设从“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

I dont use enum much, i prefer named constants but i'll assume going from "ACE" to "14" is trivial

i'm too lazy to write real java code (beside you actually have to do your homework ^^)

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

The % operator is called modulo so (15 % 13) == 2
I use this operator whenever I face the "wrap over" challenge

Edit : After re-reading your question my solution cannot work out of the box. You should reorder your enum so that TWO == 0

黑凤梨 2024-07-20 13:50:27

我建议使用位向量来表示卡片。 这避免了排序。 您可以添加 A 两次(一次作为 1,其他时间作为 K),或者您可以通过在检查 2 是否设置之前检查 ace 位是否设置来特殊情况开始情况)。 如果速度很重要,您可以构建一个大的查找表。 这种方法还可以清洁天平以找到剩余的手牌(同花、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

I recommend using a bit vector to represent the cards. This avoids having to sort. You can add the ace twice (once as a 1 the other times as a king) or you can special case the starting situation by checking if the ace bit is set before checking if the 2 is set). You can build a big look up table if speed matters. This approach also cleaning scales to find the rest of the hands (flushes, 2 pair, full houses, trips, and so on). It also makes it easy to figure out if a given straight is higher than another. And it expands cleanly to 7 card evaluator

In pseudo code it looks something like this for a very general case (you can have any number of cards. It returns the first straight)

 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
温柔戏命师 2024-07-20 13:50:27

将所有排名按顺序添加到列表中,两次。 然后,要检查一手牌是否是顺子,请按排名对该手牌进行排序,然后检查该手牌是否是该列表的子列表。

Add all the ranks in order to a list, twice. Then, to check if a hand is a straight, sort the hand by rank and then check if the hand is a sublist of that list.

魔法唧唧 2024-07-20 13:50:27

您可以编写一个类,将每张牌转换为特定的牌值

Joker = 11
皇后 = 12
国王 = 13
Ace = 0 或 14

这将使处理牌和寻找可能的手牌变得更加容易。

you could write a class that converts every card to an specific card value

Joker = 11
Queen = 12
King = 13
Ace = 0 or 14

it will make a lot easier card handling and looking for possible hands.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文