【问题标题】:Dice Question (Full House and Straight recognition)骰子问题(满屋和直认)
【发布时间】:2011-09-22 22:11:12
【问题描述】:

我正在做一个骰子游戏。有 5 个骰子,其中我有所有的值,我需要确定它们是否构成满堂彩(其中 3 个和另一个 2 个)、小顺子(1-4、2-6 或 3-6)或大顺子 (1-5, 2-6)。

也许解决这个问题的最佳方法似乎是使用正则表达式。

有谁知道我将如何在正则表达式中表示这些规则?

或者,如果您能提供更好的解决方案,我将不胜感激。

例子:

  • 满座 = 44422 或 11166 或 12212 等。
  • 小直 = 12342 或 54532 等。
  • 大直 = 12345 或 52643 等。

编辑
更改措辞以强调这是我缺乏经验的意见。

我知道如何使用代码来实现这一点,但这似乎是一个冗长的解决方案,我想知道是否有更简单的方法。

【问题讨论】:

  • 如果您不知道如何编写所需的正则表达式,为什么您认为正则表达式是最好的方法? (IMO,正则表达式在这里是一种非常糟糕的方法。)
  • 我讨厌这个新的“免费问题投票”系统。人们问这个问题有什么问题?你为什么投反对票?我知道为什么,因为它是免费的
  • 这里不需要正则表达式。
  • @ThePower - 看看这个The Great Poker Hand Evaluator Roundup - 你甚至会得到一些忍者:)
  • @Armen,我同意,问题没问题,应该为 OP 提供适当的解决方案,但是他的方法是错误的。与其投反对票,不如让人们回答并也许教。

标签: c# regex poker dice


【解决方案1】:

这是我的代码:

    public static int   CalculateTotalOfSingles       (int pipNumber)
    {
        //
        var myScore = 0;
        foreach (var myDie in Roll5Player.MyHand.Dice)
        {
            {   if (myDie.Pips == pipNumber)
                myScore+= pipNumber;
            }
        }
        //
        return myScore;
    }
    public static int   CalculateDicePips       ()
    {
        //
        var myScore = 0;
        foreach (var myDie in Roll5Player.MyHand.Dice)
        {
            {myScore += myDie.Pips;
            }
        }
        //
        return myScore;
    }
    //
    //
    //
    public static int   CalculateTotalOfAllSingles    (int pipNumber)
    {
        //
        var myScore = 0;
        for (int i = 1; i <= 6; i++)
        {
            myScore += pipNumber;
        }
        //
        return myScore;
    }
    public static bool  CalculateIsNOfaKind     (int count)
    {
        //
        for (var index = 1; index <= 6; index++)
        {
            var cntr = 0;
            foreach (var myDie in Roll5Player.MyHand.Dice)
            {
                if (myDie.Pips == index)
                    cntr++;
            }
            //
            if (cntr == count)
            {
                return true;
                ;
            }
        }
        //
        return false;
    }
    public static int   CalculateNOfaKind       (int count  )
    {
        //
        var myScore = 0;
        for (var index = 1; index <= 6; index++)
        {
            var cntr = 0;
            foreach (var myDie in Roll5Player.MyHand.Dice)
            {
                    if (myDie.Pips == index)
                        cntr++;
            }
            //
            if (cntr >= count)
            {   myScore = CalculateDicePips();
                return myScore;
                ;
            }
        }
        //
        return myScore;
    }
    /// 
    public static int   CaluclateFullHouse      (           )
    {
        // 
        var myScore = 0;
        var cntr    = new int[6];
        for (var index = 1; index <= 6; index++)
        {
            foreach (var myDie in Roll5Player.MyHand.Dice)
            {
                if (myDie.Pips == index)
                    cntr[index-1]++;
            }
        }

        //
        var boolCondA = false;
        var boolCondB = false;
        foreach (var i in cntr)
        {
            if (i == 3)
            {boolCondA = true;
                break;
            }
        }
        if (boolCondA)
        {
            foreach (var i in cntr)
            {
                if (i == 2)
                {boolCondB = true;
                    break;
                }
            }
        }


        //
        if (boolCondB ) 
            myScore = CalculateDicePips();



        //
        //
        //
        return myScore;
    }
    public static int   CaluclateStraights      (int straightCount, int score)
    {
        // 
        var tempPip     = 0;
        var myScore     = 0;
        var isFirstIteration = true;
        var cntr = 0;
        int[] sortedDice = new int[5];
        var sortedDiceLise = new List<int>();


        foreach (var myDie in Roll5Player.MyHand.Dice)
        {
            sortedDiceLise.Add(myDie.Pips);
        }
        sortedDiceLise.Sort();







        foreach (var myDie in sortedDiceLise)
        {
            //
            //
            if (!isFirstIteration)
            {
                if (myDie == tempPip + 1)
                    cntr++;
            }
            //
            isFirstIteration = false;
            tempPip = myDie;
        }





        if (cntr == straightCount - 1)
        {myScore = score;
        }

        //
        //
        //
        return myScore;
    }

    public static int   CalculateYahtzee        ()
    {
        //
        for (var index = 1; index <= 6; index++)
        {
            var cntr = 0;
            foreach (var myDie in Roll5Player.MyHand.Dice)
            {
                if (myDie.Pips == index)
                    cntr++;
            }
            //
            if (cntr == 5)
            {
                return 50;
                ;
            }
        }
        //
        return 0;
    }

