This question already has answers here:
Card Shuffling in C#
(9 answers)
Closed 7 years ago.
I'm currently trying to write my first program so my coding isn't nearly as knowledgeable as others...
I am trying to shuffle a deck of cards without using the exact code given in the Fischer-Yates method or at least my version of it...
My plan is to to assign the cards to an enum and that will assign them a number from 0-51. Then I set the cards in a list and remove the card from the list that the RNG generates. After the card is removed from the list the counter deletes one from the possible random numbers and I set the number to a temporary variable that I will then pass to a new list that will be the shuffled deck.
My issue is in finding code that will explicitly convert my first list to an int. I think I know how to remove from the first list using .RemoveAt. Will I need to make another conversion or can i store the Random Number I find into the shuffledDeck?
enum Cards
{
AceSpade,
TwoSpade,
ThreeSpade,
FourSpade,
FiveSpade,
SixSpade,
SevenSpade,
EightSpade,
NineSpade,
TenSpade,
JackSpade,
QueenSpade,
KingSpade,
AceHeart,
TwoHeart,
ThreeHeart,
FourHeart,
FiveHeart,
SixHeart,
SevenHeart,
EightHeart,
NineHeart,
TenHeart,
JackHeart,
QueenHeart,
KingHeart,
AceDiamond,
TwoDiamond,
ThreeDiamond,
FourDiamond,
FiveDiamond,
SixDiamond,
SevenDiamond,
EightDiamond,
NineDiamond,
TenDiamond,
JackDiamond,
QueenDiamond,
KingDiamond,
AceClub,
TwoClub,
ThreeClub,
FourClub,
FiveClub,
SixClub,
SevenClub,
EightClub,
NineClub,
TenClub,
JackClub,
QueenClub,
KingClub
}
class DeckShuffle
{
static Random rndCard = new Random(DateTime.Now.Millisecond);
int currentCard;
int tempCard;
int totalCards = 51;
List<Cards> currentDeck = new List<Cards>();
List<int> shuffledDeck = new List<int>();
private void CardShuffler()
{
while (totalCards > -1)
{
tempCard = rndCard.Next(0, 51);
totalCards--;
}
}
}
So you have a list of cards, currentDeck.
I'd recommend a for loop to have an integer value like:
List<Cards> currentDeck = new List<Cards>();
List<Cards> shuffledDeck = new List<Cards>();
for(int i = 0; i < currentDeck.Count - 1; i++) {
//Grab a card, insert it into ShuffledDeck
int randoNum = rndCard.Next(0, 51-i); //This will grab a new number between 1 and however many cards are left
shuffledDeck.Add(currentDeck[randoNum]);
currentDeck.RemoveAt(i);
}
This way, every loop as i increases, the number of cards left in currentDeck decreases, and we grab one, and add it to the shuffled deck.
Edit: I'd probably recommend creating a Card class though (if you're that far into learning C#) - each "Card" object would have a numeric value (1-13, 11 for Jack, 12 for Queen, 13 for King, etc) and a suit.
That'll make most card-based games a lot easier.
Related
This question already has answers here:
Randomize a List<T>
(28 answers)
Closed 5 years ago.
I want to fill a small array with unique values from a bigger array. How do I check the uniqueness?
Here's what I have:
int[] numbers45 = new int[45];
for (int i = 0; i <= 44; i++) // I create a big array
{
numbers45[i] = i + 1;
}
Random r = new Random();
int[] draw5 = new int[5]; //new small array
Console.WriteLine("The 5 draws are:");
for (int i = 1; i <= 4; i++)
{
draw5[i] = numbers45[r.Next(numbers45.Length)]; //I fill the small array with values from the big one. BUT the values might not be unique.
Console.WriteLine(draw5[i]);
}
There are multiple ways to do what you are asking.
First off, though, I would recommend to use one of the classes which wraps the array type and adds some extra functionality you could use (in this case a List would probably be a perfect structure to use)!
One way to handle this is to check if the value is already in the draw5 array. This can be done with (for example) the List<T>.Contains(T) function, and if it exists, try another.
Personally though, I would probably have randomized the first array with the OrderBy linq method and just return a random number, like:
numbers45.OrderBy(o => random.Next());
That way the numbers are already random and unique when it is supposed to be added to the second list.
And a side note: Remember that arrays indexes starts on index 0. In your second loop, you start at 1 and go to 4, that is, you wont set a value to the first index.
You could just run for (int i=0;i<5;i++) to get it right.
Inspired by Jite's answer, I changed to use Guid to randomize the numbers
var randomized = numbers45.OrderBy(o => Guid.NewGuid().ToString());
Then you could take the draws by:
var draws = randomized.Take(5).ToArray;
HashSet<int> hs = new HashSet<int>();
int next = random.next(45);
while(hs.Length <=5)
{
if(!hs.Contains(array[next]))
hs.Add(array[next]);
next = random next(45);
}
This question already has answers here:
How to access random item in list?
(12 answers)
Closed 5 years ago.
I'm trying to code in Unity and I don't know how to make this.
My idea is to declare int variables, generating the int randomly inside a range. Later, create a list with the variables and pick one randomly.
Finally, display the resulting int in a label. This is my code, which is incomplete and maybe wrong:
#Variables
int low = Random.Range (100, 120);
int standard = Random.Range (120, 140);
int high = Random.Range (140, 160);
#List
string List = new string { low, standard, high };
#Pick one random item from the list
???
#Display that item in a label as an int
???
I'm not sure if this is the most effective way to do it. Also, could be possible to display in a label two int with a "/" between? Thanks!
First of all you are making string array which is wrong, use int type list :
public List<int> RandomNumbers = new List<int>();
Then add each random number to list
RandomNumbers.Add(low);
RandomNumbers.Add(standard);
RandomNumbers.Add(high);
//Then select random number from list as int:
Int pickedNumber = RandomNumbers[Random.Range(0, (myRandomNumber.Count - 1))];
And finally display your number
GUILayout.Label(pickedNumber.ToString());
Don't know what you mean, but this is a full example of how to generate random numbers and pick them randomly.
public class ExampleClass : MonoBehaviour
{
public int randomCount = 3;
public List<int> myRandomNumber = new List<int>();
[Space(20)]
public int minRandom = 0;
public int maxRandom = 255;
private int pickedNumber;
void Start ()
{
for (int i = 0; i < randomCount; i++)
{
myRandomNumber.Add(Random.Range(minRandom, maxRandom));
}
//pick one number randomly
pickedNumber = myRandomNumber[Random.Range(0, myRandomNumber.Count)];
}
void OnGUI ()
{
//Display your picked number in game screen
GUILayout.Label(pickedNumber.ToString());
}
}
But what's the point of generating a list of random number? while you can instead just generate the number that you want to display with Random.Range() without making a list first.
I have the following code :
int GetRandNumber()
{
Random r = new Random();
return r.Next() % 6 + 1;
}
I am developing a windows store app. I have a textbox in which a single number from 1 to 6 is generated. For every number I have made a specific event. I need to make sure that every number is generated only once so that the events do not repeat.
Looks like you just need to shuffle numbers. I'd suggest to create an array of numbers from 1 to 6 and just shuffle the array. You can see some code here for how to shuffle an array/list.
First of all you need to be careful with this implementation, if you call GetRandomNumber() multiple times very close together it will give you the same result. A better function would be
int GetRandNumber(Random r)
{
return r.Next(1, 7); //This does the same as "r.Next() % 6 + 1" but removes bias.
}
//used like
Random rand = new Random();
foreach(var foo in bar)
{
//The same instance of rand is used for each call instead of a new one each time.
foo.SomeProp = GetRandNumber(rand);
}
However that is completely separate from what you need to do, you should not be generating random numbers between 1 though 6. What you need to do is make a list of 1 though 6 then shuffle the list, not use random numbers at all (well you will likely use them during the shuffle but that is a implementation detail)
List<int> numbers = new List<int>();
for(int i = 1; i <= 6; i++)
{
numbers.Add(i);
}
MyShuffleListFunction(numbers);
There are plenty of examples on this site on how to make a shuffle function.
Maybe I'm wrong, but as I understand you want something like this as an output:
344213266125
To achieve this you should keep track which numbers are already generated, and stop if all has been "rolled" at least once.
So let's have a bool array initialized to 6 false values, and after each random number generation (after each roll) set the array's corresponing element to true. Check if there are any false values in the array, if not then "roll again".
Also, you might consider generating the numbers according to the other answers, as they are of course right: this is not an ideal way.
Update
Okay, based on your question's update I also update my pseudocode (or maybe I should call this prose):
Keep track of the already "rolled" numbers (as above). When generating a new number check if it has been already generated or not. If it's been rolled before, then roll again, until you roll a new one: then update the array accordingly. Also be sure to check if there is a valid number or all has been rolled before at the beginning of the roll...
But now it seems for me that what you really are looking for is simply a shuffle, which has been proposed in other answers.
Perhaps this will work for you. The approach is to record the random results in a List and to skip the output if the results already exists in the list.
class Program
{
static int tmp;
static void Main(string[] args)
{
List<int> alreadyFired = new List<int>();
while (alreadyFired.Count != 6)
{
Random rng = new Random();
int diceresult = rng.Next(1,7);
foreach (var item in alreadyFired)
{
if (item == diceresult)
{
tmp = item;
}
}
if (!(tmp == diceresult))
{
alreadyFired.Add(diceresult);
Console.WriteLine(diceresult);
}
}
Console.WriteLine("no events left");
Console.ReadKey();
}
}
I'm writing a card game in C#, a game of blackjack, where the user presses a button and it deals a card, the value of that card gets added to a text box. If the value of the text box goes over 21 the user has lost.
I'm having a problems with the dealing of the cards, i generate a random, say 5 gets generated show the 5 of diamonds, add the value of the 5 of diamonds to the score text box and display a picture box(the 5 of diamonds playing card). However once 5 has been generated i'm having problems not generating that card again, i have the logic down of what needs to happen, i'm just not sure on the actual code itself as i'm a beginner.
So far iv tried 2 different ways, a List and a array of Boolean values and i'm still struggling, could anybody point me in the right direction in terms of code.
List<int> Diamonds = new List<int>();
Random random = new Random();
genRandom = random.Next(0, 5);
while (Diamonds.Contains(genRandom))
{
genRandom = random.Next(0, 5);
break;
}
while (!Diamonds.Contains(genRandom))
if (genRandom == 0)
{
Diamonds.add(0);
score = score += 2;
scoreTextBox.Text = score.ToString();
diamonds2.Show();
}
Thanks in advance, sorry about the bad grammar!
I would take the reverse approach, by creating a collection that holds all the possible cards, and then draw them from the collection randomly.
Say you have a class called Deck, which represents a card deck. Fill it with Card classes. Now when you start drawing cards, randomly pick a number in the collection and remove that card from the Deck. The next time the same random number is drawn, it will draw a different card from the deck, since you remove the used cards.
Just remember to generate a random number that is within bounds of the size of the deck, which will decrease after each draw.
The problem you have right now is that you don't have a card pool. You should have a list of card you can draw from and once a card is picked, it is removed from the available choices and cannot be drawn again.
List<Card> deck = new List<Card>();
deck.Add(new Card(1, CardType.Diamonds));
deck.Add(new Card(2, CardType.Diamonds));
...
Card nextCard = deck[Random.Next(0, deck.Count - 1)];
deck.Remove(nextCard);
where:
struct Card
{
public int number;
public CardType type;
public Card(int number, CardType type)
{
this.number = number;
this.type = type;
}
}
enum CardType
{
Diamonds,
Spades,
Hearts,
Clubs
}
It's a very simplistic, object oriented approach where each card is clearly defined as a unique container. It might not be the most optimal way, but probably much easier to understand.
There are many ways to do that the most i use it is as follows:
List<int> available = new List<int>(5000);
for(int i=1; i<=5; i++)
available.Add(i);
The above code will generate all random numbers.
Now you can choose from them as follows:
List<int> result = new List<int>(5000);
while(available.Count > 0)
{
int index = random.Next(availableCount);
result.Add(available[index]);
available.RemoveAt(index);
}
return result;
Since you are removing after getting they will never repeat.
You could do something like this:
List<int> Diamonds = new List<int>();
for(int i = 1; i <= 10; i++) //10 is just an example..dk how many cards :P
{
Diamonds.Add(i);
}
Random random = new Random();
int index = random.Next(0, Diamonds.Count - 1);
int nr = Diamonds[index];
Diamonds.Remove(index);
Easiest thing to do would be to sort the entire list randomly (by sorting by Rand() - 0.5), then each time you want a 'random' card, take the first one and remove it from the list. The cards are in a random order so it's the same effect statistically as picking a random one each time, and you won't pick the same card twice in a given game.
The easiest way to do this conceptually is to have an array which represents a deck of cards, and then deal cards from it.
Ideally you would use a stack for this, but unfortunately you can't shuffle a stack!
Therefore, your best bet is to use a List<Card>, where 'Card' is a class that represents a card. The Card class would have two properties: a Suite and a rank from 1 (the Ace) to 13 where 11 is Jack, 12 is Queen and 13 is King.
You would populate your List<Card> deck with all 52 possible cards, and then you could shuffle it using an implementation of the Fisher-Yates shuffle.
Here's a complete sample:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var deck = new List<Card>();
for (int rank = 1; rank <= 13; ++rank)
foreach (Suite suite in Enum.GetValues(typeof(Suite)))
deck.Add(new Card {Rank = rank, Suite = suite});
var shuffler = new Shuffler();
shuffler.Shuffle(deck);
// Deal the top 10 cards.
for (int i = 0; i < 10; ++i)
Console.WriteLine(deck[i]);
}
}
public enum Suite
{
Clubs,
Diamonds,
Hearts,
Spades
}
public sealed class Card
{
public Suite Suite;
public int Rank;
public override string ToString()
{
string rank;
switch (Rank)
{
case 1: rank = "Ace"; break;
case 11: rank = "Jack"; break;
case 12: rank = "Queen"; break;
case 13: rank = "King"; break;
default: rank = Rank.ToString(); break;
}
return string.Format("{0} of {1}", rank, Suite);
}
}
public sealed class Shuffler
{
public Shuffler()
{
_rng = new Random();
}
public void Shuffle<T>(IList<T> array)
{
for (int n = array.Count; n > 1; )
{
int k = _rng.Next(n);
--n;
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
private readonly Random _rng;
}
}
Real code should validate Rank and Suite, of course. Also, you'd be better off writing a Deck class which encapsulated shuffling and dealing (it could remove cards from the end of the List<Card> when dealing).
Ok, the cards game I'm developing is pretty similar to Scopa if someone knows it.
The deck contains 40 cards divided into 4 different suits of 10 cards each (ace => value 1, two => value 2, three = ..., four, five, six, seven, knave, queen, king => value 10).
There are 2 players (actually an AI and a human player) and they have 4 cards in their hand.
There are 4 free cards to take on the table and players can take them only respecting the following rules:
1) Court cards (knave, queen and king) can only take identical court cards (for example, if I have a queen I can only take a queen from the table).
2) Numeric cards (from ace to seven) can take identical numeric cards or smaller numeric cards by sum (for example, if I have a seven I can take a seven or { an ace, a six } or {a three, a four } or { an ace, three two }).
Now the time has come to find which cards the AI can eventually take during it's turn:
private List<List<Card>> CalculateAITake()
{
List<Int32> handValues = new List<Int32>();
List<List<Card>> takes = new List<List<Card>>();
/* here i take every hand card value, in a unique way
* in order to avoid processing two or more times the
* same value
*/
foreach (Card card in m_AIHand)
{
Int32 cardValue = (Int32)card.Rank;
if (!handValues.Contains(cardValue))
handValues.Add(cardValue);
}
/* for each hand card value now, I calculate the
* combinations of cards I can take from table
*/
foreach (Int32 handValue in handValues)
{
// it's a court card, let's use a direct and faster approach
if (handValue >= 8)
{
foreach (Card card in m_CardsOnTable)
{
if ((Int32)card.Rank == handValue)
{
List<Card> take = new List<Card>();
take.Add(card);
takes.Add(take);
}
}
}
else
// it's a numeric card, let's use recursion
CalculateAITakeRecursion(takes, (new List<Card>(m_CardsOnTable)), 0, (new List<Card>()), handValue, 0);
}
return takes;
}
private void CalculateAITakeRecursion(List<List<Card>> takes, List<Card> cardsExcluded, Int32 cardsExcludedIndex, List<Card> cardsIncluded, Int32 sumWanted, Int32 sumPartial)
{
for (Int32 i = cardsExcludedIndex; i < cardsExcluded.Count; ++i)
{
Card cardExcluded = cardsExcluded[i];
Int32 sumCurrent = sumPartial + (Int32)cardExcluded.Rank;
/* the current sum is lesser than the hand card value
* so I keep on recursing
*/
if (sumCurrent < sumWanted)
{
List<Card> cardsExcludedCopy = new List<Card>(cardsExcluded);
cardsExcludedCopy.Remove(cardExcluded);
List<Card> cardsIncludedCopy = new List<Card>(cardsIncluded);
cardsIncludedCopy.Add(cardExcluded);
CalculateAITakeRecursion(takes, cardsExcludedCopy, ++cardsExcludedIndex, cardsIncludedCopy, sumWanted, sumCurrent);
}
/* the current sum is equal to the hand card value
* we have a new valid combination!
*/
else if (sumCurrent == sumWanted)
{
cardsIncluded.Add(cardExcluded);
Boolean newTakeIsUnique = true;
Int32 newTakeCount = cardsIncluded.Count;
/* problem: sometimes in my results i can find both
* { ace of hearts, two of spades }
* { two of spades, ace of hearts }
* not good, I don't want it to happens because there
* is still a lot of work to do on those results!
* Contains() is not enought to guarantee unique results
* so I have to do this!
*/
foreach (List<Card> take in takes)
{
if (take.Count == newTakeCount)
{
Int32 matchesCount = 0;
foreach (Card card in take)
{
if (cardsIncluded.Contains(card))
matchesCount++;
}
if (newTakeCount == matchesCount)
{
newTakeIsUnique = false;
break;
}
}
}
if (newTakeIsUnique)
takes.Add(cardsIncluded);
}
}
}
Do you think that this algorithm could be improved somehow?
I'm trying to shorten this code as much as I can so that it can be easy to debug and easy to maintain... also, if someone has a more elegant solution to avoid duplicate combinations I would really, really appreciate it (I don't want to get both { ace of hearts, two of spades } and { two of spades, ace of hearts }... only one of them).
Many, many thanks in advance!
Rather than considering each numeric card in your hand and looking for free cards that total it, I would consider each possible total of free cards and looking for a numeric card in your hand that matches it. You could use some sort of bitset to speed up the check for a matching card in your hand, and if you sort the free cards in ascending order, you could avoid adding a card matching one that you skipped, and you could stop adding cards if you exceeded the highest numeric card in your hand.
EDIT: pseudocode follows (sorry, I'm no good at naming variables):
call find_subset_sum(1, List<int>, 0)
// Passing the total because it's easy to calculate as we go
sub find_subset_sum(int value, List<int> play, total)
if total > max_hand_card
return // trying to pick up too many cards
if total in hand_set
call store_play(play)
if value > max_free_card
return // no more cards available to pick up
// try picking up higher value cards only
find_subset_sum(value + 1, play, total)
// now try picking up cards of this value
for each free card
if card value = value // only consider cards of this value
total += value
play.append(card)
find_subset_sum(value + 1, play, total)
// you could remove all the added cards here
// this would avoid having to copy the list each time
// you could then also move the first recursive call here too
It looks a bit odd but that's to ensure that if you only need one card of a particular value you don't unnecessarily consider picking up each available card of that value.
You can optimise this still further by sorting the array in ascending order.