C# C语言中的洗牌
我正试图为一个项目编写一个代码,该项目列出一副牌的内容,询问这个人想要洗牌多少次,然后洗牌。它必须使用System.random类创建两个随机整数的方法 这些是我的课程: Program.cs:C# C语言中的洗牌,c#,.net,shuffle,playing-cards,C#,.net,Shuffle,Playing Cards,我正试图为一个项目编写一个代码,该项目列出一副牌的内容,询问这个人想要洗牌多少次,然后洗牌。它必须使用System.random类创建两个随机整数的方法 这些是我的课程: Program.cs: namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Deck mydeck = new Deck();
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Deck mydeck = new Deck();
foreach (Card c in mydeck.Cards)
{
Console.WriteLine(c);
}
Console.WriteLine("How Many Times Do You Want To Shuffle?");
}
}
}
Deck.cs:
namespace ConsoleApplication1
{
class Deck
{
Card[] cards = new Card[52];
string[] numbers = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "J", "Q", "K" };
public Deck()
{
int i = 0;
foreach(string s in numbers)
{
cards[i] = new Card(Suits.Clubs, s);
i++;
}
foreach (string s in numbers)
{
cards[i] = new Card(Suits.Spades, s);
i++;
}
foreach (string s in numbers)
{
cards[i] = new Card(Suits.Hearts, s);
i++;
}
foreach (string s in numbers)
{
cards[i] = new Card(Suits.Diamonds, s);
i++;
}
}
public Card[] Cards
{
get
{
return cards;
}
}
}
}
Enums.cs:
namespace ConsoleApplication1
{
enum Suits
{
Hearts,
Diamonds,
Spades,
Clubs
}
}
Card.cs:
namespace ConsoleApplication1
{
class Card
{
protected Suits suit;
protected string cardvalue;
public Card()
{
}
public Card(Suits suit2, string cardvalue2)
{
suit = suit2;
cardvalue = cardvalue2;
}
public override string ToString()
{
return string.Format("{0} of {1}", cardvalue, suit);
}
}
}
请告诉我如何让牌按照人们的意愿洗牌,然后列出洗牌后的牌。洗牌一副牌一开始看起来很简单,但通常大多数人想出的算法是不正确的 杰夫·阿特伍德(Jeff Atwood)就这一主题写了几篇非常好的文章: 尤其是第二个是必读的 您的C代码应该如下所示:
static public class FisherYates
{
static Random r = new Random();
// Based on Java code from wikipedia:
// http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
static public void Shuffle(int[] deck)
{
for (int n = deck.Length - 1; n > 0; --n)
{
int k = r.Next(n+1);
int temp = deck[n];
deck[n] = deck[k];
deck[k] = temp;
}
}
}
int firstNum = rnd.Next(52);
int secondNum = rnd.Next(52);
Card tempCard = MyCards[firstNum];
MyCards[firstNum] = MyCards[secondNum];
MyCards[secondNum] = tempCard;
我认为,在这种情况下,你可能会过于沉迷于抽象
在软件中洗牌一副牌就是以随机顺序向用户提供一副牌。这实际上并不需要你提前洗牌 在你的甲板上。我通常使用1到52之间的数字来表示卡片,并以数学方式计算出哪张卡片是正确的 通过使用随机数生成器从可用卡牌组中选择一张卡来处理一张卡。 把那张牌换成牌组末尾的那张。 减少指向牌组末端的计数器,以从牌组中移除该牌。 转到步骤1,直到您完成绘制卡片。 编辑:一般来说,如果你有一个好的随机数生成器,那么多次洗牌都不会得到任何结果
使用您展示的数据结构,这应该是可能的。您只需要添加一个Draw方法和成员变量来跟踪组的末尾。如果你执意要提前进行洗牌,那么A你的教授是个混蛋,B只要你抽52张牌,牌组就会被洗牌。抽完所有牌后,需要提供DeckEmpty方法,以及重置牌组末端以再次包括所有牌的方法。洗牌应按以下方式进行: 你在牌组中随机拿两张牌,牌组中牌的索引是随机数 交换两张牌的位置。 例如,拿索引2处的卡片和索引9处的卡片,让它们改变位置 这可以重复一定次数 算法应该如下所示:
static public class FisherYates
{
static Random r = new Random();
// Based on Java code from wikipedia:
// http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
static public void Shuffle(int[] deck)
{
for (int n = deck.Length - 1; n > 0; --n)
{
int k = r.Next(n+1);
int temp = deck[n];
deck[n] = deck[k];
deck[k] = temp;
}
}
}
int firstNum = rnd.Next(52);
int secondNum = rnd.Next(52);
Card tempCard = MyCards[firstNum];
MyCards[firstNum] = MyCards[secondNum];
MyCards[secondNum] = tempCard;
你的洗牌可能有效,但它不是真正有效的,也不是逼真的。你应该这样做:
//The shuffle goes like this: you take a portion of the deck, then put them in random places
private void Shuffle()
{
int length = DeckofCards.Count;
int level = 20; //number of shuffle iterations
List<Card> Shuffleing; //the part of the deck were putting back
Random rnd = new Random();
int PickedCount, BackPortion; //the last used random number
for (int _i = 0; _i < level; _i++)
{
PickedCount = rnd.Next(10, 30); //number of cards we pick out
Shuffleing = DeckofCards.GetRange(0, PickedCount);
DeckofCards.RemoveRange(0, PickedCount);
while (Shuffleing.Count != 0)
{
PickedCount = rnd.Next(10, DeckofCards.Count - 1); //where we place a range of cards
BackPortion = rnd.Next(1, Shuffleing.Count / 3 + 1); //the number of cards we but back in one step
DeckofCards.InsertRange(PickedCount, Shuffleing.GetRange(0, BackPortion)); //instering a range of cards
Shuffleing.RemoveRange(0, BackPortion); //we remove what we just placed back
}
}
}
通过这种方式,你可能会得到一个更逼真的洗牌,迭代次数更少要正确地洗牌一副牌,你不应该只使用Random类,种子只有2^32,这意味着你的随机对象只能给你2^32个假定的不同顺序,其中有52个!阶乘52代理真实生活甲板的方法 我使用2个guid创建32字节的随机数据->8个4字节的种子,然后我洗牌 这些卡片上有8种不同的种子 然后通过种子我得到一定数量的牌[5,5,6,6,6,7,8,9] 这是我使用的代码
public void Shuffle(Guid guid1, Guid guid2)
{
int[] cardsToGet = new int[] { 5, 5, 6, 6, 6, 7, 8, 9 };
byte[] b1 = guid1.ToByteArray();
byte[] b2 = guid2.ToByteArray();
byte[] all = new byte[b1.Length + b2.Length];
Array.Copy(b1, all, b1.Length);
Array.Copy(b2, 0, all, b1.Length, b2.Length);
List<Card> cards = new List<Card>(this);
Clear();
for (int c = 0; c < cardsToGet.Length; c++)
{
int seed = BitConverter.ToInt32(all, c * 4);
Random random = new Random(seed);
for (int d = 0; d < cardsToGet[c]; d++)
{
int index = random.Next(cards.Count);
Add(cards[index]);
cards.RemoveAt(index);
}
}
}
总的来说,我想说的是,将每个数据组视为一个对象,其中包含一个卡对象数组,每个卡对象都包含一个value和suite int属性,该属性可以应用于值和套件的枚举,以根据您使用的数据组类型收集命名版本。这将使这段代码更加通用,并且更容易进行值比较3<11 jack!~你的风格将适用于一个学校项目,我只是有点强迫症
class Card
{
public int value
{ get; set; }
public int suite
{ get; set; }
}
abstract class Deck
{
public Card[] cards
{ get; set; }
public void ShuffleCards(int timesToShuffle)
{
Card temp;
Random random = new Random();
// int timesToShuffle = random.Next(300, 600); #Had it setup for random shuffle
int cardToShuffle1, cardToShuffle2;
for (int x = 0; x < timesToShuffle; x++)
{
cardToShuffle1 = random.Next(this.cards.Length);
cardToShuffle2 = random.Next(this.cards.Length);
temp = this.cards[cardToShuffle1];
this.cards[cardToShuffle1] = this.cards[cardToShuffle2];
this.cards[cardToShuffle2] = temp;
}
}
}
这是假设您使用了一个基本的Deck类,然后将其继承到您想要创建的Deck类型,这样您就可以将相同的代码应用到Uno Deck或其他任何类型。甲板等级的正常类型代码
class NormalDeck : Deck
{
// This would go in the NormalGame class to apply the enumerators to the values as a cipher.
// Need int values for logic reasons (easier to work with numbers than J or K !!!
// Also allows for most other methods to work with other deck<Type> (ex: Uno, Go Fish, Normal cards)
public enum Suites
{
Hearts,
Diamonds,
Spades,
Clover
};
// Same comment as above.
public enum Values
{ Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King };
public void NewNormalDeck()
{
// Clear the deck of cards
if (this.cards != null)
{
Array.Clear(this.cards, 0, this.cards.Length);
}
//Set Value to length of Normal deck of Cards without Jokers
cards = new Card[52];
// to keep count of which card we are.
int curNumofCards = 0;
// Cycle through all of the suites listed in "suites" then all the values of that suite
for (int x = 0; x < Enum.GetValues(typeof(Suites)).GetLength(0); x++)
{
for (int y = 0; y < Enum.GetValues(typeof(Values)).GetLength(0); y++)
{
Card newCard = new Card();
newCard.suite = x;
newCard.value = y;
this.cards[curNumofCards] = newCard;
curNumofCards++;
}
}
}
}
修正了你的格式。一些看起来像家庭作业的标准问题。。。你试过什么?只是出于兴趣,为什么你用枚举来计算西装而不是牌的等级?这不是我想要的。我正在寻找一个人来告诉我如何洗牌通过代码我正在使用你在寻找一个人来为你写代码或告诉你怎么做?假设这是一个作业,如果你自己写的话,你会从课堂上得到更多。如果你不做作业,你通常考试不及格?嗯,我不知道它有名字。我第一次在8位Atari上用Basic实现它!我想我是八年级的学生。当我在我的Deck.cs类中使用它时,我遇到了这些错误。它说Deck是的,每个地方我都用大写字母来匹配我的代码。它说它是一个“类型”,但用作“变量”。当它说Deck.Length时,它说我的应用程序没有“Length”的定义,你不应该大写变量名“Deck”来匹配你的类名。如果您这样做,是的,您将得到一个错误,因为您将混淆一个变量与一个类。其他人告诉过你该怎么做:-创建一个包含52个整数[0..5]的数组
1] 包容性-洗牌整数-发牌是从数组中移除最上面的整数-通过将整数值转换为card+suit Good luck,将卡片表示为字符串。我知道这是一个古老的方法,但仍然是最新的方法。我不是这方面的专家,但我认为方法是估计可能结果的数量,说明许多结果需要多少随机性,然后确定你的方法是否有那么多随机性或更多。有52个!随机甲板。我相信这是225位随机性:>>>math.logfactorial52,2225.5810031237028那么MS加密库有多少位熵呢?一个快速的谷歌并没有给我答案。这并不是一个公平的洗牌。为什么不呢??假设rnd.Next函数给出了介于1和52之间的完全随机值,您需要洗牌多长时间才能获得“足够随机”?它确实执行了公平洗牌:有限置换组的任何元素在这里洗牌是52个元素的置换组的元素,可以分解为置换的乘积仅置换切换两个元素并修复其余元素加密类能否解决伪随机数生成器问题?您的随机对象只能给您2^32个假定的不同顺序-实际上,这比这更糟糕,因为从未使用负种子。如果将负种子传递给构造函数,则使用绝对值。所以你只有2^31个可能的序列。尽管如此,我还是把更糟糕的部分加上引号,因为在大多数情况下,20亿个可能的序列就足够了。