【问题标题】:Determining how well a deck is shuffled确定一副牌的洗牌程度
【发布时间】:2013-10-17 18:55:33
【问题描述】:

我正在做一个小型扑克程序,我想确定一副牌的洗牌程度。 我有一个包含 52 张牌的列表,然后我运行我的洗牌算法,我希望能够确定牌组在某种规模上洗牌的效果。 有人知道如何做到这一点吗? 谢谢

编辑: 哇。很多回应。一切都很好,但不完全是我想要的。这是我没有进一步说明我的问题的错。但我认为萨兰最接近我真正想要的。让我指定。

我不希望立即进行“完美”洗牌。我已经阅读了这一点,并实现了 Fisher-Yates。那个非常擅长提供“完美”的洗牌。我正在尝试做的是模拟一个真实世界的情况,朋友们正在玩德州扑克,庄家拿走牌组并使用 riffle shuffle 与其他洗牌混合进行洗牌。 最后,我想要的是一种衡量现实世界洗牌之间差异的方法。

一个例子。假设这副牌总是新鲜的(A 到 K 同花色,然后下一个花色 A 到 K 全部四个花色)。乔拿起牌组,做了 2 次洗牌,中间有 1 次。彼得做了 5 次剥离洗牌。我想找到一种方法来查看哪个“更好”地洗牌。

我想得越多,我就越觉得它很难确定。

再次感谢。

编辑 23.10.2013

这是我想出的方法,将 Sarans 的想法与我的想法结合起来:

 public int checkShuffle(List<Card> cardDeckToCheck,int[] previousOrder)
    {
        // Higher is worse? Sure.
        int score = 0;

        for (int i = 0; i < cardDeckToCheck.Count; i++)
        {
            Card cardToCheck = cardDeckToCheck[i];
            Card cardToLeft = null;
            Card cardToRight = null;

            // Should cost more since the card has not moved at all.
            // For this I need an array that shows me the arangement of the deck before shuffling.
            if(cardToCheck.index == previousOrder[i])
            {
                score += 3;
            }

            if (i == 0)
            {
                Console.WriteLine("i == 1");
                cardToRight = cardDeckToCheck[i+1];
                // if the card we are checking is one lower or one higher than the card to the right
                if(Math.Abs(cardToCheck.index - cardToRight.index) == 1)
                {
                    score++;
                }
                continue;
            }

            else if (i == cardDeckToCheck.Count-1)
            {
                Console.WriteLine("i == carddecktocheck.count-1");
                cardToLeft = cardDeckToCheck[i - 1];
                // if the card we are checking is one lower or one higher than 
                if (Math.Abs(cardToCheck.index - cardToLeft.index) == 1)
                {
                    score++;
                }
                continue;
            }

            else
            {
                cardToLeft = cardDeckToCheck[i - 1];
                cardToRight = cardDeckToCheck[i + 1];
                // if the card we are checking is one lower or one higher than 
                if (Math.Abs(cardToCheck.index - cardToLeft.index) == 1)
                {
                    score++;
                }
                if (Math.Abs(cardToCheck.index - cardToRight.index) == 1)
                {
                    score++;
                }
                continue;
            }

        }
        return score;
    }

我首先将牌组的外观记录到一个 int 数组中,然后将牌组洗牌,然后使用洗牌后的牌组和牌组的先前顺序运行此方法。 像这样:

int[] previousOrder = getCurrentOrder(deck.getDeck());
deck.setDeck(riffleShuffle2(3));
textBoxShuffleness.Text = "" + checkShuffle(deck.getDeck(), previousOrder);
displayDeck(deck);

当我从未洗牌的牌组开始并运行 riffle shuffle 方法 5 次时,我得到 70、33、28、5、10。 当我从未洗牌的牌组开始并运行 Durstenfeld 洗牌方法 5 次时,我得到 5,0,7,11,7.

这些结果非常符合我的预期。

如果有人能发现这种方法有问题,那么如果您能发表评论,我将不胜感激:) 谢谢

【问题讨论】:

  • 那会是什么规模?你可以洗牌无数次,最终得到完全相同的顺序。
  • 如果随机性可以衡量,那就不是好的随机性。
  • 我将此问题标记为转移到有关数学的姊妹论坛,在那里您可以询问随机性的测量。一旦您知道要使用哪种具体测量方法,我们可以帮助您在 StackOverflow 上找到执行该测量的工具 =)
  • 这真的更像是一道数学题。如果您从这里获得了测量随机性的方法:math.stackexchange.com/questions,然后需要了解如何实现它的帮助,那么 stackoverflow 对您来说会更重要。

