I'm working on a Card game in unity. where I have 5 different cards (A,B,C,D,E) and cards i can have at my hand is maximum 8. And I have a draw button. So clicking on draw button once draw one card out. So all these functions are ready. But i want to perform an action when out of those cards that are drawn. if any three cards are similar.
For eg:- I draw out 5 cards And the drawn cards are in this order: A,A,A,B,C now as you see i have 3-A I want to perform A Action. Or if cards are like this A,B,C,C,C,E if want to perform C function because there are 3 C's. So if 3 cards are same type I want to perform an action related to it.
So to brief more I'll explain the flow once. Card-Draw Button Click -> Keep getting cards per click -> Add the cards to a list called _CardList & Sort the cards in List -> If 3 Same Cards are there perform an action. Im Facing Problem at the last one of checking the card.
I have already done a method but its super huge and not advisable. So if you guys can help me in this that will help me a lot. Thanks and Ill post all my doubts and question below with what i tried.
Try#1
Have multiple list like:
List<Card> Alist;
List<Card> BList; //and so on until And keep creating list as long as card type
.
.
List<Card> Elist;
void DrawButton() // Function thats passed to the button. Meaning what to happen when draw button is clicked
{
//Here we instantiate the card randomly from a list given from inspector.
GameObject card = Instantiate(cards._cardModel, _playerHandPoints[clicks].localPosition, _playerHandPoints[clicks].localRotation, mCardHolderParent.transform);
//We access the card script attached to card and give its type and everything
Cards cardDetails = card.GetComponent<Cards>();
cardDetails._cardType = cards._cardType;
//Here we pass the instantiated card
AddNewCard(card.GetComponent<Cards>());
//Every time after adding we check if any list count is 3 and perform related action
CardMatchThreeChecker();
}
AddNewCard(Card inNewCard)
{
//in this function we check the card type and add it to their specific list & also add it to _cardList.
switch (inNewCard._cardType)
{
case CardType.A: AList.Add(inNewCard);
break;
case CardType.B: BList.Add(inNewCard);
break;
case CardType.C: CList.Add(inNewCard);
break;
case CardType.D: DList.Add(inNewCard);
break;
case CardType.E: EList.Add(inNewCard);
break;
default:
break;
}
_CardList.Add(inNewCard);
}
void CardMatchThreeChecker()
{
if (AList.Count == 3)
{
SceneManager.LoadScene(1);
}
if (BList.Count == 3)
{
SceneManager.LoadScene(2);
}
if (CList.Count == 3)
{
SceneManager.LoadScene(3);
}
if (DList.Count == 3)
{
SceneManager.LoadScene(4);
}
if (EList.Count == 3)
{
SceneManager.LoadScene(5);
}
}
Problem - 1: with the above method is if I add any new cards in future i need to keep adding many lists on and on which is not advisable as the cards playable at a time can also be 20 or more
Problem -2 : There is no use of the List "_cardList" that contains all the cards instantiated.
Question - 1 Instead I want to check if any 3 things are similar in the _CardList List itself. Like every time I draw a card they all go and add themself to cardlist's List and I want to check if any three elements are similar in the list then perform the related action. I searched in internet but dint find or get an idea for what to do or how to try.
But Yet I tried a method but now im stuck in that too.Method metioned Below
These lines below come under a function called CardChecking() That is called in DrawButton(). Here Im saying it to check the list only if card count is more than 2 because we have a match only if 3 cards are there and we cant have a match if cards are less that 3 as we are checking if there are 3 similar cards. And as we want to check the elements of the list we have a for loop with (i,i 1,i 2) making it checking elements of the cardlist. Problem of this outside the snippet.
for (int i = 0; i < _CardList.Count; i )
{
if (_CardList.Count > 2)
{
if(_CardList[i]._cardType == _CardList[i 1]._cardType && _CardList[i 1]._cardType == _CardList[i 2]._cardType)
{
SceneManager.LoadScene(_CardList[i]._cardType.ToString());
}
else
{
continue;
}
}
}
Problem that I faced is: for example if i draw 3 cards my cardlist count would be 3, which will true my condition and check the function. If my cards are not of same type it goes to next for iteration at that time my i values will be cardList[1] || cardList[2] && cardList[2] || cardList[3] meaning my card values 1,2 & 3 on second iteration for my for-loop but when it checks for cardList[3] it throws Index out of range as my cardlist count is 3 and it doesnt have the 4th element the for loop is checking for. So Dont know How to overcome this.
CodePudding user response:
To solve Problem - 1,you can use Dictionary<CardType,List> :
Dictionary<CardType,List<Card>> cardListDictionary = new Dictionary<CardType, List<Card>>();
AddNewCard(Card inNewCard)
{
if (!cardListDictionary.TryGetValue(inNewCard._cardType,out var list))
{
list = new List<Card>();
cardListDictionary.Add(inNewCard._cardType,list);
}
list.Add(inNewCard);
}
To solve Problem - 2,implement CardChecking like this :
void CardChecking()
{
if (_CardList.Count > 2)
{
var type = _CardList[0]._cardType;
var count = 1;
for (int i = 1; i < _CardList.Count; i )
{
if(_CardList[i]._cardType == type)
{
count ;
if (count == 3)
{
SceneManager.LoadScene(type.ToString());
}
}
else
{
type = _CardList[i]._cardType;
count = 1;
}
}
}
}
CodePudding user response:
I assume the order of the cards doesn't matter and think you are looking for Linq GroupBy
// Just a simplified example since you didn't show your Card class
class Card
{
public CardType _cardType;
public Card(CardType type)
{
_cardType = type;
}
}
var list = new List<Card>
{
new Card(CardType.A),
new Card(CardType.B),
new Card(CardType.C),
new Card(CardType.C),
new Card(CardType.B),
new Card(CardType.B),
new Card(CardType.A),
new Card(CardType.A),
new Card(CardType.B)
};
// This creates separated groups according to the value of the card
var groups = list.GroupBy(c => c._cardType)
// Then it filters out only those groups that have 3 or more items
.Where(g => g.Count() >= 3);
// Then you can simply iterate through them
foreach (var @group in groups)
{
// The Key is the value the grouping was based on
// so in this example the Card._cardType
Debug.Log($"There are {@group.Count()} cads with cardType = {@group.Key}");
// you can also get all the according cards if needed
//var cards = @group.ToArray();
}
will print
There are 3 cards with cardType = A
There are 4 cards with cardType = B
Further if you just want to get the first group that has 3
items and anyway already know that there will never be two or more at the same time you could go
// again first create separate groups based on the value
var group = list.GroupBy(c => c._cardType)
// Pick the first group that has at least 3 items
// or NULL if there is none
.FirstOrDefault(g => g.Count() >= 3);
if (group != null)
{
Debug.Log($"Found a group of {group.Count()} for the value = {group.Key}!");
}
else
{
Debu.Log("There is no group with 3 elements yet...");
}
CodePudding user response:
Well, not sure if I get the whole picture right. Let me simplify the question, and if it works, then there is a solution.
Question: I have a list of cards, and I need to perform an action if there are 3 instances of the card of the same type in the list.
Answer: Use Linq to group the list by the type. Then, filter the result to find the "3-cards cases".
Here you go:
var answer = _CardList
.GroupBy(c => c.GetCardType())
.ToDictionary(g => g.Key, g => g.Count()) // Count by the card type.
.Where(x => x.Value >= 3) // Three or more cards of the same type.
.Select(x => x.Key) // Fetch the card type.
.FirstOrDefault(); // Only one match is needed.
if (answer != null) {
// answer is the type of the card that is counted 3 or more times.
}
If you need to detect all the "3-cards cases" remove FirstOrDefault
and deal with the collection.