Цель этой головоломки состоит в том, чтобы взять колоду из 52 карт и перемешать ее, чтобы каждая карта находилась в случайном положении.
Данный:
- Массив
deck
из 52 различных целых чисел, представляющих карты. При запускеdeck
содержит ровно по одной каждой карточке в каком-то неизвестном порядке. - Функция,
int rand(min, max)
которая возвращает случайное целое число между целыми числамиmin
иmax
включительно. Вы можете предположить, что эта функция действительно случайна. - Функция,
void swap(x, y)
которая меняет две карты в колоде. Если вы позвонитеswap(x, y)
, карты на местахx
иy
поменяются местами.
Когда:
- Программа вызывает
shuffle()
(или,shuffle(deck)
или какdeck.shuffle()
вам нравится запускать вашу реализацию),
Потом:
deck
должен содержать ровно одну каждую карту в совершенно случайном порядке.
Поймать:
Вы не можете объявить какие-либо переменные. Вызовите swap
и rand
сколько угодно, но вы не можете объявить свои собственные переменные. Это включает в себя for
счетчики циклов - даже неявные, как в foreach
.
Разъяснения:
- Вы можете изменить мелкие детали в соответствии с выбранным вами языком. Например, вы можете написать
swap
для переключения двух целых чисел по ссылке. Изменения должны быть сделаны, чтобы это работало с вашим языком, а не чтобы облегчить задачу. deck
может быть глобальной переменной, или вы можете принять ее в качестве параметра.- Вы можете делать с содержимым все, что хотите
deck
, но не можете изменять его длину. - Ваши карты могут быть пронумерованы 0-51, 1-52 или как угодно.
- Вы можете написать это на любом языке, но без обмана с помощью встроенной
shuffle
функции вашего языка . - Да, вы можете написать одну и ту же строку 52 раза. Никто не будет впечатлен.
- Время выполнения не имеет значения, но истинная случайность имеет значение.
- Это на самом деле не гольф-код, но вы можете минимизировать / запутать ваш код.
Редактировать: код Boilerplate и визуализатор
Если вы использовали .NET или JavaScript, вот несколько тестовых кодов, которые вам могут пригодиться:
JavaScript:
- Быстрый и грязный визуализатор JavaScript с источником CoffeeScript: https://gist.github.com/JustinMorgan/3989752bdfd579291cca
- Запускаемая версия (просто вставьте в свою
shuffle()
функцию): http://jsfiddle.net/4zxjmy42/
C #:
- Визуализатор ASP.NET с кодом C #: https://gist.github.com/JustinMorgan/4b630446a43f28eb5559
- Заглушка с только
swap
иrand
полезными методами: https://gist.github.com/JustinMorgan/3bb4e6b058d70cc07d41
Этот код сортирует и перетасовывает колоду несколько тысяч раз и выполняет некоторое базовое тестирование работоспособности: для каждого перемешивания он проверяет, что в колоде находится ровно 52 карты без повторов. Затем визуализатор отображает частоту каждой карты в каждом месте колоды, отображая тепловую карту в оттенках серого.
Вывод визуализатора должен выглядеть как снег без видимого рисунка. Очевидно, что это не может доказать истинную случайность, но это быстрый и простой способ выборочной проверки. Я рекомендую использовать его или что-то подобное, потому что определенные ошибки в алгоритме тасования приводят к очень узнаваемым паттернам в выходных данных. Вот пример вывода из двух реализаций, одна с общим недостатком:
Неправильная версия частично перетасовывает колоду, поэтому может хорошо выглядеть, если вы изучили массив вручную. Визуализатор позволяет легче заметить шаблон.
источник
deck
себя.swap
вам нравится, при условии, что она выполняет свое основное назначение. Одна из причин, по которой я сделал что-swap
то, было то, что люди могли относиться к нему как к «магии» и сосредоточиться на главной проблеме, не беспокоясь о том, чтобы она работала на выбранном ими языке. Вы можете сделать это или написать свойswap
, это зависит от вас.Ответы:
JavaScript
Я считаю, что это предполагаемая форма решения, я использую карту в положении 0, чтобы отслеживать прогресс, только перетасовывая карты, которые уже использовались в качестве счетчика, это достигает стандартных 52! перестановки с идеально равным распределением. Процедура усложняется обменом XOR, не позволяющим заменить элемент самостоятельно.
Редактировать: я встроил сортировку, которая сортирует каждый элемент на месте непосредственно перед его использованием, что позволяет работать с несортированным массивом. Я также отбросил рекурсивный вызов в пользу цикла while.
источник
Haskell
Вот бессмысленная реализация. Нет переменных, формальных параметров или явной рекурсии. Я использовал lambdabot «s
@pl
(„бессмысленный“) рефакторинг функции совсем немного.Вот моя процедура тестирования, чтобы убедиться, что числа были распределены равномерно:
Вот оригинальный алгоритм:
источник
((.) .) . (. (++))
и это(((.) . (,)) .)
мои любимые. Ух ты ламбдабот. Просто вау.J
Игнорирование этой колоды является переменной, есть очевидное ...
Конечно, если вам действительно нужна функция, она есть, которая будет работать, даже если вы забудете удалить джокеров (или попытаетесь перетасовать что-то, кроме карт).
И что...
Вероятно, это выходит за рамки вопроса, заключающегося в том, чтобы реализовать случайное перемешивание из rand (
?
). Я мог бы сделать это позже, когда я не должен работать.объяснение
Объяснение
52 ? 52
:x ? y
х случайных уникальных предметов от у.Объяснение
{~ (# ? #)
сложнее из-за вилок и крючков . По сути, это то же самоеshuffle =: 3 : '((# y) ? (# y)) { y'
, что имеет один неявный аргумент (y
).# y
дает длину уx { y
это элемент y в индексе x или (в данном случае) элементы в индексах в x.Смотрите J Vocabulary для подробностей об операторах, хотя синтаксис и семантика довольно сложны из-за рангового и неявного программирования.
источник
{52?⍵}
это анонимная функция, которая берет 52 случайных элемента из своего аргумента, который здесь будет список из 52 целых чисел)питон
источник
[1:]
значит? Это рекурсивно для подмассиваdeck
?a, b = b, a
трюк.Использование факторического представления
В факторическом представлении перестановки элемент i принимает значения от 0 до Ni. Так что случайная перестановка только
rand(0,i)
для каждого Ni.В J:
где
? x
естьrand(0,x-1)
и|.>:i.52
есть52 51 ... 1
Затем, если
a
это значение Ith factoradic, мы делаем обмен:swap(deck[i], deck[i+a])
. Список пар для обмена:Обмен, который мы будем использовать, работает следующим образом:
Это не совсем «по ссылке», но в J. нет реальных функций.
Мы будем использовать length (
#deck
), чтобы избежать использования константы.Полная программа на J:
источник
C #
Вот мой собственный ответ, основанный на алгоритме Фишера-Йейтса . Должен дать вам идеальную случайность, если ваш генератор случайных чисел достаточно хорош.
Английская версия:
deck[0]
с тойdeck[v]
, гдеv
находится номинальная стоимость картыdeck[0]
. Повторять доv == 0
. Это будет частично сортировать колоду, но это не имеет значения. Теперь вы знаете, что карта 0 находится в передней части колоды, что означает, что вы можете украсть это пространство в массиве и использовать его в качестве счетчика циклов. Это ключевой «чит» для проблемы локальных переменных.i
с той, что вrand(i, 51)
. Обратите внимание, что вам нужноrand(i, 51)
, а неrand(1, 51)
. Это не гарантирует, что каждая карта рандомизирована.deck[0]
на 0. Теперь вся колода перемешивается для первой карты , за исключением, так свопаdeck[0]
с ,deck[rand(0, 51)]
и вы сделали.Версия C #:
Версия Javascript:
... где
swap(a, b)
обменdeck[a]
сdeck[b]
.источник
Рубин, одна строка
Это считается обманом? Это должно быть настолько случайным, насколько это возможно.
(
rand
Метод Руби принимает только один аргумент, а затем генерирует число n такое, что 0 <= число <аргумент.)Дополнительно - похоже на Perl-решение sogart, но, насколько я знаю, оно не страдает от проблемы:
Сортировка Ruby sort_by отличается от sort - сначала она генерирует список значений, по которым сортируется массив, и только затем сортирует его по ним. Быстрее найти свойство, по которому мы сортируем, быстрее, во всех остальных случаях - немного медленнее. Это также полезно в коде гольф: P
источник
deck[0..51]
в некоторой степени игнорирует правило «без переменных», используя особенность языка. Это справедливо, я просто думаю, что это теряет некоторые проблемы. :) Я не знаю Руби; можешь объяснить(0..51).map{deck.delete_at(rand deck.length)}
часть? Это удаляет карты изdeck
?deck
и добавляет ее во внутренний список результатов, которыйmap
накапливается. Тогда , когда не осталось ничего вdeck
вmap
результате получает копируетсяdeck
. По сути, это временный объект, но это языковая функция, а не явная переменная :)deck.sort_by!{rand}
корочеJavaScript
ПРИМЕЧАНИЕ. Технически это решение некорректно, поскольку
i
в вызове используется второй параметрshuffle
, который считается внешней переменной.Позвонить с
shuffle(deck,52)
Полный рабочий пример (пришлось
swap
немного изменить, потому что в JavaScript нет передачи по ссылке):источник
shuffle
как переменные, но я не указал это так +1. Хорошее использование рекурсии тоже.deck[rand(0,i-1)]
вместоdeck[rand(0,i-2)]
. Также поменяйте местами весь путьi=0
вместо того, чтобы останавливаться наi=1
. Это помогает?C ++
Избегает обмена элементами между собой, поэтому должен вызываться дважды, чтобы быть случайным.
источник
swap(deck[rand(1, 51)], (deck[0] - 51) / 100);
Какswap
узнать, где поставить второе значение? Вы также пропускаете)
.deck[0]
, но не так, как вы.D
источник
Другое решение Perl, которое фактически производит равномерно распределенный вывод:
Это решение использует Perl
rand
, который возвращает случайное число x в диапазоне 0 ≤ x <1. Он добавляет такое случайное число к каждому целому числу на входе, сортирует числа по дробным частям и, наконец, удаляет эти дробные части снова ,(Я считаю , что использование специальных переменных
$_
,$a
и$b
падает в духе вызов, так как те , как Perl проходит вход вmap
иsort
, и они не используются для других целей , в коде. В любом случае, я считаю , они на самом деле псевдонимы для входных значений, а не независимые копии Это фактически не перетасовка на месте, хотя,. , какmap
иsort
создавать копии входа в стеке).источник
Джава
Я удивлен, что никто не указал очевидное: (Я предполагаю, что swap (x, x) ничего не делает.
ОК, хорошо, это может быть короче:
источник
бурлеск
Что вы на самом деле просите, так это случайную перестановку списка целых чисел?
r@
даст нам все перестановки, и мы просто выберем случайную.Поскольку нам нужна настоящая случайность, то, что Бурлеск не в состоянии сделать, потому что Бурлеск не имеет функциональных возможностей ввода / вывода, вам нужно было бы предоставить какой-то источник случайности через STDIN.
Это, вероятно, что-то, что я исправлю в более поздней версии (то есть создаю случайное начальное число при запуске и помещаю его во вторичный стек или что-то в этом роде, но сам Burlesque Interpreter не имеет ввода-вывода).
источник
Javascript
Я не уверен, что это «обман», но мое решение использует собственный локальный массив аргументов функции. Я включил свои самодельные функции
rand()
swap()
иfilldeck()
. Интересно отметить, что это должно работать с колодой любого размера.источник
Tcl , 32 байта
Злоупотребления
time
функцией, которая служит для измерения того, сколько времени затрачивается на выполнение сценария, но также может служить циклическим механизмом без объявления каких-либо переменных.Попробуйте онлайн!
источник
Perl - это не правильное перемешивание, как описано в комментариях!
Я думаю, что я ничего не использовал в качестве подкачки и т. Д. Это было необходимо как часть проблемы?
источник
JavaScript 4 строки
Оригинальный ответ, который не был достаточно случайным. Своп не гарантировал прикосновения к каждому предмету в колоде.
источник
shuffle
немного изменил ваш код, чтобы он соответствовал моейswap
реализации, но здесь он дословно: jsfiddle.net/m7km4u6g