Wie mische ich Karten für ein Kartenspiel?


13

Ich versuche, ein Kartenspiel für Android zu entwickeln. Kann mir jemand vorschlagen, wie ich Code schreiben kann, um die Karten effektiv zu mischen?

Antworten:


21

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]

1
Der Algorithmus wird auch hier gut visualisiert: bost.ocks.org/mike/algorithms/#shuffling
Felsir

9

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 shuffledist eine zufällige Reihenfolge aller Ihrer Karten.


3
Dies ist als Knuths Shuffle bekannt: en.wikipedia.org/wiki/Knuth_shuffle
krolth

2

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/


Diese Antwort, wie sie derzeit formuliert ist, hilft nicht viel, wenn die URL unweigerlich von der Oberfläche des Internets abfällt. Erwägen Sie, in der Antwort die wichtigsten Punkte des verlinkten Artikels zu erläutern, damit die Antwort für sich allein stehen kann.
Lars Viklund

1
Guter Punkt, Lars, aktualisiert mit mehr Informationen, damit ein Leser zumindest mehr Informationen zu allen spezifischen Komponenten einer Lösung für das Mischen von Karten unter Verwendung einer formaterhaltenden Verschlüsselung erhalten kann. Vielen Dank!
Alan Wolfe

1

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


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

1
Nur-Code-Antworten werden nicht empfohlen.
SurvivalMachine
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.