【讨论】:

    【解决方案2】:

    您可以尝试将您的价值观放入一个列表中。这将允许您快速排序您的值。如果您添加可以帮助您的值。 111AA = 29 和 222KK = 30。只是一个想法。

    【讨论】:

      【解决方案3】:

      我决定自己尝试一下,但我最终没有使用正则表达式——我想也许由于所需的搜索很简单,正则表达式会增加比它们节省的复杂性更多的复杂性。不过,我使用了与另一个答案类似的逻辑:计算每个数字的数量并以此为基础:

        enum RollScoreType
        {
           HighDie,
           Pair,
           TwoPair,
           ThreeOfAKind,
           SmallStright,
           PairSmallStriaght,
           FullHouse,
           LargeStraight,
           FourOfAKind,
           FiveOfAKind
        }
      
        struct RollScore
        {
           public RollScoreType type;
           public byte highestDie;
           public byte nextHighestDie;
           public RollScore(RollScoreType type, byte highest, byte next)
           {
              this.type = type;
              this.highestDie = highest;
              this.nextHighestDie = next;
           }
           public override string ToString()
           {
              return string.Format("{0} {1} {2}", type, highestDie, nextHighestDie);
           }
        }
      
        static RollScore GetDiceScore(string input)
        {
           char[] dice = input.ToCharArray();
           byte[] diceCount = new byte[6];
      
           for (int i = 0; i < dice.Length; i++)
              diceCount[int.Parse(dice[i].ToString())-1]++;
      
           if (Array.IndexOf(diceCount, (byte)5) >= 0)
              return new RollScore(RollScoreType.FiveOfAKind, (byte)(Array.IndexOf(diceCount, (byte)5) + 1), 0);
           else if (Array.IndexOf(diceCount, (byte)4) >= 0)
              return new RollScore(RollScoreType.FourOfAKind, (byte)(Array.IndexOf(diceCount, (byte)4) + 1), (byte)(Array.IndexOf(diceCount, (byte)1) + 1));
           else if (Array.IndexOf(diceCount, (byte)3) >= 0)
           {
              byte three = (byte)(Array.IndexOf(diceCount, (byte)3) + 1);
              if (Array.IndexOf(diceCount, (byte)2) >= 0)
              {
                 byte pair = (byte)(Array.IndexOf(diceCount, (byte)2) + 1);
                 return new RollScore(RollScoreType.FullHouse, Math.Max(pair, three), Math.Min(pair, three));
              }
              else
                 return new RollScore(RollScoreType.ThreeOfAKind, three, (byte)(Array.LastIndexOf(diceCount, (byte)1) + 1));
           }
           else if (Array.IndexOf(diceCount, (byte)2) >= 0)
           {
              byte pair = (byte)(Array.IndexOf(diceCount, (byte)2) + 1);
              byte highPair = (byte)(Array.LastIndexOf(diceCount, (byte)2) + 1);
              if (highPair != pair)
                 return new RollScore(RollScoreType.TwoPair, highPair, pair);
              else
              {
                 byte lowMissingDie = (byte)Array.IndexOf(diceCount, (byte)0);
                 byte highMissingDie = (byte)Array.LastIndexOf(diceCount, (byte)0);
                 switch (lowMissingDie)
                 {
                    case 0:
                       if (highMissingDie == 5)
                          return new RollScore(RollScoreType.PairSmallStriaght, 5, 4);
                       if (highMissingDie == 1)
                          return new RollScore(RollScoreType.PairSmallStriaght, 6, 5);
                       break;
                    case 4:
                       return new RollScore(RollScoreType.PairSmallStriaght, 4, 3);
                 }
                 return new RollScore(RollScoreType.Pair, pair, (byte)(Array.LastIndexOf(diceCount, (byte)1) + 1));
              }
           }
           byte missingDie = (byte)Array.IndexOf(diceCount, (byte)0);
           switch(missingDie)
           {
              case 0:
                 return new RollScore(RollScoreType.LargeStraight, 6, 5);
              case 1:
                 return new RollScore(RollScoreType.SmallStright, 6, 5);
              case 4:
                 return new RollScore(RollScoreType.SmallStright, 4, 3);
              case 5:
                 return new RollScore(RollScoreType.LargeStraight, 5, 4);                  
              default:
                 return new RollScore(RollScoreType.HighDie, 6, (byte)(Array.LastIndexOf(diceCount, (byte)1, 3) + 1));
           }
        }
      

      令我惊讶的是,小顺子和大顺子的概率在 5 骰子掷骰中是相等的。是真的吗!?

      编辑:已修复;我看到当我包含包含一对的小顺子时,小顺子的概率显着上升。

      当我想到它时,对子和小顺子可能应该使用对子作为最高骰子,顺子中的最高点数作为下一个最高点(为了[正确比较两个都是对子的掷骰子一条小直线)。如果是这样,我会将处理 PairSmallStraight 的代码块替换为:

                 switch (lowMissingDie)
                 {
                    case 0:
                       if (highMissingDie == 5)
                          return new RollScore(RollScoreType.PairSmallStriaght, pair, 5);
                       if (highMissingDie == 1)
                          return new RollScore(RollScoreType.PairSmallStriaght, pair, 6);
                       break;
                    case 4:
                       return new RollScore(RollScoreType.PairSmallStriaght, pair, 4);
                 }
      

      【讨论】:

      • 其实如果分数是“HighDie”,我想你可以硬编码6和5作为最高的两个骰子。我认为如果没有包含 5 和 6,您将无法获得没有其他分数的任何滚动。
      • 我刚刚注意到,如果你有一对和一个小顺子,这将无法检测到......我想我应该这样做。
      • 这样更好。现在我可以看到小顺子甚至比满屋更常见。
      【解决方案4】:

      我会对所有数字进行递减排序,然后在每个值上执行一些线性标准匹配,无论它是 int[] 还是字符串。

      【讨论】:

      • 骰子什么时候有K、Q、J和A?每个人都在阅读 Full House 并自动认为这是扑克,而忽略了骰子被提及 3 次的事实 :)
      • Poker dice - 我知道你在说什么,但扑克算法中使用的技术非常适合骰子
      【解决方案5】:

      我不会评论您如何查找结果,而是评论您如何存储结果以供以后查找。

      由于您只有 46656 种可能的组合,并且一个字节可以存储产生的手牌强度,因此这个问题比扑克牌问题要容易得多。

      您可以有一个查找表,由作为索引的手牌组成,并与该手牌的结果(有些手牌可能有多个结果)相关联。每个字节都可以将所有手型存储为二进制表示(希望,如果不使用短)。

      您获得的每个数字(例如 66655 - 满堂)都是以六为底的数字 (1-6),将其转换为以 10 为底的数字以获取查找表中的索引。

      它将需要大约 46656 字节(+ CPU 对齐),并且可以放入 CPU L2 缓存中。速度将是巨大的,因为您需要做的唯一操作就是转换数字基数,以及提取手力的二进制 OR 操作。

      你会错过的是一手牌的真正力量。例如。 66655 比 66644 好。你可以很容易地弄清楚 - 你需要一个更大的类型来将结果存储到:)

      【讨论】:

        【解决方案6】:

        您始终可以进行LINQ 聚合查询并计算相同卡片的数量。这将类似于(无法测试):

        var query =  from card in hand
                     group card by card into groupedCards
                     select new { Card = groupedCards.Key, Count = groupedCards.Count() };
        

        这样你就可以很容易地知道你是否正在处理可能的顺子(或根本没有)、对子、三元等。

        我不是LINQ 专家,我目前无法测试这段代码,所以我不确定它是否会按原样编译,但它可能会对您有所帮助或让您了解如何处理手头的问题。

        例如:

        1. 如果计数查询 = 5:我们正在处理空手、同花或顺子 => 运行特定的同花/顺子逻辑。

        2. 如果 count query = 4 :我们正在处理一对。

        3. if count query = 3 : 我们正在处理双对或三重 => 如果 max count =3 然后三重

        4. 如果计数查询 = 2:我们正在处理满屋/扑克。如果最大计数 = 4 则扑克

        【讨论】:

          【解决方案7】:

          不了解 c#,但在脚本语言中,我会采用 regexp 路线。对于每一边,计算它在组合中出现的次数并将结果连接在一起。例如,对于12342 组合,计数器字符串将为121100。然后将计数器字符串与这些模式匹配:

          /5/         = Five of a kind
          /4/         = Four of a kind
          /20*3|30*2/ = Full house
          /1{5}/      = Large Straight
          /[12]{4}/   = Small Straight
          /3/         = Three of a kind
          /2[013]*2/  = Two pair
          /2/         = One pair
          

          【讨论】:

          • 我接受了这个作为答案,不是因为正则表达式(这也是一个很好的库匹配器),而是因为你提到了计数器字符串。我非常喜欢这种方法,让生活更轻松。谢谢。
          猜你喜欢
          • 1970-01-01
          • 2017-02-25
          • 2014-12-06
          • 1970-01-01
          • 2015-06-29
          • 2012-09-16
          • 1970-01-01
          • 1970-01-01
          • 2015-04-30
          相关资源
          最近更新 更多