Example #1
0
        public TriadDeck(IEnumerable <int> knownCardIds, IEnumerable <int> unknownCardlIds)
        {
            TriadCardDB cardDB = TriadCardDB.Get();

            knownCards = new List <TriadCard>();
            foreach (int id in knownCardIds)
            {
                TriadCard card = cardDB.cards[id];
                if (card != null && card.IsValid())
                {
                    knownCards.Add(card);
                }
            }

            unknownCardPool = new List <TriadCard>();
            foreach (int id in unknownCardlIds)
            {
                TriadCard card = cardDB.cards[id];
                if (card != null && card.IsValid())
                {
                    unknownCardPool.Add(card);
                }
            }

            UpdateDeckId();
        }
Example #2
0
        public bool Load()
        {
            List <TriadCard> loadedCards = new List <TriadCard>();
            int maxLoadedId = 0;

            try
            {
                XmlDocument xdoc       = new XmlDocument();
                Stream      dataStream = AssetManager.Get().GetAsset(DBPath);
                xdoc.Load(dataStream);

                foreach (XmlNode cardNode in xdoc.DocumentElement.ChildNodes)
                {
                    XmlElement cardElem = (XmlElement)cardNode;
                    if (cardElem != null && cardElem.Name == "card")
                    {
                        try
                        {
                            ETriadCardRarity cardRarity = ETriadCardRarity.Common;
                            ETriadCardType   cardType   = ETriadCardType.None;
                            bool             bHasRarity = TryParseCardRarity(cardElem.GetAttribute("rarity"), out cardRarity);
                            bool             bHasType   = TryParseCardType(cardElem.GetAttribute("type"), out cardType);

                            if (bHasType && bHasRarity)
                            {
                                TriadCard newCard = new TriadCard(
                                    int.Parse(cardElem.GetAttribute("id")),
                                    WebUtility.HtmlDecode(cardElem.GetAttribute("name")),
                                    cardElem.GetAttribute("icon"),
                                    cardRarity,
                                    cardType,
                                    ParseCardSideNum(cardElem.GetAttribute("up")),
                                    ParseCardSideNum(cardElem.GetAttribute("dn")),
                                    ParseCardSideNum(cardElem.GetAttribute("lt")),
                                    ParseCardSideNum(cardElem.GetAttribute("rt")),
                                    int.Parse(cardElem.GetAttribute("sort")));

                                if (newCard.IsValid())
                                {
                                    loadedCards.Add(newCard);
                                    maxLoadedId = Math.Max(maxLoadedId, newCard.Id);
                                }
                                else
                                {
                                    Logger.WriteLine("Loading failed! ob[" + newCard + "], xml:" + cardElem.OuterXml);
                                }
                            }
                            else
                            {
                                Logger.WriteLine("Loading failed! xml:" + cardElem.OuterXml);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.WriteLine("Loading failed! Exception:" + ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            if (loadedCards.Count > 0)
            {
                while (cards.Count < (maxLoadedId + 1))
                {
                    cards.Add(null);
                }

                foreach (TriadCard card in loadedCards)
                {
                    cards[card.Id] = card;
                }
            }

            sameNumberMap.Clear();
            int sameNumberId = 0;

            for (int Idx1 = 0; Idx1 < cards.Count; Idx1++)
            {
                TriadCard card1 = cards[Idx1];
                if (card1 != null && card1.SameNumberId < 0)
                {
                    bool bHasSameNumberCards = false;
                    for (int Idx2 = (Idx1 + 1); Idx2 < cards.Count; Idx2++)
                    {
                        TriadCard card2 = cards[Idx2];
                        if (card2 != null && card2.SameNumberId < 0)
                        {
                            bool bHasSameNumbers =
                                (card1.Sides[0] == card2.Sides[0]) &&
                                (card1.Sides[1] == card2.Sides[1]) &&
                                (card1.Sides[2] == card2.Sides[2]) &&
                                (card1.Sides[3] == card2.Sides[3]);

                            bHasSameNumberCards = bHasSameNumberCards || bHasSameNumbers;
                            if (bHasSameNumbers)
                            {
                                if (!sameNumberMap.ContainsKey(sameNumberId))
                                {
                                    sameNumberMap.Add(sameNumberId, new List <TriadCard>());
                                    sameNumberMap[sameNumberId].Add(card1);
                                    card1.SameNumberId = sameNumberId;
                                }

                                sameNumberMap[sameNumberId].Add(card2);
                                card2.SameNumberId = sameNumberId;
                            }
                        }
                    }

                    if (bHasSameNumberCards)
                    {
                        sameNumberId++;
                    }
                }
            }

            Logger.WriteLine("Loaded cards: " + loadedCards.Count + ", same sides: " + sameNumberMap.Count);
            return(loadedCards.Count > 0);
        }
        private bool FindCardPool(List <TriadCard> allCards, List <TriadGameModifier> modifiers, List <TriadCard> lockedCards)
        {
            currentPool = new CardPool();

            int maxRarityNum = Enum.GetValues(typeof(ETriadCardRarity)).Length;
            int priRarityNum = (int)commonRarity + 1;

            int[] mapAvailRarity = new int[maxRarityNum];

            // special case: don't include any rare slots with reverse rule if there's enough cards in common list
            bool hasReverseMod   = false;
            bool hasAscensionMod = false;

            foreach (TriadGameModifier mod in modifiers)
            {
                if (mod.GetType() == typeof(TriadGameModifierReverse))
                {
                    hasReverseMod = true;
                }
                else if (mod.GetType() == typeof(TriadGameModifierAscention))
                {
                    hasAscensionMod = true;
                }
            }

            // find number of priority lists based on unique rarity limits
            List <ETriadCardRarity> priRarityThr = new List <ETriadCardRarity>();

            for (int idxR = priRarityNum; idxR < maxRarityNum; idxR++)
            {
                ETriadCardRarity testRarity = (ETriadCardRarity)idxR;
                if (!hasReverseMod && maxSlotsPerRarity.ContainsKey(testRarity) && maxSlotsPerRarity[testRarity] > 0)
                {
                    mapAvailRarity[idxR]      = maxSlotsPerRarity[testRarity];
                    mapAvailRarity[idxR - 1] -= maxSlotsPerRarity[testRarity];

                    priRarityThr.Add(testRarity);
                }
            }

            if (debugMode)
            {
                Logger.WriteLine("FindCardPool> priRarityThr:{0}, maxAvail:[{1},{2},{3},{4},{5}], reverse:{6}, ascention:{7}", priRarityThr.Count,
                                 mapAvailRarity[0], mapAvailRarity[1], mapAvailRarity[2], mapAvailRarity[3], mapAvailRarity[4],
                                 hasReverseMod, hasAscensionMod);
            }

            // check rarity of locked cards, eliminate pri list when threshold is matched
            // when multiple pri rarities are locked, start eliminating from pool above
            // e.g. 2x 4 star locked => 4 star out, 5 star out
            currentPool.deckSlotTypes = new int[lockedCards.Count];
            int numLockedCards = 0;

            for (int idx = 0; idx < lockedCards.Count; idx++)
            {
                TriadCard card = lockedCards[idx];
                if (card != null)
                {
                    if (card.Rarity > commonRarity)
                    {
                        for (int testR = (int)card.Rarity; testR <= maxRarityNum; testR++)
                        {
                            if (mapAvailRarity[testR] > 0)
                            {
                                mapAvailRarity[testR]--;
                                break;
                            }
                        }
                    }

                    currentPool.deckSlotTypes[idx] = DeckSlotLocked;
                    numLockedCards++;
                }
                else
                {
                    currentPool.deckSlotTypes[idx] = DeckSlotCommon;
                }
            }

            if (debugMode)
            {
                Logger.WriteLine(">> adjusted for locking, numLocked:{0}, maxAvail:[{1},{2},{3},{4},{5}]", numLockedCards, mapAvailRarity[0], mapAvailRarity[1], mapAvailRarity[2], mapAvailRarity[3], mapAvailRarity[4]);
            }
            if (numLockedCards == lockedCards.Count)
            {
                return(false);
            }

            List <CardScoreData>         commonScoredList = new List <CardScoreData>();
            List <List <CardScoreData> > priScoredList    = new List <List <CardScoreData> >();

            for (int idxP = 0; idxP < priRarityThr.Count; idxP++)
            {
                priScoredList.Add(new List <CardScoreData>());
            }

            // reverse priority thresholds, idx:0 becomes strongest card
            priRarityThr.Reverse();

            // assign each owned card to scored lists
            foreach (TriadCard card in allCards)
            {
                if (card == null || !card.IsValid())
                {
                    continue;
                }

                // try to guess how good card will perform
                // - avg of sides
                // - std of sides
                // - max of sides
                // - rarity (should be reflected by sides already)
                // - corners with same number
                // - max corner number

                int   numberMax        = Math.Max(Math.Max(card.Sides[0], card.Sides[1]), Math.Max(card.Sides[2], card.Sides[3]));
                int   numberSum        = card.Sides[0] + card.Sides[1] + card.Sides[2] + card.Sides[3];
                float numberAvg        = numberSum / 4.0f;
                float numberMeanSqDiff =
                    ((card.Sides[0] - numberAvg) * (card.Sides[0] - numberAvg)) +
                    ((card.Sides[1] - numberAvg) * (card.Sides[1] - numberAvg)) +
                    ((card.Sides[2] - numberAvg) * (card.Sides[2] - numberAvg)) +
                    ((card.Sides[3] - numberAvg) * (card.Sides[3] - numberAvg));
                float numberStd = (float)Math.Sqrt(numberMeanSqDiff / 4);

                int cornerNum  = 0;
                int numCorners = 0;
                if (card.Sides[0] == card.Sides[1])
                {
                    numCorners++; cornerNum = Math.Max(cornerNum, card.Sides[0]);
                }
                if (card.Sides[1] == card.Sides[2])
                {
                    numCorners++; cornerNum = Math.Max(cornerNum, card.Sides[1]);
                }
                if (card.Sides[2] == card.Sides[3])
                {
                    numCorners++; cornerNum = Math.Max(cornerNum, card.Sides[2]);
                }
                if (card.Sides[3] == card.Sides[0])
                {
                    numCorners++; cornerNum = Math.Max(cornerNum, card.Sides[3]);
                }

                CardScoreData scoredCard = new CardScoreData()
                {
                    card = card
                };
                scoredCard.score =
                    (numberAvg * scoreAvgSides) +
                    (numberStd * scoreStdSides) +
                    (numberMax * scoreMaxSides) +
                    (numCorners * scoreSameCorners) +
                    (cornerNum * scoreMaxCorner) +
                    ((int)card.Rarity * scoreRarity);

                foreach (TriadGameModifier mod in modifiers)
                {
                    mod.OnScoreCard(card, ref scoredCard.score);
                }

                for (int idxP = 0; idxP < priRarityThr.Count; idxP++)
                {
                    if (card.Rarity <= priRarityThr[idxP])
                    {
                        priScoredList[idxP].Add(scoredCard);
                    }
                }

                if (card.Rarity <= commonRarity)
                {
                    commonScoredList.Add(scoredCard);
                }
            }

            if (debugMode)
            {
                Logger.WriteLine(">> card lists sorted, common:{0}", commonScoredList.Count);
            }
            bool isPoolValid = (commonScoredList.Count > 0);

            if (isPoolValid)
            {
                int numPriLists = 0;
                int deckSlotIdx = isOrderImportant ? 1 : 0;

                for (int idx = 0; idx < priScoredList.Count; idx++)
                {
                    int numAvail = mapAvailRarity[(int)priRarityThr[idx]];
                    if (debugMode)
                    {
                        Logger.WriteLine("  pri list[{0}]:{1}, rarity:{2}, avail:{3}", idx, priScoredList[idx].Count, priRarityThr[idx], numAvail);
                    }
                    if ((numAvail > 0) && (priScoredList[idx].Count > 0))
                    {
                        // initial deckSlotIdx should be already past only available spot (e.g. all slots but [0] are locked), make sure to wrap around
                        // find fist available Common slot to overwrite with priority list, repeat numAvail times
                        for (int idxAvail = 0; idxAvail < numAvail; idxAvail++)
                        {
                            for (int idxD = 0; idxD < currentPool.deckSlotTypes.Length; idxD++)
                            {
                                if (currentPool.deckSlotTypes[deckSlotIdx] == DeckSlotCommon)
                                {
                                    break;
                                }

                                deckSlotIdx++;
                            }

                            currentPool.deckSlotTypes[deckSlotIdx] = numPriLists;
                        }

                        numPriLists++;
                    }
                    else
                    {
                        priScoredList[idx].Clear();
                    }
                }

                // ascension modifier special case: same type across all pools is best
                // aply after priority lists were trimmed
                if (hasAscensionMod)
                {
                    ApplyAscentionFilter(commonScoredList, priScoredList);
                }

                if (numPriLists > 0)
                {
                    currentPool.priorityLists = new TriadCard[numPriLists][];
                    if (debugMode)
                    {
                        Logger.WriteLine(">> num priority lists:{0}", numPriLists);
                    }

                    int idxP = 0;
                    for (int idxL = 0; idxL < priScoredList.Count; idxL++)
                    {
                        int maxPriorityToUse = Math.Min(numPriorityToBuild, priScoredList[idxL].Count);
                        if (maxPriorityToUse > 0)
                        {
                            currentPool.priorityLists[idxP] = new TriadCard[maxPriorityToUse];
                            priScoredList[idxL].Sort();

                            for (int idxC = 0; idxC < maxPriorityToUse; idxC++)
                            {
                                currentPool.priorityLists[idxP][idxC] = priScoredList[idxL][idxC].card;
                            }

                            idxP++;
                        }
                    }
                }

                // adjust pool of common cards based on avail common slots
                // - all common: use requested size
                // - scale down 20% per every priority list slot
                int numPriSlots = 0;
                for (int idx = 0; idx < currentPool.deckSlotTypes.Length; idx++)
                {
                    numPriSlots += (currentPool.deckSlotTypes[idx] >= 0) ? 1 : 0;
                }

                int maxCommonToUse = Math.Min(numCommonToBuild - (numCommonToBuild * numPriSlots * numCommonPctToDropPerPriSlot / 100), commonScoredList.Count);
                if (debugMode)
                {
                    Logger.WriteLine(">> adjusting common pool based on priSlots:{0} and drop:{1}% => {2}", numPriSlots, numCommonPctToDropPerPriSlot, maxCommonToUse);
                }

                currentPool.commonList = new TriadCard[maxCommonToUse];
                commonScoredList.Sort();

                for (int idx = 0; idx < currentPool.commonList.Length; idx++)
                {
                    currentPool.commonList[idx] = commonScoredList[idx].card;
                }
            }

            if (debugMode)
            {
                Logger.WriteLine(">> deck slot types:[{0}, {1}, {2}, {3}, {4}]", currentPool.deckSlotTypes[0], currentPool.deckSlotTypes[1], currentPool.deckSlotTypes[2], currentPool.deckSlotTypes[3], currentPool.deckSlotTypes[4]);
            }
            return(isPoolValid);
        }
Example #4
0
        private Dictionary <int, TriadCard> ParseCards(string folderPath)
        {
            Dictionary <int, ETriadCardType>    typeMap     = ParseCardTypes(folderPath);
            Dictionary <int, string>            nameMap     = ParseCardNames(folderPath);
            Dictionary <string, ETriadCardType> typeNameMap = CreateCardTypeNameMap();

            string patternRarity = "TripleTriadCardRarity#";

            Dictionary <int, TriadCard> loadedCards = new Dictionary <int, TriadCard>();
            List <string[]>             cardData    = ParseCSVFile(folderPath + "TripleTriadCardResident.csv");

            if (cardData.Count > 0 && cardData[0].Length == 10)
            {
                for (int Idx = 0; Idx < cardData.Count; Idx++)
                {
                    int keyIdx = int.Parse(cardData[Idx][0]);

                    int rarityIdx = 0;
                    if (cardData[Idx][6].StartsWith(patternRarity))
                    {
                        rarityIdx = int.Parse(cardData[Idx][6].Substring(patternRarity.Length));
                    }
                    else
                    {
                        rarityIdx = int.Parse(cardData[Idx][6]);
                    }

                    ETriadCardType cardType = ETriadCardType.None;
                    string         typeDef  = cardData[Idx][7];
                    if (typeDef.Length == 1)
                    {
                        int typeDefInt = int.Parse(typeDef);
                        cardType = typeMap[typeDefInt];
                    }
                    else if (typeDef.Length > 0)
                    {
                        cardType = typeNameMap[typeDef];
                    }

                    int    iconId   = 82500 + keyIdx;
                    string iconPath = iconId.ToString("000000") + ".png";

                    int numUp    = int.Parse(cardData[Idx][2]);
                    int numDown  = int.Parse(cardData[Idx][3]);
                    int numRight = int.Parse(cardData[Idx][4]);
                    int numLeft  = int.Parse(cardData[Idx][5]);

                    if (numUp > 0 && numDown > 0 && numRight > 0 && numLeft > 0)
                    {
                        TriadCard cardOb = new TriadCard(0, nameMap[keyIdx], iconPath,
                                                         (ETriadCardRarity)(rarityIdx - 1), cardType,
                                                         numUp, numDown, numLeft, numRight,
                                                         int.Parse(cardData[Idx][9]));

                        if (cardOb.IsValid())
                        {
                            loadedCards.Add(keyIdx, cardOb);
                        }
                    }
                }
            }
            else
            {
                throw new Exception("Unable to parse cards from csv!");
            }

            return(loadedCards);
        }