Bir kart oyunu için kartları nasıl karıştırırım?


13

Android için bir kart oyunu geliştirmeye çalışıyorum Herkes bana oyun kartlarını etkili bir şekilde karıştırmak için kod yazmayı önerebilir mi?

Yanıtlar:


21

Kart karıştırma, sezgisel olarak yazılması ve bunu yaparak tamamen yanlış olan bir algoritmadır. Wikipedia'da kart karıştırmayı doğru bir şekilde uygulamak için iyi bir referans var . Burada sunduğum şey, modern algoritma altında bu sayfada kapsanan algoritmanın çok az basitleştirilmiş bir sürümüdür .

İşte temel ingilizce olan temel fikir:

Bir deste kart düşünün. Bu tartışma için destede istediğiniz sayıda kart olabilir ve herhangi bir sırada başlayabilirler.

Destedeki "konum" hakkında konuşacağız. Burada "konum", destedeki kartların o pozisyondaki karttan daha yüksek olduğu yerdir. Örneğin, destenin üstündeki kart 0 konumunda, altındaki kart 1 konumunda (ondan daha yüksek 1 kart olduğu için - üst kart) ve standart 52 kartlı destede, alt 51 kart destede olduğundan daha yüksek olduğu için kart 51. konumdadır.

Şimdi, güvertedeki her pozisyonu, her seferinde bir tane, alttan başlayarak yukarı doğru çalışıyoruz.

Her pozisyon için, o pozisyonda veya daha düşük numaralı bir pozisyonda bulunan kartlardan birini rastgele seçiyoruz (unutmayın, destenin üstü 0'dır ve destenin altından yukarı doğru çalışıyoruz, bu yüzden her pozisyon için, o pozisyonun üstündeki ve üzerindeki tüm kartları etkili bir şekilde toplarsınız ve bu kartlardan birini rastgele seçersiniz)

Rastgele seçim yaptığımızda, kartı rastgele seçtiğimiz kartla şu anda düşündüğümüz pozisyonda değiştiririz. O konumda bulunan kartı rastgele seçersek, takas yapılmaz.

Takas ettikten sonra (veya takas etmedikçe, zaten düşündüğümüz pozisyonda olan kartı rastgele seçtiysek), destedeki bir sonraki pozisyona geçip devam ediyoruz.

Pseudocode ile N güverte kart sayısını olan ve bir güverte, böyle bir algoritma görünüm temsil eden bir dizi söz konusu olur:

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

1
Algoritma da burada güzel bir şekilde görselleştirildi: bost.ocks.org/mike/algorithms/#shuffling
Felsir

9

Önce karıştırmak istediğiniz tüm kartların bir sırasını tanımlarsınız:

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

Sonra dizideki her pozisyondan geçip rastgele bir kart atarsınız.

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

Şimdi shuffledtüm kartlarınızın rastgele bir sırası.


3
Bu
Knuth'un

2

Bir oyunda kartları karıştırmak için bir yöntem olarak "format şifrelemeyi koru" dan bahsetmek istiyorum.

Temelde 0 ila 51 değerini alan bir şifreleme algoritması ve bir anahtar (karışık tohum) ve 0 ila 51 değerini veren bir şifreleme algoritmasıdır. Şifreleme tanımı gereği tersine çevrilebilir olduğundan, herhangi bir 2 giriş numarası şifrelenemez aynı çıkış numarası, yani 0 ila 51'i şifrelerseniz, farklı bir sırayla çıkış olarak 0 ila 51 alırsınız. Başka bir deyişle, karıştırmanız var ve gerçek bir karıştırma yapmanıza bile gerek yok.

Bu durumda, 6 bit alan ve 6 bit (0-63) tüküren bir şifreleme algoritması oluşturmanız veya bulmanız gerekir. Bir sonraki kartı desteden çekmek için, sıfırdan başlayan bir dizin değişkeniniz olur, bu dizini şifrelersiniz, dizini artırır ve şifreden çıkan değere bakarsınız. Değer> = 52 ise, onu yok sayar ve yeni bir sayı oluşturur (ve elbette dizini tekrar artırır). 0-63 şifrelemesi çıktı olarak 0-63 ile sonuçlanacağından, farklı bir sırayla, = 52 gelen herhangi bir değeri yok sayıyorsunuz, böylece 0-51 alan ve 0-51 çıkan algoritmanız var.

Desteyi yeniden karıştırmak için dizini sıfıra geri ayarlayın ve şifreleme anahtarını (karışık tohum) değiştirin.

Algoritmanızın kriptografik kalite olması gerekmez (ve olmamalıdır, çünkü bu hesaplama açısından pahalıdır!). Bunun gibi özel boyutlu bir şifreleme algoritması bulmanın gerçekten iyi bir yolu, ihtiyaçlarınıza bağlı olarak boyutu ve kaliteyi özelleştirmenizi sağlayan bir feistel ağ kullanmak olacaktır. Feistel ağının yuvarlak işlevi için, murmurhash3 gibi bir şey öneriyorum çünkü hızlı ve iyi bir çığ etkisi var, bu da karışıkların iyi rastgele görünmesini sağlayacak.

Daha ayrıntılı bilgi ve kaynak kodu için blog gönderime göz atın: http://blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/


Şu anda ifade edildiği için bu yanıt, URL kaçınılmaz olarak İnternet'in yüzeyinden düştüğünde çok yardımcı olmaz. Yanıtın, bağlantılı makalenin göze çarpan noktaları üzerindeki ayrıntılarını düşünün, böylece cevap kendi başına durabilir.
Lars Viklund

1
İyi bir nokta Lars, daha fazla bilgi ile güncellendi, böylece bir okuyucu en azından format koruma şifrelemesini kullanarak kart karıştırma için bir çözümün tüm belirli bileşenleri hakkında daha fazla bilgi arayabilir. Teşekkürler!
Alan Wolfe

1

Java 1.5 enum öğretici , güverte kadar bina karıştırma ve uğraşan bir deste kart uygulamak için ilginç bir yol vardır. Hepsi enums veCollections

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

Ve güverte yönetmek için sınıf.

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
Yalnızca kod yanıtları önerilmez.
SurvivalMachine
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.