Answers:
卡洗牌是一种算法,它很容易直观地编写,并且这样做会完全出错。对于在Wikipedia上正确实现卡片改组有很好的参考。我在这里介绍的是该页面上“现代算法”下算法的一个非常简化的版本。
这是简单的英语基本概念:
考虑一副纸牌。在本次讨论中,您可以在牌组中放置任意数量的卡,并且它们可以以任何顺序开始。
我们将要讨论牌组中的“位置”,其中“位置”是指牌组中的卡数高于该位置中的牌数。例如,卡组顶部的卡位于位置0,卡组下方的卡位于位置1(因为比卡高1卡-顶部卡),而标准52卡组的卡底部卡片在位置51,因为51张卡片比卡组中的卡片高。
现在,我们考虑甲板上的每个位置,一次从底部开始,一直到顶部。
对于每个位置,我们随机选择位于该位置或编号较低位置的卡片之一(请记住,牌组的顶部为0,我们从牌组的底部开始向上移动,因此对于每个位置,您实际上是在该位置及其上方拾取所有纸牌,并随机选择其中一张纸牌)。
进行随机选择后,我们会将当前正在考虑的位置的卡与我们随机选择的卡交换。如果我们随机选择已经在该位置的卡,则不会执行任何交换。
交换(或不交换,如果我们随机选择了已经在考虑的位置的卡)之后,我们继续进入牌组中的下一个位置并继续。
用伪代码,其中n是卡组中的卡数,而a是代表卡组的数组,该算法如下所示:
for each i in [n .. 1] do
j ← random integer in [ 0 .. i ]
exchange a[j] and a[i]
首先,定义要洗牌的所有卡的序列:
List<Card> shuffled = new ArrayList<Card>();
shuffled.addAll(allCards);
然后,您遍历序列中的每个位置并随机分配一张卡片。
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);
}
现在shuffled
是所有卡片的随机序列。
我想提一下,并提及“格式保留加密”作为在游戏中改组卡片的方法。
从本质上讲,您所拥有的是一种加密算法,该算法接受0到51的值,以及一个密钥(随机种子)并吐出0到51的值。由于定义上是可逆的,这意味着任何2个输入数字都不能加密为相同的输出编号,这意味着如果您将0到51加密,则会以不同的顺序获得0到51的输出。换句话说,您已经洗牌,甚至不需要进行任何实际的洗牌。
在这种情况下,您必须制定或找到一个采用6位并吐出6位(0-63)的加密算法。为了从卡组中抽取下一张卡片,您将有一个从零开始的索引变量,您需要加密该索引,增加索引并查看从密码中得出的值。如果该值> = 52,则忽略它并生成一个新数字(当然,再增加一次索引)。由于加密0-63将导致以0-63作为输出,因此以不同的顺序,您只是忽略了> = 52的任何值,因此您的算法接受0-51并吐出0-51。
要重新洗牌,请将索引重新设置为零并更改加密密钥(洗牌种子)。
您的算法不必具有加密质量(也不应具有加密质量,因为这在计算上会非常昂贵!)。提出像这样的自定义大小的加密算法的一种非常好的方法是使用feistel网络,该网络可以让您根据需要自定义大小和质量。对于feistel网络的圆形函数,我建议使用murmurhash3之类的东西,因为它速度快且具有良好的雪崩效果,这会使随机播放显得很好随机。
查看我的博客文章,以获取更多详细信息和源代码:http : //blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/
在Java 1.5的枚举教程必须实现的一副牌一个有趣的方式,建立了甲板,洗牌和处理。使用enum
和都非常简单Collections
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
}
}
和班级来管理甲板。
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上使用像itertools这样的函数即可。我不知道Java中相同函数的名称,请尝试“ 。http://code.google.com/p/neoitertools/ ”
找出对象“卡”的所有排列
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);