Reputation: 41
This may be a duplicate but I have been looking for a couple of hours now and I keep coming up short. So here goes:
I don't have any code yet. I got p*ssed and deleted most of it! :P
I am writing a simple program, that will draw a hand of five cards from a deck of cards. Now, that I can do. However, I am making a button that will keep drawing from a fresh deck until it hits a pair.
Now the issue is the comparison of the five drawn cards. I am drawing them from a list
List<Card> TheDeck
and adding them to another list
List<Card> TheHand
The card class is pretty simple and only contains the first letter of the suit and a number.
public string suit;
public int number;
public Card(string suit, int number)
{
this.suit = suit;
this.number = number;
}
Now to draw a pair, I have to compare the numbers of the five drawn cards, to see if any of them match. The last way I did that, was by doing a GIANT if statement,
if (TheHand[0].number == TheHand[1].number ||
TheHand[0].number == TheHand[2].number || TheHand[0].number == TheHand[3].number ||
TheHand[0].number == TheHand[4].number /* .. and so on and so on .. */)
This I could do, but it just seems so excessive. So there you have my question. What is the easier way to do this comparison of all the cards? Any help will be greatly appreciated.
Upvotes: 0
Views: 1141
Reputation: 4313
Depending on the game you are creating, you can rate your cards independant. For now, the cards get compared by Number, see details: https://learn.microsoft.com/en-us/dotnet/api/system.icomparable?redirectedfrom=MSDN&view=netframework-4.7.2
The CardComparer can be used to sort the cards, I have sorted first on suit and then number, depending on the game you might decide to change this, remember when comparing cards, you always compare the 2 so you rules of comparing are nicely in the Compare method contained.
when adding items to the hand, you can use the following:
int index = TheHand.BinarySearch(newCard);
if (index>-1) //now a card with same number is found and you can take action
else
TheHand.Add(newCard);
Here the class code:
public class Card : IComparable<Card>
{
public Card(string suit, int number)
{
this.Suit = suit;
this.Number = number;
}
public string Suit { get; }
public int Number { get; }
public int CompareTo(Card other)
{
return Number.CompareTo(other.Number);
}
}
Extra so you understand the concept better: For sorting use: TheHand.Sort(new CardComparer());
public class CardComparer : IComparer<Card>
{
public int Compare(Card x, Card y)
{
int compResult = x.Suit.CompareTo(y.Suit);
if (compResult == 0)
{
compResult = x.Number.CompareTo(y.Number);
}
return compResult;
}
}
Note: when the queen of spades is the strongest, you can add this logic to the comparer. E.g. You can make a play comparer which compares the cards on the table.
Upvotes: 0
Reputation: 604
You could also make your Card class to inherit from IEqutable, and using Equals method, define how you decide if two cards are pairs, and then use Linq.GroupBy as Selman is suggesting, but this time without specifying any conditions for groupBy.
input.GroupBy(c => c).Where(g => g.Count() > 1)
The code is below, together with some test methods:
public class Card : IEquatable<Card>
{
public string suit;
public int number;
public Card(string suit, int number)
{
this.suit = suit;
this.number = number;
}
public bool Equals(Card other)
{
if (ReferenceEquals(other, null))
{
return false;
}
return Equals(number, other.number);
}
public override int GetHashCode()
{
return number.GetHashCode();
}
}
public class FindCardPairs
{
public static List<IGrouping<Card, Card>> FindAllPairs(List<Card> input)
{
List<IGrouping<Card,Card>> allPairs = input.GroupBy(c => c).Where(g => g.Count() > 1).ToList();
return allPairs;
}
}
[TestMethod]
public void Card_Test_Equality()
{
var card1 = new Card(string.Empty, 2);
var card2 = new Card("card2", 2);
Assert.IsTrue(card1.Equals(card2));
}
[TestMethod]
public void Test_FindAllPairs()
{
var cards = new List<Card>
{
new Card(string.Empty, 2),
new Card("card2", 2)
};
List<IGrouping<Card, Card>> actual = FindCardPairs.FindAllPairs(cards);
Assert.IsTrue(actual.Any());
Assert.AreEqual(1, actual.Count());
}
Upvotes: 1
Reputation: 101681
You can group the cards by number and check if there is any group that has more than one card:
TheHand.GroupBy(c => c.number).Any(g => g.Count() > 1)
To select the cards that match you can use Where
:
TheHand.GroupBy(c => c.number).Where(g => g.Count() > 1).SelectMany(g => g);
Upvotes: 0