我正在为一副纸牌写一个代码,这些代码可以洗牌。我测试了代码,但我真的不知道它是否真的正在做它应该正确做的事情?你觉得怎么样?
这是shuffle方法的代码:
public void shuffle()
{
for( int x = myDeck.size(); x > 0 ; x--)
{
Random rn = new Random();
int index1 = rn.nextInt(52);
Card c = myDeck.remove(index1);
myDeck.add(c);
}
}
我的输出似乎在其数字中被洗牌,但不是像黑桃心脏等卡片的名称,
例如,当我测试代码时,这是我的输出:
Deuce of spades
Seven of spades
Eight of spades
Ace of spades
Three of hearts
Five of hearts
Six of hearts
Seven of hearts
Nine of hearts
Ten of hearts
Queen of hearts
King of hearts
Ace of hearts
Seven of diamonds
Eight of diamonds
Jack of diamonds
King of diamonds
Three of clubs
Seven of clubs
Nine of clubs
Jack of clubs
Queen of clubs
King of clubs
Ace of clubs
Queen of spades
Deuce of clubs
Three of spades
Nine of diamonds
Four of spades
Four of clubs
Deuce of hearts
Jack of spades
Ten of clubs
Six of diamonds
Jack of hearts
Six of clubs
Four of diamonds
Five of diamonds
Ace of diamonds
Four of hearts
Nine of spades
Ten of spades
Five of spades
Three of diamonds
Six of spades
Five of clubs
Deuce of diamonds
Eight of hearts
King of spades
Ten of diamonds
Eight of clubs
Queen of diamonds
就像总有重复的名字一样。这是不对的,因为改组的目的是混淆它?
这是一个实际的问题:当打牌时,重要的是洗牌,也就是说 安排事情,使卡片以随机顺序处理。有 几种方法来实现这一目标。一种策略涉及反复挑选卡片 从甲板上随机移动到最后。以下代码使用 Random类(您在第8页的“ArrayLists”部分遇到过 在线课程)执行一个这样的“选择并移动到最后”操作:
Random rn = new Random();
int index1 = rn.nextInt( 52 );
Card c = myDeck.remove( index1 );
myDeck.add( c );
要有效地洗牌,此操作应重复多次 (比方说,500次)。为Deck类创建一个新的实例方法shuffle 使用单个Random对象和for循环来重新调整myDeck。后 适当修改主要方法,用它来测试你的新代码。
所以我的主要问题是:我做错了吗?
答案 0 :(得分:16)
只需将rn.nextInt(52);
更改为rn.nextInt(x)
即可Fisher-Yates shuffle。无需进行超过52次迭代。
为什么会这样:
在第一次迭代中(当x
为52时),您将从整个牌组中选择一张随机牌并将其最后移动。
在第二次迭代中(当x
为51时),您将从剩余的卡中选择一张随机卡并将其移动到最后。
......等等。
经过52次迭代后,所选的第一张牌将在第一张索引中结束。由于这张卡是从完整套牌中随机选择的,因此每张卡都是同样可能的。
同样适用于第二个索引,第三个索引,......
因此,甲板上每种可能的排列都是可能的。
(在生产代码中,只需在这些情况下使用Collections.shuffle
。)
答案 1 :(得分:2)
执行此操作的最佳方法是使用内置的Collections.shuffle()
方法,该方法将以随机方式为您播放ArrayList(或接近随机播放。)
目前您的逻辑问题在于它从牌组中挑出一张随机牌,并将其放在最后 - 并且这样做了52次。现在你已经有了一个很好的改变,你最终会多次对多张卡片进行这种改变,而有些卡片根本就没有 - 因此你可能会遇到许多看似没有随机化的卡片的问题。“ / p>
你似乎有这样的逻辑,你需要对牌组中的牌数进行此操作,这是有缺陷的;你需要多次执行它。
你有两个主要的逻辑解决方案,你可以先做多次 - 比你现在做的多10倍,或者你可以重新设计代码以使用内置(或更有效) )改组算法。
答案 2 :(得分:1)
这个问题给出了一个提示:
为了有效地洗牌,这个操作应该重复多次(比方说,500次)。
而你的循环只运行52次(myDeck.size()
)。所以你取出一张卡并随机更换52次。这似乎还不够。
ps:写for(int i = 0; i < max; i++)
比for (int i = max; i >0 i--)
更常见。
答案 3 :(得分:0)
将循环更改为:
ArrayList<Integer> myDeck = new ArrayList<Integer>();
for(int i=0; i< 52; i++){
myDeck.add(i);
}
Random rn = new Random();
for( int x = 52; !myDeck.isEmpty() ; x--) {
int index1 = rn.nextInt(myDeck.size());
//Card c = (Card)myDeck.remove(index1); -> this comment here should be removed
System.out.print(index1 + ", ");
}
}
这样你就不会重复选择相同的卡,而且你总是会选择一个数字(单元格)&lt;你删除牌时不断变化的myDeck.size(),当牌组中没有牌时纾困