예제 #1
0
 public KnowledgeState(int ThisPlayerSittingOrder, PlayerController[] AllPlayers)
 {
     // Save the player data
     PlayerCount    = AllPlayers.Length;
     MySittingOrder = ThisPlayerSittingOrder;
     HiddenHands    = new int[PlayerCount - 1];
     // Initialize distributions
     DeckDistribution = new Distribution1D(CARD_VECTOR_LENGTH);
     SingleOpponentHandDistribution  = new Distribution1D(CARD_VECTOR_LENGTH);
     TwoOpponentsHandsDistribution   = new Distribution2D(CARD_VECTOR_LENGTH, CARD_VECTOR_LENGTH);
     ThreeOpponentsHandsDistribution = new Distribution3D(CARD_VECTOR_LENGTH, CARD_VECTOR_LENGTH, CARD_VECTOR_LENGTH);
     HandDistribution = new Distribution1D[PlayerCount];
     for (int p = 0; p < PlayerCount; p++)
     {
         HandDistribution[p] = new Distribution1D(CARD_VECTOR_LENGTH);
     }
     CountUnaccountedForCards = new int[GameController.CARD_COUNT.Length];
     TheDeck = AllPlayers[ThisPlayerSittingOrder].Game.Deck;
     // Perform precomputations of static variables if necessary
     if (!PrecomputationsComplete)
     {
         PrecomputationsComplete = true;
         PrecomputeStaticArrays();
     }
     // Other opponent data
     PlayerIsKnockedOut      = new bool[PlayerCount];
     PlayerKnowsThatMyHandIs = new int[PlayerCount];
     PlayerHasTargetedMe     = new int[PlayerCount];
     PlayerHasKnockouts      = new int[PlayerCount];
     // Initialize memory
     Reset();
 }
예제 #2
0
 /// <summary>
 /// Adds another matrix of same size to the current one, optionally weighting them.
 /// </summary>
 /// <param name="other">The matrix to be added to this one.</param>
 /// <param name="ownWeight">A factor to multiply own values before addion (optional, default: 1).</param>
 /// <param name="otherWeight">A factor to multiply the other's values before addion (optional, default: 1).</param>
 public void Add(ProbabilityDistribution3D other, float ownWeight = 1f, float otherWeight = 1f)
 {
     if (other.GetLength(0) != GetLength(0) || other.GetLength(1) != GetLength(1) || other.GetLength(2) != GetLength(2))
     {
         throw new ArgumentException("Cannot add distributions of different sizes!");
     }
     if (ownWeight < 0)
     {
         throw new ArgumentOutOfRangeException("ownWeight", ownWeight, "Cannot weight elements by a negative factor!");
     }
     if (otherWeight < 0)
     {
         throw new ArgumentOutOfRangeException("otherWeight", otherWeight, "Cannot multiply elements by a negative factor!");
     }
     for (int x = 0; x < GetLength(0); x++)
     {
         for (int y = 0; y < GetLength(1); y++)
         {
             for (int z = 0; z < GetLength(2); z++)
             {
                 this[x, y, z] = this[x, y, z] * ownWeight + other[x, y, z] * otherWeight;
             }
         }
     }
 }
