【问题标题】:How to find if 3 elements in list are same in Unity3D如何在Unity3D中查找列表中的3个元素是否相同
【发布时间】:2021-12-11 13:35:17
【问题描述】:

我正在统一开发一款纸牌游戏。我有 5 张不同的牌(A、B、C、D、E),我手上最多可以有 6 张牌。而且我有一个按钮。所以一旦我抽出一张牌就点击按钮。所以所有这些功能都准备好了。但是我想在抽出的牌中执行一个动作。如果任何三张卡片相似。

例如:- 我抽出 5 张牌,抽出的牌按以下顺序排列:A、A、A、B、C 现在如您所见,我有 3-AI 想要执行 A 动作.或者如果卡片是这样的 A,B,C,C,C,E 如果想要执行 C 功能,因为有 3 个 C。因此,如果 3 张卡片类型相同,我想执行与之相关的操作。

所以为了简单起见,我将解释一下流程。 Card-Draw Button 点击​​ -> 每次点击继续获取卡片 -> 将卡片添加到名为 _CardList 的列表中并对列表中的卡片进行排序 -> 如果有 3 张相同的卡片,则执行操作。我在最后一次检查卡时遇到问题。

我已经做了一个方法,但它超级庞大,不可取。因此,如果你们能在这方面帮助我,那将对我有很大帮助。谢谢,我会用我尝试的方法在下面发布我所有的疑问和问题。

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 the 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 
 card.GetComponent<Cards>()._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);
        }
}


问题 - 1:使用上述方法是,如果我将来添加任何新卡,我需要继续添加许多列表,并且不建议在这些列表上添加,因为一次可玩的卡也可以是 20 或更多

问题-2:没有使用包含所有实例化卡片的列表“_cardList”。

问题 - 1 相反,我想检查 _CardList 列表本身中是否有任何 3 件事相似。就像每次我抽一张牌一样,他们都会将自己添加到卡片列表的列表中,我想检查列表中是否有任何三个元素相似,然后执行相关操作。我在互联网上搜索过,但没有找到或知道该做什么或如何尝试。

但是我尝试了一种方法,但现在我也陷入了这种状态。方法在下面提到

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;
                }
            }
        }

我面临的问题是:例如,如果我抽了 3 张牌,我的牌张数将为 3,这将满足我的条件并检查功能。如果我的卡不是同一类型,那么它将进入下一个迭代,那时我的 i 值将是 cardList[1] ||卡片列表[2] && 卡片列表[2] || cardList[3] 表示我的卡值在我的 for 循环的第二次迭代中为 1,2 和 3,但是当它检查 cardList[3] 时,它会抛出索引超出范围,因为我的卡列表计数为 3,并且它没有第 4 个元素for 循环正在检查。所以不知道如何克服这个。

【问题讨论】:

    标签: c# list unity3d card


    【解决方案1】:

    要解决问题 - 1,您可以使用 Dictionary

        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);
        }
    

    为了解决问题 - 2,像这样实现 CardChecking :

    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;
                    }
                
                }
            }
        }
    

    【讨论】:

    • 您能简要介绍一下 Dictionary 的工作原理吗?就像它如何减少添加许多列表和新卡片类型一样。
    • 对于 Linq 查询来说,这是一个非常好的替代方案,因为它不会一直迭代卡片列表
    • 您可以阅读 Microsoft 文档以了解 Dictionary 的工作原理。docs.microsoft.com/en-us/dotnet/api/…
    • @JianSun 只是一个疑问。我在我的问题中看到了 -1。我试着把问题说清楚,并且也给出了我所有不同的尝试来获得解决方案。还有什么我应该让我的问题更好的吗?征求意见。所以我可以尝试并朝着它努力
    • 使用字典,您甚至不需要稍后查看列表..只需执行例如foreach(var kvp in cardListDictionary){ if(kvp.Value.Count &gt;= 3) { SceneManager.LoadScene((int)kvp.Key); } }
    【解决方案2】:

    我认为卡片的顺序无关紧要,并认为您正在寻找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();
    }
    

    将打印

    There are 3 cards with cardType = A
    There are 4 cards with cardType = B
    

    此外,如果您只想获得第一个拥有 3 项目的组,并且无论如何已经知道永远不会同时有两个或更多,那么您可以去

    // 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...");
    }
    

    【讨论】:

    • 以前从未使用过 Linq。但会研究它。但想澄清一件事。我已经有一门叫卡的课了。 list.GroupBy(c =&gt; c.value).Where(g =&gt; g.Count() &gt;= 3); 我正在尝试做这样的事情,但在 _cardlist 列表中。我的任何三个元素都有相同的 cardType。
    • 如前所述,我没有看到您的卡类实现,所以这只是一个示例......只需将 value 替换为您的字段,例如c =&gt; c._cardType .. c 基本上来自foreach(var c in list) ;)
    • 非常感谢您的回答......
    • 只是一个疑问。我在我的问题中看到了 -1。我试着把问题说清楚,并且也给出了我所有不同的尝试来获得解决方案。还有什么我应该让我的问题更好的吗?征求意见。所以我可以尝试并朝着它努力
    【解决方案3】:

    嗯,我不确定我是否理解了整个画面。让我把问题简单化一下,如果它有效,那么就有一个解决方案。

    问题:我有一个卡片列表,如果列表中有 3 个相同类型的卡片实例,我需要执行一个操作。

    答案:使用 Linq 按类型对列表进行分组。然后,过滤结果以找到“三张牌”。

    给你:

    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.
    }
    

    如果您需要检测所有“三张牌案”,请删除 FirstOrDefault 并处理集合。

    【讨论】:

    • a) 这基本上就是我所说的here ;) 和 b) 目前这行不通!在您执行 Select 之后,IEnumerable 类型现在是 CardType,这是一个 enum 并且 从不 null ;)
    • @real4X。感谢您的回复....我需要查看 Linq。所以我会先这样做,这个答案帮助了我
    • @derHugo 当我开始写我的答案时,没有其他答案。抱歉,没有进行快速刷新:) 至于 enum/null 问题,您在技术上是正确的。但是,这是一个原型代码。我从未尝试过 IRL。细微的语法更改可以解决它,但我认为这并不重要。 FWIW,GetCardType() 可以返回一个字符串,而不是一个枚举。不行吗?
    • @real4x 目前它还没有达到它的目的,所以我会说是的,这很重要 ^^ 好吧,关于时间安排很公平,但请注意,两个好的答案已经在你之前 20 分钟发布了; ) ... 在 OP 的代码中没有 GetCardType 而是 Card._cardType 类型为 CardType ;) 你为什么要在那里返回一个字符串?
    • @derHugo 我不在这个网站上赚取分数。我给了我的选择。有帮助吗?好的。没有?没什么大不了的,这个论坛上还有其他有合适技能的人。
    猜你喜欢
    • 2012-08-22
    • 2020-11-20
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 2011-04-20
    • 1970-01-01
    • 2018-09-14
    相关资源
    最近更新 更多