public void Initialize(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            this.npc         = npc;
            numPossibleDecks = 1;
            numTestedDecks   = 0;
            numMsElapsed     = 0;

            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            currentSolver = new TriadGameSession();
            currentSolver.modifiers.AddRange(npc.Rules);
            currentSolver.modifiers.AddRange(regionMods);
            currentSolver.UpdateSpecialRules();

            isOrderImportant = false;
            foreach (TriadGameModifier mod in currentSolver.modifiers)
            {
                isOrderImportant = isOrderImportant || mod.IsDeckOrderImportant();
            }

            bool foundCards = FindCardPool(playerDB.ownedCards, currentSolver.modifiers, lockedCards);

            if (foundCards)
            {
                UpdatePossibleDeckCount();
            }
        }
Beispiel #2
0
        private void contextMenuStripPickCard_Opened(object sender, EventArgs e)
        {
            toolStripComboBoxPick.BeginUpdate();

            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();
            TriadCardDB      cardsDB  = TriadCardDB.Get();
            int numExpected           = toolStripMenuOnlyOwned.Checked ? playerDB.ownedCards.Count : cardsDB.cards.Count;

            if (numExpected != toolStripComboBoxPick.Items.Count)
            {
                toolStripComboBoxPick.Items.Clear();
                foreach (TriadCard card in cardsDB.cards)
                {
                    if (card != null && (!toolStripMenuOnlyOwned.Checked || playerDB.ownedCards.Contains(card)))
                    {
                        toolStripComboBoxPick.Items.Add(new DeckCardPicker(card));
                    }
                }
            }

            for (int Idx = 0; Idx < toolStripComboBoxPick.Items.Count; Idx++)
            {
                DeckCardPicker cardOb = (DeckCardPicker)toolStripComboBoxPick.Items[Idx];
                if (cardOb.Card == cardClickOwner.GetCard())
                {
                    toolStripComboBoxPick.SelectedIndex = Idx;
                    break;
                }
            }

            toolStripComboBoxPick.EndUpdate();
            toolStripComboBoxPick.Focus();
        }
Beispiel #3
0
        public void PrepareStats(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards, out string numOwnedStr, out string numPossibleStr)
        {
            bool bIsOrderImportant = false;

            foreach (TriadGameModifier mod in npc.Rules)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }
            foreach (TriadGameModifier mod in regionMods)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }

            //TriadCardDB playerDB = TriadCardDB.Get();
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            int numOwned = playerDB.ownedCards.Count;

            numOwnedStr = numOwned.ToString();

            if (bUseScoredBuilder)
            {
                UpdatePossibleDeckCount(numRareToBuild, numCommonToBuild, lockedCards, bIsOrderImportant);
            }
            else
            {
                UpdatePossibleDeckCount(numOwned, bIsOrderImportant);
            }

            numPossibleStr = numPossibleDecks.ToString("N0");
        }
Beispiel #4
0
        public void InitializeAssets(ImageList cardImageList)
        {
            cardImages = cardImageList;

            for (int Idx = 0; Idx < boardControls.Length; Idx++)
            {
                boardControls[Idx].cardIcons = cardImages;
            }
            for (int Idx = 0; Idx < redDeckKnownCards.Length; Idx++)
            {
                redDeckKnownCards[Idx].cardIcons   = cardImages;
                redDeckUnknownCards[Idx].cardIcons = cardImages;
            }

            deckCtrlBlue.cardIcons      = cardImages;
            deckCtrlRed.cardIcons       = cardImages;
            deckCtrlBlue.allowRearrange = false;
            deckCtrlRed.allowRearrange  = false;
            deckCtrlBlue.enableHitTest  = false;
            deckCtrlRed.enableHitTest   = false;
            deckCtrlBlue.drawMode       = ECardDrawMode.ImageOnly;
            deckCtrlRed.drawMode        = ECardDrawMode.ImageOnly;
            deckCtrlBlue.clickAction    = EDeckCtrlAction.None;
            deckCtrlRed.clickAction     = EDeckCtrlAction.None;
            deckCtrlBlue.deckOwner      = ETriadCardOwner.Blue;
            deckCtrlRed.deckOwner       = ETriadCardOwner.Red;

            checkBoxAutoScan.Checked = PlayerSettingsDB.Get().useAutoScan;
        }
Beispiel #5
0
        public ETriadDeckState GetDeckState()
        {
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            int[] rarityCounters = new int[5];

            for (int DeckIdx = 0; DeckIdx < knownCards.Count; DeckIdx++)
            {
                TriadCard deckCard = knownCards[DeckIdx];
                bool      bIsOwned = playerDB.ownedCards.Contains(deckCard);
                if (!bIsOwned)
                {
                    return(ETriadDeckState.MissingCards);
                }

                for (int TestIdx = 0; TestIdx < knownCards.Count; TestIdx++)
                {
                    if ((TestIdx != DeckIdx) && knownCards[TestIdx].Equals(deckCard))
                    {
                        return(ETriadDeckState.HasDuplicates);
                    }
                }

                rarityCounters[(int)deckCard.Rarity]++;
            }

            int numRare5  = rarityCounters[(int)ETriadCardRarity.Legendary];
            int numRare45 = rarityCounters[(int)ETriadCardRarity.Epic] + numRare5;

            // temporary, can be removed once all game clients are on 5.5+ version
            // step up your releases SE :P
            bool isUsingRulesVer54 =
                LocalizationDB.Languages[LocalizationDB.UserLanguageIdx] == "cn" ||
                LocalizationDB.Languages[LocalizationDB.UserLanguageIdx] == "ko";

            if (isUsingRulesVer54)
            {
                if (numRare45 > 1)
                {
                    // reuse "single 5 star" error, don't have better description anymore
                    return(ETriadDeckState.TooMany5Star);
                }
            }
            else
            {
                if (numRare5 > 1)
                {
                    return(ETriadDeckState.TooMany5Star);
                }
                else if (numRare45 > 2)
                {
                    return(ETriadDeckState.TooMany4Star);
                }
            }

            return(ETriadDeckState.Valid);
        }
Beispiel #6
0
        private void buttonAdd_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Yes;

            deck.Name = textBox1.Text;
            PlayerSettingsDB.Get().UpdateFavDeck(slotIdx, deck);

            Close();
        }
