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 SolverPlayRandomTurn(TriadGameData gameData, Random random) { #if DEBUG Stopwatch timer = new Stopwatch(); timer.Start(); #endif // DEBUG const int boardPosMax = TriadGameData.boardSize * TriadGameData.boardSize; int boardPos = -1; if (gameData.numCardsPlaced < boardPosMax) { int testPos = random.Next(boardPosMax); for (int passIdx = 0; passIdx < boardPosMax; passIdx++) { testPos = (testPos + 1) % boardPosMax; if (gameData.board[testPos] == null) { boardPos = testPos; break; } } } #if DEBUG perfStats.PlayRandomTurnSelectSpot += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG int cardIdx = -1; TriadDeckInstance useDeck = (gameData.state == ETriadGameState.InProgressBlue) ? gameData.deckBlue : gameData.deckRed; if (useDeck.availableCardMask > 0) { int testIdx = random.Next(TriadDeckInstance.maxAvailableCards); for (int passIdx = 0; passIdx < TriadDeckInstance.maxAvailableCards; passIdx++) { testIdx = (testIdx + 1) % TriadDeckInstance.maxAvailableCards; if ((useDeck.availableCardMask & (1 << testIdx)) != 0) { cardIdx = testIdx; break; } } } #if DEBUG perfStats.PlayRandomTurnSelectCard += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG bool bResult = false; if (cardIdx >= 0) { bResult = PlaceCard(gameData, cardIdx, useDeck, (gameData.state == ETriadGameState.InProgressBlue) ? ETriadCardOwner.Blue : ETriadCardOwner.Red, boardPos); } #if DEBUG perfStats.PlayRandomTurnPlaceCard += timer.ElapsedTicks; timer.Stop(); #endif // DEBUG return(bResult); }
public bool SolverPlayRandomTurn(TriadGameData gameData, Random random) { const int boardPosMax = TriadGameData.boardSize * TriadGameData.boardSize; int boardPos = -1; if (gameData.numCardsPlaced < boardPosMax) { int testPos = random.Next(boardPosMax); for (int passIdx = 0; passIdx < boardPosMax; passIdx++) { testPos = (testPos + 1) % boardPosMax; if (gameData.board[testPos] == null) { boardPos = testPos; break; } } } int cardIdx = -1; TriadDeckInstance useDeck = (gameData.state == ETriadGameState.InProgressBlue) ? gameData.deckBlue : gameData.deckRed; if (useDeck.availableCardMask > 0) { int testIdx = random.Next(TriadDeckInstance.maxAvailableCards); for (int passIdx = 0; passIdx < TriadDeckInstance.maxAvailableCards; passIdx++) { testIdx = (testIdx + 1) % TriadDeckInstance.maxAvailableCards; if ((useDeck.availableCardMask & (1 << testIdx)) != 0) { cardIdx = testIdx; break; } } } bool bResult = false; if (cardIdx >= 0) { bResult = PlaceCard(gameData, cardIdx, useDeck, (gameData.state == ETriadGameState.InProgressBlue) ? ETriadCardOwner.Blue : ETriadCardOwner.Red, boardPos); } return(bResult); }
public TriadGameData(TriadGameData copyFrom) { board = new TriadCardInstance[copyFrom.board.Length]; for (int Idx = 0; Idx < board.Length; Idx++) { board[Idx] = (copyFrom.board[Idx] == null) ? null : new TriadCardInstance(copyFrom.board[Idx]); } typeMods = new int[copyFrom.typeMods.Length]; for (int Idx = 0; Idx < typeMods.Length; Idx++) { typeMods[Idx] = copyFrom.typeMods[Idx]; } deckBlue = copyFrom.deckBlue.CreateCopy(); deckRed = copyFrom.deckRed.CreateCopy(); state = copyFrom.state; numCardsPlaced = copyFrom.numCardsPlaced; numRestarts = copyFrom.numRestarts; resolvedSpecial = copyFrom.resolvedSpecial; // bDebugRules not copied, only first step needs it }
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 PlaceCard(TriadGameData gameData, int cardIdx, TriadDeckInstance cardDeck, ETriadCardOwner owner, int boardPos) { bool bResult = false; bool bIsAllowedOwner = ((owner == ETriadCardOwner.Blue) && (gameData.state == ETriadGameState.InProgressBlue)) || ((owner == ETriadCardOwner.Red) && (gameData.state == ETriadGameState.InProgressRed)); TriadCard card = cardDeck.GetCard(cardIdx); if (bIsAllowedOwner && (boardPos >= 0) && (gameData.board[boardPos] == null) && (card != null)) { gameData.board[boardPos] = new TriadCardInstance(card, owner); gameData.numCardsPlaced++; if (owner == ETriadCardOwner.Blue) { gameData.deckBlue.OnCardPlacedFast(cardIdx); gameData.state = ETriadGameState.InProgressRed; } else { gameData.deckRed.OnCardPlacedFast(cardIdx); gameData.state = ETriadGameState.InProgressBlue; } bResult = true; bool bAllowCombo = false; if ((modFeatures & TriadGameModifier.EFeature.CardPlaced) != 0) { foreach (TriadGameModifier mod in modifiers) { mod.OnCardPlaced(gameData, boardPos); bAllowCombo = bAllowCombo || mod.AllowsCombo(); } } List <int> comboList = new List <int>(); int comboCounter = 0; CheckCaptures(gameData, boardPos, comboList, comboCounter); while (bAllowCombo && comboList.Count > 0) { if (gameData.bDebugRules) { Logger.WriteLine(">> combo step: {0}", string.Join(",", comboList)); } List <int> nextCombo = new List <int>(); comboCounter++; foreach (int pos in comboList) { CheckCaptures(gameData, pos, nextCombo, comboCounter); } comboList = nextCombo; } if ((modFeatures & TriadGameModifier.EFeature.PostCapture) != 0) { foreach (TriadGameModifier mod in modifiers) { mod.OnPostCaptures(gameData, boardPos); } } if (gameData.numCardsPlaced == gameData.board.Length) { OnAllCardsPlaced(gameData); } } return(bResult); }
public bool PlaceCard(TriadGameData gameData, int cardIdx, TriadDeckInstance cardDeck, ETriadCardOwner owner, int boardPos) { bool bResult = false; bool bIsAllowedOwner = ((owner == ETriadCardOwner.Blue) && (gameData.state == ETriadGameState.InProgressBlue)) || ((owner == ETriadCardOwner.Red) && (gameData.state == ETriadGameState.InProgressRed)); TriadCard card = cardDeck.GetCard(cardIdx); if (bIsAllowedOwner && (boardPos >= 0) && (gameData.board[boardPos] == null) && (card != null)) { #if DEBUG Stopwatch timer = new Stopwatch(); timer.Start(); #endif // DEBUG gameData.board[boardPos] = new TriadCardInstance(card, owner); gameData.numCardsPlaced++; if (owner == ETriadCardOwner.Blue) { gameData.deckBlue.OnCardPlacedFast(cardIdx); gameData.state = ETriadGameState.InProgressRed; } else { gameData.deckRed.OnCardPlacedFast(cardIdx); gameData.state = ETriadGameState.InProgressBlue; } #if DEBUG perfStats.PlaceCardOnPlaced += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG bResult = true; bool bAllowCombo = false; if ((modFeatures & TriadGameModifier.EFeature.CardPlaced) != 0) { foreach (TriadGameModifier mod in modifiers) { mod.OnCardPlaced(gameData, boardPos); bAllowCombo = bAllowCombo || mod.AllowsCombo(); } } #if DEBUG perfStats.PlaceCardOnPlacedMods += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG List <int> comboList = new List <int>(); int comboCounter = 0; CheckCaptures(gameData, boardPos, comboList, comboCounter); #if DEBUG perfStats.PlaceCardCaptures += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG while (bAllowCombo && comboList.Count > 0) { List <int> nextCombo = new List <int>(); comboCounter++; foreach (int pos in comboList) { CheckCaptures(gameData, pos, nextCombo, comboCounter); } comboList = nextCombo; } #if DEBUG perfStats.PlaceCardCapturesCombo += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG if ((modFeatures & TriadGameModifier.EFeature.PostCapture) != 0) { foreach (TriadGameModifier mod in modifiers) { mod.OnPostCaptures(gameData, boardPos); } } #if DEBUG perfStats.PlaceCardPostCaptures += timer.ElapsedTicks; timer.Restart(); #endif // DEBUG if (gameData.numCardsPlaced == gameData.board.Length) { OnAllCardsPlaced(gameData); } #if DEBUG timer.Stop(); perfStats.PlaceCardAllPlaced += timer.ElapsedTicks; #endif // DEBUG } return(bResult); }