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