如何在抽卡游戏中检测"Hand"

How to detect "Hand" in a card drawing game

有一个数组代表从整副牌(52 张牌)中挑选出的 5 张牌。
所以一手随机的牌看起来像这样 ['H3','H6','D3','D4','S4'],(这里是 h 2 对 4 和 3) .
我正在寻找一种方法来了解随机 5 张卡片的属性:

一旦您考虑到存在基于值的层次结构,识别一手牌就很容易了。所以虽然同花顺也是同花顺,葫芦也是两对,但你总是会选择更有价值的分类。

这意味着如果您按照每手牌的价值降序检查您的五张牌,则第一张匹配将是正确的。 (像 strategy pattern 这样的东西在这里可能非常有用。)

至于概率,我只是look them up。 (请注意,一副完整的牌是 52 张而不是 54 张。)

关于每手牌的概率,这是一个简单的计数问题,考虑到有52选择5 = 2,598,960不同的手牌,所以你只需要计算每种手牌有多少手牌并除以 2598960。

例如有 4 个不同的皇家同花顺 -> 4/2,598,960 的机会 = 0.000153907%

有 4*10=40 个不同的同花顺 -> 40/2,598,960=0.00153907%

的几率

有 13*48=624 个不同的四边形 -> 624/2,598,960 的几率=0.024009603%

等等..

如果您不喜欢计算问题,您可以使用您的程序来枚举这 2,598,960 手牌并计算有多少次同花、四条等等。

关于检测手牌的代码——我会按排序顺序存储手牌(根据卡片的 rank/height,忽略花色,即 ['H3'、'D3' ,'D4','S4','H6'])。这将帮助您非常有效地检测对、两对、三胞胎、四胞胎、葫芦和顺子。 检测同花很容易 - 只需检查所有五张牌是否来自同一花色。大功告成!

首先设置一些数据结构来表示花色、点数、牌和手牌。有很多方法可以做到这一点以获得良好的性能,例如使用位向量,但假设我们想让它可读:为花色和等级制作枚举,为纸牌制作结构,为手牌制作 class。顺便说一下,这种类型的示例正是您希望的地方 using F#

注:代码仅供参考:从未见过编译器。不要期望粘贴这个 & 运行。

enum Suit { Spades, Hearts, Diamonds, Clubs }
enum Rank { Two, Three, Four, Five, Six, Seven, 
            Eight, Nine, Ten, Jack, Queen, King, Ace }

enum HandType { Nothing, Pair, TwoPair, ThreeOfAKind, Straight,
     Flush, FullHouse, FourOfAKind, StraightFlush }    

public struct Card 
{
   public Suit Suit { get; private set; }
   public Rank Rank { get; private set; }
   public Card(Rank rank, Suit suit)
   {
      Suit = suit;
      Rank = rank;
   }     
}

public class Hand 
{
   public IReadOnlyList<Card> Cards { get; private set };
   public Hand(IEnumerable<Card> cards) 
   { 
      this.Cards = cards.OrderByDescending(c => c.Rank).ToList(); 
   }   
}

评估可以用一种方法来完成,该方法接受一只手和 returns 一只手的种类。请注意,这只是 class 确定 这手牌,它实际上并没有计算出完整的排名,例如较高的顺子击败较低的顺子等等。我省略了实际的实现,但这里有一个框架:

public static class HandEvaluator
{
    public static HandType GetHandType(Hand hand)
    {           
       bool isFlush = hand.Cards.Distinct(c => c.Suit).Count() == 1;
       bool isStraight = // five consecutive ranks. Mind the wheel straight Ace->5! 
       if (isStraight && isFlush)
         return HandType.StraightFlush;           

       // group cards by rank, then find the group count & sizes
       var groups = hand.Cards.GroupBy(c => c.Rank);

       if (/* max group size = 4 */)
          return HandType.FourOfAKind;
       if (/* two groups and max group size = 3 */)
          return HandType.FullHouse;
       if (isFlush)
         return HandType.Flush;
       if (isStraight)
         return HandType.Straight;   
       if (/* three groups and max group size 3 */)
          return HandType.ThreeOfAKind;

       // ... And so on for two pair, pair. 

       return HandType.Nothing;
    }
}

至于不同手牌的概率:那些你应该能够在纸上做的比用程序更容易,但是一旦你有一个 classifying 程序,你可以通过生成所有可能的手,class 化它们,grouping/counting 评估手型的结果。