制作随机播放方法

本文关键字:方法 播放 随机 | 更新日期: 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);