如何在Java中测试卡片是否已经洗牌

时间:2011-02-17 09:47:01

标签: java algorithm random shuffle playing-cards

我必须测试并查看这种方法是否已经改组了一副牌。 这里如果代码为实际的洗牌部分。

 public void randomShuffle () {
               for (int i = 0; i < DECK_SIZE; i++) {
                   int place = (int)((Math.random()*(51-i))+i);
                   Card temp = this.cardAt(i);
                   this.cardList[i] = this.cardAt(place);
                   this.cardList[place] = temp;
           }
       }

测试它是否被洗牌的问题是我只能切换两张卡而且它会被认为是洗牌。 这是我到目前为止对随机shuffle的测试。

static void randomShuffleTest () {
       Deck deck1 = Deck.newDeckOf52();
       Deck deck2 = Deck.newDeckOf52();
       deck2.randomShuffle();           

       assert false == deck1.equals(deck2);
    }

所以,我的问题是,我如何测试某些东西是否足够洗牌?

7 个答案:

答案 0 :(得分:6)

单个样本无法做到这一点。但是你可能能够做的就是对一些洗牌的甲板进行统计分析,以寻找非随机性的迹象。

我认为你可以在math.stackexchange.com上更好地问这个问题......聪明的家伙们会在那里闲逛。如果他们能用简单的术语解释“数学”(对于像你我这样愚蠢的IT人员),你应该能够用Java编写测试代码。


当我说“你不能这样做”时......很明显你可以测试一下甲板是否没有被洗牌,或者洗牌是否已经破坏了牌组。但这些都不是对你的标准的可靠测试......“足够改组”。

答案 1 :(得分:4)

你做不到。无法确定是否对牌组进行了改组,因为从理论上讲,改组可以产生一个完全正确的牌组。

答案 2 :(得分:4)

确切的测试不可能。只要相信你的算法。或使用Collections.shuffle()

答案 3 :(得分:2)

一个衡量标准可能是对洗牌后的牌组进行排序,并检查所需的“操作”次数。显然,这一措施将取决于排序算法。

或者,您可能会在某处找到一些统计指标:http://en.wikipedia.org/wiki/Randomness_tests

答案 4 :(得分:2)

正如Mark Byers所说,一个改组算法可能会生成一个完全按顺序排列的牌组。但如果它在每次连续运行中都这样做,那么它肯定是一个糟糕的算法!因此,适当的改组算法应该创建卡片序列,使得第i个位置上的卡片分布是均匀的。设S(i)={c(1)(i),c(2)(i),...,c(54)(i)}为第i个序列(算法的第i个结果)。然后关于(i)的c(j)(i)应遵循(近似)均匀分布。要检查是否成立,请运行您的算法数千次,并且在每个位置j = 1,2,...,54计算每个不同卡出现的频率。数字应该或多或少相等。理想情况下,如果您运行算法54000次,您应该在每个位置看到每张卡1000次。我强烈怀疑使用Math.random()是否会出现这种情况。使用java.util.Random可获得更好的结果。这就是你使用Random的方法:

final java.util.Random random = new java.util.Random(seed);

每次你需要一个随机的双倍:

random.nextDouble();

方法Collections.shuffle();就是这样做的。如果您需要比Java的Random实现更好的RNG,那么您最有可能继续执行自己的实现。

答案 5 :(得分:1)

首先,我喜欢这个问题(有趣)。

  • 首先,我想知道你的定义是什么?“足够改组?”。你能测量它吗?你有指导吗?例如应该至少有五张牌但是在不同的位置?你可以轻松地编写一个测试来验证一些卡片或在不同的位置,但这是否足够?
  • 我也认为Mark正确地制作了一个模仿原始牌组的洗牌牌(虽然我怀疑概率非常低)。所以测试会非常困难,或者如果它模仿原始的话,你可以丢弃洗牌的牌组。这样你的测试就足够了
  • 此外我相信你应该使用Jigar提到的Collections.shuffle()而不是自己写一些东西?

答案 6 :(得分:0)

我发现测试它的最佳方法是测试1,000次左右的不同时间并记录每次测试成功。最终你真的想知道测试工作的时间是98-99%,所以只要结果是~99%+ / - 1%你应该是好的并且测试应该总是通过。

  • 洗牌的手不应该等于原件。
  • 两者的长度应该相同。
  • 所有卡片的总和应该相同(或相似)

swift中的示例代码:

func testShuffled() {
    var hand1 = [3,4,5,6,7,1,2,8,9,10,11,12,2,3,4,5,6,7,8,9,10,11,12]
    var count =  0

    for _ in 0..<1000 {
        let hand2 = hand1.shuffled()

        if (hand1 != hand2 && hand1.count == hand2.count &&
            hand1.reduce(0, combine: +) == hand2.reduce(0, combine: +)) {
            count += 1
        }
        hand1 = hand2
    }
    let result = Double(count) / 1000.00
    XCTAssertEqualWithAccuracy(result, 1, accuracy: 0.02)
}