7

对于家庭作业,我得到了一个 Card 类,其中列举了 Rank 和 Suit 的类型。我需要比较两手牌(每手是ArrayList5 张牌)并决定获胜者。

这个isStraight()功能真的很困扰我,因为我必须在 Ace 之后重新开始计数。例如,

女王、国王、王牌、二、三

还是算直的。编写此功能的最佳方法是什么?

如果有帮助,这是 Rank/Suit 枚举类型代码。

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

10 回答 10

10

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

于 2009-02-09T22:10:45.180 回答
4

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

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)
于 2009-02-20T16:12:59.687 回答
3

一般来说,解决扑克手牌的一个好方法是为每张牌分配一个位值,其中位 ((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 的二次幂倍数。
  5. 对于刷新,V2 将精确设置一个位。
  6. 对于满屋,V1 将设置两个位,而 V2 将非零。
  7. 对于四类,要么 V1 将是 v0 的两倍,并且都设置了一个位,或者 V0 将恰好设置了两个位,并且 V1 将为零。
  8. 对于同花顺,将满足同花顺和同花顺的条件。

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

于 2011-12-19T04:26:15.183 回答
2

由于您列出的只有 5 张卡片,因此您可以对其进行排序并确定 2 张连续卡片之间的差异。如果它包含一张 A,您也需要将其视为低牌。如果所有的差异都是 1(或 -1,取决于排序顺序),那么你就有顺子。

于 2009-02-10T00:17:17.293 回答
0

我认为,鉴于 RANK 的定义,直道只能以 ACE.points() - 4 的最大值开始。

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

如果 ACE 可以是高或低,那么就选择 SHS 的回答。

于 2009-02-09T22:44:05.897 回答
0

使用内部循环非常简单,挑战是在没有内部循环的情况下做到这一点......

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

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

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

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

(在重新阅读问题后再次编辑以将 1 替换为 14)

于 2009-02-09T23:00:50.707 回答
0

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

于 2009-02-10T00:11:21.193 回答
0

我建议使用位向量来表示卡片。这避免了必须排序。您可以添加两次 ace(一次作为 1,其他时间作为国王),或者您可以通过在检查 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
于 2009-02-10T00:31:58.007 回答
0

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

于 2009-02-10T20:13:47.457 回答
-2

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

小丑 = 11 皇后 = 12 国王 = 13 王牌 = 0 或 14

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

于 2009-02-09T22:36:50.953 回答