Beispiel #7
0
        public ETriadDeckState GetDeckState()
        {
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            int[] rarityCounters = new int[5];

            for (int DeckIdx = 0; DeckIdx < knownCards.Count; DeckIdx++)
            {
                TriadCard deckCard = knownCards[DeckIdx];
                bool      bIsOwned = playerDB.ownedCards.Contains(deckCard);
                if (!bIsOwned)
                {
                    return(ETriadDeckState.MissingCards);
                }

                for (int TestIdx = 0; TestIdx < knownCards.Count; TestIdx++)
                {
                    if ((TestIdx != DeckIdx) && knownCards[TestIdx].Equals(deckCard))
                    {
                        return(ETriadDeckState.HasDuplicates);
                    }
                }

                rarityCounters[(int)deckCard.Rarity]++;
            }

            int numRare45   = rarityCounters[(int)ETriadCardRarity.Epic] + rarityCounters[(int)ETriadCardRarity.Legendary];
            int numRare345  = rarityCounters[(int)ETriadCardRarity.Rare] + numRare45;
            int numRare2345 = rarityCounters[(int)ETriadCardRarity.Uncommon] + numRare345;

            if (playerDB.ownedCards.Count < 30)
            {
                if (numRare2345 > 1)
                {
                    return(ETriadDeckState.TooManyRaresUncomon);
                }
            }
            else if (playerDB.ownedCards.Count < 60)
            {
                if (numRare345 > 1)
                {
                    return(ETriadDeckState.TooManyRaresRare);
                }
            }
            else
            {
                if (numRare45 > 1)
                {
                    return(ETriadDeckState.TooManyRaresEpic);
                }
            }

            return(ETriadDeckState.Valid);
        }
Beispiel #8
0
        private void buttonRemove_Click(object sender, EventArgs e)
        {
            DialogResult ret = MessageBox.Show("Favorite deck will be removed, do you want to continue?", Text, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (ret == DialogResult.Yes)
            {
                DialogResult = DialogResult.No;
                PlayerSettingsDB.Get().UpdateFavDeck(slotIdx, null);

                Close();
            }
        }
        private void buttonOk_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            if (comboBox1.SelectedItem != null)
            {
                TriadCard card = comboBox1.SelectedItem as TriadCard;

                // check modified numbers
                for (int idx = 0; idx < 4; idx++)
                {
                    if (card.Sides[idx] != cardState.sideNumber[idx])
                    {
                        ImageHashData digitPattern = new ImageHashData()
                        {
                            type = EImageHashType.CardNumber, previewBounds = cardState.sideInfo[idx].scanBox, previewContextBounds = cardState.scanBox, isKnown = true
                        };
                        digitPattern.CalculateHash(cardState.sideInfo[idx].hashValues);
                        digitPattern.ownerOb = card.Sides[idx];

                        PlayerSettingsDB.Get().RemoveKnownHash(digitPattern);

                        if (card.Sides[idx] != cardState.sideInfo[idx].matchNum)
                        {
                            PlayerSettingsDB.Get().AddKnownHash(digitPattern);
                            cardState.sideInfo[idx].hasOverride = true;
                        }

                        cardState.sideNumber[idx] = card.Sides[idx];
                        cardState.card            = card;
                        cardState.failedMatching  = false;
                        DialogResult = DialogResult.OK;
                    }
                }

                // check multicard hash
                if (comboBox1.Items.Count > 1 &&
                    cardState.cardImageHash != null &&
                    cardState.card != card)
                {
                    cardState.cardImageHash.ownerOb = card;

                    PlayerSettingsDB.Get().RemoveKnownHash(cardState.cardImageHash);
                    PlayerSettingsDB.Get().AddKnownHash(cardState.cardImageHash);

                    cardState.card = card;
                    DialogResult   = DialogResult.OK;
                }
            }

            Close();
        }
Beispiel #10
0
        private void toolStripMenuOnlyOwned_CheckedChanged(object sender, EventArgs e)
        {
            toolStripComboBoxPick.Items.Clear();

            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();
            TriadCardDB      cardsDB  = TriadCardDB.Get();

            foreach (TriadCard card in cardsDB.cards)
            {
                if (card != null && (!toolStripMenuOnlyOwned.Checked || playerDB.ownedCards.Contains(card)))
                {
                    toolStripComboBoxPick.Items.Add(new DeckCardPicker(card));
                }
            }
        }
Beispiel #11
0
        public bool MergeWithContent(string jsonString)
        {
            PlayerSettingsDB mergeDB            = new PlayerSettingsDB();
            bool             bLoaded            = mergeDB.LoadFromJson(jsonString);
            bool             bHadUniqueSettings = false;

            if (bLoaded)
            {
                bool bUpdatedOwnedCards = false;
                foreach (TriadCard card in mergeDB.ownedCards)
                {
                    if (!ownedCards.Contains(card))
                    {
                        ownedCards.Add(card);
                        bUpdatedOwnedCards = true;
                    }
                }
                bHadUniqueSettings = bHadUniqueSettings || (ownedCards.Count > mergeDB.ownedCards.Count);

                bool bUpdatedNpcs = false;
                foreach (TriadNpc npc in mergeDB.completedNpcs)
                {
                    if (!completedNpcs.Contains(npc))
                    {
                        completedNpcs.Add(npc);
                        bUpdatedNpcs = true;
                    }
                }
                bHadUniqueSettings = bHadUniqueSettings || (completedNpcs.Count > mergeDB.completedNpcs.Count);

                bool bUpdatedDecks = false;
                foreach (KeyValuePair <TriadNpc, TriadDeck> kvp in mergeDB.lastDeck)
                {
                    if (!lastDeck.ContainsKey(kvp.Key))
                    {
                        lastDeck.Add(kvp.Key, kvp.Value);
                    }

                    // replace existing? skip for now...
                }
                bHadUniqueSettings = bHadUniqueSettings || (lastDeck.Count > mergeDB.lastDeck.Count);

                OnUpdated.Invoke(bUpdatedOwnedCards, bUpdatedNpcs, bUpdatedDecks);
            }

            return(bHadUniqueSettings);
        }
