I am working on an assignment for school (Assignment Here).
I am currently trying to shuffle a deck of cards. I have used PlayingCards from Codeplex (sorry, could only have two links...) to create a collection of cards to create a deck. Please help, when I click the Shuffle button, nothing happens. You can see my progress here it's easier to see the entire code: Github
public void Shuffle()
{
PlayingCards.Deck theDeck = new PlayingCards.Deck();
random = new Random();
for (int i = 0; i < theDeck.Cards.Count; i++)
{
int second = random.Next(NUMBER_OF_CARDS);
PlayingCards.Card temp = theDeck.Cards[i];
theDeck.Cards[i] = theDeck.Cards[second];
theDeck.Cards[second] = temp;
}
}
You are creating a new instance of PlayingCards.Deck, shuffling it, and then throwing it away at the end of the shuffle.
PlayingCards.Deck theDeck = new PlayingCards.Deck();
You need to change the call to Shuffle to include PlayingCards.Deck as a parameter, so you should be doing this:
public void Shuffle(PlayingCards.Deck theDeck)
{
random = new Random();
for (int i = 0; i < theDeck.Cards.Count; i++)
{
int second = random.Next(NUMBER_OF_CARDS);
PlayingCards.Card
temp = theDeck.Cards[i];
theDeck.Cards[i] = theDeck.Cards[second];
theDeck.Cards[second] = temp;
}
}
You should also move the new Random() outside of this method as you may find that if you tried to create two shuffled decks immediately after one another that they'll have the same order because the seed Random uses is based on the system clock.
I had a look at the code you've got for adding the cards to the deck. You should use this code instead:
foreach (var face in Enum.GetValues(typeof(PlayingCards.CardSuits)).Cast<PlayingCards.CardSuits>())
{
foreach (var value in Enum.GetValues(typeof(PlayingCards.CardValues)).Cast<PlayingCards.CardValues>())
{
theDeck.Cards.Add(new PlayingCards.Card(face, value));
}
}
Related
I'm trying to create some pairs of unique numbers using pretty simple algorithm.
For some unknown reason after compiling Unity goes into an endless "not responding" state. Seems like it's stuck in a do..while loop, but I don't see any reason for that.
//Creating two lists to store random numbers
List<int> xList = new List<int>();
List<int> yList = new List<int>();
int rx, ry;
for(int i = 0; i < 10; i++)
{
// look for numbers until they are unique(while they are in lists)
do
{
rx = rand.Next(0, width);
ry = rand.Next(0, height);
}
while(xList.Contains(rx) || yList.Contains(ry));
//add them to lists
xList.Add(rx);
yList.Add(ry);
Debug.Log(rx + ", " + ry);
// some actions with these numbers
gridArray[rx,ry].isBomb = true;
gridArray[rx,ry].changeSprite(bombSprite);
}
As mentioned the issue is that once all unique numbers have been used once you are stuck in the do - while loop.
Instead you should rather simply
generate the plain index lists for all possible pairs.
I will use the Unit built-in type Vector2Int but you could do the same using your own struct/class
For each bomb to place pick a random entry from the list of pairs
Remove according random picked item from the pairs so it is not available anymore in the next go
Something like
// create the plain pair list
var pairs = new List<Vector2Int>(width * height);
for(var x = 0; x < width; x++)
{
for(var y = 0; y < height; y++)
{
pairs.Add(new Vector2Int(x,y));
}
}
// so now you have all possible permutations in one list
if(pairs.Count < BOMB_AMOUNT_TO_PLACE)
{
Debug.LogError("You are trying more bombs than there are fields in the grid!");
return;
}
// Now place your bombs one by one on a random spot in the grid
for(var i = 0; i < BOMB_AMOUNT_TO_PLACE; i++)
{
// now all you need to do is pick one random index from the possible entries
var randomIndexInPairs = Random.Range(0, pairs.Count);
var randomPair = pairs[randomIndexInPairs];
// and at the same time remove the according entry
pairs.RemoveAt(randomIndexInPairs);
// Now you have completely unique but random index pairs
var rx = randomPair.x;
var ry = randomPair.y;
gridArray[rx, ry].isBomb = true;
gridArray[rx, ry].changeSprite(bombSprite);
}
Depending on your use-case as alternative to generate the pairs list and then remove entries again you could also generate it once and then use
if(pairs.Count < BOMB_AMOUNT_TO_PLACE)
{
Debug.LogError("You are trying more bombs than there are fields in the grid!");
return;
}
var random = new System.Random();
var shuffledPairs = pairs.OrderBy(e => random.Next());
for(var i = 0; i < BOMB_AMOUNT_TO_PLACE; i++)
{
// then you can directly use
var randomPair = shuffledPairs[i];
// Now you have completely unique but random index pairs
var rx = randomPair.x;
var ry = randomPair.y;
gridArray[rx, ry].isBomb = true;
gridArray[rx, ry].changeSprite(bombSprite);
}
Although your algorithm is maybe not the best way to generate ten bombs in a grid, it should work.
The problem is that your while condition is using a OR statement, which means that if you have a bomb in the first line (in any column), it will not be able to add another bomb in that line.
Therefore you will pretty soon end up with an infinite loop because for every bomb you lock the line and column.
If you put an AND condition, you make sure the pair is unique because you lock only that cell.
Provided of course that width x height is more than ten.
This is my first time using C#. I have to convert an old project from Java. The old project works, but when I attempted to convert it, something went wrong? The Card class sets the default card to the Ace of Spades, but it is displaying Ace of Clubs. Ace and Clubs are each the first listed of the enums so I guess it is not using the default?
Since it is displaying the same card I thought it would be something wrong with my shuffle method..but I am unsure at this point.
There is a Card, Deck, and Hand class. Then Enums for Suit and Face.
UPDATE: I believe the error is in the method directly below? I need to figure out how to use the 'n' in c#. It is needed in a different class.
In Java I had it as:
public Card(int n)
{
face = Face.values()[n % 13];
suit = Suit.values()[n % 4];
} //end Card (int n) method
c#:
public Card(int n) //??
{
var face = (Face) 13;
var suit = (Suit) 4;
}
The code above is in the Card class? I know that is not too helpful, but the only other way it to post ALL of the code here.
//Some of the Deck class
public void Shuffle()
{
Random ran = new Random();
for (int nextCard = 0; nextCard < deck.Length; nextCard++)
{
Card hold = deck[nextCard];
int random = ran.Next(deck.Length);
deck[nextCard] = deck[random];
deck[random] = hold;
}
}
public Card DealACard()
{
if (nextCard > 51)
{
return null;
}
return deck[nextCard++];
}
public Hand DealAHand(int handSize)
{
Hand hand = new Hand(handSize);
for (int i = 0; i < handSize; i++)
{
hand.AddCard(DealACard());
}
return hand;
}
//Some of the Hand Class
public void AddCard(Card card)
{
hand[cardsInHand] = card;
cardsInHand++;
}
public override string ToString()
{
String handToString = ""; //string to hold display format
//for loop to display each card in a hand
for (int n = 0; n < cardsInHand; n++)
{
handToString += hand[n].ToString() + "\n";
}
return handToString;
}
// Driver Class
Deck deck1 = new Deck();
int cardsToGet = 53;
do
{
Console.Write("How many cards are in one hand? ");
int handSize = Convert.ToInt32(Console.ReadLine());
// int handSize = Console.Read();
Console.Write("How many players are playing? ");
int players = Convert.ToInt32(Console.ReadLine());
cardsToGet = handSize * players;
if (cardsToGet < 53) // if to shuffle deck and display players' hands
{
deck1.Shuffle();
for (int i = 0; i < players; i++) // displays each players hand
{
Console.WriteLine("\nPlayer " + (i + 1) + ":");
Console.WriteLine(deck1.DealAHand(handSize));
}
}
else
{
Console.WriteLine("\nThere are not enough cards in the deck to deal " + players + " hands of " + handSize + " cards. Try again.\n");
}
}
while (cardsToGet > 52);
It is suppose to ask for a number of cards per hand and a number of players then displays a hand for each player without duplicating cards. Currently, it fills every players hand with Ace of Clubs. There are no errors showing.
Now that you've updated your question, this is answerable. The mistake is in your Card constructor, which no matter the value of n that you pass in, creates every card with the Face with value 13 and the Suit with value 4. You have the right method for turning an int into a Face or Suit enum (just cast it), so you just need to do the modulo operation like your Java version did:
public Card(int n)
{
var face = (Face) n % 13;
var suit = (Suit) n % 4;
}
Well, almost. The var keyword in C# just creates a local variable that's not visible outside the scope it's declared in: in this case, the constructor. What you meant to do is assign values to instance properties of your Card class. You haven't shown us what those properties are named, but I'm going to assume they're named Face and Suit (with initial uppercase as is C# naming convention); rename as appropriate:
public Card(int n)
{
this.Face = (Face) n % 13;
this.Suit = (Suit) n % 4;
}
And now your cards should all be different, rather than all being the ace of clubs.
Hello TJ and welcome to S/O, coming from other languages can be a learning curve. Same as if I switched to Java. I quickly threw this together to introduce working with lists and classes within C#. Not perfect, but does what you are looking to get at. Hope it helps. I originally wrote this with C# via a WPF application vs Console app, but the core is all the same (only thing that would be different is the "MessageBox.Show()" that shows each hand vs the Console output which I also included.
I am notorious for commenting through my code and hope this all (or most of it) makes sense as you dive into C#...
I'm starting with enums for the card faces and suits.
public enum CardFace
{
Two = 0,
Three = 1,
Four = 2,
Five = 3,
Six = 4,
Seven = 5,
Eight = 6,
Nine = 7,
Ten = 8,
Jack = 9,
Queen = 10,
King = 11,
Ace = 12
}
public enum CardSuit
{
Hearts = 0,
Clubs = 1,
Diamonds = 2,
Spades = 3
}
Next, a class to represent a single card
public class SingleCard
{
public CardFace Face { get; set; }
public CardSuit Suit { get; set; }
// place-holder for randomizing cards
public int RndNumber { get; set; }
// return the name of the card based on it's parts as single string
public string NameOfCard { get { return $"{Face} of {Suit}"; } }
}
Now, the class for building the initial deck of cards, shuffling, dealing and displaying the cards (of the entire deck, or of the individual hands)
public class DeckOfCards
{
public List<SingleCard> SingleDeck { get; private set; } = new List<SingleCard>();
public List<SingleCard> ShuffledDeck { get; private set; }
// create a single random generator ONCE and leave active. This to help prevent
// recreating every time you need to shuffle and getting the same sequences.
// make static in case you want multiple decks, they keep using the same randomizing object
private static Random rndGen = new Random();
public DeckOfCards()
{
// build the deck of cards once...
// Start going through each suit
foreach (CardSuit s in typeof(CardSuit).GetEnumValues())
{
// now go through each card within each suit
foreach (CardFace f in typeof(CardFace).GetEnumValues())
// Now, add a card to the deck of the suite / face card
SingleDeck.Add(new SingleCard { Face = f, Suit = s });
}
// so now you have a master list of all cards in your deck declared once...
}
public void ShuffleDeck()
{
// to shuffle a deck, assign the next random number sequentially to the deck.
// don't just do random of 52 cards, but other to prevent duplicate numbers
// from possibly coming in
foreach (var oneCard in SingleDeck)
oneCard.RndNumber = rndGen.Next(3901); // any number could be used...
// great, now every card has a randomized number assigned.
// return the list sorted by that random number...
ShuffledDeck = SingleDeck.OrderBy( o => o.RndNumber).ToList();
}
public void DisplayTheCards( List<SingleCard> theCards )
{
// show the deck of cards, or a single person's hand of cards
var sb = new StringBuilder();
foreach (var c in theCards)
sb = sb.AppendLine( c.NameOfCard );
MessageBox.Show(sb.ToString());
}
public void ConsoleDisplayTheCards(List<SingleCard> theCards)
{
// show the deck of cards, or a single person's hand of cards
foreach (var c in theCards)
Console.WriteLine(c.NameOfCard);
}
public List<List<SingleCard>> DealHands( int Players, int CardsPerHand )
{
// create a list of how many hands to be dealt...
// each player hand will consist of a list of cards
var Hands = new List<List<SingleCard>>(Players);
// prepare every players hand before dealing cards
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// each player gets their own list of cards
Hands.Add( new List<SingleCard>());
// prepare card sequence to deal
var nextCard = 0;
// loop for as many cards per hand
for (var oneCard = 0; oneCard < CardsPerHand; oneCard++)
{
// loop every player gets a card at a time vs one player gets all, then next player
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// add whatever the next card is to each individual's hand
Hands[curPlayer].Add(ShuffledDeck[nextCard++]);
}
return Hands;
}
}
I did not include the input of getting how many players, how many cards as you already had that. I also did not validate total cards to be dealt as you had that too. HTH
I've just started learning about methods and classes, I would like to know if I can have something like,
CarsSold Day1 = new CarsSold();
in a for loop where it will create a new instance of a new day each time it runs. For example on the second time the loop runs I want it to create an instance like this,
CarsSold Day2 = new CarsSold();
I have tried to use an array but either it cant be done with arrays or I'm using the wrong syntax. Thanks in advance.
Full code
class Program
{
static void Main(string[] args)
{
int[] weekDay = new int[7];
int userInput;
int x;
for (x = 0; x < weekDay.Length; x++)
{
Console.Write("Enter the number of cars sold: ");
bool ifInt = int.TryParse(Console.ReadLine(), out userInput);
CarsSold Day[x] = new CarsSold(userInput);
}
}
}
The problem is how you're trying to define your array. The syntax is invalid, and you're doing it in the wrong place.
You should define the array before your loop, and then only assign values to the array within the loop.
static void Main(string[] args)
{
int userInput;
CarsSold[] days = new CarsSold[7]; // create an array with 7 items
int x;
for (x = 0; x < days.Length; x++)
{
Console.Write("Enter the number of cars sold: ");
bool ifInt = int.TryParse(Console.ReadLine(), out userInput);
days[x] = new CarsSold(userInput); // assign a value to the days array at position x.
}
}
Note also that arrays start from 0, not 1, so the first item is actually days[0], and the last is days[6] (for a 7-item array). I took the liberty of removing weekDays since it wasn't needed here, and replaced it in the loop with days.Length.
Arrays can have set amount of things in them, so if you declare an array like this
object[] objectArray = new object[10];
Then that array can hold only 10 objects. If you want to add anything to an array you have to chose an index to which that thing will be assigned to, for example:
objectArray[2] = "some value";
in Your case you could iterate through the array and add new object to each index like this
for (var i = 0; i < objectArray.Length; i++)
{
objectArray[i] = new YourObject();
}
If the amount of objects you want to store is unknown and can change then you should use collections, for example a List
List<object> listOfObjects = new List<object>();
Now if you want to add anything to that list you simply do
listOfObjects.Add(itemYouWantToAddToTheList);
You access lists the same way you would access arrays, so you can use indexes like
var someValue = listOfObjects[0];
As you probably noticed this list has a generic parameter <object>, it tells the list what type of data it can store, in my example its the object type so it can pretty much store anything, but you can set it to string or int or any other type like your own class types and then this list would store only those types of objects.
If you don't know the number of days, then:
IList<CarsSold> soldCarsList = new List<CarsSold>();
foreach(var day in Days)
{
soldCarsList.Add(new CarsSold());
}
If you know the number of days(e.g:7), then:
CarsSold[] soldCarsArray = new CarsSold[7];
for (int i = 0; i < days.Length; x++)
{
soldCarsArray[i] = new CarsSold();
}
I have a button event in which generates some random numbers based upon the number typed into a textbox (for example, if I type 5, it should generate 5 different random numbers). When I type in a number into the textbox, and click the btnGenerateScores button, it generates a single number and puts that number in the listbox 5 times (or however many times based upon the number in the textbox). This behavior is not correct, it should generate 5 different numbers and list each in the listbox. If I put a MessageBox.Show (I was using it for debugging) command anywhere in the code block, it works correctly. Commenting out the MessageBox.show breaks the code. Does anyone see any reason why it would not work correctly when I don't show the message box? The code is below:
private void btnGenerateScores_Click(object sender, EventArgs e)
{
strInput = txtInputNumber.Text;
intRandCount = Convert.ToInt16(strInput);
scoresArray = new int[intRandCount];
intArrayCount = scoresArray.Length;
btnGenerateScores.Enabled = false;
// Loop to generate random number
for (intRndCount = 0; intRndCount < intRandCount; intRndCount++)
{
GetRand(intRandCount);
scoresArray[intCount] = intRandomNum;
intGenRandom = intRandomNum;
intArrScores = scoresArray[intCount];
lstRdmScores.Items.Add(Convert.ToString(intArrScores));
insertionSortArray = new int[intArrayCount];
Array.Copy(scoresArray, insertionSortArray, intArrayCount);
// Instantiate an instance of the class
arraySort mySort = new arraySort();
// Get the number of elements to store in the array
string s = Convert.ToString(intCount);
mySort.x = Int16.Parse(s);
// Get array elements
for (int i = 0; i < mySort.x; i++)
{
intInsertionSort = insertionSortArray[intCount];
string s1 = Convert.ToString(intInsertionSort);
mySort.a[i] = Int16.Parse(s1);
}
// Sort the array and display in the second list box
mySort.sortArray();
intSortScores = insertionSortArray[intCount];
lstSortScores.Items.Add(Convert.ToString(intSortScores));
// This is the the MessageBox.Show command in question:
MessageBox.Show("The random number generated is: "); //+ Convert.ToString(intGenRandom));
}
}
ignore the fact that the array does not sort correctly, I will get to that later. I want to work on one thing at a time.
I am using VS 2013 and the code was originally created in VS 2005.
As your requirement, and view the source, I rewrite the app for short:
private void btnGenerateScores_Click_1(object sender, EventArgs e)
{
int genTimes;
if (Int32.TryParse(txtInputNumber.Text, out genTimes))
{
var ints = new List<int>();
for (var i = 0; i < genTimes; i++)
{
var r = new Random(Guid.NewGuid().GetHashCode());
var rInt = r.Next(0, int.MaxValue); //for ints
ints.Add(rInt);
}
var copyInts = ints.ToList();
copyInts.AddRange(this.listBox1.Items.Cast<int>());
copyInts = copyInts.Distinct().OrderBy(x => x).ToList();
this.listBox1.Items.Clear();
this.listBox1.Items.AddRange(copyInts.Cast<object>().ToArray());
MessageBox.Show("The random number generated is: " + String.Join(",", ints));
}
}
}
Hope this help.
Since having a list<list<>> is bad practice, i have created a class containing 2 lists:
public class TouchSet
{
public List<DateTime> timeList = new List<DateTime>(ammountOfXValues);
public List<int> touchList = new List<int>(ammountOfXValues);
}
Then i have a function that is used to initialize the entire thing so i can use it further down the road:
public void initializeTouchDataListObject()
{
touchSetList = new List<DataStructure.TouchSet>(DataStructure.maxButtonsActive);
List<int> tempTouchList = new List<int>();
List<DateTime> tempTimeList = new List<DateTime>();
for (int a = 0; a < DataStructure.maxButtonsActive; a++)
{
DataStructure.TouchSet tempTouchSet = new DataStructure.TouchSet();
tempTouchSet.timeList = tempTimeList;
tempTouchSet.touchList = tempTouchList;
touchSetList.Add(tempTouchSet);
}
}
This is the loop where i add values to the list:
for (int i = 0; i < DataStructure.maxButtonsActive; i++)
{
if(touchSetList[i].timeList.Count == DataStructure.ammountOfXValues)
{
//RemoveAt removes at the given index within a list
touchSetList[i].timeList.RemoveAt(0);
touchSetList[i].touchList.RemoveAt(0);
//add
touchSetList[i].timeList.Add(DateTime.Now);
touchSetList[i].touchList.Add(temp);
}
else if(touchSetList[i].timeList.Count < DataStructure.ammountOfXValues)
{
//add
touchSetList[i].timeList.Add(DateTime.Now);
touchSetList[i].touchList.Add(temp);
}
else
{
int overLength = touchSetList[i].timeList.Count - DataStructure.ammountOfXValues;
//remove
touchSetList[i].timeList.RemoveRange(0, overLength + 1);
touchSetList[i].touchList.RemoveRange(0, overLength + 1);
//add
touchSetList[i].timeList.Add(DateTime.Now);
touchSetList[i].touchList.Add(temp);
}
}
The issue I'm facing is, that within a single pass through the for loop , it adds temp to every touchList not just the touchList of touchSetList[i].
For example after adding temp to touchSetList[i].touchList every other touchList also contains temp, not just the one where the index i applies to the class within the list.
I'm not sure why the List is behaving this way, and why it adds the value to every list not just the one with the corresponding index. I was under the impression that you can use an index to access a single item within a list. Any pointers or advice is appreciated.
public void initializeTouchDataListObject()
{
touchSetList = new List<DataStructure.TouchSet>(DataStructure.maxButtonsActive);
for (int a = 0; a < DataStructure.maxButtonsActive; a++)
{
List<DateTime> tempTimeList = new List<DateTime>();
List<int> tempTouchList = new List<int>();
DataStructure.TouchSet tempTouchSet = new DataStructure.TouchSet();
tempTouchSet.timeList = tempTimeList;
tempTouchSet.touchList = tempTouchList;
touchSetList.Add(tempTouchSet);
}
}
You don't create a new tempTimeList and tempTouchList for every new tempTouchSet, so they all get passed pointers to THE SAME list.
Do the initialization for tempTimeList and tempTouchList within your loop and you get a new one for every tempTouchSet.
Actually I'd redesign the entire thing. What I read from your code is that you want to store the timestamp of a touch event together with some information about the touch event.
So I'd design a class that contains all that data:
public class TouchInfo
{
public DateTime touchTime;
public int touchEvent;
}
Then you can easily store one list of touch events, instead having to keep two lists in sync.
List<TouchInfo> touchEvents = new List<TouchInfo>();
public void initializeTouchDataListObject()
{
for (int a = 0; a < DataStructure.maxButtonsActive; a++)
{
touchEvents.add(new TouchInfo());
}
}
In your initializeTouchDataListObject() method, you create tempTouchList and tempTimeList. Then, for EVERY TouchSet, you add these lists as their timeList and touchList. The problem here is that the two created lists are passed by REFERENCE, meaning that every single TouchSet has a reference to the two exact same lists. They all share the same lists and thus lists are changed for every TouchSet in every iteration.
You have 3 conditions. Add(temp) is in all 3.
1) a < b
2) a = b
3) a > c