public bool PlaceCard(TriadGameData gameData, TriadCard card, ETriadCardOwner owner, int boardPos) { TriadDeckInstance useDeck = (owner == ETriadCardOwner.Blue) ? gameData.deckBlue : gameData.deckRed; int cardIdx = useDeck.GetCardIndex(card); return(PlaceCard(gameData, cardIdx, useDeck, owner, boardPos)); }
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 && forcedBlueCard != null) { int forcedBlueCardIdx = useDeck.GetCardIndex(forcedBlueCard); availCardsMask = 1 << forcedBlueCardIdx; } 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); }