标签: c# random entropy


【解决方案1】:

要想有任何希望,您需要一遍又一遍地运行洗牌程序,始终从相同的初始牌组开始,然后比较结果。

如果完全公平,您预计任何给定的牌在洗牌后都有 52 分之一的机会出现在任何位置。

如果存在偏见,您会发现它在某些地方比其他地方更频繁地出现。

当然,与理想的 1-in-52 有所不同。
可接受的变化量可以通过统计数据和各种置信区间来预测。 (95%?97%?)

即使你得到了一个完美的分布,这并不意味着你的洗牌是随机的。
(想象一个洗牌算法,它只是在每次连续洗牌时将牌组旋转一张牌......它会有完美的 1-in-52 结果,但绝不是随机的)

要寻找的另一个方面是卡片之间的相关性。
例如,黑桃 A 和黑桃 K 的最终位置应该完全不相关。
一个糟糕的洗牌算法可能会将这两张牌一起移动,从而导致高相关性。 检查每张卡片与其他卡片的相关性在计算上很昂贵,但应该是一种简单的算法。

我认为最终结果是您无法证明您的算法是公平/良好的洗牌。 您只能设置各种测试来寻找“坏”的洗牌(非均匀分布,或牌位的高度相关性)。如果您通过了所有针对 bad-shuffle 的测试,这并不意味着您的算法在测试未涵盖的其他方面没有缺陷。
但它确实让您更有信心。

可能有更好的方法来测试随机性,但它是computationally impossible

正如Coding Horror Blog 条目所指出的,更好的方法可能是针对非常小的一副纸牌(本文使用三张纸牌)运行您的算法,并仔细评估这些结果。只有 3 张卡片,应该更容易追踪所有路径,并查看所有结果是否同样可能。

【讨论】:

    【解决方案2】:

    这里有一些信息:Randomness tests。值得注意的是,如果您的 shuffle “通过”所有此类测试,则表明 shuffle 可能是真正随机的。但是,如果您使用的是伪随机生成器,那么您已经知道它不是。

    【讨论】:

      【解决方案3】:

      对此的一个想法是获取列表并用整数值填充它(每张卡 1 个整数)。制作另一组代码,获取 int 值并将其转换为您的卡值,这样您就可以保留哪些卡属于哪些数字。随机化整数列表,然后遍历列表中的每一行,并标记有多少在一组范围内或从前一个数字开始的 1-2 个整数范围内。最后,您为差、好、好等设置一组百分比刻度...

      这可能不是最佳解决方案,但您将能够了解列表的分布情况。

      【讨论】:

      • 我认为您可能正在做某事。所以你的意思是,如果我真正的牌组中的一张牌远离其原始位置,则表明洗牌良好,而如果它在其原始位置的某个阈值内,则表明洗牌不好.对吗?
      • Sorta,您也可以随时使用它。我最初的想法是在洗牌后获取列表并遍历列表,将每个行项目与下一个项目进行比较。如果它们散开,这意味着 int 不在 1-2 个整数(1 + 1 或 1 + 2)内,那么 shuffle 就很好。 (第 1 项 = 整数 10,第 2 项 = 整数 30,相差 20 整数)。
      • 啊,是的。我懂了。我将尝试实现这两个测试。现在我将不回答这个问题......
      • 很抱歉这么晚才回答,但我一直很忙。所以我在我的程序中实现了一个方法来检查一副牌的洗牌情况。它建立在 Sarans 的想法之上,据我所知,它运作良好。它输出一个整数,整数越高,我的洗牌越差。 0 是“完美”的随机播放分数。我会将 Sarans 的答案标记为正确的答案。
      【解决方案4】:

      你无法衡量一副牌的洗牌程度,因为每张牌组合的概率都是一样的。

      但是,您可以衡量您的洗牌算法的实际性能有多好。 Jeff Atwood 有一些关于这个特殊问题的帖子:

      http://www.codinghorror.com/blog/2007/12/shuffling.html

      http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-24
        • 2015-08-25
        相关资源
        最近更新 更多