예제 #3
0
    // Precomputes the static arrays for quicker access
    protected static void PrecomputeStaticArrays()
    {
        // Initialized base deck distribution
        BaseDeckDistribution = new Distribution1D(CARD_VECTOR_LENGTH);
        for (int CardIndex = 0; CardIndex < CARD_VECTOR_LENGTH; CardIndex++)
        {
            BaseDeckDistribution[CardIndex] = ((float)GameController.CARD_COUNT[CardIndex + 1]) / GameController.TOTAL_CARD_COUNT;
        }
        // Initialize base joint hand distribution
        BaseThreeOpponentsHandsDistribution = new Distribution3D(CARD_VECTOR_LENGTH, CARD_VECTOR_LENGTH, CARD_VECTOR_LENGTH);
        // Optimization for the following calculation:
        int[] tempRemainingCards = new int[CARD_VECTOR_LENGTH]; // We can't use virtualRemainingCards in a static method...
        Array.Copy(GameController.CARD_COUNT, 1, tempRemainingCards, 0, CARD_VECTOR_LENGTH);
        float SumOfArray = 0, ScalingFactor = 1f / GameController.TOTAL_CARD_COUNT / (GameController.TOTAL_CARD_COUNT - 1) / (GameController.TOTAL_CARD_COUNT - 2);

        // Calculate base joint hand distribution
        for (int Hand1Index = 0; Hand1Index < CARD_VECTOR_LENGTH; Hand1Index++)
        {
            // Account for this value of the first hand
            float Hand1Prob = ScalingFactor * tempRemainingCards[Hand1Index];
            tempRemainingCards[Hand1Index] -= 1;
            // And loop through all possible second and third hidden hands
            for (int Hand2Index = 0; Hand2Index < CARD_VECTOR_LENGTH; Hand2Index++)
            {
                // Account for this value of the second hand
                float Hand2JointProb = Hand1Prob * tempRemainingCards[Hand2Index];
                tempRemainingCards[Hand2Index] -= 1;
                // And loop through all possible third hidden hands
                for (int Hand3Index = 0; Hand3Index < CARD_VECTOR_LENGTH; Hand3Index++)
                {
                    // If this is an impossible case, just jump to the next iteration
                    if (Hand2JointProb <= 0 || tempRemainingCards[Hand3Index] <= 0)
                    {
                        continue;
                    }
                    // Otherwise, calculate the joint probability of this case and store it
                    float jointProb = Hand2JointProb * tempRemainingCards[Hand3Index];
                    BaseThreeOpponentsHandsDistribution[Hand1Index, Hand2Index, Hand3Index] = jointProb;
                    SumOfArray += jointProb;
                }
                // Reset card counts for the next iteration
                tempRemainingCards[Hand2Index] += 1;
            }
            // Reset card counts for the next iteration
            tempRemainingCards[Hand1Index] += 1;
        }
        Debug.Assert(AIUtil.Approx(SumOfArray, 1f));
    }
        /// <summary>
        /// Returns a tensor product of this matrix (on the X and Y axes) with another vector (on the Y axis).
        /// </summary>
        /// <param name="other">The vector to multiply with.</param>
        /// <returns>A 3D probability distribution representing the tensor product of the matrix and the vector.</returns>
        public ProbabilityDistribution3D GetTensorProduct(ProbabilityDistribution1D other)
        {
            ProbabilityDistribution3D result = new ProbabilityDistribution3D(GetLength(0), GetLength(1), other.Length);

            for (int x = 0; x < GetLength(0); x++)
            {
                for (int y = 0; y < GetLength(1); y++)
                {
                    for (int z = 0; z < other.Length; z++)
                    {
                        result[x, y, z] = this[x, y] * other[z];
                    }
                }
            }
            return(result);
        }
예제 #5
0
    /// <summary>
    /// Computes a partial hand distribution of the specified player's new hand after being targeted by the Prince,
    /// for an assumed world state and the observation of which card they previously discarded.
    /// </summary>
    /// <param name="PlayerIndex">Index of the player for whom the computation is performed.</param>
    /// <param name="Hand0">The index of the card the first of the three remaining opponents is asssumed to hold.</param>
    /// <param name="Hand1">The index of the card the second of the three remaining opponents is asssumed to hold.</param>
    /// <param name="Hand2">The index of the card the third of the three remaining opponents is asssumed to hold.</param>
    /// <param name="DiscardedIndex">The observed index of the card that the player had discarded.</param>
    /// <param name="OutDistribution">A reference to a probability distribution that containts return values.</param>
    protected void PrinceDiscardAndDrawPartialUpdate(int PlayerIndex, int Hand0, int Hand1, int Hand2, int DiscardedIndex, ref Distribution3D OutDistribution)
    {
        // Don't continue if priori probability is zero
        float PrioriProbability = ThreeOpponentsHandsDistribution[Hand0, Hand1, Hand2];

        if (PrioriProbability <= 0)
        {
            return;
        }
        // Determine which card in the current data belongs to PlayerIndex
        int[] idx        = new int[] { Hand0, Hand1, Hand2 };
        int   playerHand = idx[PlayerIndex];

        if (playerHand != DiscardedIndex)
        {
            return;
        }
        // Make a copy of the unaccounted card counters and update it with the "virtually" accounted-for cards
        Array.Copy(CountUnaccountedForCards, 1, virtualRemainingCards, 0, CARD_VECTOR_LENGTH);
        if (--virtualRemainingCards[Hand0] < 0 || --virtualRemainingCards[Hand1] < 0 || --virtualRemainingCards[Hand2] < 0)
        {
            return; // If a counter goes below zero, this is an impossible case, so return without an update
        }
        // Prepare computation
        int remainingDeckSize = AIUtil.SumUpArray(virtualRemainingCards);

        if (remainingDeckSize < 1)
        {
            return; // The game is over, anyway.
        }
        Debug.Assert(remainingDeckSize > 0);
        // Now loop through each deck card and see if the card that was played could have been played from hand or from deck
        for (int dc = 0; dc < CARD_VECTOR_LENGTH; dc++)
        {
            if (virtualRemainingCards[dc] > 0)
            {
                // Calculate the joint probability of such play and increment the output array
                idx[PlayerIndex] = dc;
                OutDistribution[idx[0], idx[1], idx[2]] += PrioriProbability * virtualRemainingCards[dc] / remainingDeckSize;
            }
        }
    }
