Exemple #1
0
        /// <summary>
        /// Computes the transitions for a player.
        /// </summary>
        /// <param name="player">The player.</param>
        private void ComputeTransitionsForPlayer(MatchPlayer player)
        {
            var transitions = new SparseMatrix(StrokeLimit + 2, StrokeLimit + 2);
            var points      = new DenseVector(StrokeLimit + 2);
            var errors      = new DenseVector(StrokeLimit + 2);

            // Fill the transitions
            for (int i = 1; i < transitions.ColumnCount - 1; ++i)
            {
                // Determine which player has to serve for our player to
                // make this stroke.  For odd numbers, it's the player herself,
                // but for even numbers, she plays the return.
                var server = i % 2 == 0 ? player.Other() : player;

                // Get all rallies that are actually long enough for our player
                // to get to stroke i+1
                var rallies = this.Match.FinishedRallies
                              .Where(r => r.Length >= i && r.Server == server);

                // Now determine how many rallies end here
                var endingRallies = rallies.Where(r => r.Length == i);

                // The number of transitions to the next stroke by the other
                // player is then obviously the number of all rallies long enough,
                // minus the number of ending rallies.
                transitions[i, i + 1] = rallies.Count() - endingRallies.Count();

                // And now let's just find out quickly, how the ending rallies
                // ended: With a point or an error of our player
                points[i] = endingRallies.Count(r => r.Winner == player);
                errors[i] = endingRallies.Count(r => r.Winner == player.Other());
            }

            // Now compute the catch all state.
            var allRemainingRallies = this.Match.FinishedRallies
                                      .Where(r => r.Length > StrokeLimit);

            var remainingRalliesEnding = allRemainingRallies
                                         .Where(r => r.Server == (r.Length % 2 == 0 ? player.Other() : player));

            transitions[StrokeLimit + 1, StrokeLimit + 1] = allRemainingRallies
                                                            .Sum(r =>
            {
                // Calculate the number of transitions from our player to
                // the other player, this rally as gone through above the
                // stroke limit.
                var no = (r.Length - StrokeLimit) / 2.0;
                return((int)(r.Server == player ? Math.Floor(no) : Math.Ceiling(no)));
            }) - remainingRalliesEnding.Count();

            points[StrokeLimit + 1] = remainingRalliesEnding.Count(r => r.Winner == player);
            errors[StrokeLimit + 1] = remainingRalliesEnding.Count(r => r.Winner == player.Other());

            this.PointsAtStrokeByPlayer[player] = points;
            this.ErrorsAtStrokeByPlayer[player] = errors;
            this.TransitionsByPlayer[player]    = transitions;
        }
        private double Performance(Rally rally, MatchPlayer mp)
        {
            var score        = rally.FinalRallyScore;
            var winningScore = score.Highest;

            double bias  = rally.Winner == mp ? +1 : -1;
            var    @base = winningScore == 11 ?
                           score.Of(mp) - score.Of(mp.Other()) - 11 :
                           -11 + (bias / (double)(winningScore - 11));

            return(Math.Pow(@base, 2));
        }
        /// <summary>
        /// Gets the number of scores of <paramref name="player"/> in rallies
        /// of length <paramref name="n"/>.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="n">The rally length.</param>
        /// <returns>The scores of <paramref name="player"/> in rallies of length <paramref name="n"/></returns>
        public double ScoresAtLength(MatchPlayer player, int n)
        {
            var points = this.Transitions.PointsAtStrokeByPlayer[player];

            if (n < 0 || n >= points.Count)
            {
                throw new ArgumentOutOfRangeException("Cannot compute errors for stroke " + n);
            }

            var otherErrors = this.Transitions.ErrorsAtStrokeByPlayer[player.Other()];

            if (n == points.Count - 1)
            {
                return(points[n] + otherErrors[n] + points[n - 1]);
            }
            else if (n == points.Count - 2)
            {
                return(points[n]);
            }
            else
            {
                return(points[n] + otherErrors[n + 1]);
            }
        }
        /// <summary>
        /// Gets the number of errors of <paramref name="player"/> in rallies
        /// of length <paramref name="n"/>.
        /// </summary>
        /// <param name="player">The player</param>
        /// <param name="n">The rally length</param>
        /// <returns>The errors of <paramref name="player"/> in rallies of length <paramref name="n"/></returns>
        public double ErrorsAtLength(MatchPlayer player, int n)
        {
            var errors = this.Transitions.ErrorsAtStrokeByPlayer[player];

            if (n < 1 || n >= errors.Count)
            {
                throw new ArgumentOutOfRangeException("Cannot compute errors for stroke " + n);
            }

            var otherPoints = this.Transitions.PointsAtStrokeByPlayer[player.Other()];

            if (n == 0)
            {
                return(errors[n]);
            }
            else if (n == errors.Count - 1)
            {
                return(errors[n] + otherPoints[n - 1] + otherPoints[n] + this.ErrorsAtLength(player, n - 1));
            }
            else
            {
                return(errors[n] + otherPoints[n - 1]);
            }
        }