C# 中的反向 Fisher-Yates 洗牌

问题描述 投票:0回答:4

我正在尝试创建一个控制台程序来模拟拥有一副纸牌,用户应该能够;

  • 随机挑选一些卡片
  • 洗牌组
  • 将甲板恢复到原来的状态

我正在努力想办法让牌组回到起点

当我尝试使用以下命令再次初始化数组时: string[] Deck = { x,x,x } 它似乎也不喜欢那样

任何指点将不胜感激!代码如下;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CardArranger
{  
    class Program
    {

        static void Main(string[] args)
        {

            string[] Deck =
            {
                "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "DJ", "DQ", "DK",
                "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "HJ", "HQ", "HK",
                "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "CJ", "CQ", "CK",
                "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "SJ", "SQ", "SK",
            };

            Random r1 = new Random();       

            while (true)
            {
                //display number of random cards
                Console.WriteLine("write shuffle to shuffle or 'sort' to organise the deck again");
                string Uinput = Console.ReadLine();

                bool isCount = int.TryParse(Uinput, out int noCards);

                if (isCount)
                {
                    for (int i = 0; i < noCards; i++)
                    {
                        Console.WriteLine(Deck[r1.Next(0, 52)]);
                    }
                }
                else
                {
                    if (Uinput.Equals("shuffle"))
                    {
                        Shuffle(ref Deck, r1);
                        Console.WriteLine("Shuffled Deck");
                        for (int i = 0; i < Deck.Length; i++)
                        {
                            Console.WriteLine(Deck[i] + " , ");                        
                        }
                        Console.WriteLine();
                        Console.WriteLine("---");
                    }
                    else if (Uinput.Equals("sort"))
                    {
                        //Implement your sort method here
                        Console.WriteLine("Sorted Deck");
                        for (int i = 0; i < Deck.Length; i++)
                        {
                            Console.WriteLine(Deck[i] + " , ");
                        }
                        Console.WriteLine();
                        Console.WriteLine("---");
                    }
                    else
                    {                    
                        Console.WriteLine("Unrecognised Command");
                    }

                }
                Console.WriteLine("Press Any Key to Repeat");
                Console.ReadKey();
            }

        }

        //Fisher-Yates Shuffle
        static void Shuffle(ref string[] OriginalArray, Random Rnd)
        {            
            for (int i = 0; i < OriginalArray.Length; i++)
            {
                string tmp = OriginalArray[i];
                int r = Rnd.Next(0, OriginalArray.Length);
                OriginalArray[i] = OriginalArray[r];
                OriginalArray[r] = tmp;
            }
        }



        static void Sort(ref string[] ShuffledArray)
        {
           // sort the deck back in order
        }
    }
}
c# sorting playing-cards array-algorithms
4个回答
1
投票

简单地将数组分配给原始数组的副本可能是处理此问题的最简单方法。话虽如此,使用

Array.sort()
和自定义比较器函数对其进行排序是很有帮助的,因为您可能希望将来维护卡片的状态(见下文):

static void Sort(ref string[] ShuffledArray)
{
    Array.Sort(ShuffledArray, CardComparator);
}

public static int CardComparator(string a, string b)
{
    Dictionary<string, int> rank = new Dictionary<string, int>()
    {
        {"A", 0}, {"1", 1}, {"2", 2}, {"3", 3}, {"4", 4}, 
        {"5", 5}, {"6", 6}, {"7", 7}, {"8", 8}, {"9", 9}, 
        {"10", 10}, {"J", 11}, {"Q", 12}, {"K", 13}, 
    };
    int cmp = "HCS".IndexOf(a[0]) - "HCS".IndexOf(b[0]);

    if (cmp == 0) 
    {
        return rank[a.Substring(1)] - rank[b.Substring(1)];
    }

    return cmp;
}

尝试一下!

这应该说明您可能很快就会遇到的程序的一些设计问题。问题是排序需要解析字符串才能确定每张牌的排名和花色。这对于编写游戏逻辑来说会有问题;相反,您将花费大量精力进行解析。

为了解决这个问题,我建议编写一个结构体或类来封装卡片。成员属性可以是

