/// <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="PlayedCardIndex">The index of the card that was played by the opponent.</param> /// <param name="HandIndex">The index of the card that the other player is assumed to have in their hand.</param> /// <param name="OutDistribution">A reference to a probability distribution that containts return values.</param> protected void UpdatePartialHandDistribution(int PlayedCardIndex, int PlayerHand, ref Distribution1D OutDistribution) { // Don't continue if priori probability is zero float PrioriProbability = SingleOpponentHandDistribution[PlayerHand]; 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[PlayerHand] < 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); 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; // Calculate the joint probability of such play OutDistribution[otherCard] += PrioriProbability * virtualRemainingCards[dc] / remainingDeckSize * PosterioriPerceptor.LikelihoodOfPlay[PlayedCardIndex + 1, otherCard + 1]; } } }
// Convenience function for easier deck distribution calculation // Note that because it is CUMULATIVE, DeckDistributionBuffer contains intermediary results and may not be cleared! protected void CumulativeUpdateDeckDistribution(float Probability, int[] RemainingCards, ref Distribution1D DeckDistributionBuffer) { Debug.Assert(RemainingCards.Length == CARD_VECTOR_LENGTH); Debug.Assert(DeckDistributionBuffer.Length == CARD_VECTOR_LENGTH); if (Probability > 0) { int sum = AIUtil.SumUpArray(RemainingCards); if (sum > 0) { for (int i = 0; i < CARD_VECTOR_LENGTH; i++) { if (RemainingCards[i] > 0) { DeckDistributionBuffer[i] += Probability * RemainingCards[i] / sum; } } } } }
/// <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); } } }
/// <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; } } }