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 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 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 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"); }
public void SetNpc(TriadNpc inNpc) { npc = inNpc; UpdateStatusDescription(); labelNpc.Text = "NPC: " + ((npc != null) ? npc.ToString() : "unknown"); labelRules.Text = "Rules: npc changed, waiting for scan..."; }
public Task Process(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards) { this.npc = npc; numTestedDecks = 0; numMsElapsed = 0; bAbort = false; return(Task.Run(() => { FindDecksScored(regionMods, lockedCards); })); }
public TriadGameScreenMemory() { gameSession = new TriadGameSession(); gameState = new TriadGameData(); deckBlue = new TriadDeckInstanceScreen(); deckRed = new TriadDeckInstanceScreen(); blueDeckHistory = new List <TriadCard[]>(); bHasSwapRule = false; swappedBlueCardIdx = -1; lastScanNpc = null; }
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(); } }
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 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 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 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); }
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); }
public static void RunTest(string configPath, bool debugMode) { string testName = System.IO.Path.GetFileNameWithoutExtension(configPath); string configText = System.IO.File.ReadAllText(configPath); JsonParser.ObjectValue rootOb = JsonParser.ParseJson(configText); if (rootOb["type"] != "Screen") { return; } ScannerTriad.VerifyConfig configData = new ScannerTriad.VerifyConfig(); configData.Load(rootOb); // setup npc & modifiers TriadNpc testNpc = TriadNpcDB.Get().Find(configData.npc); if (testNpc == null) { string exceptionMsg = string.Format("Test {0} failed! Can't find npc: {1}", testName, configData.npc); throw new Exception(exceptionMsg); } ScannerTriad.GameState screenGame = new ScannerTriad.GameState(); 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) { screenGame.mods.Add(mapValidationRules[modName]); } 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); }; bool needsLockedBlue = false; for (int idx = 0; idx < 5; idx++) { screenGame.blueDeck[idx] = ConvertToTriadCard(configData.deckBlue[idx]); screenGame.redDeck[idx] = ConvertToTriadCard(configData.deckRed[idx]); if (configData.deckBlue[idx].state == ScannerTriad.ECardState.Locked) { needsLockedBlue = true; } } if (needsLockedBlue) { for (int idx = 0; idx < 5; idx++) { if (configData.deckBlue[idx].state == ScannerTriad.ECardState.Visible) { screenGame.forcedBlueCard = screenGame.blueDeck[idx]; break; } } } for (int idx = 0; idx < 9; idx++) { screenGame.board[idx] = ConvertToTriadCard(configData.board[idx]); screenGame.boardOwner[idx] = configData.board[idx].state == ScannerTriad.ECardState.PlacedBlue ? ETriadCardOwner.Blue : configData.board[idx].state == ScannerTriad.ECardState.PlacedRed ? ETriadCardOwner.Red : ETriadCardOwner.Unknown; } TriadGameScreenMemory screenMemory = new TriadGameScreenMemory { logScan = false }; screenMemory.OnNewScan(screenGame, testNpc); screenMemory.gameSession.SolverFindBestMove(screenMemory.gameState, out int solverBoardPos, out TriadCard solverTriadCard, out TriadGameResultChance bestChance); if (bestChance.expectedResult == ETriadGameState.BlueLost && bestChance.winChance <= 0.0f && bestChance.drawChance <= 0.0f) { string exceptionMsg = string.Format("Test {0} failed! Can't find move!", testName); throw new Exception(exceptionMsg); } }
public bool Load() { List <TriadNpc> loadedNpcs = new List <TriadNpc>(); int maxLoadedId = 0; List <TriadGameModifier> modObjects = new List <TriadGameModifier>(); foreach (Type type in Assembly.GetAssembly(typeof(TriadGameModifier)).GetTypes()) { if (type.IsSubclassOf(typeof(TriadGameModifier))) { modObjects.Add((TriadGameModifier)Activator.CreateInstance(type)); } } try { XmlDocument xdoc = new XmlDocument(); xdoc.Load(AssetManager.Get().GetAsset(DBPath)); foreach (XmlNode npcNode in xdoc.DocumentElement.ChildNodes) { XmlElement npcElem = (XmlElement)npcNode; if (npcElem != null && npcElem.Name == "npc") { try { List <TriadGameModifier> rules = new List <TriadGameModifier>(); List <TriadCard> rewards = new List <TriadCard>(); int[] deckA = new int[5]; int[] deckV = new int[5]; foreach (XmlNode innerNode in npcElem.ChildNodes) { XmlElement testElem = (XmlElement)innerNode; if (testElem != null) { if (testElem.Name == "rule") { rules.Add(ParseRule(testElem.GetAttribute("name"), modObjects)); } else if (testElem.Name == "reward") { int cardId = int.Parse(testElem.GetAttribute("id")); rewards.Add(TriadCardDB.Get().cards[cardId]); } else if (testElem.Name == "deckA") { deckA[0] = int.Parse(testElem.GetAttribute("id0")); deckA[1] = int.Parse(testElem.GetAttribute("id1")); deckA[2] = int.Parse(testElem.GetAttribute("id2")); deckA[3] = int.Parse(testElem.GetAttribute("id3")); deckA[4] = int.Parse(testElem.GetAttribute("id4")); } else if (testElem.Name == "deckV") { deckV[0] = int.Parse(testElem.GetAttribute("id0")); deckV[1] = int.Parse(testElem.GetAttribute("id1")); deckV[2] = int.Parse(testElem.GetAttribute("id2")); deckV[3] = int.Parse(testElem.GetAttribute("id3")); deckV[4] = int.Parse(testElem.GetAttribute("id4")); } } } TriadNpc newNpc = new TriadNpc( int.Parse(npcElem.GetAttribute("id")), WebUtility.HtmlDecode(npcElem.GetAttribute("name")), WebUtility.HtmlDecode(npcElem.GetAttribute("location")), rules, rewards, deckA, deckV); loadedNpcs.Add(newNpc); maxLoadedId = Math.Max(maxLoadedId, newNpc.Id); } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } } } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } if (loadedNpcs.Count > 0) { while (npcs.Count < (maxLoadedId + 1)) { npcs.Add(null); } foreach (TriadNpc npc in loadedNpcs) { npcs[npc.Id] = npc; } } Logger.WriteLine("Loaded npcs: " + npcs.Count); return(loadedNpcs.Count > 0); }
private Dictionary <int, TriadNpc> ParseNpcs(string folderPath, Dictionary <int, TriadCard> cardMap) { int DataFormat = 2; Dictionary <int, TriadGameModifier> ruleMap = ParseGameRules(folderPath); Dictionary <int, string> npcNameMap = ParseNpcNames(folderPath); Dictionary <int, int> npcTriadIdMap = ParseNpcTriadIds(folderPath); Dictionary <int, int> npcBaseIdMap = ParseNpcTriadNpcIds(folderPath, npcTriadIdMap); Dictionary <int, string> npcLocationMap = ParseNpcLocations(folderPath, npcBaseIdMap.Values.ToList()); Dictionary <int, int> rewardMap = (DataFormat == 1) ? ParseRewardItems(folderPath, cardMap) : null; Dictionary <string, TriadCard> cardNameMap = (DataFormat == 2) ? BuildCardNameMap(cardMap) : null; Dictionary <string, TriadGameModifier> ruleNameMap = (DataFormat == 2) ? BuildRuleNameMap() : null; Dictionary <int, TriadNpc> loadedNpcs = new Dictionary <int, TriadNpc>(); List <string[]> npcData = ParseCSVFile(folderPath + "TripleTriad.csv"); if (npcData.Count > 0 && npcData[0].Length == 31) { for (int Idx = 0; Idx < npcData.Count; Idx++) { int npcKey = int.Parse(npcData[Idx][0]); if (npcKey <= 0 || !npcBaseIdMap.ContainsKey(npcKey)) { continue; } int npcBaseId = npcBaseIdMap[npcKey]; int npcId = npcTriadIdMap[npcKey]; List <int> cardsFixed = new List <int>(); List <int> cardsVar = new List <int>(); if (DataFormat == 1) { cardsFixed.Add(int.Parse(npcData[Idx][1])); cardsFixed.Add(int.Parse(npcData[Idx][2])); cardsFixed.Add(int.Parse(npcData[Idx][3])); cardsFixed.Add(int.Parse(npcData[Idx][4])); cardsFixed.Add(int.Parse(npcData[Idx][5])); for (int cardIdx = cardsFixed.Count - 1; cardIdx >= 0; cardIdx--) { if (cardsFixed[cardIdx] == 0) { cardsFixed.RemoveAt(cardIdx); } else { cardsFixed[cardIdx] = cardMap[cardsFixed[cardIdx]].Id; } } cardsVar.Add(int.Parse(npcData[Idx][6])); cardsVar.Add(int.Parse(npcData[Idx][7])); cardsVar.Add(int.Parse(npcData[Idx][8])); cardsVar.Add(int.Parse(npcData[Idx][9])); cardsVar.Add(int.Parse(npcData[Idx][10])); for (int cardIdx = cardsVar.Count - 1; cardIdx >= 0; cardIdx--) { if (cardsVar[cardIdx] == 0) { cardsVar.RemoveAt(cardIdx); } else { cardsVar[cardIdx] = cardMap[cardsVar[cardIdx]].Id; } } } else { for (int InnerIdx = 1; InnerIdx <= 5; InnerIdx++) { if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0") { TriadCard matchingCard = cardNameMap[npcData[Idx][InnerIdx]]; cardsFixed.Add(matchingCard.Id); } } for (int InnerIdx = 6; InnerIdx <= 10; InnerIdx++) { if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0") { TriadCard matchingCard = cardNameMap[npcData[Idx][InnerIdx]]; cardsVar.Add(matchingCard.Id); } } } if (cardsFixed.Count == 0 && cardsVar.Count == 0) { continue; } List <TriadGameModifier> rules = new List <TriadGameModifier>(); if (DataFormat == 1) { int rule1 = int.Parse(npcData[Idx][11]); if (rule1 != 0) { rules.Add(ruleMap[rule1]); } int rule2 = int.Parse(npcData[Idx][12]); if (rule2 != 0) { rules.Add(ruleMap[rule2]); } } else { if (npcData[Idx][11].Length > 0) { rules.Add(ruleNameMap[npcData[Idx][11]]); } if (npcData[Idx][12].Length > 0) { rules.Add(ruleNameMap[npcData[Idx][12]]); } } List <TriadCard> rewardCards = new List <TriadCard>(); if (DataFormat == 1) { int[] rewardItems = new int[4] { int.Parse(npcData[Idx][27]), int.Parse(npcData[Idx][28]), int.Parse(npcData[Idx][29]), int.Parse(npcData[Idx][30]) }; foreach (int itemId in rewardItems) { if (itemId > 0) { int cardId = rewardMap[itemId]; TriadCard cardOb = cardMap[cardId]; rewardCards.Add(cardOb); } } } else { for (int InnerIdx = 27; InnerIdx <= 30; InnerIdx++) { if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0") { string cardName = npcData[Idx][InnerIdx]; if (cardName.EndsWith(" Card")) { cardName = cardName.Remove(cardName.Length - 5); } TriadCard matchingCard = cardNameMap[cardName]; rewardCards.Add(matchingCard); } } } string npcDesc = npcNameMap[npcBaseId]; string locationDesc = npcLocationMap[npcBaseId]; TriadNpc npcOb = new TriadNpc(0, npcDesc, locationDesc, rules, rewardCards, cardsFixed.ToArray(), cardsVar.ToArray()); loadedNpcs.Add(npcId, npcOb); } } else { throw new Exception("Unable to parse npcs from csv!"); } return(loadedNpcs); }
private bool UpdateNpcs(Dictionary <int, TriadNpc> npcMap) { TriadNpcDB npcDB = TriadNpcDB.Get(); int newNpcId = npcDB.npcs[npcDB.npcs.Count - 1].Id + 1; bool hasChanges = false; foreach (KeyValuePair <int, TriadNpc> kvp in npcMap) { if (kvp.Key >= newNpcId) { kvp.Value.Id = newNpcId; newNpcId++; while (npcDB.npcs.Count < newNpcId) { npcDB.npcs.Add(null); } npcDB.npcs[kvp.Value.Id] = kvp.Value; Logger.WriteLine("Newly added npc: " + kvp.Value.ToString()); hasChanges = true; continue; } TriadNpc npcMatch = npcDB.Find(kvp.Value.Name); if (npcMatch == null) { foreach (TriadNpc testNpc in npcDB.npcs) { if (testNpc != null && HasMatchingRewards(testNpc.Rewards, kvp.Value.Rewards) && HasMatchingRules(testNpc.Rules, kvp.Value.Rules) && testNpc.Deck.Equals(kvp.Value.Deck)) { Logger.WriteLine("Npc name remap: " + testNpc.ToString() + " => " + kvp.Value.Name); npcMatch = testNpc; hasChanges = true; break; } } } if (npcMatch != null) { kvp.Value.Id = npcMatch.Id; npcDB.npcs[kvp.Value.Id] = kvp.Value; } else { Logger.WriteLine("Newly added npc: " + kvp.Value.ToString()); kvp.Value.Id = newNpcId; newNpcId++; hasChanges = true; while (npcDB.npcs.Count < newNpcId) { npcDB.npcs.Add(null); } npcDB.npcs[kvp.Value.Id] = kvp.Value; } } if (hasChanges) { npcDB.Save(); } return(hasChanges); }
public EUpdateFlags OnNewScan(ScreenshotAnalyzer.GameStateTriad screenGame, TriadNpc selectedNpc) { EUpdateFlags updateFlags = EUpdateFlags.None; // check if game from screenshot can be continuation of cached one // is current state a continuation of last one? // ideally each blue turn is a capture until game resets = any card disappears from board // guess work for adding sense of persistence to screen decks bool bContinuesPrevState = (deckRed.deck == selectedNpc.Deck) && (lastScanNpc == selectedNpc); if (bContinuesPrevState) { for (int Idx = 0; Idx < gameState.board.Length; Idx++) { bool bWasNull = gameState.board[Idx] == null; bool bIsNull = screenGame.board[Idx] == null; if (!bWasNull && bIsNull) { bContinuesPrevState = false; Logger.WriteLine("Can't continue previous state: board[" + Idx + "] disappeared "); } } } else { Logger.WriteLine("Can't continue previous state: npc changed"); } bool bModsChanged = (gameSession.modifiers.Count != screenGame.mods.Count) || !gameSession.modifiers.All(screenGame.mods.Contains); if (bModsChanged) { bHasSwapRule = false; bHasRestartRule = false; bHasOpenRule = false; gameSession.modifiers.Clear(); gameSession.modifiers.AddRange(screenGame.mods); gameSession.specialRules = ETriadGameSpecialMod.None; gameSession.modFeatures = TriadGameModifier.EFeature.None; foreach (TriadGameModifier mod in gameSession.modifiers) { gameSession.modFeatures |= mod.GetFeatures(); // swap rule is bad for screenshot based analysis, no good way of telling what is out of place if (mod is TriadGameModifierSwap) { bHasSwapRule = true; } else if (mod is TriadGameModifierSuddenDeath) { bHasRestartRule = true; } else if (mod is TriadGameModifierAllOpen) { bHasOpenRule = true; } } updateFlags |= EUpdateFlags.Modifiers; bContinuesPrevState = false; Logger.WriteLine("Can't continue previous state: modifiers changed"); deckRed.SetSwappedCard(null, -1); } // wipe blue deck history when playing with new npc (or region modifiers have changed) bool bRemoveBlueHistory = bModsChanged || (lastScanNpc != selectedNpc); if (bRemoveBlueHistory) { blueDeckHistory.Clear(); if (bHasSwapRule) { Logger.WriteLine("Blue deck history cleared"); } } bool bRedDeckChanged = (lastScanNpc != selectedNpc) || !IsDeckMatching(deckRed, screenGame.redDeck) || (deckRed.deck != selectedNpc.Deck); if (bRedDeckChanged) { updateFlags |= EUpdateFlags.RedDeck; deckRed.deck = selectedNpc.Deck; lastScanNpc = selectedNpc; // needs to happen before any changed to board (gameState) UpdateAvailableRedCards(deckRed, screenGame.redDeck, screenGame.blueDeck, screenGame.board, deckBlue.cards, gameState.board, bContinuesPrevState); } bool bBlueDeckChanged = !IsDeckMatching(deckBlue, screenGame.blueDeck); if (bBlueDeckChanged) { updateFlags |= EUpdateFlags.BlueDeck; deckBlue.UpdateAvailableCards(screenGame.blueDeck); } gameSession.forcedBlueCard = screenGame.forcedBlueCard; gameState.state = ETriadGameState.InProgressBlue; gameState.deckBlue = deckBlue; gameState.deckRed = deckRed; gameState.numCardsPlaced = 0; bool bBoardChanged = false; for (int Idx = 0; Idx < gameState.board.Length; Idx++) { bool bWasNull = gameState.board[Idx] == null; bool bIsNull = screenGame.board[Idx] == null; if (bWasNull && !bIsNull) { bBoardChanged = true; gameState.board[Idx] = new TriadCardInstance(screenGame.board[Idx], screenGame.boardOwner[Idx]); Logger.WriteLine(" board update: [" + Idx + "] " + gameState.board[Idx].owner + ": " + gameState.board[Idx].card.Name); } else if (!bWasNull && bIsNull) { bBoardChanged = true; gameState.board[Idx] = null; } else if (!bWasNull && !bIsNull) { if (gameState.board[Idx].owner != screenGame.boardOwner[Idx] || gameState.board[Idx].card != screenGame.board[Idx]) { bBoardChanged = true; gameState.board[Idx] = new TriadCardInstance(screenGame.board[Idx], screenGame.boardOwner[Idx]); } } gameState.numCardsPlaced += (gameState.board[Idx] != null) ? 1 : 0; } if (bBoardChanged) { updateFlags |= EUpdateFlags.Board; foreach (TriadGameModifier mod in gameSession.modifiers) { mod.OnScreenUpdate(gameState); } } // start of game, do additional checks when swap rule is active if (bHasSwapRule && gameState.numCardsPlaced <= 1) { updateFlags |= DetectSwapOnGameStart(); } Logger.WriteLine("OnNewScan> board:" + (bBoardChanged ? "changed" : "same") + ", blue:" + (bBlueDeckChanged ? "changed" : "same") + ", red:" + (bRedDeckChanged ? "changed" : "same") + ", mods:" + (bModsChanged ? "changed" : "same") + ", continuePrev:" + bContinuesPrevState + " => " + ((updateFlags != EUpdateFlags.None) ? ("UPDATE[" + updateFlags + "]") : "skip")); return(updateFlags); }
public bool Load() { try { XmlDocument xdoc = new XmlDocument(); xdoc.Load(AssetManager.Get().GetAsset(DBPath)); foreach (XmlNode npcNode in xdoc.DocumentElement.ChildNodes) { XmlElement npcElem = (XmlElement)npcNode; if (npcElem != null && npcElem.Name == "npc") { try { List <TriadGameModifier> rules = new List <TriadGameModifier>(); List <TriadCard> rewards = new List <TriadCard>(); int[] deckA = new int[5]; int[] deckV = new int[5]; foreach (XmlNode innerNode in npcElem.ChildNodes) { XmlElement testElem = (XmlElement)innerNode; if (testElem != null) { if (testElem.Name == "rule") { int ruleId = int.Parse(testElem.GetAttribute("id")); rules.Add(TriadGameModifierDB.Get().mods[ruleId].Clone()); } else if (testElem.Name == "reward") { int cardId = int.Parse(testElem.GetAttribute("id")); rewards.Add(TriadCardDB.Get().cards[cardId]); } else if (testElem.Name == "deckA") { deckA[0] = int.Parse(testElem.GetAttribute("id0")); deckA[1] = int.Parse(testElem.GetAttribute("id1")); deckA[2] = int.Parse(testElem.GetAttribute("id2")); deckA[3] = int.Parse(testElem.GetAttribute("id3")); deckA[4] = int.Parse(testElem.GetAttribute("id4")); } else if (testElem.Name == "deckV") { deckV[0] = int.Parse(testElem.GetAttribute("id0")); deckV[1] = int.Parse(testElem.GetAttribute("id1")); deckV[2] = int.Parse(testElem.GetAttribute("id2")); deckV[3] = int.Parse(testElem.GetAttribute("id3")); deckV[4] = int.Parse(testElem.GetAttribute("id4")); } } } TriadNpc newNpc = new TriadNpc( int.Parse(npcElem.GetAttribute("id")), rules, rewards, deckA, deckV); newNpc.LocationX = int.Parse(npcElem.GetAttribute("mx")); newNpc.LocationY = int.Parse(npcElem.GetAttribute("my")); while (npcs.Count <= newNpc.Id) { npcs.Add(null); } npcs[newNpc.Id] = newNpc; } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } } } } catch (Exception ex) { Logger.WriteLine("Loading failed! Exception:" + ex); } Logger.WriteLine("Loaded npcs: " + npcs.Count); return(npcs.Count > 0); }