制作一个洗牌方法

时间:2013-06-15 10:04:18

标签: c# memory shuffle

我目前正在制作一个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)];
        }
    }

所以我想知道是否有人可以帮助我,提前谢谢!史蒂芬。

5 个答案:

答案 0 :(得分:2)

考虑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;
}

您当前代码的问题:

你没有将randoms保存到局部变量中,所以当你尝试交换它们时,你真的有4个random,而不是2个randoms。

此外,对于交换数组中的两个元素,您应该使用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

答案 1 :(得分:2)

您的代码的第一个大问题是您正在创建两个Random的实例。 new Random()的糟糕播种意味着这些实例很可能会返回完全相同的序列。

使用new Random()

Environment.TickCount种子,每隔几毫秒才会更改一次。因此,如果您快速连续创建两个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次。标准的混洗算法是Jon-Skeet在Is using Random and OrderBy a good shuffle algorithm?描述的Fisher-Yates shuffle。

答案 2 :(得分:0)

首先,您可以使用这种方便的扩展方法,称为交换:

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));
    }
}

答案 3 :(得分:0)

它改变了arraylist元素

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;
        }
    }

答案 4 :(得分:0)

Fisher-Yates洗牌

步骤1.从牌组中随机抽出一张牌

步骤2.将其置于新牌组

步骤3.如果deck不为空,则重复1和2

将此添加到您的班级

public List<Card> Shuffle(List<Card> deck){
    List<Card> Shuffeled = new List<Card>();
    int count = deck.Count;
    int selection = 0;
    Random rand = new Random();
    for(int i = 0; i< count; i++){
        selection = rand.next(deck.Count-1);
        Shuffeled.Add(deck[selection]);
        deck.RemoveAt(selection);
    }
    return Shuffeled;
}

来自您的游戏致电kaarten = Shuffle(kaarten);