Das Ziel dieses Puzzles ist es, ein Kartenspiel mit 52 Karten zu nehmen und es so zu mischen, dass sich jede Karte in einer zufälligen Position befindet.
Gegeben:
- Ein Array
deck
von 52 verschiedenen Ganzzahlen, die die Karten darstellen.deck
Enthält zu Beginn genau eine Karte in einer unbekannten Reihenfolge. - Eine Funktion,
int rand(min, max)
die eine zufällige Ganzzahl zwischen intsmin
undmax
inclusive zurückgibt . Sie können davon ausgehen, dass diese Funktion wirklich zufällig ist. - Eine Funktion,
void swap(x, y)
die zwei Karten im Stapel vertauscht. Wenn Sie callenswap(x, y)
, wechseln die Karten an Positionenx
undy
Stellen.
Wann:
- Das Programm ruft auf
shuffle()
(odershuffle(deck)
oderdeck.shuffle()
oder wie auch immer Ihre Implementierung es mag),
Dann:
deck
sollte genau eine von jeder Karte in vollkommen zufälliger Reihenfolge enthalten.
Der Fang:
Sie können keine Variablen deklarieren. Rufen Sie swap
und rand
so oft Sie möchten auf, aber Sie können keine eigenen Variablen deklarieren. Dies schließt for
Schleifenzähler ein - auch implizite wie in a foreach
.
Klarstellungen:
- Sie können kleinere Details an Ihre gewählte Sprache anpassen. Beispielsweise können Sie schreiben
swap
, um zwei Ganzzahlen durch Verweis zu wechseln. Änderungen sollten darin bestehen, diese Arbeit mit Ihrer Sprache zu machen, nicht um das Rätsel zu vereinfachen. deck
kann eine globale Variable sein oder als Parameter verwendet werden.- Sie können alles tun, was Sie wollen, um den Inhalt von
deck
, aber Sie können die Länge nicht ändern. - Ihre Karten können mit 0-51, 1-52 oder einer beliebigen Nummer versehen werden.
- Sie können dies in jeder Sprache schreiben, aber mit der in Ihrer Sprache integrierten
shuffle
Funktion können Sie nicht schummeln . - Ja, Sie könnten die gleiche Zeile 52 Mal schreiben. Niemand wird beeindruckt sein.
- Die Ausführungszeit spielt keine Rolle, aber die wahre Zufälligkeit.
- Dies ist nicht wirklich Code-Golf, aber Sie können Ihren Code gerne minimieren / verschleiern.
Bearbeiten: Kesselschild-Code und Visualizer
Wenn Sie .NET oder JavaScript verwendet haben, finden Sie hier einige nützliche Testcodes:
JavaScript:
- Schneller JavaScript-Visualizer mit CoffeeScript-Quelle: https://gist.github.com/JustinMorgan/3989752bdfd579291cca
- Lauffähige Version (fügen Sie einfach Ihre
shuffle()
Funktion ein): http://jsfiddle.net/4zxjmy42/
C #:
- ASP.NET Visualizer mit C # -CodeBehind: https://gist.github.com/JustinMorgan/4b630446a43f28eb5559
- Stub nur mit den Dienstprogrammmethoden
swap
undrand
: https://gist.github.com/JustinMorgan/3bb4e6b058d70cc07d41
Dieser Code sortiert und mischt das Deck mehrere tausend Mal und führt einige grundlegende Vernunftstests durch: Bei jedem Mischen wird überprüft, ob sich genau 52 Karten ohne Wiederholungen im Deck befinden. Anschließend zeichnet der Visualizer die Häufigkeit jeder Karte auf, die an jeder Stelle im Stapel landet, und zeigt eine Graustufen-Heatmap an.
Die Ausgabe des Visualizers sollte wie Schnee ohne erkennbares Muster aussehen. Offensichtlich kann es keine echte Zufälligkeit beweisen, aber es ist eine schnelle und einfache Möglichkeit zur Stichprobenprüfung. Ich empfehle es oder ähnliches zu verwenden, da bestimmte Fehler im Mischalgorithmus zu sehr erkennbaren Mustern in der Ausgabe führen. Hier ist ein Beispiel für die Ausgabe von zwei Implementierungen, von denen eine einen gemeinsamen Fehler aufweist:
Die fehlerhafte Version mischt das Deck teilweise, sodass es gut aussehen kann, wenn Sie das Array von Hand untersuchen. Der Visualizer erleichtert das Erkennen eines Musters.
quelle
deck
selbst gemacht werden kann.swap
Sie möchten, solange sie ihren grundlegenden Zweck erfüllt. Ein Teil meines Grundes,swap
ein gegebenes zu machen, war, dass die Leute es als "Magie" betrachten und sich auf das Hauptproblem konzentrieren konnten, ohne sich darum sorgen zu müssen, dass es in der Sprache ihrer Wahl funktioniert. Sie können dies entweder tun oder selbst schreibenswap
, es liegt an Ihnen.Antworten:
JavaScript
Ich glaube, dies ist die beabsichtigte Form der Lösung. Ich benutze die Karte in Position 0, um den Fortschritt zu verfolgen. Ich mische nur die Karten, die bereits als Zähler verwendet wurden. Dies erreicht den Standard 52! Permutationen mit perfekter Gleichverteilung. Die Prozedur wird durch den XOR-Austausch kompliziert, der nicht zulässt, dass ein Element von selbst ausgetauscht wird.
Bearbeiten: Ich habe eine Sortierung eingebaut, die jedes Element an der richtigen Stelle sortiert, bevor es verwendet wird, sodass dies mit einem unsortierten Array funktioniert. Ich habe auch rekursive Aufrufe zugunsten einer while-Schleife verworfen.
quelle
Haskell
Hier ist eine sinnlose Umsetzung. Keine Variablen, formalen Parameter oder explizite Rekursion. Ich gebrauchte lambdabot ‚s
@pl
(‚sinnlos‘) Refactoring - Funktion eine ganze Menge .Hier ist meine Testprozedur, um sicherzustellen, dass die Nummern gleichmäßig verteilt sind:
Hier ist der ursprüngliche Algorithmus:
quelle
((.) .) . (. (++))
und das(((.) . (,)) .)
sind meine Favoriten. Wow Lambdabot. Einfach wow.J
Das Ignorieren dieses Decks ist eine Variable, es gibt die offensichtliche ...
Natürlich, wenn Sie wirklich eine Funktion wollen, gibt es diese, die auch dann funktioniert, wenn Sie vergessen, die Joker zu entfernen (oder versuchen, etwas anderes als Karten zu mischen).
Damit...
Dies liegt wahrscheinlich außerhalb der Absicht der Frage, die darin bestehen würde, die Zufallswiedergabe selbst von rand (
?
) aus zu implementieren . Ich könnte das später machen, wenn ich nicht arbeiten soll.Erläuterung
Erklärung von
52 ? 52
:x ? y
ist x zufällige Unikate von y.Erklärung von
{~ (# ? #)
ist wegen der Gabeln und der Haken härter . Grundsätzlich ist es dasselbe wieshuffle =: 3 : '((# y) ? (# y)) { y'
, das ein implizites Argument hat (y
).# y
gibt die Länge von y anx { y
ist das Element von y im Index x oder (in diesem Fall) Elemente in den Indizes in x.Siehe J Vocabulary für Details zu Operatoren, obwohl die Syntax und die Semantik aufgrund der Rang- und impliziten Programmierung ziemlich schwierig sind.
quelle
{52?⍵}
eine anonyme Funktion, die 52 zufällige Elemente aus ihrem Argument entnimmt, was hier eine Liste von 52 ganzen Zahlen wäre)Python
quelle
[1:]
bedeuten? Gilt das für ein Sub-Array vondeck
?a, b = b, a
Trick mögen .Factoradic Representation verwenden
In der faktoradischen Darstellung einer Permutation nimmt ein Element i Werte von 0 bis Ni an. Eine zufällige Permutation gilt also nur
rand(0,i)
für jedes Ni.In J:
wo
? x
istrand(0,x-1)
und|.>:i.52
ist52 51 ... 1
Dann wenn
a
der Wert des i - ten factoradic ist, haben wir die Swap:swap(deck[i], deck[i+a])
. Die Liste der auszutauschenden Paare lautet:Der Swap, den wir verwenden werden, funktioniert folgendermaßen:
Es ist nicht wirklich "per Referenz", aber es gibt keine wirklichen Funktionen in J.
Wir werden Decklänge verwenden (
#deck
), um die Verwendung einer Konstante zu vermeiden.Gesamtprogramm in J:
quelle
C #
Hier ist meine eigene Antwort basierend auf dem Fisher-Yates-Algorithmus . Sollte Ihnen ein perfektes Shuffle ermöglichen, wenn Ihr Zufallsgenerator gut genug ist.
Englische Version:
deck[0]
gegen die bei ausdeck[v]
, wobeiv
der Nennwert der Karte bei istdeck[0]
. Wiederhole bisv == 0
. Dadurch wird das Deck teilweise sortiert, aber das spielt keine Rolle. Sie wissen jetzt, dass sich Karte 0 vorne im Stapel befindet. Das heißt, Sie können diesen Bereich im Array stehlen und ihn als Schleifenzähler verwenden. Dies ist der Schlüssel "Betrug" für das Problem der lokalen Variablen.i
gegen die umrand(i, 51)
. Beachten Sierand(i, 51)
, dass Sie NICHT benötigenrand(1, 51)
. Das wird nicht sicherstellen, dass jede Karte zufällig ist.deck[0]
auf 0. Jetzt wird das gesamte Deck bis auf die erste Karte gemischt, also tauschen Siedeck[0]
mitdeck[rand(0, 51)]
und Sie sind fertig.C # -Version:
Javascript-Version:
... wo
swap(a, b)
tauschtdeck[a]
mitdeck[b]
.quelle
Ruby, eine Zeile
Wird dies als Betrug angesehen? Es sollte so zufällig sein, wie es nur geht.
(Rubys
rand
Methode nimmt nur ein Argument und erzeugt dann eine Zahl n, so dass 0 <= Zahl <Argument.)Zusätzlich - ähnlich wie die Perl-Lösung von Sogart, aber meines Wissens leidet es nicht unter dem Problem:
Rubys sort_by unterscheidet sich von sort - es generiert zuerst die Liste der Werte, nach denen das Array sortiert werden soll, und sortiert sie dann erst danach. Es ist schneller, wenn es teuer ist, die Eigenschaft zu finden, nach der wir sortieren, in allen anderen Fällen etwas langsamer. Es ist auch im Codegolf nützlich: P
quelle
deck[0..51]
umgeht die Regel "Keine Variablen" ein wenig, indem ich ein Merkmal der Sprache benutze. Es ist fair, ich denke nur, es verliert etwas von der Herausforderung. :) Ich kenne Ruby nicht; Kannst du den(0..51).map{deck.delete_at(rand deck.length)}
Teil erklären ? Löscht das Karten vondeck
?deck
und fügt sie der internen Liste der Ergebnisse hinzu, diemap
sich ansammeln. Dann , wenn es nichts mehr indeck
dasmap
Ergebnis wird in kopiertdeck
. Grundsätzlich gibt es eine vorübergehende, aber es ist einedeck.sort_by!{rand}
ist kürzer.JavaScript
Hinweis: diese Lösung ist technisch nicht korrekt, da es einen zweiten Parameter
i
in dem Aufruf von verwendetshuffle
, der als eine externe Variable zählt.Mit anrufen
shuffle(deck,52)
Ein vollständiges Arbeitsbeispiel (musste
swap
leicht modifiziert werden, da es in JavaScript keine Pass-by-Reference von Ints gibt):quelle
shuffle
als Variablen zu betrachten, aber ich habe das nicht so + 1 angegeben. Auch eine gute Verwendung der Rekursion.deck[rand(0,i-1)]
anstelle von "" verwendedeck[rand(0,i-2)]
. Tauschen Sie auch den gesamten Weg aus,i=0
um einen Zwischenstopp einzulegeni=1
. Hilft das?C ++
Vermeidet, Elemente mit sich selbst zu tauschen, muss also zweimal aufgerufen werden, um zufällig zu sein.
quelle
swap(deck[rand(1, 51)], (deck[0] - 51) / 100);
Woher soll manswap
wissen, wo man den zweiten Wert setzt? Sie vermissen auch eine)
.deck[0]
, aber nicht in der Art, wie Sie haben.D
quelle
Eine andere Perl-Lösung, die tatsächlich eine gleichmäßig verteilte Ausgabe erzeugt:
Diese Lösung verwendet Perls
rand
, die eine Zufallszahl x im Bereich von 0 ≤ x <1 zurückgeben. Sie addiert eine solche Zufallszahl zu jeder Ganzzahl in der Eingabe, sortiert die Zahlen nach ihren Bruchteilen und entfernt diese Bruchteile schließlich wieder .(Ich glaube , dass die Verwendung der speziellen Variablen
$_
,$a
und$b
fällt in den Geist der Herausforderung, denn die sind , wie Perl die Eingabe geht aufmap
undsort
, und sie sind nicht für andere Zwecke im Code verwendet. Auf jeden Fall glaube ich, Sie sind tatsächlich Aliase zu den Eingabewerten und keine unabhängigen Kopien. Dies ist jedoch kein direktes Shuffle. Beidemap
undsort
erstellen Kopien der Eingabe auf dem Stapel.)quelle
Java
Ich bin überrascht, dass niemand das Offensichtliche gesagt hat: (Ich gehe davon aus, dass Swap (x, x) nichts tut.
OK, ok, es kann kürzer sein:
quelle
Burleske
Was Sie tatsächlich verlangen, ist eine zufällige Permutation einer Liste von ganzen Zahlen?
r@
wird uns alle Permutationen geben, und wir wählen nur eine zufällige.Da wir echte Zufälligkeit benötigen, ist etwas, was Burlesque nicht kann, da Burlesque keine E / A-Funktionalität hat, die Sie benötigen, um eine Quelle für Zufälligkeit über STDIN bereitzustellen.
Das ist wahrscheinlich etwas, das ich in einer späteren Version korrigieren werde (dh beim Start einen zufälligen Startwert generieren und auf den sekundären Stapel oder ähnliches verschieben, aber der Burlesque-Interpreter selbst hat keine E / A).
quelle
Javascript
Ich bin nicht sicher, ob es sich um "Betrug" handelt, aber meine Lösung verwendet das native lokale Array der Argumente einer Funktion. Ich habe meine selbst erstellten Funktionen von
rand()
swap()
und eingebundenfilldeck()
. Interessanterweise sollte dies mit einem Deck jeder Größe funktionieren.quelle
Tcl , 32 Bytes
Missbrauchsfunktion
time
, mit der gemessen wird, wie viel Zeit ein Skript benötigt, aber auch als Schleifenmechanismus verwendet werden kann, ohne dass Variablen deklariert werden.Probieren Sie es online!
quelle
Perl - Dies ist kein richtiger Shuffle, wie in den Kommentaren erklärt!
Ich glaube, ich habe nichts als Swap usw. verwendet. Wurde das als Teil des Problems benötigt?
quelle
JavaScript 4 Zeilen
Ursprüngliche Antwort, die nicht zufällig genug war. Es wurde nicht garantiert, dass der Tausch jeden Gegenstand im Deck berührt.
quelle
shuffle
Code leicht an meineswap
Implementierung angepasst