Rank
Suit
以及相应的 getter 和 setter(如果适用)。从长远来看,这种重构将带来巨大的回报(!)。
Deck
类也是合适的,它包含
Card
的成员数组以及
Sort
Shuffle
函数。

另外,你的随机播放代码似乎有偏见;检查 Wikipedia 上的 pseudocode 并尝试重新实现它,直到你可以在大型数据集上运行它的无偏排序。以下是对数据集运行数十万次排序并记录元素最终位置的示例分布(无偏排序将提供均匀分布):

111258
104215
99394
96347
95288
95949
98992
104344
111426

0
投票

Deck
函数中初始化你的
Sort

static void Sort( ref string[] ShuffledArray ) {
    // sort the deck back in order
    string[] Deck =
    {
        "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "DJ", "DQ", "DK",
        "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "HJ", "HQ", "HK",
        "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "CJ", "CQ", "CK",
        "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "SJ", "SQ", "SK",
    };


    ShuffledArray = (string[])Deck.Clone();

}

在你的

Main

string[] Deck = new string[ 52 ];

Sort( ref Deck );

Random r1 = new Random();

.....
.....

0
投票

尝试在洗牌时跟踪交换位置,通过向后迭代撤消;像这样:

public sealed class ShuffleBag<T> : IEnumerable<T>, IEnumerator<T>
{
    private readonly Random m_randomNumberGenerator;
    private readonly int[] m_swaps;
    private readonly T[] m_values;

    private int m_currentIndex;
    private T m_currentValue;

    object IEnumerator.Current => Current;
    public T Current => m_currentValue;

    public ShuffleBag(Random randomNumberGenerator, T[] values) {
        if (randomNumberGenerator == null) {
            throw new ArgumentNullException(message: "random number generator cannot be null", paramName: nameof(randomNumberGenerator));
        }

        if (values == null) {
            throw new ArgumentNullException(message: "array of values cannot be null", paramName: nameof(values));
        }

        m_currentIndex = 0;
        m_currentValue = default(T);
        m_randomNumberGenerator = randomNumberGenerator;
        m_swaps = new int[values.Length];
        m_values = values;
    }

    public void Dispose() { }
    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator() {
        while (MoveNext()) {
            yield return Current;
        }
    }
    public bool MoveNext() {
        if (m_currentIndex < m_values.Length) {
            var randomIndex = m_randomNumberGenerator.Next(m_currentIndex, m_values.Length);

            m_currentValue = m_values[randomIndex];
            m_swaps[m_currentIndex] = randomIndex;
            m_values[randomIndex] = m_values[m_currentIndex];
            m_values[m_currentIndex] = m_currentValue;

            m_currentIndex++;

            return true;
        }
        else {
            return false;
        }
    }
    public void Reset(bool unshuffle) {
        if (unshuffle) {
            var count = m_values.Length;

            while (0 < count--) {
                var tempValue = m_values[m_swaps[count]];

                m_values[m_swaps[count]] = m_values[count];
                m_values[count] = tempValue;
            }
        }
        else {
            var count = m_swaps.Length;

            while (0 < count--) {
                m_swaps[count] = 0;
            }
        }

        m_currentIndex = 0;
        m_currentValue = default(T);
    }
    public void Reset() {
        Reset(unshuffle: true);
    }
}

用途:

var shuffleBag = new ShuffleBag<string>(new Random(42), new[] { "a", "b", "c", "d", "e" });

foreach (var item in shuffleBag) {
    Console.WriteLine(item);
}

shuffleBag.Reset();

0
投票

如果您坚持要对已洗好的牌重新洗牌,那么这是最简单的方法:

string[] deck =
{
    "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "DJ", "DQ", "DK",
    "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "HJ", "HQ", "HK",
    "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "CJ", "CQ", "CK",
    "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "SJ", "SQ", "SK",
};

var r = new Random();

string[] shuffled = deck.OrderBy(x => r.Next()).ToArray();

string[] unshuffled = shuffled.OrderBy(x => Array.IndexOf(deck, x)).ToArray();
© www.soinside.com 2019 - 2024. All rights reserved.