Mélange de cartes en C#
je suis en train d'écrire un code pour un projet qui liste le contenu d'un jeu de cartes, demande combien de fois la personne veut battre les cartes, puis les mélange. Il doit utiliser une méthode pour créer deux entiers aléatoires en utilisant le système.Hasard de classe.
ce sont mes classes:
programme.cs:
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?");
}
}
}
Pont .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;
}
}
}
}
les Énumérations.cs:
namespace ConsoleApplication1
{
enum Suits
{
Hearts,
Diamonds,
Spades,
Clubs
}
}
de la Carte.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);
}
}
}
s'il vous Plaît me dire comment faire les cartes shuffle autant que la personne veut et ensuite la liste des cartes déplacées.
9 réponses
Utiliser shuffle de Fisher-Yates .
votre code C doit ressembler à quelque chose comme ceci:
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;
}
}
}
mélanger un jeu de cartes est quelque chose qui semble trivial au début, mais habituellement l'algorithme que la plupart des gens viennent avec est incorrect.
Jeff Atwood ( Coding Horror ) a écrit quelques très bons articles sur le sujet:
http://www.codinghorror.com/blog/archives/001008.html
http://www.codinghorror.com/blog/archives/001015.html
(en particulier le deuxième est un must-read)
je pense que c'est un cas où vous peut-être simplement se laisser emporter dans l'abstraction.
aléatoire d'un jeu de cartes dans le logiciel est une question de fournir le pont de l'utilisateur dans un ordre aléatoire. Cela ne vous oblige pas à les mélanger à l'avance.
sur votre pont. (J'utilise généralement un nombre de 1 à 52 pour représenter la carte et mathmatically calculer la carte.)
- Affaire d'une carte par utilisation d'un générateur de nombres aléatoires pour choisir une carte dans le paquet de cartes disponibles.
- Échange cette carte avec celle au bout du paquet.
- décrémente un compteur pointant vers l'extrémité du pont, pour retirer cette carte du pont.
- aller à l'étape 1 jusqu'à ce que vous avez terminé le dessin des cartes.
Edit : et de manière générale, si vous avez un bon générateur de nombres aléatoires rien n'est gagné en le" mélangeant " plusieurs fois.
cela devrait être possible en utilisant les structures de données que vous avez montré. Vous avez juste besoin d'ajouter une méthode "Draw", et une variable de membre pour garder la trace de l'extrémité du deck. Si vous êtes bien décidé à effectuer le "shuffle" à l'avance, alors A votre professeur est un con, b chaque fois que vous tirez 52 cartes le jeu sera shuffled. Une fois que vous avez tiré toutes les cartes, vous devez fournir une méthode" DeckEmpty", et la méthode pour réinitialiser l'extrémité du Deck pour inclure toutes les cartes à nouveau.
pour mélanger correctement un deck, vous ne devez pas seulement utiliser la classe aléatoire, la graine est seulement 2^32 ce qui signifie que votre Objet aléatoire peut vous donner seulement 2^32 (supposé) l'ordre différent où il y a 52! (factoriel 52) façon d'agencer un pont de la vie réelle.
j'utilise 2 guid pour créer 32bytes de données aléatoires - > 8 graines de 4bytes et je mélange les cartes avec ces 8 graines différentes
puis par graine je reçois un certain nombre de cartes [5,5,6,6,6,7,8,9]
voici le code que j'utilise
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);
}
}
}
votre mélange peut fonctionner, mais ce n'est pas vraiment efficace et pas réaliste. Vous devriez essayer de cette façon:
//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
}
}
}
de cette façon, vous pourriez obtenir un brassage plus réaliste avec moins d'itérations
le mélange doit fonctionner de cette manière:
vous prenez deux cartes aléatoires dans le deck (l'index de la carte dans le deck est les nombres aléatoires) Et échanger les positions des deux cartes. Par exemple, prenez la carte à l'index 2 et la carte à l'index 9 et faites-les changer de place.
Et qui peut être répété un certain nombre de fois.
L'algorithme devrait ressembler à quelque chose comme ceci:
int firstNum = rnd.Next(52);
int secondNum = rnd.Next(52);
Card tempCard = MyCards[firstNum];
MyCards[firstNum] = MyCards[secondNum];
MyCards[secondNum] = tempCard;
dans l'ensemble je dirais regarder chaque deck comme un objet qui contient un tableau d'objets de carte, que chaque objet de carte contient une valeur et une suite propriété int, qui peut être appliqué à un Enum de valeurs et suites pour rassembler la version nommée selon le Type de Deck que vous utilisez. (Cela permettrait à ce bit de code d'être plus polyvalent et permettre des comparaisons de valeur plus faciles 3 < 11 (jack) !~) Votre style de travail pour un projet scolaire, je suis juste en train de trouble obsessionnel-compulsif avec elle!
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;
}
}
}
qui suppose que vous avez utilisé une classe de Deck de base, puis héritez-en au type de deck que vous voulez (ce qui fait que vous pouvez appliquer ce même code aux decks Uno ou ce qui plus est.) Code pour le type normal de classe de pont.
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++;
}
}
}
}
j'ai fait un programme qui contient 7 cartes, puis mélanger et j'espère prendre afin de les aider.
Programme de classe{
static void Main(string[] args)
{
Random random = new Random();
var cards = new List<string>();
//CARDS VECRTOR
String[] listas = new String[] { "Card 1", "Card 2", "Card 3", "Card 4", "Card 5", "Card 6", "Card 7"};
for (int i = 0; i<= cards.Count; i++)
{
int number = random.Next(0, 7); //Random number 0--->7
for (int j = 0; j <=6; j++)
{
if (cards.Contains(listas[number])) // NO REPEAT SHUFFLE
{
number = random.Next(0, 7); //AGAIN RANDOM
}
else
{
cards.Add(listas[number]); //ADD CARD
}
}
}
Console.WriteLine(" LIST CARDS");
foreach (var card in cards)
{
Console.Write(card + " ,");
}
Console.WriteLine("Total Cards: "+cards.Count);
//REMOVE
for (int k = 0; k <=6; k++)
{
// salmons.RemoveAt(k);
Console.WriteLine("I take the card: "+cards.ElementAt(k));
cards.RemoveAt(k); //REMOVE CARD
cards.Insert(k,"Card Taken"); //REPLACE INDEX
foreach (var card in cards)
{
Console.Write(card + " " + "\n");
}
}
Console.Read(); //just pause
}
}
static void Shuffle(List<int> cards)
{
Console.WriteLine("");
Console.WriteLine("Shuffling");
Console.WriteLine("---------");
cards = cards.OrderBy(x => Guid.NewGuid()).ToList();
foreach (var card in cards)
{
Console.WriteLine(card.ToString());
}
}