public void UpdatePlayerDeckForNpc(TriadNpc npc, TriadDeck deck) { if (npc != null && deck != null && deck.knownCards.Count == 5) { bool bIsStarterDeck = true; for (int Idx = 0; Idx < starterCards.Length; Idx++) { bIsStarterDeck = bIsStarterDeck && (starterCards[Idx] == deck.knownCards[Idx]); } if (!bIsStarterDeck) { bool bChanged = true; if (lastDeck.ContainsKey(npc)) { if (lastDeck[npc].Equals(deck)) { bChanged = false; } else { lastDeck.Remove(npc); } } if (bChanged) { TriadCard[] deckCardsCopy = deck.knownCards.ToArray(); lastDeck.Add(npc, new TriadDeck(deckCardsCopy)); MarkDirty(); } } } }
public TriadDeckInstanceManual(TriadDeck deck) { this.deck = deck; numUnknownPlaced = 0; numPlaced = 0; availableCardMask = (1 << (deck.knownCards.Count + deck.unknownCardPool.Count)) - 1; }
// special logic, covered by GUI public static void StaticSwapCards(TriadGameData gameData, TriadCard swapFromBlue, int blueSlotIdx, TriadCard swapFromRed, int redSlotIdx) { // implement this rule only for manual mode, screen captures get everything automatically TriadDeckInstanceManual deckBlueEx = gameData.deckBlue as TriadDeckInstanceManual; TriadDeckInstanceManual deckRedEx = gameData.deckRed as TriadDeckInstanceManual; if (deckBlueEx != null && deckRedEx != null) { bool bIsRedFromKnown = redSlotIdx < deckRedEx.deck.knownCards.Count; if (gameData.bDebugRules) { TriadGameModifierSwap DummyOb = new TriadGameModifierSwap(); Logger.WriteLine(">> " + DummyOb.RuleName + "! blue[" + blueSlotIdx + "]:" + swapFromBlue.Name + " <-> red[" + redSlotIdx + (bIsRedFromKnown ? "" : ":Opt") + "]:" + swapFromRed.Name); } TriadDeck blueDeckSwapped = new TriadDeck(deckBlueEx.deck.knownCards, deckBlueEx.deck.unknownCardPool); TriadDeck redDeckSwapped = new TriadDeck(deckRedEx.deck.knownCards, deckRedEx.deck.unknownCardPool); // ignore order in red deck redDeckSwapped.knownCards.Add(swapFromBlue); redDeckSwapped.knownCards.Remove(swapFromRed); redDeckSwapped.unknownCardPool.Remove(swapFromRed); // preserve order in blue deck blueDeckSwapped.knownCards[blueSlotIdx] = swapFromRed; gameData.deckBlue = new TriadDeckInstanceManual(blueDeckSwapped); gameData.deckRed = new TriadDeckInstanceManual(redDeckSwapped); } }
public static void RunSolverStressTest() { int numIterations = 1000 * 1000; Logger.WriteLine("Solver testing start, numIterations:" + numIterations); Stopwatch timer = new Stopwatch(); timer.Start(); TriadDeck testDeck = new TriadDeck(new int[] { 10, 20, 30, 40, 50 }); TriadNpc testNpc = TriadNpcDB.Get().Find("Garima"); Random randStream = new Random(); TriadGameSession solver = new TriadGameSession(); solver.modifiers.AddRange(testNpc.Rules); solver.UpdateSpecialRules(); for (int Idx = 0; Idx < numIterations; Idx++) { TriadGameData testData = solver.StartGame(testDeck, testNpc.Deck, ETriadGameState.InProgressBlue); Random sessionRand = new Random(randStream.Next()); solver.SolverPlayRandomGame(testData, sessionRand); } timer.Stop(); Logger.WriteLine("Solver testing finished, time taken:" + timer.ElapsedMilliseconds + "ms"); if (Debugger.IsAttached) { Debugger.Break(); } }
public bool Equals(TriadDeck otherDeck) { if ((knownCards.Count != otherDeck.knownCards.Count) || (unknownCardPool.Count != otherDeck.unknownCardPool.Count)) { return(false); } for (int Idx = 0; Idx < knownCards.Count; Idx++) { if (!knownCards[Idx].Equals(otherDeck.knownCards[Idx])) { return(false); } } for (int Idx = 0; Idx < unknownCardPool.Count; Idx++) { if (!unknownCardPool[Idx].Equals(otherDeck.unknownCardPool[Idx])) { return(false); } } return(true); }
public void SetDeck(TriadDeck deck) { if (this.deck == null || deck == null || !this.deck.Equals(deck)) { this.deck = deck; CalcWinChance(); } }
public TriadNpc(int id, List <TriadGameModifier> rules, List <TriadCard> rewards, TriadDeck deck) { Id = id; Name = LocalizationDB.Get().FindOrAddLocString(ELocStringType.NpcName, id); LocationMap = LocalizationDB.Get().FindOrAddLocString(ELocStringType.NpcLocation, id); Rules = rules; Rewards = rewards; Deck = deck; }
public TriadNpc(int id, List <TriadGameModifier> rules, List <TriadCard> rewards, int[] cardsAlways, int[] cardsPool) { Id = id; Name = LocalizationDB.Get().FindOrAddLocString(ELocStringType.NpcName, id); LocationMap = LocalizationDB.Get().FindOrAddLocString(ELocStringType.NpcLocation, id); Rules = rules; Rewards = rewards; Deck = new TriadDeck(cardsAlways, cardsPool); }
public TriadNpc(int id, string name, string location, List <TriadGameModifier> rules, List <TriadCard> rewards, int[] cardsAlways, int[] cardsPool) { Id = id; Name = name; Location = location; Rules = rules; Rewards = rewards; Deck = new TriadDeck(cardsAlways, cardsPool); }
public TriadGameData StartGame(TriadDeck deckBlue, TriadDeck deckRed, ETriadGameState state) { TriadGameData gameData = new TriadGameData { state = state, deckBlue = new TriadDeckInstanceManual(deckBlue), deckRed = new TriadDeckInstanceManual(deckRed) }; currentProgress = 0; return(gameData); }
// shared with three open public static void StaticMakeKnown(TriadGameData gameData, List <int> redIndices) { const int deckSize = 5; TriadDeckInstanceManual deckRedEx = gameData.deckRed as TriadDeckInstanceManual; if (deckRedEx != null && redIndices.Count <= deckSize) { if (gameData.bDebugRules) { Logger.WriteLine(">> Open:{0}! red indices:{1}", redIndices.Count, string.Join(", ", redIndices)); } TriadDeck redDeckVisible = new TriadDeck(deckRedEx.deck.knownCards, deckRedEx.deck.unknownCardPool); for (int idx = 0; idx < redIndices.Count; idx++) { int cardIdx = redIndices[idx]; if (cardIdx < deckRedEx.deck.knownCards.Count) { // already known, ignore } else { int idxU = cardIdx - deckRedEx.deck.knownCards.Count; var cardOb = deckRedEx.deck.unknownCardPool[idxU]; redDeckVisible.knownCards.Add(cardOb); redDeckVisible.unknownCardPool.Remove(cardOb); } } // safety for impossible state for (int idx = 0; (idx < redDeckVisible.knownCards.Count) && (redDeckVisible.knownCards.Count > deckSize); idx++) { var cardOb = redDeckVisible.knownCards[idx]; int orgIdx = deckRedEx.GetCardIndex(cardOb); if (!redIndices.Contains(orgIdx)) { redDeckVisible.knownCards.RemoveAt(idx); idx--; } } gameData.deckRed = new TriadDeckInstanceManual(redDeckVisible); } }
private int GetDeckScore(TriadGameSession solver, TriadDeck testDeck, Random randomGen, int numGamesDiv) { int deckScore = 0; int maxGames = (numGamesToPlay / numGamesDiv) / 2; for (int IdxGame = 0; IdxGame < maxGames; IdxGame++) { TriadGameData gameDataR = solver.StartGame(testDeck, npc.Deck, ETriadGameState.InProgressRed); ETriadGameState gameRState = solver.SolverPlayRandomGame(gameDataR, randomGen); deckScore += (gameRState == ETriadGameState.BlueWins) ? 2 : (gameRState == ETriadGameState.BlueDraw) ? 1 : 0; TriadGameData gameDataB = solver.StartGame(testDeck, npc.Deck, ETriadGameState.InProgressBlue); ETriadGameState gameBState = solver.SolverPlayRandomGame(gameDataB, randomGen); deckScore += (gameBState == ETriadGameState.BlueWins) ? 2 : (gameBState == ETriadGameState.BlueDraw) ? 1 : 0; } return(deckScore); }
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; }
public static void RunSolverStressTest() { #if DEBUG int numIterations = 1000 * 100; Logger.WriteLine("Solver testing start, numIterations:" + numIterations); perfStats = new SolverPerfStats(); Stopwatch timer = new Stopwatch(); timer.Start(); TriadDeck testDeck = new TriadDeck(new int[] { 10, 20, 30, 40, 50 }); TriadNpc testNpc = TriadNpcDB.Get().Find("Garima"); Random randStream = new Random(); TriadGameSession solver = new TriadGameSession(); solver.modifiers.AddRange(testNpc.Rules); solver.UpdateSpecialRules(); for (int Idx = 0; Idx < numIterations; Idx++) { TriadGameData testData = solver.StartGame(testDeck, testNpc.Deck, ETriadGameState.InProgressBlue); Random sessionRand = new Random(randStream.Next()); solver.SolverPlayRandomGame(testData, sessionRand); } timer.Stop(); Logger.WriteLine("Solver testing finished, time taken:" + timer.ElapsedMilliseconds + "ms"); float TicksToMs = 1000.0f / Stopwatch.Frequency; Logger.WriteLine(">> PlayRandomTurn.SelectSpot: " + (perfStats.PlayRandomTurnSelectSpot * TicksToMs) + "ms"); Logger.WriteLine(">> PlayRandomTurn.SelectCard: " + (perfStats.PlayRandomTurnSelectCard * TicksToMs) + "ms"); Logger.WriteLine(">> PlayRandomTurn.PlaceCard: " + (perfStats.PlayRandomTurnPlaceCard * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.OnPlaced: " + (perfStats.PlaceCardOnPlaced * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.OnPlacedMods: " + (perfStats.PlaceCardOnPlacedMods * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.Captures: " + (perfStats.PlaceCardCaptures * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.CapturesCombo: " + (perfStats.PlaceCardCapturesCombo * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.PostCaptures: " + (perfStats.PlaceCardPostCaptures * TicksToMs) + "ms"); Logger.WriteLine(" >> PlaceCard.AllPlaced: " + (perfStats.PlaceCardAllPlaced * TicksToMs) + "ms"); #endif // DEBUG }
public void SetDeck(TriadDeck deck) { if ((clickAction == EDeckCtrlAction.Highlight) && (cardClickOwner != null)) { cardClickOwner.SetHighlighted(false); cardClickOwner = null; } if (cardCtrls != null) { int prevCtrlCount = cardCtrls.Length; int numCards = deck.knownCards.Count + deck.unknownCardPool.Count; if (prevCtrlCount == numCards) { this.deck = null; for (int Idx = 0; Idx < cardCtrls.Length; Idx++) { setDeckCard(Idx, deck.GetCard(Idx), true); } this.deck = deck; return; } } if (deck.unknownCardPool.Count == 0) { SetDeck(deck.knownCards); } else { List <TriadCard> allCards = new List <TriadCard>(); allCards.AddRange(deck.knownCards); allCards.AddRange(deck.unknownCardPool); SetDeck(allCards); } this.deck = deck; }
public TriadDeckNamed(TriadDeck copyFrom) : base(copyFrom.knownCards) { }
public void UpdatePlayerDeck(TriadDeck playerDeck) { playerDeckPattern = playerDeck.knownCards.ToArray(); }
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 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; }
public bool LoadFromJson(string jsonStr) { TriadCardDB cardDB = TriadCardDB.Get(); TriadNpcDB npcDB = TriadNpcDB.Get(); ownedCards.Clear(); completedNpcs.Clear(); lastDeck.Clear(); favDecks.Clear(); try { JsonParser.ObjectValue jsonOb = JsonParser.ParseJson(jsonStr); JsonParser.ObjectValue uiOb = (JsonParser.ObjectValue)jsonOb["ui", null]; if (uiOb != null) { JsonParser.Value BoolTrue = new JsonParser.BoolValue(true); JsonParser.Value BoolFalse = new JsonParser.BoolValue(false); useXInput = (JsonParser.BoolValue)uiOb["xInput", BoolTrue]; alwaysOnTop = (JsonParser.BoolValue)uiOb["onTop", BoolFalse]; forcedLanguage = (JsonParser.StringValue)uiOb["lang", null]; TryGettingFloatValue(uiOb, "fontSize", ref fontSize); TryGettingFloatValue(uiOb, "markerCard", ref markerDurationCard); TryGettingFloatValue(uiOb, "markerSwap", ref markerDurationSwap); TryGettingFloatValue(uiOb, "markerCactpot", ref markerDurationCactpot); TryGettingIntValue(uiOb, "lastNpcId", ref lastNpcId); TryGettingFloatValue(uiOb, "lastWidth", ref lastWidth); TryGettingFloatValue(uiOb, "lastHeight", ref lastHeight); fontSize = Math.Min(Math.Max(fontSize, 10), 40); } JsonParser.ObjectValue cloudOb = (JsonParser.ObjectValue)jsonOb["cloud", null]; if (cloudOb != null) { useCloudStorage = (JsonParser.BoolValue)cloudOb["use", JsonParser.BoolValue.Empty]; cloudToken = (JsonParser.StringValue)cloudOb["token", null]; } JsonParser.ArrayValue cardsArr = (JsonParser.ArrayValue)jsonOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in cardsArr.entries) { int cardId = (JsonParser.IntValue)value; ownedCards.Add(cardDB.cards[cardId]); } JsonParser.ArrayValue npcsArr = (JsonParser.ArrayValue)jsonOb["npcs", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in npcsArr.entries) { int npcId = (JsonParser.IntValue)value; completedNpcs.Add(npcDB.npcs[npcId]); } JsonParser.ArrayValue decksArr = (JsonParser.ArrayValue)jsonOb["decks", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in decksArr.entries) { JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value; int npcId = (JsonParser.IntValue)deckOb["id"]; TriadNpc npc = TriadNpcDB.Get().npcs[npcId]; if (npc != null) { TriadDeck deckCards = new TriadDeck(); cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value cardValue in cardsArr.entries) { int cardId = (JsonParser.IntValue)cardValue; deckCards.knownCards.Add(cardDB.cards[cardId]); } lastDeck.Add(npc, deckCards); } } JsonParser.ArrayValue favDecksArr = (JsonParser.ArrayValue)jsonOb["favDecks", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in favDecksArr.entries) { JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value; TriadDeckNamed deckCards = new TriadDeckNamed(); cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value cardValue in cardsArr.entries) { int cardId = (JsonParser.IntValue)cardValue; deckCards.knownCards.Add(cardDB.cards[cardId]); } if (deckCards.knownCards.Count > 0) { deckCards.Name = deckOb["name", JsonParser.StringValue.Empty]; favDecks.Add(deckCards); } } JsonParser.ObjectValue imageHashesOb = (JsonParser.ObjectValue)jsonOb["images", null]; if (imageHashesOb != null) { customHashes = ImageHashDB.Get().LoadImageHashes(imageHashesOb); ImageHashDB.Get().hashes.AddRange(customHashes); } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } Logger.WriteLine("Loaded player cards: " + ownedCards.Count + ", npcs: " + completedNpcs.Count + ", hashes: " + customHashes.Count); return(ownedCards.Count > 0); }
public static void RunTest(string configPath, bool debugMode) { string testName = System.IO.Path.GetFileNameWithoutExtension(configPath); string configText = System.IO.File.ReadAllText(configPath); JsonParser.ObjectValue configOb = JsonParser.ParseJson(configText); if (configOb["type"] != "Solver") { return; } TriadGameSession testSession = new TriadGameSession(); // intial state ScannerTriad.VerifyConfig configData = new ScannerTriad.VerifyConfig(); configData.Load(configOb); if (mapValidationRules == null) { mapValidationRules = new Dictionary <string, TriadGameModifier>(); foreach (TriadGameModifier mod in ImageHashDB.Get().modObjects) { mapValidationRules.Add(mod.GetCodeName(), mod); } } foreach (string modName in configData.rules) { testSession.modifiers.Add(mapValidationRules[modName]); } testSession.UpdateSpecialRules(); TriadGameData testGameData = new TriadGameData() { bDebugRules = debugMode }; if (configData.board.Length > 0) { Func <ScannerTriad.VerifyCard, TriadCard> ConvertToTriadCard = configCard => { if (configCard.state == ScannerTriad.ECardState.None) { return(null); } if (configCard.state == ScannerTriad.ECardState.Hidden) { return(TriadCardDB.Get().hiddenCard); } TriadCard matchingCard = !string.IsNullOrEmpty(configCard.name) ? TriadCardDB.Get().Find(configCard.name) : TriadCardDB.Get().Find(configCard.sides[0], configCard.sides[1], configCard.sides[2], configCard.sides[3]); if (matchingCard == null) { string exceptionMsg = string.Format("Test {0} failed! Can't match validation card: '{1}' [{2},{3},{4},{5}]", testName, configCard.name, configCard.sides[0], configCard.sides[1], configCard.sides[2], configCard.sides[3]); throw new Exception(exceptionMsg); } return(matchingCard); }; for (int idx = 0; idx < configData.board.Length; idx++) { var configState = configData.board[idx].state; if (configState != ScannerTriad.ECardState.None) { testGameData.board[idx] = new TriadCardInstance(ConvertToTriadCard(configData.board[idx]), (configState == ScannerTriad.ECardState.PlacedBlue) ? ETriadCardOwner.Blue : (configState == ScannerTriad.ECardState.PlacedRed) ? ETriadCardOwner.Red : ETriadCardOwner.Unknown); } } } var deckRed = new TriadDeck(); var deckBlue = new TriadDeck(); testGameData.deckBlue = new TriadDeckInstanceManual(deckBlue); testGameData.deckRed = new TriadDeckInstanceManual(deckRed); JsonParser.ArrayValue moveArr = configOb.entries["moves"] as JsonParser.ArrayValue; for (int idx = 0; idx < moveArr.entries.Count; idx++) { var move = new VerifyMove(); move.Load(moveArr.entries[idx] as JsonParser.ObjectValue); var useDeck = (move.owner == ETriadCardOwner.Blue) ? deckBlue : deckRed; useDeck.knownCards.Add(move.card); if (idx == 0) { testGameData.state = (move.owner == ETriadCardOwner.Blue) ? ETriadGameState.InProgressBlue : ETriadGameState.InProgressRed; } if (debugMode) { Logger.WriteLine("move[{0}]: [{1}] {2}: {3}", idx, move.boardPos, move.owner, move.card); } bool result = testSession.PlaceCard(testGameData, move.card, move.owner, move.boardPos); if (!result) { string exceptionMsg = string.Format("Test {0} failed! Can't place card!", testName); throw new Exception(exceptionMsg); } result = move.VerifyState(testGameData, debugMode); if (!result) { string exceptionMsg = string.Format("Test {0} failed! Finished with bad state!", testName); throw new Exception(exceptionMsg); } } }
public bool LoadFromJson(string jsonStr) { TriadCardDB cardDB = TriadCardDB.Get(); TriadNpcDB npcDB = TriadNpcDB.Get(); try { JsonParser.ObjectValue jsonOb = JsonParser.ParseJson(jsonStr); JsonParser.ObjectValue uiOb = (JsonParser.ObjectValue)jsonOb["ui", null]; if (uiOb != null) { useAutoScan = (JsonParser.BoolValue)uiOb["autoScan", JsonParser.BoolValue.Empty]; } JsonParser.ObjectValue cloudOb = (JsonParser.ObjectValue)jsonOb["cloud", null]; if (cloudOb != null) { useCloudStorage = (JsonParser.BoolValue)cloudOb["use", JsonParser.BoolValue.Empty]; cloudToken = (JsonParser.StringValue)cloudOb["token", null]; } JsonParser.ArrayValue cardsArr = (JsonParser.ArrayValue)jsonOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in cardsArr.entries) { int cardId = (JsonParser.IntValue)value; ownedCards.Add(cardDB.cards[cardId]); } JsonParser.ArrayValue npcsArr = (JsonParser.ArrayValue)jsonOb["npcs", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in npcsArr.entries) { int npcId = (JsonParser.IntValue)value; completedNpcs.Add(npcDB.npcs[npcId]); } JsonParser.ArrayValue decksArr = (JsonParser.ArrayValue)jsonOb["decks", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in decksArr.entries) { JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value; int npcId = (JsonParser.IntValue)deckOb["id"]; TriadNpc npc = TriadNpcDB.Get().npcs[npcId]; if (npc != null) { TriadDeck deckCards = new TriadDeck(); cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value cardValue in cardsArr.entries) { int cardId = (JsonParser.IntValue)cardValue; deckCards.knownCards.Add(cardDB.cards[cardId]); } lastDeck.Add(npc, deckCards); } } JsonParser.ArrayValue favDecksArr = (JsonParser.ArrayValue)jsonOb["favDecks", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value value in favDecksArr.entries) { JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value; TriadDeckNamed deckCards = new TriadDeckNamed(); cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty]; foreach (JsonParser.Value cardValue in cardsArr.entries) { int cardId = (JsonParser.IntValue)cardValue; deckCards.knownCards.Add(cardDB.cards[cardId]); } if (deckCards.knownCards.Count > 0) { deckCards.Name = deckOb["name", JsonParser.StringValue.Empty]; favDecks.Add(deckCards); } } JsonParser.ObjectValue imageHashesOb = (JsonParser.ObjectValue)jsonOb["images", null]; if (imageHashesOb != null) { customHashes = ImageHashDB.Get().LoadImageHashes(imageHashesOb); } JsonParser.ArrayValue digitHashesArr = (JsonParser.ArrayValue)jsonOb["digits", null]; if (digitHashesArr != null) { customDigits = ImageHashDB.Get().LoadDigitHashes(digitHashesArr); } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } return(ownedCards.Count > 0); }
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; }
public void UpdatePlayerDeck(TriadDeck activeDeck) { screenMemory.UpdatePlayerDeck(activeDeck); }
private bool UpdateNpcs(GameDataLists gameDataLists, Dictionary <string, TriadGameModifier> mapRuleNames) { Logger.WriteLine("Updating npc list..."); TriadCardDB cardDB = TriadCardDB.Get(); TriadNpcDB npcDB = TriadNpcDB.Get(); var validDeckIds = new List <string>(); foreach (var npcData in gameDataLists.npcs) { if (npcData.LinkedNpcId == null) { continue; } if (npcData.LinkedNpcId.LinkedName == null || npcData.LinkedNpcId.LinkedLocation == null) { continue; } TriadDeck npcDataDeck = new TriadDeck(); foreach (var cardData in npcData.LinkedCardsFixed) { npcDataDeck.knownCards.Add(cardDB.cards[cardData.Id]); } foreach (var cardData in npcData.LinkedCardsVariable) { npcDataDeck.unknownCardPool.Add(cardDB.cards[cardData.Id]); } npcDataDeck.UpdateDeckId(); validDeckIds.Add(npcDataDeck.deckId); // mistakes were made... TriadNpc npcOb = npcDB.FindByDeckId(npcDataDeck.deckId); int npcId = (npcOb == null) ? npcDB.npcs.Count : npcOb.Id; if (npcOb != null) { // ensure decks are the same if (!npcOb.Deck.Equals(npcDataDeck)) { Logger.WriteLine("FAILED npc update, id:{0} name:{1} is not matching cards!", npcId, npcData.LinkedNpcId.LinkedName.Name.GetCodeName()); return(false); } } else { while (npcDB.npcs.Count <= npcId) { npcDB.npcs.Add(null); } var listMods = new List <TriadGameModifier>(); foreach (var ruleData in npcData.LinkedRules) { listMods.Add(mapRuleNames[ruleData.Name.GetCodeName()]); } var listRewards = new List <TriadCard>(); foreach (var rewardData in npcData.LinkedRewards) { listRewards.Add(cardDB.cards[rewardData.LinkedCard.Id]); } npcOb = new TriadNpc(npcId, listMods, listRewards, npcDataDeck); Logger.WriteLine(">> adding new npc: " + npcOb.ToString()); npcDB.npcs[npcId] = npcOb; } var linkedLoc = npcData.LinkedNpcId.LinkedLocation; linkedLoc.LinkedMap.GetCoords(linkedLoc.ScaledPosX, linkedLoc.ScaledPosZ, out npcOb.LocationX, out npcOb.LocationY); npcOb.Name.Text = npcData.LinkedNpcId.LinkedName.Name.Text; npcOb.LocationMap.Text = npcData.LinkedNpcId.LinkedLocation.LinkedMap.LinkedPlace.Name.Text; } for (int idx = 0; idx < npcDB.npcs.Count; idx++) { TriadNpc npcOb = npcDB.npcs[idx]; if (npcOb != null) { if (!validDeckIds.Contains(npcOb.Deck.deckId)) { Logger.WriteLine(">> removing npc: " + npcOb.ToString() + ", deck:" + npcOb.Deck.ToString()); npcDB.npcs[idx] = null; continue; } if (npcOb.Id != idx) { Logger.WriteLine("FAILED npc update, index mismatch for npc[{0}].Id:{1}, Name:{2}", idx, npcOb.Id, npcOb.Name.GetCodeName()); return(false); } } } return(true); }
public bool LoadFromXmlStream(Stream stream) { TriadCardDB cardDB = TriadCardDB.Get(); TriadNpcDB npcDB = TriadNpcDB.Get(); try { XmlDocument xdoc = new XmlDocument(); xdoc.Load(stream); foreach (XmlNode testNode in xdoc.DocumentElement.ChildNodes) { try { XmlElement testElem = (XmlElement)testNode; if (testElem != null && testElem.Name == "ui") { int autoScanNum = int.Parse(testElem.GetAttribute("autoScan")); useAutoScan = (autoScanNum == 1); } else if (testElem != null && testElem.Name == "cloud") { int useNum = int.Parse(testElem.GetAttribute("use")); useCloudStorage = (useNum == 1); cloudToken = testElem.HasAttribute("token") ? testElem.GetAttribute("token") : null; } else if (testElem != null && testElem.Name == "card") { int cardId = int.Parse(testElem.GetAttribute("id")); ownedCards.Add(cardDB.cards[cardId]); } else if (testElem != null && testElem.Name == "npc") { int npcId = int.Parse(testElem.GetAttribute("id")); completedNpcs.Add(npcDB.npcs[npcId]); } else if (testElem != null && testElem.Name == "deck") { int npcId = int.Parse(testElem.GetAttribute("id")); TriadNpc npc = TriadNpcDB.Get().npcs[npcId]; if (npc != null) { TriadDeck deckCards = new TriadDeck(); foreach (XmlAttribute attr in testElem.Attributes) { if (attr.Name.StartsWith("card")) { string cardNumStr = attr.Name.Substring(4); int cardNum = int.Parse(cardNumStr); while (deckCards.knownCards.Count < (cardNum + 1)) { deckCards.knownCards.Add(null); } int cardId = int.Parse(attr.Value); deckCards.knownCards[cardNum] = TriadCardDB.Get().cards[cardId]; } } lastDeck.Add(npc, deckCards); } } else { ImageHashData customHash = ImageHashDB.Get().LoadHashEntry(testElem); if (customHash != null) { customHashes.Add(customHash); } else { ImagePatternDigit customDigit = ImageHashDB.Get().LoadDigitEntry(testElem); if (customDigit.Value > 0) { customDigits.Add(customDigit); } } } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } return(ownedCards.Count > 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; }