Antworten:
Das Mischen von Karten ist ein Algorithmus, der leicht intuitiv zu schreiben ist und dabei völlig falsch liegt. Es gibt eine gute Referenz für die korrekte Implementierung des Kartenmischens in Wikipedia . Was ich hier präsentiere, ist eine leicht vereinfachte Version des Algorithmus, der auf dieser Seite unter Der moderne Algorithmus behandelt wird .
Hier ist die Grundidee im Klartext:
Betrachten Sie ein Kartenspiel. Für diese Diskussion können Sie eine beliebige Anzahl von Karten im Stapel haben, die in beliebiger Reihenfolge beginnen können.
Wir werden über "Position" im Stapel sprechen, wobei "Position" bedeutet, wie viele Karten im Stapel höher sind als die Karte in dieser Position. Zum Beispiel befindet sich die Karte oben auf dem Stapel auf Position 0, die Karte darunter auf Position 1 (da 1 Karte höher ist - die oberste Karte) und in einem Standardstapel mit 52 Karten auf der Unterseite Karte ist auf Position 51, da 51 Karten höher sind als im Stapel.
Nun betrachten wir jede Position im Deck, eine nach der anderen, von unten beginnend und nach oben arbeitend.
Für jede Position wählen wir zufällig eine der Karten aus, die sich an dieser Position oder an einer niedrigeren Position befindet Für jede Position nehmen Sie effektiv alle Karten an und über dieser Position und wählen zufällig eine dieser Karten aus.
Wenn wir die zufällige Auswahl getroffen haben, tauschen wir die Karte an der Position, die wir gerade betrachten, gegen die Karte aus, die wir zufällig ausgewählt haben. Wenn wir zufällig die Karte ausgewählt haben, die sich bereits in dieser Position befand, wird kein Tausch durchgeführt.
Nachdem wir getauscht haben (oder nicht getauscht haben, wenn wir zufällig die Karte ausgewählt haben, die sich bereits in der von uns in Betracht gezogenen Position befand), gehen wir zur nächsten Position im Stapel und fahren fort.
In Pseudo - Code, mit n der Anzahl der Karten im Stapel zu sein, und ein ein Array wobei das Deck darstellt, geht der Algorithmus wie folgt aussieht:
for each i in [n .. 1] do
j ← random integer in [ 0 .. i ]
exchange a[j] and a[i]
Sie definieren zunächst eine Folge aller Karten, die Sie mischen möchten:
List<Card> shuffled = new ArrayList<Card>();
shuffled.addAll(allCards);
Dann gehen Sie jede Position in der Sequenz durch und weisen ihr zufällig eine Karte zu.
Random random = new Random();
for (int i = shuffled.size() - 1; i >= 0; i--) {
int j = random.nextInt(i + 1);
/* swap cards i,j */
Card card = shuffled.get(i);
shuffled.set(i, shuffled.get(j));
shufflet.set(j, card);
}
Jetzt shuffled
ist eine zufällige Reihenfolge aller Ihrer Karten.
Ich möchte "formatbewahrende Verschlüsselung" als Methode zum Mischen von Karten in einem Spiel erwähnen.
Im Wesentlichen hätten Sie einen Verschlüsselungsalgorithmus, der einen Wert von 0 bis 51 und einen Schlüssel (Shuffle Seed) und einen Wert von 0 bis 51 ausgibt. Da die Verschlüsselung per Definition umkehrbar ist, bedeutet dies, dass 2 beliebige Eingabenummern nicht verschlüsseln können Dieselbe Ausgabenummer, dh wenn Sie 0 bis 51 verschlüsselt haben, erhalten Sie 0 bis 51 als Ausgabe in einer anderen Reihenfolge. Mit anderen Worten, Sie haben Ihr Shuffle und müssen nicht einmal wirklich mischen.
In diesem Fall müssten Sie einen Verschlüsselungsalgorithmus erstellen oder finden, der 6 Bits verwendet und 6 Bits (0-63) ausspuckt. Um die nächste Karte aus dem Stapel zu ziehen, hätten Sie eine Indexvariable, die bei Null anfing, Sie würden diesen Index verschlüsseln, den Index erhöhen und den Wert betrachten, der aus der Chiffre herauskam. Wenn der Wert> = 52 ist, ignorieren Sie ihn und generieren eine neue Zahl (und erhöhen den Index natürlich erneut). Da das Verschlüsseln von 0-63 zu einer Ausgabe von 0-63 in einer anderen Reihenfolge führt, ignorieren Sie nur jeden Wert, der> = 52 ausgegeben wird, sodass Ihr Algorithmus 0-51 aufnimmt und 0-51 ausgibt.
Um das Deck neu zu mischen, setzen Sie den Index auf Null und ändern Sie den Verschlüsselungsschlüssel (Shuffle Seed).
Ihr Algorithmus muss keine kryptografische Qualität aufweisen (und sollte es auch nicht sein, da dies rechenintensiv wäre!). Eine wirklich gute Möglichkeit, einen Verschlüsselungsalgorithmus in einer benutzerdefinierten Größe wie diesen zu entwickeln, ist die Verwendung eines Feistel-Netzwerks, mit dem Sie Größe und Qualität an Ihre Bedürfnisse anpassen können. Für die Rundungsfunktion des Feistelnetzwerks würde ich etwas wie murmurhash3 empfehlen, da es schnell ist und einen guten Lawineneffekt hat, wodurch die Mischvorgänge gut zufällig erscheinen würden.
Weitere Informationen und Quellcode finden Sie in meinem Blogbeitrag: http://blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/
Das Java 1.5 Enum-Tutorial bietet eine interessante Möglichkeit, ein Kartenspiel zu implementieren, das Deck aufzubauen, zu mischen und zu handeln. Alles ganz einfach mit enum
s undCollections
public class Card {
public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }
private final Rank rank;
private final Suit suit;
private Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Rank rank() { return rank; }
public Suit suit() { return suit; }
public String toString() { return rank + " of " + suit; }
private static final List<Card> protoDeck = new ArrayList<Card>();
// Initialize prototype deck
static {
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
protoDeck.add(new Card(rank, suit));
}
public static ArrayList<Card> newDeck() {
return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
}
}
Und die Klasse, um das Deck zu verwalten.
public class Deal {
public static void main(String args[]) {
int numHands = Integer.parseInt(args[0]);
int cardsPerHand = Integer.parseInt(args[1]);
List<Card> deck = Card.newDeck();
Collections.shuffle(deck);
for (int i=0; i < numHands; i++)
System.out.println(deal(deck, cardsPerHand));
}
public static ArrayList<Card> deal(List<Card> deck, int n) {
int deckSize = deck.size();
List<Card> handView = deck.subList(deckSize-n, deckSize);
ArrayList<Card> hand = new ArrayList<Card>(handView);
handView.clear();
return hand;
}
}
Verwenden Sie einfach eine Funktion wie itertools auf Python. Mir ist der Name der gleichen Funktion in Java nicht bekannt. " Http://code.google.com/p/neoitertools/ "
Finde alle Permutationen des Objekts "Karten" heraus
ArrayList deckCards = new ArrayList<Card>();
//add your cards to the deck
deckCards.add(card1);
deckCards.add(card2);
deckCards.add(card3);
....
//shuffle the array list
Collections.shuffle(deckCards);