Celem tej układanki jest wzięcie talii 52 kart i przetasowanie jej tak, aby każda karta znajdowała się w losowej pozycji.
Dany:
- Tablica złożona
deck
z 52 różnych liczb całkowitych reprezentujących karty. Po uruchomieniudeck
zawiera dokładnie jedną kartę w nieznanej kolejności. - Funkcja,
int rand(min, max)
która zwraca losową liczbę całkowitą między liczbami całkowitymimin
imax
włącznie. Możesz założyć, że ta funkcja jest naprawdę losowa. - Funkcja,
void swap(x, y)
która zamienia dwie karty w talii. Jeśli zadzwoniszswap(x, y)
, karty na pozycjachx
iy
zamieniają się miejscami.
Gdy:
- Wywołania programu
shuffle()
(alboshuffle(deck)
albodeck.shuffle()
albo jednak implementacja lubi działać),
Następnie:
deck
powinien zawierać dokładnie jedną z każdej karty w idealnie losowej kolejności.
The Catch:
Nie możesz zadeklarować żadnych zmiennych. Dzwoń swap
i rand
ile chcesz, ale nie możesz zadeklarować własnych zmiennych. Obejmuje to for
liczniki pętli - nawet niejawne, takie jak w foreach
.
Wyjaśnienia:
- Możesz zmienić drobne szczegóły w celu dopasowania do wybranego języka. Na przykład możesz napisać,
swap
aby zamienić dwie liczby całkowite przez odniesienie. Zmiany powinny polegać na ułatwieniu pracy z Twoim językiem, a nie na ułatwieniu układanki. deck
może być zmienną globalną lub możesz przyjąć ją jako parametr.- Możesz zrobić wszystko, co chcesz
deck
, ale nie możesz zmienić jego długości. - Twoje karty mogą mieć numery 0-51, 1-52 lub cokolwiek innego.
- Możesz napisać to w dowolnym języku, ale bez oszustwa dzięki wbudowanej
shuffle
funkcji języka . - Tak, możesz napisać tę samą linię 52 razy. Nikt nie będzie pod wrażeniem.
- Czas wykonania nie ma znaczenia, ale prawdziwa przypadkowość ma znaczenie.
- To nie jest tak naprawdę kod golfowy, ale możesz zminimalizować / zaciemnić kod.
Edycja: Kod Boilerplate i wizualizator
Jeśli korzystasz z .NET lub JavaScript, oto kod testowy, który może Ci się przydać:
JavaScript:
- Szybki i brudny wizualizator JavaScript ze źródłem CoffeeScript: https://gist.github.com/JustinMorgan/3989752bdfd579291cca
- Wersja do uruchomienia (wystarczy wkleić w swojej
shuffle()
funkcji): http://jsfiddle.net/4zxjmy42/
DO#:
- Wizualizator ASP.NET z C # codebehind: https://gist.github.com/JustinMorgan/4b630446a43f28eb5559
- Stub za pomocą tylko
swap
irand
narzędziowych metod: https://gist.github.com/JustinMorgan/3bb4e6b058d70cc07d41
Ten kod sortuje i tasuje talię kilka tysięcy razy i wykonuje podstawowe testy poprawności poczytalności: Dla każdego losowania sprawdza, czy w talii są dokładnie 52 karty bez powtórzeń. Następnie wizualizator wykreśla częstotliwość każdej karty kończącej się w każdym miejscu w talii, wyświetlając mapę cieplną w skali szarości.
Wyjście wizualizatora powinno wyglądać jak śnieg bez widocznego wzoru. Oczywiście nie może udowodnić prawdziwej przypadkowości, ale jest to szybki i łatwy sposób sprawdzenia na miejscu. Polecam użycie tego lub czegoś podobnego, ponieważ pewne błędy w algorytmie tasowania prowadzą do bardzo rozpoznawalnych wzorców na wyjściu. Oto przykład danych wyjściowych z dwóch implementacji, jednej ze wspólną wadą:
Błędna wersja częściowo tasuje talię, więc może wyglądać dobrze, jeśli sprawdzisz tablicę ręcznie. Wizualizator ułatwia zauważenie wzoru.
źródło
deck
sam.swap
, pod warunkiem, że spełnia ona swój podstawowy cel. Jednym z powodów, dla których stworzyłemswap
dany artykuł, było to, że ludzie mogli traktować go jako „magię” i skoncentrować się na głównym problemie, nie martwiąc się o to, że działa w wybranym przez siebie języku. Możesz to zrobić lub napisać własneswap
, to zależy od Ciebie.Odpowiedzi:
JavaScript
Wierzę, że jest to zamierzona forma rozwiązania, używam karty w pozycji 0, aby śledzić postęp, tylko tasując karty, które zostały już użyte jako licznik, osiąga to standard 52! permutacje z idealnie równym rozkładem. Procedura jest skomplikowana z powodu zamiany XOR, która nie pozwala na zamianę samego elementu.
Edycja: Wbudowałem sortowanie, które sortuje każdy element na miejscu tuż przed jego użyciem, umożliwiając w ten sposób pracę z nieposortowaną tablicą. Porzuciłem również wywołanie rekurencyjne na korzyść pętli while.
źródło
Haskell
Oto implementacja bez punktów. Brak zmiennych, parametrów formalnych lub wyraźnej rekurencji. Kiedyś lambdabot „s
@pl
(«bez sensu»), funkcja refactoring całkiem sporo.Oto moja procedura testowa, aby upewnić się, że liczby były równomiernie rozmieszczone:
Oto oryginalny algorytm:
źródło
((.) .) . (. (++))
i to(((.) . (,)) .)
są moje ulubione. Wow lambdabot. Wow.jot
Ignorowanie tej talii jest zmienne, jest oczywiste ...
Oczywiście, jeśli naprawdę potrzebujesz funkcji, jest taka, która zadziała, nawet jeśli zapomnisz usunąć jokery (lub spróbować przetasować coś innego niż karty).
Po to aby...
Prawdopodobnie jest to poza intencją pytania, które polegałoby na samodzielnym wykonaniu losowania z rand (
?
). Mogę to zrobić później, kiedy nie powinienem pracować.Wyjaśnienie
Wyjaśnienie
52 ? 52
:x ? y
jest x losowymi unikalnymi przedmiotami od y.Wyjaśnienie
{~ (# ? #)
jest trudniejsze ze względu na widelce i haki . Zasadniczo jest to to samoshuffle =: 3 : '((# y) ? (# y)) { y'
, co, które ma jeden domyślny argument (y
).# y
podaje długość yx { y
oznacza element yw indeksie x lub (w tym przypadku) elementy w indeksach w x.Zobacz J Słownictwo, aby uzyskać szczegółowe informacje na temat operatorów, chociaż składnia i semantyka są dość skomplikowane z powodu programowania rangowego i milczącego.
źródło
{52?⍵}
jest to anonimowa funkcja, która bierze 52 losowe elementy z argumentu, którym byłaby lista 52 liczb całkowitych)Pyton
źródło
[1:]
znaczy Czy to się powtarza w pod-macierzydeck
?a, b = b, a
sztuczka.Korzystanie z reprezentacji czynnikowej
W reprezentacji czynnikowej permutacji element i przyjmuje wartości od 0 do Ni. Tak więc przypadkowa permutacja dotyczy tylko
rand(0,i)
każdego Ni.W J:
gdzie
? x
jestrand(0,x-1)
i|.>:i.52
jest52 51 ... 1
Następnie, jeśli
a
jest wartość Ith factoradic robimy swap:swap(deck[i], deck[i+a])
. Lista par do wymiany to:Zamiana, której będziemy używać, działa w następujący sposób:
Nie jest to tak naprawdę „odniesienie”, ale w J. nie ma żadnych rzeczywistych funkcji
Użyjemy długości talii (
#deck
), aby uniknąć użycia stałej.Kompletny program w J:
źródło
DO#
Oto moja własna odpowiedź oparta na algorytmie Fisher-Yatesa . Powinien dać ci idealny los, jeśli generator liczb losowych jest wystarczająco dobry.
Angielska wersja:
deck[0]
atdeck[v]
, gdziev
jest wartość nominalna karty wdeck[0]
. Powtarzaj dov == 0
. To częściowo uporządkuje talię, ale to nie ma znaczenia. Wiesz już, że Karta 0 znajduje się z przodu talii, co oznacza, że możesz ukraść to miejsce w tablicy i użyć go jako licznika pętli. Jest to kluczowe „oszustwo” dla problemu zmiennych lokalnych.i
zrand(i, 51)
. Zauważ, że potrzebujeszrand(i, 51)
, NIErand(1, 51)
. To nie gwarantuje, że każda karta jest losowa.deck[0]
z powrotem do 0. Teraz cała talia jest tasuje wyjątkiem pierwszej karcie, więc zamianadeck[0]
zdeck[rand(0, 51)]
i gotowe.Wersja C #:
Wersja Javascript:
... gdzie
swap(a, b)
zamienia siędeck[a]
zdeck[b]
.źródło
Ruby, jedna linia
Czy to jest uważane za oszukiwanie? Powinno być tak losowe, jak to możliwe.
(Ruby's
rand
Metoda przyjmuje tylko jeden argument, a następnie generuje liczbę n taką, że 0 <= liczba <argument.)Dodatkowo - podobny do rozwiązania Perla firmy sogart, ale o ile wiem, nie ma problemu:
Ruby sort_by różni się od sortowania - najpierw generuje listę wartości do posortowania tablicy, a dopiero potem sortuje ją według nich. Szybciej jest, gdy znalezienie nieruchomości, którą sortujemy, jest drogie, nieco wolniejsze we wszystkich innych przypadkach. Jest także przydatny w golfie kodowym: P
źródło
deck[0..51]
omija nieco zasadę „brak zmiennych”, używając funkcji języka. To uczciwe, po prostu myślę, że traci część wyzwań. :) Nie znam Ruby; czy możesz wyjaśnić tę(0..51).map{deck.delete_at(rand deck.length)}
część? Czy to usuwa karty zdeck
?deck
i dodaje ją do wewnętrznej listy wyników, któramap
się kumuluje. Wtedy, gdy nie ma nic wdeck
tymmap
wyniku zostanie skopiowany dodeck
. Zasadniczo istnieje tymczasowa, ale jest to funkcja językowa, a nie wyraźna zmienna :)deck.sort_by!{rand}
jest krótszy.JavaScript
UWAGA: To rozwiązanie jest technicznie niepoprawne, ponieważ wykorzystuje drugi parametr
i
w wywołaniushuffle
, który liczy się jako zmienna zewnętrzna.Zadzwoń z
shuffle(deck,52)
Kompletny działający przykład (musiałem
swap
nieznacznie zmodyfikować, ponieważ w JavaScript nie ma żadnego przekazu referencyjnego):źródło
shuffle
jako zmiennych, ale nie określiłem tego tak +1. Przyjemne wykorzystanie rekurencji.deck[rand(0,i-1)]
zamiastdeck[rand(0,i-2)]
. Zamień również do samego końcai=0
zamiast zatrzymywania się nai=1
. To pomaga?C ++
Unika zamiany elementów ze sobą, więc musi zadzwonić dwa razy, aby być losowym.
źródło
swap(deck[rand(1, 51)], (deck[0] - 51) / 100);
Skąd będzieswap
wiedzieć, gdzie umieścić drugą wartość? Tęsknisz także za)
.deck[0]
, ale nie w taki sposób, jak ty.re
źródło
Kolejne rozwiązanie Perla, które faktycznie wytwarza równomiernie rozłożone wyjście:
To rozwiązanie wykorzystuje Perla
rand
, który zwraca liczbę losową x z zakresu 0 ≤ x <1. Dodaje taką liczbę losową do każdej liczby całkowitej na wejściu, sortuje liczby według ich części ułamkowych, a na koniec usuwa te części ułamkowe ponownie .(Wierzę, że użycie specjalnych zmiennych
$_
,$a
i$b
mieści się w duchu wyzwanie, ponieważ te są jak Perl przechodzi wejście domap
isort
, i nie są one wykorzystywane do innych celów w kodzie. W każdym razie, uważam, oni faktycznie aliasy do wartości wejściowych, a nie niezależne kopie to nie jest rzeczywiście losowe w miejscu, choć;. zarównomap
isort
tworzenia kopii wejścia na stosie).źródło
Jawa
Dziwi mnie, że nikt nie stwierdził oczywistości: (Zakładam, że zamiana (x, x) nic nie robi.
OK, ok, może być krótszy:
źródło
Groteska
To, o co właściwie prosisz, to losowa permutacja listy liczb całkowitych?
r@
da nam wszystkie permutacje, a my wybieramy losową.Ponieważ potrzebujemy prawdziwej losowości, coś, czego Burlesque nie jest w stanie zrobić, ponieważ Burlesque nie ma funkcji We / Wy, musisz zapewnić jakieś źródło losowości za pośrednictwem STDIN.
Prawdopodobnie jest to coś, co naprawię w późniejszej wersji (tj. Wygeneruję losowe ziarno przy starcie i wypchnę go na drugi stos lub coś w tym rodzaju, ale sam Burlesque Interpreter nie ma I / O).
źródło
JavaScript
Nie jestem pewien, czy to „oszustwo”, ale moje rozwiązanie wykorzystuje natywną lokalną tablicę argumentów funkcji. Zawarłem moje samodzielnie wykonane funkcje
rand()
swap()
ifilldeck()
. Co ciekawe, powinno to działać z talią dowolnego rozmiaru.źródło
Tcl , 32 bajty
Nadużywanie
time
funkcji, która służy do pomiaru czasu, jaki skrypt wykonuje, ale może również służyć jako mechanizm zapętlający bez deklarowania żadnych zmiennych.Wypróbuj online!
źródło
perl - nie jest to właściwe tasowanie, jak wyjaśniono w komentarzach!
Myślę, że nie użyłem niczego jako zamiany itp. Czy to było potrzebne jako część problemu?
źródło
JavaScript 4 linie
Oryginalna odpowiedź, która nie była wystarczająco losowa. Zamiana nie gwarantowała dotknięcia każdego przedmiotu w talii.
źródło
shuffle
Lekko zmieniłem twój kod, aby pasował do mojejswap
implementacji, ale tutaj jest dosłownie: jsfiddle.net/m7km4u6g