制作随机播放方法
本文关键字:方法 播放 随机 | 更新日期: 2023-09-27 18:18:36
我目前正在制作一个 C# 版本的内存(游戏(,我现在需要制作一个洗牌的方法。我有这样的东西(但它还没有工作(:
public void shuffle()
{
for (int i = 0; i < 100000; i++)
{
Random k = new Random();
Random k2 = new Random();
kaarten[k.Next(0, 11)] = kaarten[k2.Next(0,11)];
kaarten[k2.Next(0, 11)] = kaarten[k.Next(0, 11)];
}
}
所以我想知道是否有人可以帮助我,提前感谢!史蒂文。
考虑到kaarten
是代表卡片的东西的List
......
public void Shuffle()
{
// Insert cards at random order into the shuffled list
var shuffled = new List<Card>();
var rand = new Random();
// As long as there are any cards left to insert randomly
while (kaarten.Count != 0)
{
// Get the index of the random card to insert
var i = rand.Next(kaarten.Count);
// Insert it
shuffled.Add(kaarten[i]);
// Remove from non-shuffled list
kaarten.RemoveAt(i);
}
// Set the list of cards to the shuffled list
kaarten = shuffled;
}
当前代码的问题:
您不会将随机数保存到局部变量中,因此当您尝试交换它们时,您实际上有 4 个随机数,而不是 2 个随机数。
此外,要交换数组中的两个元素,您应该使用 tmp 变量,正如在 Swap 算法中所看到的那样,几乎可以在您查看的任何地方看到。
然而,对于完全洗牌,我的方法不需要决定你循环掉期多少次以获得足够的洗牌,因此更有效,也更容易理解。
还有另一种方法可以打乱列表,如果您愿意,它有点混乱(效率最低(,但更短:
var rand = new Random();
kaarten = kaarten.Select(x => new{X=x,R=rand.Next()})
.OrderBy(x => x.R)
.Select(x => x.X)
.ToList();
//.ToArray(); if kaarten is an array and not a list
代码的第一个大问题是你正在创建两个Random
实例。new Random()
的糟糕播种意味着这些实例很可能会返回完全相同的序列。
使用Environment.TickCount
new Random()
种子,它每隔几毫秒才改变一次。因此,如果您快速连续创建两个Random
实例,则时间将是相同的,因此它们输出相同的序列。
正确的解决方案是在开始时只创建一个Random
实例,并使用 if 来满足所有随机性需求。请注意多线程,Random
的实例不是线程安全的。
另请注意,random.Next
的上限是排他性的,因此您的代码仅适用于包含 11 个元素的数组。最好使用集合大小,而不是对值进行硬编码。
代码的另一个问题是您没有实现正确的交换。要交换,您需要交换有两个问题:您将新索引用于第二个方向,并且您不会在局部变量中创建临时副本以避免读取覆盖的值,而不是原始值。
修复这些问题后,您的代码如下所示:
Random random = new Random();//one persistent instance
public void shuffle()
{
for (int i = 0; i < 100000; i++)
{
var i1=random.Next(kaarten.Count);
var i2=random.Next(kaarten.Count);
var temp=kaarten[i1];
karten[i1]=kaarten[i2];
karten[i2]=temp;
}
}
也就是说,你的方法有点低效,因为你迭代了 100000 次。标准的洗牌算法是 Fisher-Yates 洗牌,Jon-Skeet 在 Is Using Random and OrderBy 一个好的洗牌算法?中描述了它。
它会打乱数组列表元素
public void Shuffle(System.Collections.ArrayList elements)
{
int temp;
Random randomNumber=new Random();
for (int n = elements.Count; n > 1; )
{
int k = randomNumber.Next(n); //returning random number less than the value of 'n'
--n; //decrease radom number generation area by 1
//swap the last and selected values
temp = Convert.ToInt16(elements[n]);
elements[n] = elements[k];
elemetns[k] = temp;
}
}
首先,您可以使用这个方便的扩展方法,称为 Swap:
public static void Swap<T>(this IList<T> source, int one, int two)
{
T temp = source[one];
source[one] = source[two];
source[two] = temp;
}
现在,您的代码应该很简单:
public void Shuffle()
{
int count = kaarten.Count;
Random rnd = new Random();
for (int i = 0; i < 1000; i++)
{
kaarten.Swap(rnd.Next(0, count), rnd.Next(0, count));
}
}
Fisher-Yates shuffle
步骤1.从卡组中随机抽出一张牌
步骤 2. 将其放置在新卡组中
步骤 3. 如果 Deck 不为空,则重复 1 和 2
将此添加到您的课程中
public List<Card> Shuffle(List<Card> deck){
List<Card> Shuffeled = new List<Card>();
int deckSize = deck.Count;
int selection = 0;
Random rand = new Random();
for(int i = 0; i < deckSize; i++){
selection = rand.next(deck.Count-1);
Shuffeled.Add(deck[selection]);
deck.RemoveAt(selection);
}
return Shuffeled;
}
从您的游戏调用kaarten = Shuffle(kaarten);