Как проверить, достаточно ли перетасована колода карт в Java

Я должен проверить и посмотреть, перетасовал ли этот метод колоду карт. Здесь, если код для фактической части перетасовки.

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

Итак, мой вопрос: как мне проверить, достаточно ли что-то перетасовано?


person frodosamoa    schedule 17.02.2011    source источник
comment
Как кто-то сказал, вам нужно определение «достаточно». Вы можете рассчитать что-то вроде энтропии перетасовки, но я бы сказал, что проще сделать то, что сказал Джигар Джоши, и использовать Collections.shuffle().   -  person Erik    schedule 17.02.2011
comment
Честная перетасовка (такая как fisher-yates, реализация которой является вашей) выберет все перетасовки с равной вероятностью. Пытаясь исключить «менее перемешанные» результаты, вы на самом деле уменьшаете случайность перетасовки.   -  person Nick Johnson    schedule 01.03.2011


Ответы (7)


Вы не можете сделать это с одним образцом. Но что вы могли бы сделать, так это выполнить статистический анализ ряда перетасованных колод, чтобы найти признаки неслучайности.

Я думаю, вам лучше спросить об этом на math.stackexchange.com ... где тусуются умные ребята. Если они могут объяснить «математику» простыми словами (для таких тупых айтишников, как вы и я), вы должны уметь кодировать тесты на Java.


Когда я говорю: «Вы не можете этого сделать»… очевидно, вы можете проверить, не перетасовывалась ли колода вообще, или же перетасовка испортила колоду. Но ни один из них не является надежным тестом для ваших критериев ... «достаточно перетасован».

person Stephen C    schedule 17.02.2011
comment
И теперь есть сайт статистики, который может быть немного более ориентирован на то, что вы ищете: stats.stackexchange.com - person Gordon Gustafson; 14.04.2012

Вы не можете. Невозможно определить, перетасована ли колода, поскольку теоретически в результате перетасовки может получиться колода в точном порядке.

person Mark Byers    schedule 17.02.2011
comment
можно ли сравнить первую карту в колоде с другой и добавить к счетчику? затем сравнить первые две карты колоды со следующими двумя картами колоды? так далее и так далее. таким образом, чем выше счетчик, тем больше его перетасовывали? - person frodosamoa; 17.02.2011
comment
@frodosamoa: Может быть, эта аналогия поможет вам. Представьте, что у вас есть функция, которая утверждает, что возвращает случайные целые числа от одного до десяти (включительно). Вы хотите проверить, насколько это случайно. Вы решаете, что если результат один или десять, то это недостаточно случайно. Все остальное достаточно случайно. Проблема в том, что этот тест отклоняет действительно случайные функции в 20% случаев и принимает функции, которые вообще не являются случайными (например, return 4;). То, что вы делаете, в основном то же самое, что и в этом простом примере, за исключением того, что вы выбираете 52 случайных числа вместо одного. - person Mark Byers; 17.02.2011

Точная проверка невозможна. Просто доверься своему алгоритму. или используйте Collections.shuffle()

person jmj    schedule 17.02.2011
comment
можно ли сравнить первую карту в колоде с другой и добавить к счетчику? затем сравнить первые две карты колоды со следующими двумя картами колоды? так далее и так далее. таким образом, чем выше счетчик, тем больше его перетасовывали? - person frodosamoa; 17.02.2011
comment
снова рассмотрим наихудший случай. вы перетасовали, и он выровнялся, как было раньше, вы перетасовали (но не на самом деле). вы можете изменить свой алгоритм, который будет отслеживать предыдущий порядок и перемешивать столько, сколько он не соответствует предыдущему состоянию в любом случае - person jmj; 17.02.2011

Одной из мер может быть сортировка перетасованной колоды и проверка того, сколько «операций» она потребовала. Очевидно, что эта мера будет зависеть от алгоритма сортировки.

Кроме того, вы можете найти некоторые статистические показатели здесь: http://en.wikipedia.org/wiki/Randomness_tests< /а>.

person SimonC    schedule 17.02.2011

В точности, как сказал Марк Байерс, алгоритм перетасовки может создать колоду в точном порядке. Но если это происходит при каждом последующем прогоне, то это определенно плохой алгоритм! Таким образом, правильный алгоритм тасования должен создавать такие последовательности карт, чтобы распределение карт на i-й позиции было равномерным. Пусть S(i)={c(1)(i),c(2)(i),...,c(54)(i)} будет i-й последовательностью (i-й результат вашего алгоритма). Тогда c(j)(i) относительно (i) должно следовать (приблизительно) равномерному распределению. Чтобы проверить, верно ли это, запустите свой алгоритм несколько тысяч раз и в каждой позиции j=1,2,...,54 подсчитайте частоту появления каждой отдельной карты. Числа должны быть более или менее равными. В идеале, если вы запустите алгоритм 54000 раз, вы должны увидеть каждую карту в каждой позиции 1000 раз. Сильно сомневаюсь, что так будет при использовании Math.random(). Используйте java.util.Random для лучших результатов. Вот как вы работаете со случайным:

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

и каждый раз вам нужен случайный двойной:

random.nextDouble();

Метод Collections.shuffle(); делает именно это. Если вам нужны ГСЧ лучше, чем реализация Java Random, вам, скорее всего, следует продолжить свою собственную реализацию.

person Pantelis Sopasakis    schedule 17.02.2011
comment
Я сильно сомневаюсь, что это произойдет с использованием Math.random(). Используйте java.util.Random для лучших результатов - нет, это то же самое. Math.random() javadoc говорит: Когда этот метод вызывается впервые, он создает один новый генератор псевдослучайных чисел, точно так же, как если бы выражение new java.util.Random Если вам нужны RNG лучше, чем реализация Java Random, вам, скорее всего, следует приступайте к собственной реализации. - нет, если вам нужны ГСЧ лучше этого, вы должны использовать java.util.SecureRandom, что почти наверняка лучше, чем то, что мог бы реализовать неспециалист. - person Cowan; 17.02.2011
comment
Тем не менее, в остальном отличный ответ. Тестирование дистрибутива — единственный реальный способ проверить это. - person Cowan; 17.02.2011
comment
@Cowan: Я согласен с тем, что SecureRandom - очень хороший RNG, но (возможно) лучше /dev/random в Linux, который использует шум окружающей среды, собранный из драйверов устройств. - person Pantelis Sopasakis; 17.02.2011

Во-первых, мне нравится этот вопрос (интересный).

  • Прежде всего, я хотел бы знать, каково ваше определение «достаточно перетасованного?». Можешь хотя бы измерить? У вас есть рекомендации по этому поводу? Нужно, например, не менее пяти карт, но в другом месте? Вы можете легко написать тест для проверки этого количества карточек или в другом месте, но достаточно ли этого?
  • Я также думаю, что Марк прав в отношении создания перетасованной колоды, которая имитирует оригинальную колоду (хотя я сомневаюсь, что вероятность очень мала). Поэтому тестирование будет очень сложным, иначе вы можете отказаться от перетасованной колоды, если она имитирует оригинал. Таким образом, вашего теста будет достаточно
  • Кроме того, я считаю, что вам, вероятно, следует использовать упоминание Джигара о Collections.shuffle() вместо того, чтобы писать что-то самому?
person Alfred    schedule 17.02.2011

Лучший способ проверить это, который я нашел, — это протестировать 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)
}
person Chéyo    schedule 28.04.2016
comment
Это не проверяет достаточность перетасовки ... если только ваш единственный критерий достаточности - это вообще. Кроме того, это не код Java. - person Stephen C; 06.02.2017