Beispiel #12
0
        private Rectangle GetGameWindowBounds(HandleRef windowHandle)
        {
            Rectangle result       = GetGameWindowBoundsRaw(windowHandle);
            Screen    activeScreen = Screen.FromHandle(windowHandle.Handle);

            if (result.Width > 0 && PlayerSettingsDB.Get().useFullScreenCapture)
            {
                result       = Screen.GetBounds(result);
                activeScreen = Screen.FromRectangle(result);
            }

            if (activeScreen != cachedScreen)
            {
                cachedScreen = activeScreen;

                DEVMODE dm = new DEVMODE();
                dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
                EnumDisplaySettings(cachedScreen.DeviceName, -1, ref dm);

                if (dm.dmPelsWidth == cachedScreen.Bounds.Width)
                {
                    cachedScreenScaling = 1.0f;
                }
                else
                {
                    cachedScreenScaling = (float)cachedScreen.Bounds.Width / (float)dm.dmPelsWidth;
                }

                if (Logger.IsSuperVerbose())
                {
                    Logger.WriteLine("GetGameWindowBounds, caching screen data: bounds:{0}, pelsWidth:{1} => scale:{2}", cachedScreen.Bounds, dm.dmPelsWidth, cachedScreenScaling);
                }
            }

            if (cachedScreenScaling != 1.0f)
            {
                result.X      = cachedScreen.Bounds.X + (int)((result.X - cachedScreen.Bounds.X) / cachedScreenScaling);
                result.Y      = cachedScreen.Bounds.Y + (int)((result.Y - cachedScreen.Bounds.Y) / cachedScreenScaling);
                result.Width  = (int)(result.Width / cachedScreenScaling);
                result.Height = (int)(result.Height / cachedScreenScaling);
            }

            return(result);
        }
Beispiel #13
0
        private void buttonOk_Click(object sender, EventArgs e)
        {
            HashOwnerItem hashComboItem = (HashOwnerItem)comboBoxOwner.SelectedItem;

            if (hashComboItem != null)
            {
                if (hashData.ownerOb == null || (labelHashOrg.Text != hashComboItem.SourceObject.ToString()))
                {
                    PlayerSettingsDB.Get().RemoveKnownHash(hashData);
                    hashData.ownerOb       = hashComboItem.SourceObject;
                    hashData.matchDistance = 0;
                    hashData.isAuto        = false;

                    PlayerSettingsDB.Get().AddKnownHash(hashData);
                }
            }

            DialogResult = DialogResult.OK;
            Close();
        }
Beispiel #14
0
        public void InitDeck(int slotIdx, TriadDeck copyFrom, ImageList cardImages, ImageList cardTypes, ImageList cardRarity)
        {
            this.slotIdx = slotIdx;

            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            if (slotIdx < playerDB.favDecks.Count)
            {
                deck           = playerDB.favDecks[slotIdx];
                buttonAdd.Text = "Update";
            }
            else
            {
                deck      = new TriadDeckNamed(copyFrom);
                deck.Name = "Fav #" + (slotIdx + 1).ToString();
            }

            deckCtrl1.SetImageLists(cardImages, cardTypes, cardRarity);
            deckCtrl1.SetDeck(deck);
            textBox1.Text = deck.Name;
        }
Beispiel #15
0
        private void UpdatePossibleDeckCount(int numRare, int numCommon, List <TriadCard> lockedCards, bool bIsOrderImportant)
        {
            int numLocked = 0;

            foreach (TriadCard card in lockedCards)
            {
                if (card != null)
                {
                    numLocked++;
                }
            }

            if (numLocked > 0)
            {
                ETriadCardRarity rareThreshold = GetRareThreshold(PlayerSettingsDB.Get().ownedCards);
                ECardSlotState[] cardSlots     = BuildCardSlots(lockedCards, numRare, numCommon, rareThreshold, bIsOrderImportant);
                UpdatePossibleDeckCount(numRare, numCommon, cardSlots, bIsOrderImportant);
            }
            else
            {
                // num possible decks: numRare * (num 4 element combinations from numCommon set)
                // num 4 elem: numCommon! / (4! * (numCommon - 4)!)

                numPossibleDecks = numRare;
                for (int Idx = 0; Idx < 4; Idx++)
                {
                    numPossibleDecks *= (numCommon - Idx);
                }

                int Fact4 = (4 * 3 * 2 * 1);
                if (!bIsOrderImportant || !bAllowPermutationChecks)
                {
                    numPossibleDecks /= Fact4;
                }
            }
        }
