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(); } }
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 static void RunTriadSolverTests(string path) { string testRoot = AssetManager.Get().CreateFilePath(path); IEnumerable <string> configPaths = Directory.EnumerateFiles(testRoot, "*.json"); foreach (var configPath in configPaths) { Logger.WriteLine("==> Testing: " + Path.GetFileNameWithoutExtension(configPath)); bool bNeedsDebugRun = false; try { TriadGameScreenMemory.RunTest(configPath, bNeedsDebugRun); TriadGameSession.RunTest(configPath, bNeedsDebugRun); } catch (Exception ex) { Logger.WriteLine("Exception:" + ex); bNeedsDebugRun = true; } if (bNeedsDebugRun) { TriadGameScreenMemory.RunTest(configPath, bNeedsDebugRun); TriadGameSession.RunTest(configPath, bNeedsDebugRun); } } }
public TriadGameScreenMemory() { gameSession = new TriadGameSession(); gameState = new TriadGameData(); deckBlue = new TriadDeckInstanceScreen(); deckRed = new TriadDeckInstanceScreen(); blueDeckHistory = new List <TriadCard[]>(); bHasSwapRule = false; swappedBlueCardIdx = -1; lastScanNpc = null; }
static void Main(string[] Args) { Logger.Initialize(Args); bool bUpdatePending = GithubUpdater.FindAndApplyUpdates(); if (bUpdatePending) { return; } bool bInit = Form1.InitializeGameAssets(); if (bInit) { if (Args.Contains("-dataConvert")) { DataConverter converter = new DataConverter(); converter.Run(); } else if (Args.Contains("-solverStress")) { TriadGameSession.RunSolverStressTest(); } else { #if DEBUG if (Args.Contains("-runTests")) { TestManager.RunTests(); } #endif // DEBUG Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } else { MessageBox.Show("Failed to initialize resources!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Stop); } Logger.Close(); }
public void Update(TriadGameSession currentGame, TriadNpc npc) { bool isDirty = true; if (session != null && session.modifiers.Count == currentGame.modifiers.Count) { int numMatching = 0; for (int Idx = 0; Idx < currentGame.modifiers.Count; Idx++) { TriadGameModifier currentMod = session.modifiers[Idx]; TriadGameModifier reqMod = currentGame.modifiers[Idx]; if (currentMod.GetType() == reqMod.GetType()) { numMatching++; } } isDirty = (numMatching != session.modifiers.Count); } if (npc != this.npc) { this.npc = npc; isDirty = true; } if (isDirty) { session = new TriadGameSession(); session.solverName = "Fav #" + (contextId + 1); foreach (TriadGameModifier mod in currentGame.modifiers) { TriadGameModifier modCopy = (TriadGameModifier)Activator.CreateInstance(mod.GetType()); modCopy.OnMatchInit(); session.modifiers.Add(modCopy); } session.UpdateSpecialRules(); CalcWinChance(); } }
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 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 }
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 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); } } }
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; }