private void FindNextMove(out int blueCardIdx, out int boardCardIdx, out TriadGameResultChance bestChance) { boardCardIdx = -1; screenMemory.gameSession.SolverFindBestMove(screenMemory.gameState, out int solverBoardPos, out TriadCard solverTriadCard, out bestChance); blueCardIdx = screenMemory.deckBlue.GetCardIndex(solverTriadCard); if (blueCardIdx >= 0) { boardCardIdx = solverBoardPos; } }
public void UpdateChance(TriadGameResultChance chance) { labelChance.Text = chance.winChance.ToString("P2"); }
public bool SolverFindBestMove(TriadGameData gameData, out int boardPos, out TriadCard card, out TriadGameResultChance probabilities) { bool bResult = false; card = null; boardPos = -1; currentProgress = 0; string namePrefix = string.IsNullOrEmpty(solverName) ? "" : ("[" + solverName + "] "); // prepare available board data int availBoardMask = 0; int numAvailBoard = 0; for (int Idx = 0; Idx < gameData.board.Length; Idx++) { if (gameData.board[Idx] == null) { availBoardMask |= (1 << Idx); numAvailBoard++; } } // prepare available cards data TriadDeckInstance useDeck = (gameData.state == ETriadGameState.InProgressBlue) ? gameData.deckBlue : gameData.deckRed; ETriadCardOwner turnOwner = (gameData.state == ETriadGameState.InProgressBlue) ? ETriadCardOwner.Blue : ETriadCardOwner.Red; int availCardsMask = 0; if (gameData.state == ETriadGameState.InProgressBlue && gameData.forcedCardIdx >= 0) { availCardsMask = 1 << gameData.forcedCardIdx; } else { availCardsMask = useDeck.availableCardMask; } if ((modFeatures & TriadGameModifier.EFeature.FilterNext) != 0) { foreach (TriadGameModifier mod in modifiers) { mod.OnFilterNextCards(gameData, ref availCardsMask); } } int numAvailCards = 0; for (int Idx = 0; Idx < TriadDeckInstance.maxAvailableCards; Idx++) { numAvailCards += ((availCardsMask & (1 << Idx)) != 0) ? 1 : 0; } // check all combinations if ((numAvailCards > 0) && (numAvailBoard > 0)) { int numCombinations = numAvailCards * numAvailBoard; TriadGameResultChance bestProb = new TriadGameResultChance(-1.0f, 0); int cardProgressCounter = 0; for (int cardIdx = 0; cardIdx < TriadDeckInstance.maxAvailableCards; cardIdx++) { bool bCardNotAvailable = (availCardsMask & (1 << cardIdx)) == 0; if (bCardNotAvailable) { continue; } currentProgress = 100 * cardProgressCounter / numAvailCards; cardProgressCounter++; for (int boardIdx = 0; boardIdx < gameData.board.Length; boardIdx++) { bool bBoardNotAvailable = (availBoardMask & (1 << boardIdx)) == 0; if (bBoardNotAvailable) { continue; } TriadGameData gameDataCopy = new TriadGameData(gameData); bool bPlaced = PlaceCard(gameDataCopy, cardIdx, useDeck, turnOwner, boardIdx); if (bPlaced) { TriadGameResultChance gameProb = SolverFindWinningProbability(gameDataCopy); if (gameProb.IsBetterThan(bestProb)) { bestProb = gameProb; card = useDeck.GetCard(cardIdx); boardPos = boardIdx; bResult = true; } } } } probabilities = bestProb; Logger.WriteLine(namePrefix + "Solver win:" + bestProb.winChance.ToString("P2") + " (draw:" + bestProb.drawChance.ToString("P2") + "), blue[" + gameData.deckBlue + "], red[" + gameData.deckRed + "], turn:" + turnOwner + ", availBoard:" + numAvailBoard + " (" + availBoardMask.ToString("x") + ") availCards:" + numAvailCards + " (" + (useDeck == gameData.deckBlue ? "B" : "R") + ":" + availCardsMask.ToString("x") + ")"); } else { probabilities = new TriadGameResultChance(0, 0); Logger.WriteLine(namePrefix + "Can't find move! availSpots:" + numAvailBoard + " (" + availBoardMask.ToString("x") + ") availCards:" + numAvailCards + " (" + (useDeck == gameData.deckBlue ? "B" : "R") + ":" + availCardsMask.ToString("x") + ")"); } return(bResult); }
public bool IsBetterThan(TriadGameResultChance other) { return(compScore > other.compScore); }