Come mischiare le carte per un gioco di carte?


13

Sto cercando di sviluppare un gioco di carte per Android Qualcuno può suggerirmi come scrivere codice per mescolare efficacemente le carte da gioco?

Risposte:


21

Il mescolamento delle carte è un algoritmo che è facile da scrivere in modo intuitivo e sbagliare completamente. C'è un buon riferimento per l'implementazione corretta del mescolamento delle carte su Wikipedia . Quello che sto presentando qui è una versione leggermente semplificata dell'algoritmo coperto in quella pagina in Il moderno algoritmo .

Ecco l'idea di base, in parole povere:

Prendi in considerazione un mazzo di carte. Per questa discussione, puoi avere un numero qualsiasi di carte nel mazzo e possono iniziare in qualsiasi ordine.

Parleremo di "posizione" nel mazzo, dove "posizione" indica quante carte sono più alte nel mazzo rispetto alla carta in quella posizione. Ad esempio, la carta in cima al mazzo è nella posizione 0, la carta sotto quella nella posizione 1 (perché c'è 1 carta più alta di essa - la carta in alto), e in un mazzo standard da 52 carte, il fondo la carta è nella posizione 51, poiché 51 carte sono più alte di quelle nel mazzo.

Ora consideriamo ogni posizione nel mazzo, una alla volta, partendo dal basso e procedendo fino alla cima.

Per ogni posizione, selezioniamo casualmente una delle carte che si trovano in quella posizione o in una posizione con un numero più basso (ricordate, la cima del mazzo è 0, e stiamo salendo dalla parte inferiore del mazzo, quindi per ogni posizione, stai effettivamente raccogliendo tutte le carte in quella posizione e sopra e raccogliendo casualmente una di quelle carte).

Dopo aver effettuato la selezione casuale, scambiamo la carta nella posizione che stiamo attualmente considerando con la carta selezionata casualmente. Se abbiamo selezionato casualmente la carta che era già in quella posizione, allora non viene effettuato alcun cambio.

Dopo aver scambiato (o non scambiato, se abbiamo scelto casualmente la carta che era già nella posizione che stavamo prendendo in considerazione), passiamo alla posizione successiva nel mazzo e continuiamo.

In pseudocodice, con n il numero di carte nel mazzo e un essere un array che rappresenta il mazzo, l'algoritmo appare così:

for each i in [n .. 1] do
     j  random integer in [ 0 .. i ]
     exchange a[j] and a[i]

1
L'algoritmo è anche ben visualizzato qui: bost.ocks.org/mike/algorithms/#shuffling
Felsir

9

Per prima cosa definisci una sequenza di tutte le carte che vuoi mescolare:

List<Card> shuffled = new ArrayList<Card>();
shuffled.addAll(allCards);

Quindi attraversi ogni posizione della sequenza e le assegni una carta a caso.

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

Ora shuffledè una sequenza casuale di tutte le tue carte.


3
questo è noto come shuffle di Knuth: en.wikipedia.org/wiki/Knuth_shuffle
krolth

2

Vorrei entrare e menzionare il "formato che preserva la crittografia" come metodo per mescolare le carte in un gioco.

Fondamentalmente quello che avresti è un algoritmo di crittografia che accetta un valore da 0 a 51 e una chiave (shuffle seed) e sputa un valore da 0 a 51. Poiché la crittografia è reversibile per definizione, ciò significa che qualsiasi 2 numeri di input non possono crittografare in lo stesso numero di output, il che significa che se si crittografava da 0 a 51, si otterrebbero da 0 a 51 come output in un ordine diverso. In altre parole, hai il tuo shuffle e non hai nemmeno bisogno di fare un vero shuffle.

In questo caso dovresti creare o trovare un algoritmo di crittografia che impiega 6 bit e ne espande 6 bit (0-63). Per pescare la carta successiva dal mazzo avresti una variabile indice che inizia da zero, devi crittografare quell'indice, incrementare l'indice e guardare il valore che è uscito dal codice. Se il valore è> = 52, lo si ignora e si genera un nuovo numero (e ovviamente si incrementa nuovamente l'indice). Poiché la crittografia 0-63 si tradurrà in 0-63 come output, in un ordine diverso, stai semplicemente ignorando qualsiasi valore che esce> = 52 in modo da avere il tuo algoritmo che accetta 0-51 e sputa 0-51.

Per rimescolare il mazzo, riportare l'indice a zero e cambiare la chiave di crittografia (shuffle seed).

Il tuo algoritmo non ha bisogno di essere di qualità crittografica (e non dovrebbe esserlo, perché sarebbe computazionalmente costoso!). Un ottimo modo per elaborare un algoritmo di crittografia di dimensioni personalizzate come questo sarebbe quello di utilizzare una rete feistel, che consente di personalizzare dimensioni e qualità in base alle proprie esigenze. Per la funzione rotonda della rete feistel, consiglierei qualcosa come murmurhash3 perché è veloce e ha un buon effetto valanghe, il che renderebbe i riordini ben randomizzati.

Dai un'occhiata al mio post sul blog per informazioni e codice sorgente ancora più dettagliati: http://blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/


Questa risposta così come è attualmente formulata non aiuta molto quando l'URL inevitabilmente cade dalla superficie di Internet. Prendi in considerazione di elaborare la risposta sui punti salienti dell'articolo collegato, in modo che la risposta possa essere autonoma.
Lars Viklund,

1
Buon punto Lars, aggiornato con più informazioni in modo che un lettore possa almeno cercare maggiori informazioni su tutti i componenti specifici di una soluzione per mescolare le carte usando il formato che preserva la crittografia. Grazie!
Alan Wolfe,

1

Il tutorial enum di Java 1.5 ha un modo interessante di implementare un mazzo di carte, costruendo il mazzo, mescolando e distribuendo. Tutto molto semplice usando enums eCollections

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

E la classe per gestire il mazzo.

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
Le risposte di solo codice sono scoraggiate.
SurvivalMachine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.