예제 #6
0
    /// <summary>
    /// Computes a partial hand distribution of the specified player,
    /// for an assumed world state and the observation of which card they played.
    /// </summary>
    /// <param name="TurnData">Complete data of the turn being analyzed.</param>
    /// <param name="Hand0">The index of the card the first of the three remaining opponents is asssumed to hold.</param>
    /// <param name="Hand1">The index of the card the second of the three remaining opponents is asssumed to hold.</param>
    /// <param name="Hand2">The index of the card the third of the three remaining opponents is asssumed to hold.</param>
    /// <param name="OutDistribution">A reference to a probability distribution that containts return values.</param>
    protected void UpdatePartialHandDistribution(MoveData TurnData, int Hand0, int Hand1, int Hand2, ref Distribution3D OutDistribution)
    {
        // Don't continue if priori probability is zero
        float PrioriProbability = ThreeOpponentsHandsDistribution[Hand0, Hand1, Hand2];

        if (PrioriProbability <= 0)
        {
            return;
        }
        // Make a copy of the unaccounted card counters and update it with the "virtually" accounted-for cards
        Array.Copy(CountUnaccountedForCards, 1, virtualRemainingCards, 0, CARD_VECTOR_LENGTH);
        if (--virtualRemainingCards[Hand0] < 0 || --virtualRemainingCards[Hand1] < 0 || --virtualRemainingCards[Hand2] < 0)
        {
            return; // If a counter goes below zero, this is an impossible case, so return without an update
        }
        // Parse the turn data
        int PlayerIndex     = GetHiddenHandIndex(TurnData.Player.SittingOrder),
            PlayedCardIndex = TurnData.Card.Value - 1,
            TargetIndex     = (TurnData.Target == null || TurnData.Target.SittingOrder == MySittingOrder) ? -1 : GetHiddenHandIndex(TurnData.Target.SittingOrder);

        // Determine which card in the current data belongs to PlayerIndex
        int[] idx        = new int[] { Hand0, Hand1, Hand2 };
        int   playerHand = idx[PlayerIndex],
              targetHand = TargetIndex != -1 ? idx[TargetIndex] : -1;
        // Prepare computation
        int remainingDeckSize = AIUtil.SumUpArray(virtualRemainingCards);

        Debug.Assert(remainingDeckSize > 0);
        // Now loop through each deck card and see if the card that was played could have been played from hand or from deck
        for (int dc = 0; dc < CARD_VECTOR_LENGTH; dc++)
        {
            if (virtualRemainingCards[dc] > 0 && (PlayedCardIndex == playerHand || PlayedCardIndex == dc))
            {
                // Compute which card the player has left in their hand, given PlayedCardIndex
                int otherCard = (PlayedCardIndex == playerHand) ? dc : playerHand;
                // Prepare the index values for the update
                idx[PlayerIndex] = otherCard;
                // Calculate the joint probability of such play and increment the output array
                OutDistribution[idx[0], idx[1], idx[2]] += PrioriProbability * virtualRemainingCards[dc] / remainingDeckSize
                                                           * GetLikelihoodOfPlay(TurnData, otherCard + 1, targetHand + 1);
            }
        }
    }