Yanıtlar:
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]
Ö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 shuffled
tüm kartlarınızın rastgele bir sırası.
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/
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 enum
s 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;
}
}
Python'da olduğu gibi itertools gibi bir işlev kullanın. Java ile aynı işlevin adının farkında değilim ". Http://code.google.com/p/neoitertools/ "
"Kartlar" adı verilen nesnenin tüm permütasyonlarını öğrenin
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);