Beispiel #16
0
        private void FindDecksScored(TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();
            //TriadCardDB playerDB = TriadCardDB.Get();

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            TriadGameSession solver = new TriadGameSession();

            solver.modifiers.AddRange(npc.Rules);
            solver.modifiers.AddRange(regionMods);
            solver.UpdateSpecialRules();

            bool bIsOrderImportant = false;

            foreach (TriadGameModifier mod in solver.modifiers)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }

            List <TriadCard> rareList   = new List <TriadCard>();
            List <TriadCard> commonList = new List <TriadCard>();

            FindCardsToUse(playerDB.ownedCards, solver.modifiers, rareList, commonList);

            ETriadCardRarity rareThreshold = GetRareThreshold(playerDB.ownedCards);

            ECardSlotState[] cardSlots = BuildCardSlots(lockedCards, rareList.Count, commonList.Count, rareThreshold, bIsOrderImportant);

            object    lockOb    = new object();
            int       bestScore = 0;
            TriadDeck bestDeck  = new TriadDeck(PlayerSettingsDB.Get().starterCards);

            List <TriadCard>[] slotLists = new List <TriadCard> [cardSlots.Length];
            int numLocked    = 0;
            int numRareSlots = 0;

            for (int Idx = 0; Idx < slotLists.Length; Idx++)
            {
                switch (cardSlots[Idx])
                {
                case ECardSlotState.Common:
                    slotLists[Idx] = commonList;
                    break;

                case ECardSlotState.Rare:
                    slotLists[Idx] = rareList;
                    numRareSlots++;
                    break;

                default:
                    slotLists[Idx] = new List <TriadCard>()
                    {
                        lockedCards[Idx]
                    };
                    numLocked++;
                    break;
                }
            }

            if (numLocked > 0)
            {
                // slower when ran for all 5 slots
                UpdatePossibleDeckCount(rareList.Count, commonList.Count, cardSlots, bIsOrderImportant);

                //for (int IdxS0 = 0; IdxS0 < slotLists[0].Count; IdxS0++)
                Parallel.For(0, slotLists[0].Count, IdxS0 =>
                {
                    if (!bAbort)
                    {
                        //for (int IdxS1 = 0; IdxS1 < slotLists[1].Count; IdxS1++)
                        Parallel.For(0, slotLists[1].Count, IdxS1 =>
                        {
                            if (!bAbort)
                            {
                                //for (int IdxS2 = 0; IdxS2 < slotLists[2].Count; IdxS2++)
                                Parallel.For(0, slotLists[2].Count, IdxS2 =>
                                {
                                    if (!bAbort)
                                    {
                                        //for (int IdxS3 = 0; IdxS3 < slotLists[3].Count; IdxS3++)
                                        Parallel.For(0, slotLists[3].Count, IdxS3 =>
                                        {
                                            if (!bAbort)
                                            {
                                                //for (int IdxS4 = 0; IdxS4 < slotLists[4].Count; IdxS4++)
                                                Parallel.For(0, slotLists[4].Count, IdxS4 =>
                                                {
                                                    if (!bAbort)
                                                    {
                                                        TriadCard[] testDeckCards = new TriadCard[] { slotLists[0][IdxS0], slotLists[1][IdxS1], slotLists[2][IdxS2], slotLists[3][IdxS3], slotLists[4][IdxS4] };
                                                        if (testDeckCards[0] != testDeckCards[1] &&
                                                            testDeckCards[0] != testDeckCards[2] &&
                                                            testDeckCards[0] != testDeckCards[3] &&
                                                            testDeckCards[0] != testDeckCards[4] &&
                                                            testDeckCards[1] != testDeckCards[2] &&
                                                            testDeckCards[1] != testDeckCards[3] &&
                                                            testDeckCards[1] != testDeckCards[4] &&
                                                            testDeckCards[2] != testDeckCards[3] &&
                                                            testDeckCards[2] != testDeckCards[4] &&
                                                            testDeckCards[3] != testDeckCards[4])
                                                        {
                                                            Random randomGen = GetRandomStream(IdxS0, IdxS1, IdxS2, IdxS3, IdxS4);
                                                            // TODO: custom permutation lookup
                                                            {
                                                                TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                                int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                                if (testScore > bestScore)
                                                                {
                                                                    lock (lockOb)
                                                                    {
                                                                        bestScore = testScore;
                                                                        bestDeck  = testDeck;
                                                                        OnFoundDeck.Invoke(testDeck);
                                                                    }
                                                                }
                                                            }
                                                        }

                                                        lock (lockOb)
                                                        {
                                                            numTestedDecks++;
                                                        }
                                                    }
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        });
                    }
                });
            }
            else
            {
                // faster loops when nothing is locked
                // A: single rare slot, most common case
                if (numRareSlots == 1)
                {
                    UpdatePossibleDeckCount(rareList.Count, commonList.Count, lockedCards, bIsOrderImportant);

                    Parallel.For(0, rareList.Count, IdxR0 =>
                    {
                        if (!bAbort)
                        {
                            Parallel.For(0, commonList.Count, IdxC1 =>
                            {
                                if (!bAbort)
                                {
                                    for (int IdxC2 = IdxC1 + 1; IdxC2 < commonList.Count; IdxC2++)
                                    {
                                        for (int IdxC3 = IdxC2 + 1; IdxC3 < commonList.Count; IdxC3++)
                                        {
                                            for (int IdxC4 = IdxC3 + 1; IdxC4 < commonList.Count; IdxC4++)
                                            {
                                                TriadCard[] testDeckCards = new TriadCard[] { rareList[IdxR0], commonList[IdxC1], commonList[IdxC2], commonList[IdxC3], commonList[IdxC4] };
                                                Random randomGen          = GetRandomStream(IdxR0, IdxC1, IdxC2, IdxC3, IdxC4);

                                                if (bIsOrderImportant)
                                                {
                                                    if (bAllowPermutationChecks)
                                                    {
                                                        for (int IdxP = 0; IdxP < permutationList.Length; IdxP++)
                                                        {
                                                            int[] UseOrder            = permutationList[IdxP];
                                                            TriadCard[] permDeckCards = new TriadCard[] { testDeckCards[UseOrder[0]], testDeckCards[UseOrder[1]], testDeckCards[UseOrder[2]], testDeckCards[UseOrder[3]], testDeckCards[UseOrder[4]] };
                                                            TriadDeck permDeck        = new TriadDeck(permDeckCards);
                                                            int testScore             = GetDeckScore(solver, permDeck, randomGen, 10);
                                                            if (testScore > bestScore)
                                                            {
                                                                lock (lockOb)
                                                                {
                                                                    bestScore = testScore;
                                                                    bestDeck  = permDeck;
                                                                    OnFoundDeck.Invoke(permDeck);
                                                                }
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        testDeckCards = new TriadCard[] { commonList[IdxC1], rareList[IdxR0], commonList[IdxC2], commonList[IdxC3], commonList[IdxC4] };
                                                    }
                                                }

                                                {
                                                    TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                    int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                    if (testScore > bestScore)
                                                    {
                                                        lock (lockOb)
                                                        {
                                                            bestScore = testScore;
                                                            bestDeck  = testDeck;
                                                            OnFoundDeck.Invoke(testDeck);
                                                        }
                                                    }
                                                }

                                                lock (lockOb)
                                                {
                                                    numTestedDecks++;
                                                    if (bAbort)
                                                    {
                                                        IdxC2 = commonList.Count;
                                                        IdxC3 = commonList.Count;
                                                        IdxC4 = commonList.Count;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            });
                        }
                    });
                }
                else if (numRareSlots == 0)
                {
                    // remove part of common list for faster procesing, normally it would use 1 rare slot (smaller pool)
                    // randomly for all thta matters...
                    int    maxCommonToUse = commonList.Count * 80 / 100;
                    Random pruneRng       = new Random();

                    while (commonList.Count > maxCommonToUse)
                    {
                        int idxToRemove = pruneRng.Next(0, commonList.Count);
                        commonList.RemoveAt(idxToRemove);
                    }

                    // call simpler version of max possible combinations, 1 list in use
                    UpdatePossibleDeckCount(maxCommonToUse, bIsOrderImportant);
                    OnUpdateMaxSearchDecks?.Invoke(numPossibleDecks.ToString());

                    Parallel.For(0, commonList.Count, IdxC1 =>
                    {
                        if (!bAbort)
                        {
                            for (int IdxC2 = IdxC1 + 1; IdxC2 < commonList.Count; IdxC2++)
                            {
                                for (int IdxC3 = IdxC2 + 1; IdxC3 < commonList.Count; IdxC3++)
                                {
                                    for (int IdxC4 = IdxC3 + 1; IdxC4 < commonList.Count; IdxC4++)
                                    {
                                        for (int IdxC5 = IdxC4 + 1; IdxC5 < commonList.Count; IdxC5++)
                                        {
                                            TriadCard[] testDeckCards = new TriadCard[] { commonList[IdxC1], commonList[IdxC2], commonList[IdxC3], commonList[IdxC4], commonList[IdxC5] };
                                            Random randomGen          = GetRandomStream(IdxC1, IdxC2, IdxC3, IdxC4, IdxC5);

                                            if (bIsOrderImportant && bAllowPermutationChecks)
                                            {
                                                for (int IdxP = 0; IdxP < permutationList.Length; IdxP++)
                                                {
                                                    int[] UseOrder            = permutationList[IdxP];
                                                    TriadCard[] permDeckCards = new TriadCard[] { testDeckCards[UseOrder[0]], testDeckCards[UseOrder[1]], testDeckCards[UseOrder[2]], testDeckCards[UseOrder[3]], testDeckCards[UseOrder[4]] };
                                                    TriadDeck permDeck        = new TriadDeck(permDeckCards);
                                                    int testScore             = GetDeckScore(solver, permDeck, randomGen, 10);
                                                    if (testScore > bestScore)
                                                    {
                                                        lock (lockOb)
                                                        {
                                                            bestScore = testScore;
                                                            bestDeck  = permDeck;
                                                            OnFoundDeck.Invoke(permDeck);
                                                        }
                                                    }
                                                }
                                            }

                                            {
                                                TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                if (testScore > bestScore)
                                                {
                                                    lock (lockOb)
                                                    {
                                                        bestScore = testScore;
                                                        bestDeck  = testDeck;
                                                        OnFoundDeck.Invoke(testDeck);
                                                    }
                                                }
                                            }

                                            lock (lockOb)
                                            {
                                                numTestedDecks++;
                                                if (bAbort)
                                                {
                                                    IdxC2 = commonList.Count;
                                                    IdxC3 = commonList.Count;
                                                    IdxC4 = commonList.Count;
                                                    IdxC5 = commonList.Count;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    });
                }
                else
                {
                    Logger.WriteLine("Unexpected slot setup: " + string.Join(", ", cardSlots) + ", bailing out");
                }
            }

            stopwatch.Stop();
            Logger.WriteLine("Building list of decks: " + stopwatch.ElapsedMilliseconds + "ms, num:" + numPossibleDecks);
            optimizedDeck = bestDeck;
        }
Beispiel #17
0
        private void FindDecks(TriadGameModifier[] regionMods)
        {
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();
            //TriadCardDB playerDB = TriadCardDB.Get();

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            ETriadCardRarity RarityLimitThr =
                (playerDB.ownedCards.Count < 30) ? ETriadCardRarity.Uncommon :
                (playerDB.ownedCards.Count < 60) ? ETriadCardRarity.Rare :
                ETriadCardRarity.Epic;

            TriadGameSession solver = new TriadGameSession();

            solver.modifiers.AddRange(npc.Rules);
            solver.modifiers.AddRange(regionMods);
            solver.UpdateSpecialRules();

            bool bIsOrderImportant = false;

            foreach (TriadGameModifier mod in solver.modifiers)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }

            object    lockOb    = new object();
            int       bestScore = 0;
            TriadDeck bestDeck  = new TriadDeck(PlayerSettingsDB.Get().starterCards);

            Parallel.For(1, playerDB.ownedCards.Count, Idx1 =>
            {
                Parallel.For(Idx1 + 1, playerDB.ownedCards.Count, Idx2 =>
                {
                    int rareCounterLv2 =
                        ((playerDB.ownedCards[Idx1].Rarity >= RarityLimitThr) ? 1 : 0) +
                        ((playerDB.ownedCards[Idx2].Rarity >= RarityLimitThr) ? 1 : 0);
                    if (rareCounterLv2 <= 1)
                    {
                        Parallel.For(Idx2 + 1, playerDB.ownedCards.Count, Idx3 =>
                        {
                            int rareCounterLv3 =
                                ((playerDB.ownedCards[Idx1].Rarity >= RarityLimitThr) ? 1 : 0) +
                                ((playerDB.ownedCards[Idx2].Rarity >= RarityLimitThr) ? 1 : 0) +
                                ((playerDB.ownedCards[Idx3].Rarity >= RarityLimitThr) ? 1 : 0);

                            if (rareCounterLv3 <= 1)
                            {
                                Parallel.For(Idx3 + 1, playerDB.ownedCards.Count, Idx4 =>
                                {
                                    int rareCounterLv4 =
                                        ((playerDB.ownedCards[Idx1].Rarity >= RarityLimitThr) ? 1 : 0) +
                                        ((playerDB.ownedCards[Idx2].Rarity >= RarityLimitThr) ? 1 : 0) +
                                        ((playerDB.ownedCards[Idx3].Rarity >= RarityLimitThr) ? 1 : 0) +
                                        ((playerDB.ownedCards[Idx4].Rarity >= RarityLimitThr) ? 1 : 0);
                                    if (rareCounterLv4 <= 1)
                                    {
                                        for (int Idx5 = Idx4 + 1; Idx5 < playerDB.ownedCards.Count; Idx5++)
                                        {
                                            int rareCounterLv5 = rareCounterLv4 +
                                                                 ((playerDB.ownedCards[Idx5].Rarity >= RarityLimitThr) ? 1 : 0);
                                            if (rareCounterLv5 <= 1)
                                            {
                                                TriadCard[] testDeckCards = new TriadCard[] { playerDB.ownedCards[Idx1], playerDB.ownedCards[Idx2], playerDB.ownedCards[Idx3], playerDB.ownedCards[Idx4], playerDB.ownedCards[Idx5] };
                                                Random randomGen          = GetRandomStream(Idx1, Idx2, Idx3, Idx4, Idx5);

                                                if (bIsOrderImportant)
                                                {
                                                    if (bAllowPermutationChecks)
                                                    {
                                                        for (int IdxP = 0; IdxP < permutationList.Length; IdxP++)
                                                        {
                                                            int[] UseOrder     = permutationList[IdxP];
                                                            TriadDeck permDeck = new TriadDeck(new TriadCard[] { testDeckCards[UseOrder[0]], testDeckCards[UseOrder[1]], testDeckCards[UseOrder[2]], testDeckCards[UseOrder[3]], testDeckCards[UseOrder[4]] });

                                                            int testScore = GetDeckScore(solver, permDeck, randomGen, 10);
                                                            if (testScore > bestScore)
                                                            {
                                                                lock (lockOb)
                                                                {
                                                                    bestScore = testScore;
                                                                    bestDeck  = permDeck;
                                                                }
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        int fixedRareSlot = 2;
                                                        for (int TestSlotIdx = 0; TestSlotIdx < testDeckCards.Length; TestSlotIdx++)
                                                        {
                                                            if (testDeckCards[TestSlotIdx].Rarity > testDeckCards[fixedRareSlot].Rarity)
                                                            {
                                                                TriadCard swapOb             = testDeckCards[TestSlotIdx];
                                                                testDeckCards[TestSlotIdx]   = testDeckCards[fixedRareSlot];
                                                                testDeckCards[fixedRareSlot] = swapOb;
                                                            }
                                                        }
                                                    }
                                                }

                                                {
                                                    TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                    int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                    if (testScore > bestScore)
                                                    {
                                                        lock (lockOb)
                                                        {
                                                            bestScore = testScore;
                                                            bestDeck  = testDeck;
                                                        }
                                                    }
                                                }
                                            }

                                            numTestedDecks++;
                                        }
                                    }
                                    else
                                    {
                                        numTestedDecks += playerDB.ownedCards.Count - Idx4;
                                    }
                                });
                            }
                            else
                            {
                                numTestedDecks += (playerDB.ownedCards.Count - Idx3) * (playerDB.ownedCards.Count - Idx3 - 1);
                            }
                        });
                    }
                    else
                    {
                        numTestedDecks += (playerDB.ownedCards.Count - Idx2) * (playerDB.ownedCards.Count - Idx2 - 1) * (playerDB.ownedCards.Count - Idx2 - 2);
                    }
                });
            });

            stopwatch.Stop();
            Logger.WriteLine("Building list of decks: " + stopwatch.ElapsedMilliseconds + "ms, num:" + numPossibleDecks);
            optimizedDeck = bestDeck;
        }
        private void FindDecksScored(TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            if (currentPool.commonList == null && currentPool.priorityLists == null)
            {
                stopwatch.Stop();
                Logger.WriteLine("Skip deck building, everything was locked");

                optimizedDeck = new TriadDeck(lockedCards);
                return;
            }

            object    lockOb    = new object();
            int       bestScore = 0;
            TriadDeck bestDeck  = new TriadDeck(PlayerSettingsDB.Get().starterCards);

            // no more flexible slot count after this point => loop land
            const int numSlots = 5;

            TriadCard[][] slotLists = new TriadCard[numSlots][];
            for (int idx = 0; idx < numSlots; idx++)
            {
                slotLists[idx] =
                    (currentPool.deckSlotTypes[idx] == DeckSlotCommon) ? currentPool.commonList :
                    (currentPool.deckSlotTypes[idx] >= 0) ? currentPool.priorityLists[currentPool.deckSlotTypes[idx]] :
                    new TriadCard[1] {
                    lockedCards[idx]
                };
            }

            Func <int, int, int, int, int, int> FindLoopStart = (SlotIdx, IdxS0, IdxS1, IdxS2, IdxS3) =>
            {
                if (bAbort)
                {
                    return(slotLists[SlotIdx].Length);
                }
                if (currentPool.deckSlotTypes[SlotIdx] != DeckSlotCommon)
                {
                    return(0);
                }

                if (SlotIdx >= 4 && currentPool.deckSlotTypes[3] == DeckSlotCommon)
                {
                    return(IdxS3 + 1);
                }
                if (SlotIdx >= 3 && currentPool.deckSlotTypes[2] == DeckSlotCommon)
                {
                    return(IdxS2 + 1);
                }
                if (SlotIdx >= 2 && currentPool.deckSlotTypes[1] == DeckSlotCommon)
                {
                    return(IdxS1 + 1);
                }
                if (SlotIdx >= 1 && currentPool.deckSlotTypes[0] == DeckSlotCommon)
                {
                    return(IdxS0 + 1);
                }

                return(0);
            };

            Parallel.For(0, slotLists[0].Length, IdxS0 =>
                         //for (int IdxS0 = 0; IdxS0 < slotLists[0].Length; IdxS0++)
            {
                int startS1 = FindLoopStart(1, IdxS0, -1, -1, -1);
                Parallel.For(startS1, slotLists[1].Length, IdxS1 =>
                             //for (int IdxS1 = startS1; IdxS1 < slotLists[1].Length; IdxS1++)
                {
                    int startS2 = FindLoopStart(2, IdxS0, IdxS1, -1, -1);
                    Parallel.For(startS2, slotLists[2].Length, IdxS2 =>
                                 //for (int IdxS2 = startS2; IdxS2 < slotLists[2].Length; IdxS2++)
                    {
                        int startS3 = FindLoopStart(3, IdxS0, IdxS1, IdxS2, -1);
                        for (int IdxS3 = startS3; IdxS3 < slotLists[3].Length; IdxS3++)
                        {
                            int startS4 = FindLoopStart(4, IdxS0, IdxS1, IdxS2, IdxS3);
                            for (int IdxS4 = startS4; IdxS4 < slotLists[4].Length; IdxS4++)
                            {
                                TriadCard[] testDeckCards = new TriadCard[] { slotLists[0][IdxS0], slotLists[1][IdxS1], slotLists[2][IdxS2], slotLists[3][IdxS3], slotLists[4][IdxS4] };
                                if (testDeckCards[0] != testDeckCards[1] &&
                                    testDeckCards[0] != testDeckCards[2] &&
                                    testDeckCards[0] != testDeckCards[3] &&
                                    testDeckCards[0] != testDeckCards[4] &&
                                    testDeckCards[1] != testDeckCards[2] &&
                                    testDeckCards[1] != testDeckCards[3] &&
                                    testDeckCards[1] != testDeckCards[4] &&
                                    testDeckCards[2] != testDeckCards[3] &&
                                    testDeckCards[2] != testDeckCards[4] &&
                                    testDeckCards[3] != testDeckCards[4])
                                {
                                    Random randomGen = GetRandomStream(IdxS0, IdxS1, IdxS2, IdxS3, IdxS4);
                                    // TODO: custom permutation lookup
                                    {
                                        TriadDeck testDeck = new TriadDeck(testDeckCards);
                                        int testScore      = GetDeckScore(currentSolver, testDeck, randomGen, 1);
                                        if (testScore > bestScore)
                                        {
                                            lock (lockOb)
                                            {
                                                bestScore = testScore;
                                                bestDeck  = testDeck;
                                                OnFoundDeck.Invoke(testDeck);
                                            }
                                        }
                                    }
                                }

                                lock (lockOb)
                                {
                                    numTestedDecks++;
                                }
                            }
                        }
                    });
                });
            });

            stopwatch.Stop();
            Logger.WriteLine("Building list of decks: " + stopwatch.ElapsedMilliseconds + "ms, num:" + numPossibleDecks);
            optimizedDeck = bestDeck;
        }
Beispiel #19
0
 private void checkBoxFullScreenScan_CheckedChanged(object sender, EventArgs e)
 {
     PlayerSettingsDB.Get().useFullScreenCapture = checkBoxFullScreenScan.Checked;
     UpdateScreenState(screenReader);
     OnUpdateState.Invoke();
 }
Beispiel #20
0
        public static object FindMatchingHash(FastBitmapHash hashData, EImageHashType hashType, out int bestDistance, bool bDebugMode = false)
        {
            string debugDesc      = bDebugMode ? hashData.Hash + " >> " : "";
            int    debugDescParts = 0;

            object bestMatchOb = null;

            bestDistance = -1;

            bool bIsLocked = PlayerSettingsDB.Get().IsLockedHash(hashData.Hash);

            foreach (ImageHashData hashInfo in PlayerSettingsDB.Get().customHashes)
            {
                if (hashInfo.Type == hashType)
                {
                    bool bIsMatching = hashInfo.IsHashMatching(hashData.Hash, out int testDistance);
                    if (bDebugMode)
                    {
                        debugDesc += ((hashType == EImageHashType.Card) ? ((TriadCard)hashInfo.Owner).ToShortString() : hashInfo.Owner.ToString()) + ":" + testDistance + ", ";
                        debugDescParts++;
                    }

                    if (bIsLocked && testDistance != 0)
                    {
                        continue;
                    }

                    if (bIsMatching && (bestDistance < 0 || bestDistance > testDistance))
                    {
                        bestDistance = testDistance;
                        bestMatchOb  = hashInfo.Owner;
                    }
                }
            }

            if (bestDistance < 0)
            {
                foreach (ImageHashData hashInfo in ImageHashDB.Get().hashes)
                {
                    if (hashInfo.Type == hashType)
                    {
                        bool bIsMatching = hashInfo.IsHashMatching(hashData.Hash, out int testDistance);
                        if (bDebugMode)
                        {
                            debugDesc += ((hashType == EImageHashType.Card) ? ((TriadCard)hashInfo.Owner).ToShortString() : hashInfo.Owner.ToString()) + ":" + testDistance + ", ";
                            debugDescParts++;
                        }

                        if (bIsLocked && testDistance != 0)
                        {
                            continue;
                        }

                        if (bIsMatching && (bestDistance < 0 || bestDistance > testDistance))
                        {
                            bestDistance = testDistance;
                            bestMatchOb  = hashInfo.Owner;
                        }
                    }
                }
            }

            if (bDebugMode)
            {
                if (debugDescParts > 0)
                {
                    debugDesc = debugDesc.Remove(debugDesc.Length - 2, 2);
                }
                debugDesc += " >> ";
                debugDesc += (bestMatchOb == null) ? "unknown" :
                             ((hashType == EImageHashType.Card) ? ((TriadCard)bestMatchOb).ToShortString() : bestMatchOb.ToString());

                Logger.WriteLine(debugDesc);
            }

            return(bestMatchOb);
        }
Beispiel #21
0
        private void FindDecksScored(TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();
            //TriadCardDB playerDB = TriadCardDB.Get();

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            TriadGameSession solver = new TriadGameSession();

            solver.modifiers.AddRange(npc.Rules);
            solver.modifiers.AddRange(regionMods);
            solver.UpdateSpecialRules();

            bool bIsOrderImportant = false;

            foreach (TriadGameModifier mod in solver.modifiers)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }

            List <TriadCard> rareList   = new List <TriadCard>();
            List <TriadCard> commonList = new List <TriadCard>();

            FindCardsToUse(playerDB.ownedCards, solver.modifiers, rareList, commonList);

            ETriadCardRarity rareThreshold = GetRareThreshold(playerDB.ownedCards);

            ECardSlotState[] cardSlots = BuildCardSlots(lockedCards, rareList.Count, commonList.Count, rareThreshold, bIsOrderImportant);

            object    lockOb    = new object();
            int       bestScore = 0;
            TriadDeck bestDeck  = new TriadDeck(PlayerSettingsDB.Get().starterCards);

            List <TriadCard>[] slotLists = new List <TriadCard> [cardSlots.Length];
            int numLocked = 0;

            for (int Idx = 0; Idx < slotLists.Length; Idx++)
            {
                switch (cardSlots[Idx])
                {
                case ECardSlotState.Common: slotLists[Idx] = commonList; break;

                case ECardSlotState.Rare: slotLists[Idx] = rareList; break;

                default:
                    slotLists[Idx] = new List <TriadCard>()
                    {
                        lockedCards[Idx]
                    };
                    numLocked++;
                    break;
                }
            }

            if (numLocked > 0)
            {
                // slower when ran for all 5 slots
                UpdatePossibleDeckCount(rareList.Count, commonList.Count, cardSlots, bIsOrderImportant);

                //for (int IdxS0 = 0; IdxS0 < slotLists[0].Count; IdxS0++)
                Parallel.For(0, slotLists[0].Count, IdxS0 =>
                {
                    if (!bAbort)
                    {
                        //for (int IdxS1 = 0; IdxS1 < slotLists[1].Count; IdxS1++)
                        Parallel.For(0, slotLists[1].Count, IdxS1 =>
                        {
                            if (!bAbort)
                            {
                                //for (int IdxS2 = 0; IdxS2 < slotLists[2].Count; IdxS2++)
                                Parallel.For(0, slotLists[2].Count, IdxS2 =>
                                {
                                    if (!bAbort)
                                    {
                                        //for (int IdxS3 = 0; IdxS3 < slotLists[3].Count; IdxS3++)
                                        Parallel.For(0, slotLists[3].Count, IdxS3 =>
                                        {
                                            if (!bAbort)
                                            {
                                                //for (int IdxS4 = 0; IdxS4 < slotLists[4].Count; IdxS4++)
                                                Parallel.For(0, slotLists[4].Count, IdxS4 =>
                                                {
                                                    if (!bAbort)
                                                    {
                                                        TriadCard[] testDeckCards = new TriadCard[] { slotLists[0][IdxS0], slotLists[1][IdxS1], slotLists[2][IdxS2], slotLists[3][IdxS3], slotLists[4][IdxS4] };
                                                        if (testDeckCards[0] != testDeckCards[1] &&
                                                            testDeckCards[0] != testDeckCards[2] &&
                                                            testDeckCards[0] != testDeckCards[3] &&
                                                            testDeckCards[0] != testDeckCards[4] &&
                                                            testDeckCards[1] != testDeckCards[2] &&
                                                            testDeckCards[1] != testDeckCards[3] &&
                                                            testDeckCards[1] != testDeckCards[4] &&
                                                            testDeckCards[2] != testDeckCards[3] &&
                                                            testDeckCards[2] != testDeckCards[4] &&
                                                            testDeckCards[3] != testDeckCards[4])
                                                        {
                                                            Random randomGen = GetRandomStream(IdxS0, IdxS1, IdxS2, IdxS3, IdxS4);
                                                            // TODO: custom permutation lookup
                                                            {
                                                                TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                                int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                                if (testScore > bestScore)
                                                                {
                                                                    lock (lockOb)
                                                                    {
                                                                        bestScore = testScore;
                                                                        bestDeck  = testDeck;
                                                                        OnFoundDeck.Invoke(testDeck);
                                                                    }
                                                                }
                                                            }
                                                        }

                                                        lock (lockOb)
                                                        {
                                                            numTestedDecks++;
                                                        }
                                                    }
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        });
                    }
                });
            }
            else
            {
                // faster loops when nothing is locked
                UpdatePossibleDeckCount(rareList.Count, commonList.Count, lockedCards, bIsOrderImportant);

                Parallel.For(0, rareList.Count, IdxR0 =>
                {
                    if (!bAbort)
                    {
                        Parallel.For(0, commonList.Count, IdxC1 =>
                        {
                            if (!bAbort)
                            {
                                for (int IdxC2 = IdxC1 + 1; IdxC2 < commonList.Count; IdxC2++)
                                {
                                    for (int IdxC3 = IdxC2 + 1; IdxC3 < commonList.Count; IdxC3++)
                                    {
                                        for (int IdxC4 = IdxC3 + 1; IdxC4 < commonList.Count; IdxC4++)
                                        {
                                            TriadCard[] testDeckCards = new TriadCard[] { rareList[IdxR0], commonList[IdxC1], commonList[IdxC2], commonList[IdxC3], commonList[IdxC4] };
                                            Random randomGen          = GetRandomStream(IdxR0, IdxC1, IdxC2, IdxC3, IdxC4);

                                            if (bIsOrderImportant)
                                            {
                                                if (bAllowPermutationChecks)
                                                {
                                                    for (int IdxP = 0; IdxP < permutationList.Length; IdxP++)
                                                    {
                                                        int[] UseOrder            = permutationList[IdxP];
                                                        TriadCard[] permDeckCards = new TriadCard[] { testDeckCards[UseOrder[0]], testDeckCards[UseOrder[1]], testDeckCards[UseOrder[2]], testDeckCards[UseOrder[3]], testDeckCards[UseOrder[4]] };
                                                        TriadDeck permDeck        = new TriadDeck(permDeckCards);
                                                        int testScore             = GetDeckScore(solver, permDeck, randomGen, 10);
                                                        if (testScore > bestScore)
                                                        {
                                                            lock (lockOb)
                                                            {
                                                                bestScore = testScore;
                                                                bestDeck  = permDeck;
                                                                OnFoundDeck.Invoke(permDeck);
                                                            }
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    testDeckCards = new TriadCard[] { commonList[IdxC1], rareList[IdxR0], commonList[IdxC2], commonList[IdxC3], commonList[IdxC4] };
                                                }
                                            }

                                            {
                                                TriadDeck testDeck = new TriadDeck(testDeckCards);
                                                int testScore      = GetDeckScore(solver, testDeck, randomGen, 1);
                                                if (testScore > bestScore)
                                                {
                                                    lock (lockOb)
                                                    {
                                                        bestScore = testScore;
                                                        bestDeck  = testDeck;
                                                        OnFoundDeck.Invoke(testDeck);
                                                    }
                                                }
                                            }

                                            lock (lockOb)
                                            {
                                                numTestedDecks++;
                                                if (bAbort)
                                                {
                                                    IdxC2 = commonList.Count;
                                                    IdxC3 = commonList.Count;
                                                    IdxC4 = commonList.Count;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        });
                    }
                });
            }

            stopwatch.Stop();
            Logger.WriteLine("Building list of decks: " + stopwatch.ElapsedMilliseconds + "ms, num:" + numPossibleDecks);
            optimizedDeck = bestDeck;
        }