4

我必须测试一下,看看这个方法是否洗过一副牌。这里是实际洗牌部分的代码。

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

测试它是否被洗过的问题是我只能交换两张牌,它会被认为是洗过的。这是我迄今为止对随机洗牌的测试。

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

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

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

4

7 回答 7

6

您不能对单个样本执行此操作。但是你可以做的是对一些洗牌的牌组进行统计分析,以寻找非随机性的迹象。

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


当我说“你不能这样做”时......显然你可以测试看看甲板是否根本没有被洗牌,或者洗牌是否破坏了甲板。但这些都不是你标准的可靠测试......“洗牌足够”。

于 2011-02-17T10:02:55.587 回答
4

你不能。不可能确定一副牌是否经过洗牌,因为理论上洗牌可以产生一副完全有序的牌。

于 2011-02-17T09:50:40.067 回答
4

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

于 2011-02-17T09:51:56.840 回答
2

一种措施可能是对洗牌后的牌组进行排序并检查它进行了多少“操作”。显然,该度量将取决于排序算法。

或者,您可能会在这里的某个地方找到一些统计度量:http ://en.wikipedia.org/wiki/Randomness_tests 。

于 2011-02-17T10:04:39.673 回答
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,您很可能应该继续自己的实现。

于 2011-02-17T10:13:01.643 回答
1

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

  • 首先,我想知道您对“足够洗牌”的定义是什么。你甚至可以测量它吗?你有这方面的指导方针吗?例如应该至少有五张牌但在不同的位置?您可以轻松地编写一个测试来验证多张卡片或在不同的位置,但这是否足够?
  • 我也认为马克制作一个模仿原始套牌的洗牌套牌是正确的(尽管我怀疑这种可能性非常低)。所以测试这将是非常困难的,或者如果它模仿原始的,你可以丢弃洗牌的牌组。这样你的测试就足够了
  • 此外,我相信您可能应该使用 Jigar 的提及Collections.shuffle()而不是自己写一些东西?
于 2011-02-17T10:03:13.697 回答
1

我发现测试这一点的最佳方法是测试 1000 次左右不同的时间,并记录每次测试成功的时间。最终,您真的想知道测试在 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)
}
于 2016-04-28T18:21:29.857 回答