Пример #1
0
    // Analyzes the most recent turn made in the game
    protected override IEnumerator AnalyzeTurn(int id)
    {
        Debug.Assert(TurnHistory != null && TurnHistory.Count >= id);
        Debug.Assert(id == NextTurnToAnalyze);
        // Get the actual turn
        MoveData turn = TurnHistory[id];

        // Precompute some helpful booleans
        bool ItWasMyTurn         = (turn.Player == MyController);
        bool IWasTheTarget       = (turn.Target == MyController);
        bool ThereWasAKnockOut   = (turn.KnockedOut != null);
        bool PlayerWasKnockedOut = (ThereWasAKnockOut && turn.KnockedOut == turn.Player);
        bool TargetWasKnockedOut = (ThereWasAKnockOut && turn.KnockedOut == turn.Target);

        // Wait for some random time, just to ease the computational load per frame
        yield return(new WaitForSecondsRealtime(UnityEngine.Random.Range(0, Time.fixedDeltaTime * PlayerCount)));

        // This flag will be set to true in certain cases if no renormalization is requires
        bool RenormalizationCommenced = false;

        // Basic precomputations before getting into the specifics of card effects
        if (ItWasMyTurn)
        {
            // Update my own hand distribution, just for simplicity
            UpdateOwnHandDistribution();
            // Update my own play statistic
            UpdatePlayStatistics(turn);
            // Other players' knowledge of your hand becomes irrelevant after your own turn
            Array.Clear(PlayerKnowsThatMyHandIs, 0, PlayerCount);
            // We don't need to update unaccounted-for cards with the card just played and the card distribution,
            // because that was done at the end of the last analysis run (of the player immediately before us)
        }
        else
        {
            // When analyzing another player's turn, filter their hand first:
            FilterHiddenHandWithPlayedCard(turn.Player.SittingOrder, turn.Card.Value);
            // The card they just played lands on the discard pile, so update the unaccounted-for list
            AccountForCard(turn.Card.Value);

            // Also update this player's stats
            if (turn.Target == MyController)
            {
                PlayerHasTargetedMe[turn.Player.SittingOrder] += 1;
            }
            if (turn.KnockedOut != null && turn.KnockedOut != turn.Player)
            {
                PlayerHasKnockOuts[turn.Player.SittingOrder] += 1;
            }
        }

        // Wait some more
        yield return(new WaitForSecondsRealtime(UnityEngine.Random.Range(0, Time.fixedDeltaTime * PlayerCount)));

        // If there was a knock-out by something other than a Baron, then the filtering is simple
        if (ThereWasAKnockOut && turn.Card.Value != CardController.VALUE_BARON)
        {
            KnockOutFilter(turn.KnockedOut.SittingOrder, turn.AdditionalDiscard.Value);
        }
        else if (!turn.NoEffect)
        {
            // Otherwise, if the card effect wasn't blocked by a Handmaid, we check specific card effects
            switch (turn.Card.Value)
            {
            case CardController.VALUE_GUARD:
                // If the guard wasn't played against me and the target is still in the game,
                // I at least know what their hand is NOT
                if (!IWasTheTarget)
                {
                    HiddenHandIsNot(turn.Target.SittingOrder, turn.TargetHandGuess);
                    UpdateSameHands(turn.Target.SittingOrder);
                }
                break;

            case CardController.VALUE_PRIEST:
                // If it was my turn, I now know the target's hand
                if (ItWasMyTurn)
                {
                    // With a Priest, I now know the target's hand
                    Debug.Assert(turn.Target == lastLearnedHandOf);
                    UpdateHandDistributionWithCertainty(lastLearnedHandOf.SittingOrder, lastLearnedCard.Value);
                    UpdateSameHands(lastLearnedHandOf.SittingOrder);
                }
                else if (IWasTheTarget)
                {
                    // But if I was the target, the other player now knows my hand!
                    PlayerKnowsThatMyHandIs[turn.Player.SittingOrder] = myHand.Value;
                }
                break;

            case CardController.VALUE_BARON:
                // If either the player or the target were knocked out by Baron, we apply the Baron KO filter
                if (PlayerWasKnockedOut)
                {
                    BaronEffectFilterWithKnockout(turn.Target.SittingOrder, turn.Player.SittingOrder, turn.AdditionalDiscard.Value);
                }
                else if (TargetWasKnockedOut)
                {
                    BaronEffectFilterWithKnockout(turn.Player.SittingOrder, turn.Target.SittingOrder, turn.AdditionalDiscard.Value);
                }
                else
                {
                    // On a draw between two other players, their hand distributions are now equal
                    BaronEffectFilterWithDraw(turn.Player.SittingOrder, turn.Target.SittingOrder);
                }
                // If there was a draw involving me, the other player now knows my hand!
                if (!ThereWasAKnockOut && (ItWasMyTurn || IWasTheTarget))
                {
                    PlayerKnowsThatMyHandIs[ItWasMyTurn ? turn.Target.SittingOrder : turn.Player.SittingOrder] = myHand.Value;
                }
                break;

            case CardController.VALUE_PRINCE:
                // If I was the target of the Prince, I just need to update my hand
                if (IWasTheTarget)
                {
                    // Even if it was my turn, I have already accounted for my old hand and the card I just drew (both of which I have discarded),
                    // as well as have updated my own hand distribution, therefore I only need to account for the new card in my hand
                    Debug.Assert(DrawnBecauseOfThePrince != null);
                    UpdateHandDistributionWithCertainty(MyController.SittingOrder, DrawnBecauseOfThePrince.Value);
                    AccountForCard(DrawnBecauseOfThePrince.Value);
                    DrawnBecauseOfThePrince = null;
                }
                else
                {
                    // Otherwise, the special Prince filter logic applies (the values are automatically renormalized)
                    PrinceEffectFilterWithoutKnockout(turn.Target.SittingOrder, turn.AdditionalDiscard.Value);
                    RenormalizationCommenced = true;
                    ClearSameHands(turn.Target.SittingOrder);
                }
                break;

            case CardController.VALUE_KING:
                // If I was involved in the swap, I know quite a lot about the other player's hand now (and vice versa)
                if (ItWasMyTurn)
                {
                    KingEffectFilterInvolvingMe(turn.Target.SittingOrder);
                }
                else if (IWasTheTarget)
                {
                    KingEffectFilterInvolvingMe(turn.Player.SittingOrder);
                }
                else
                {
                    // If I wasn't involved, just swap the hand distributions of both players who were
                    SwapHandDistributions(turn.Player.SittingOrder, turn.Target.SittingOrder);
                }
                break;

            default:
                // Nothing to do when Handmaid, Countess, or Princess were played
                break;
            }
        }

        // Wait some more
        yield return(new WaitForSecondsRealtime(UnityEngine.Random.Range(0, Time.fixedDeltaTime * PlayerCount)));

        // If I'm up next, wait until I've drawn my next card before finishing the analysis
        if (turn.Player != MyController && MyController.Game.Deck.CountCardsLeft > 1 && NextPlayerIndex == MyController.SittingOrder)
        {
            yield return(new WaitUntil(() => ((myHand != null && justDrawn != null)) || MyController.Game.RoundOver));

            if (!MyController.Game.RoundOver)
            {
                // And update the distributions accordingly
                AccountForCard(justDrawn.Value);
                RenormalizeDeckAndHandsDistributions();
            }
        }
        else if (!RenormalizationCommenced)
        {
            // If a renormalization is still required, do it now (it is a very expensive call)
            RenormalizeDeckAndHandsDistributions();
        }

        // Finally, finish the update and return
        NextTurnToAnalyze = id + 1;
        if (FullLogging)
        {
            displayCurrentBeliefs();
            if (SameHands.Count > 0)
            {
                Debug.Log(name + " also knows following same hands: " + AIUtil.FormatDictionary(SameHands));
            }
        }
        yield return(new WaitForFixedUpdate());

        AnalysisOngoing = false;
    }