Exemple #1
0
        private static void OneOnTwoBalancedPartialPlay()
        {
            // This scenario uses the "Partial Play" feature

            var gameInfo = GameInfo.DefaultGameInfo;

            // Player 1 is normal and just has a default rating
            // This player is the only person on the first team

            var p1    = new Player(1);
            var team1 = new Team(p1, gameInfo.DefaultRating);

            // Team 2 is much more interesting. Here we specify that
            // player 2 was on the team, but played for 0% of the game
            // and player 3 was on the team but played for 100% of the
            // game and thus should be updated appropriately.
            var p2 = new Player(2, 0.0);
            var p3 = new Player(3, 1.00);

            var team2 = new Team()
                        .AddPlayer(p2, gameInfo.DefaultRating)
                        .AddPlayer(p3, gameInfo.DefaultRating);

            var teams        = Teams.Concat(team1, team2);
            var newRatings   = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2);
            var matchQuality = TrueSkillCalculator.CalculateMatchQuality(gameInfo, teams);
        }
Exemple #2
0
        private static void TwoPlayerTestNotDrawn()
        {
            // Here's the most simple case: you have two players and one wins
            // against the other.

            // Let's new up two players. Note that the argument passed into to Player
            // can be anything. This allows you to wrap any object. Here I'm just
            // using a simple integer to represent the player, but you could just as
            // easily pass in a database entity representing a person/user or any
            // other custom class you have.

            var player1 = new Player(1);
            var player2 = new Player(2);

            // The algorithm has several parameters that can be tweaked that are
            // found in the "GameInfo" class. If you're just starting out, simply
            // use the defaults:
            var gameInfo = GameInfo.DefaultGameInfo;

            // A "Team" is a collection of "Player" objects. Here we have a team
            // that consists of single players.

            // Note that for each player on the team, we indicate that they have
            // the "DefaultRating" which means that the algorithm has never seen
            // them before. In a real implementation, you'd pull this previous
            // rating for the player based on the player.Id value. It could come
            // from a database.
            var team1 = new Team(player1, gameInfo.DefaultRating);
            var team2 = new Team(player2, gameInfo.DefaultRating);

            // We bundle up all of our teams together so that we can feed them to
            // the algorithm.
            var teams = Teams.Concat(team1, team2);

            // Before we know the actual results of the game, we can ask the
            // calculator for what it perceives as the quality of the match (higher
            // means more fair/equitable)
            AssertMatchQuality(0.447, TrueSkillCalculator.CalculateMatchQuality(gameInfo, teams));

            // This is the key line. We ask the calculator to calculate new ratings
            // Pay careful attention to the numbers at the end. This indicates that
            // team1 came in first place and team2 came in second place. TrueSkill
            // is flexible and allows scenarios such as team1 and team2 drawing which
            // could be represented as "1,1" since they both came in first place.
            var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2);

            // The result of the calculation is a dictionary mapping the players to
            // their new rating. Here we get the ratings out for each player
            var player1NewRating = newRatings[player1];
            var player2NewRating = newRatings[player2];

            // In a real implementation, you'd store these values in a persistent
            // store like a database (note that you can use the player.Id to map
            // the Player class to the class of your choice.
            AssertRating(29.39583201999924, 7.171475587326186, player1NewRating);
            AssertRating(20.60416798000076, 7.171475587326186, player2NewRating);
        }
Exemple #3
0
        private static void TwoOnFourOnTwoWinDraw()
        {
            // Let's really take advantage of the algorithm by having three teams play:

            // Default info is fine
            var gameInfo = GameInfo.DefaultGameInfo;

            // The first team:
            var player1 = new Player(1);
            var player2 = new Player(2);

            var team1 = new Team()
                        .AddPlayer(player1, new Rating(40, 4))
                        .AddPlayer(player2, new Rating(45, 3));

            // The second team:
            var player3 = new Player(3);
            var player4 = new Player(4);
            var player5 = new Player(5);
            var player6 = new Player(6);

            var team2 = new Team()
                        .AddPlayer(player3, new Rating(20, 7))
                        .AddPlayer(player4, new Rating(19, 6))
                        .AddPlayer(player5, new Rating(30, 9))
                        .AddPlayer(player6, new Rating(10, 4));

            var player7 = new Player(7);
            var player8 = new Player(8);

            // The third team:
            var team3 = new Team()
                        .AddPlayer(player7, new Rating(50, 5))
                        .AddPlayer(player8, new Rating(30, 2));


            // Put all three teams into one parameter:
            var teams = Teams.Concat(team1, team2, team3);

            // Note that we tell the calculator that there was a first place outcome of team 1, and then team 2 and 3 tied/drew
            var newRatingsWinLose = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2, 2);

            // Winners
            AssertRating(40.877, 3.840, newRatingsWinLose[player1]);
            AssertRating(45.493, 2.934, newRatingsWinLose[player2]);
            AssertRating(19.609, 6.396, newRatingsWinLose[player3]);
            AssertRating(18.712, 5.625, newRatingsWinLose[player4]);
            AssertRating(29.353, 7.673, newRatingsWinLose[player5]);
            AssertRating(9.872, 3.891, newRatingsWinLose[player6]);
            AssertRating(48.830, 4.590, newRatingsWinLose[player7]);
            AssertRating(29.813, 1.976, newRatingsWinLose[player8]);

            // We can even see match quality for the entire match consisting of three teams
            AssertMatchQuality(0.367, TrueSkillCalculator.CalculateMatchQuality(gameInfo, teams));
        }
Exemple #4
0
        private static void ThreeOnTwoTests()
        {
            // To make things interesting, here is a team of three people playing
            // a team of two people.
            // Initialize the players on the first team. Remember that the argument
            // passed to the Player constructor can be anything. It's strictly there
            // to help you uniquely identify people.
            var player1 = new Player(1);
            var player2 = new Player(2);
            var player3 = new Player(3);
            // Note the fluent-like API where you can add players to the Team and
            // specify the rating of each using their mean and standard deviation
            // (for more information on these parameters, see the accompanying post
            // http://www.moserware.com/2010/03/computing-your-skill.html )
            var team1 = new Team()
                        .AddPlayer(player1, new Rating(28, 7))
                        .AddPlayer(player2, new Rating(27, 6))
                        .AddPlayer(player3, new Rating(26, 5));
            // Create players for the second team
            var player4 = new Player(4);
            var player5 = new Player(5);
            var team2   = new Team()
                          .AddPlayer(player4, new Rating(30, 4))
                          .AddPlayer(player5, new Rating(31, 3));
            // The default parameters are fine
            var gameInfo = GameInfo.DefaultGameInfo;
            // We only have two teams, combine the teams into one parameter
            var teams = Teams.Concat(team1, team2);
            // Specify that the outcome was a 1st and 2nd place
            var newRatingsWinLoseExpected = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2);

            // Winners
            AssertRating(28.658, 6.770, newRatingsWinLoseExpected[player1]);
            AssertRating(27.484, 5.856, newRatingsWinLoseExpected[player2]);
            AssertRating(26.336, 4.917, newRatingsWinLoseExpected[player3]);
            // Losers
            AssertRating(29.785, 3.958, newRatingsWinLoseExpected[player4]);
            AssertRating(30.879, 2.983, newRatingsWinLoseExpected[player5]);
            // For fun, let's see what would have happened if there was an "upset" and the better players lost
            var newRatingsWinLoseUpset = TrueSkillCalculator.CalculateNewRatings(gameInfo, Teams.Concat(team1, team2), 2, 1);

            // Winners
            AssertRating(32.012, 3.877, newRatingsWinLoseUpset[player4]);
            AssertRating(32.132, 2.949, newRatingsWinLoseUpset[player5]);
            // Losers
            AssertRating(21.840, 6.314, newRatingsWinLoseUpset[player1]);
            AssertRating(22.474, 5.575, newRatingsWinLoseUpset[player2]);
            AssertRating(22.857, 4.757, newRatingsWinLoseUpset[player3]);
            // Note that we could have predicted this wasn't a very balanced game ahead of time because
            // it had low match quality.
            AssertMatchQuality(0.254, TrueSkillCalculator.CalculateMatchQuality(gameInfo, teams));
        }
Exemple #5
0
        private void UpdateTrueSkill(int player1_position, int player2_position)
        {
            // setup teams with updated ratings
            var _team1 = new Team(_player1, _rating1);
            var _team2 = new Team(_player2, _rating2);
            var _teams = Teams.Concat(_team1, _team2);

            // update the ratings
            _rating        = TrueSkillCalculator.CalculateNewRatings(_gameInfo, _teams, player1_position, player2_position);
            _rating1       = _rating [_player1];
            _rating2       = _rating [_player2];
            _match_quality = TrueSkillCalculator.CalculateMatchQuality(_gameInfo, _teams);
        }
Exemple #6
0
        public static async Task <MMgame> GenMatch(List <MMplayer> qplayers, int size)
        {
            List <MMplayer> result = new List <MMplayer>();
            int             c      = 0;

            List <MMplayer> players = new List <MMplayer>();

            players = qplayers.Where(x => x.Game == null).ToList();

            if (players.Count < size)
            {
                return(null);
            }

            double bestquality = 0;

            return(await Task.Run(() => {
                while (true)
                {
                    c++;
                    int i = 0;
                    var team1 = new Team();
                    var team2 = new Team();

                    var rnd = new Random();
                    List <MMplayer> thisresult = new List <MMplayer>(players.Select(x => new { value = x, order = rnd.Next() })
                                                                     .OrderBy(x => x.order).Select(x => x.value).Take(size).ToList());


                    foreach (var pl in thisresult)
                    {
                        if (i < result.Count() / 2)
                        {
                            team1.AddPlayer(new Player(i), new Rating(pl.MU, pl.SIGMA));
                        }
                        else
                        {
                            team2.AddPlayer(new Player(i), new Rating(pl.MU, pl.SIGMA));
                        }
                        i++;
                    }

                    var gameInfo = GameInfo.DefaultGameInfo;
                    var teams = Teams.Concat(team1, team2);

                    double thisquality = TrueSkillCalculator.CalculateMatchQuality(gameInfo, teams);

                    if (thisquality > bestquality)
                    {
                        bestquality = thisquality;
                        result = new List <MMplayer>(thisresult);
                    }

                    if (c > 10 && bestquality > 0.5)
                    {
                        break;
                    }
                    if (c > 50 && bestquality > 0.4)
                    {
                        break;
                    }
                    if (c > 200)
                    {
                        break;
                    }
                }

                MMgame game = new MMgame();
                game.Quality = bestquality;
                game.ID = 1;
                int j = 0;
                foreach (var pl in result)
                {
                    if (j < result.Count() / 2)
                    {
                        game.Team1.Add(new BasePlayer(pl));
                    }
                    else
                    {
                        game.Team2.Add(new BasePlayer(pl));
                    }
                    j++;
                }

                return game;
            }));
        }
Exemple #7
0
        /// <summary>
        /// Gets players that are most suited for competition (would provide as close as possible to an even match).  Both @candidates and @target need to have the TSCharacterComponent attached.
        /// </summary>
        /// <param name="candidates">the possible candidates to match against</param>
        /// <param name="target">the player for whom we wish to find matches</param>
        /// <returns>a list of character IDs in order of </returns>
        public static List <SkillMatchInfo> GetTopQualityMatches(IEnumerable <ICharacterInfo> candidates, ICharacterInfo target, int maxResults)
        {
            DateTime start = DateTime.UtcNow;
            List <SkillMatchInfo> matches = new List <SkillMatchInfo>();

            try
            {
                GameInfo gi = GameInfo.DefaultGameInfo;

                Player targetPlayer  = new Player(target.ID);
                double targetMu      = target.Properties.GetDoubleProperty((int)TSPropertyID.RatingMean).GetValueOrDefault();
                double targetSigma   = target.Properties.GetDoubleProperty((int)TSPropertyID.RatingStandardDeviation).GetValueOrDefault();
                Rating targetRating  = new Rating(targetMu, targetSigma);
                Team   targetTeam    = new Team(targetPlayer, targetRating);
                int    numCandidates = 0;

                IEnumerator <ICharacterInfo> enu = candidates.GetEnumerator();
                while (enu.MoveNext())
                {
                    numCandidates++;
                    Player player  = new Player(enu.Current.ID);
                    double mu      = enu.Current.Properties.GetDoubleProperty((int)TSPropertyID.RatingMean).GetValueOrDefault();
                    double sigma   = enu.Current.Properties.GetDoubleProperty((int)TSPropertyID.RatingStandardDeviation).GetValueOrDefault();
                    Rating rating  = new Rating(mu, sigma);
                    Team   team    = new Team(player, rating);
                    double quality = TrueSkillCalculator.CalculateMatchQuality(gi, Teams.Concat(targetTeam, team));

                    matches.Add(new SkillMatchInfo(enu.Current.ID, quality));
                }

                // Sort it
                matches.OrderBy(i => i.MatchQuality);

                // trim it, if necessary
                if (maxResults > 0)
                {
                    if (maxResults > matches.Count)
                    {
                        maxResults = matches.Count;
                    }

                    matches = matches.GetRange(0, maxResults - 1);
                }

                DateTime end            = DateTime.UtcNow;
                TimeSpan exeTime        = end - start;
                int      highestQuality = 0;
                if (matches.Count > 0)
                {
                    highestQuality = (int)Math.Floor(matches[0].MatchQuality * 100);
                }

                Log.LogMsg("TrueSkill match maker tested [" + numCandidates + "] candidates for character [" + target.CharacterName + " | " + target.ID + "]. Returned [" + matches.Count + "] possible matches in [" + exeTime.TotalMilliseconds + " ms]. Best match found had a [" + highestQuality + "%] quality rating.");
            }
            catch (Exception e)
            {
                Log.LogMsg("TrueSkill match maker encountered an error when searching for match candidates. " + e.Message);
            }

            return(matches);
        }
Exemple #8
0
 public static double GetRatingFor(List <Participant> redPlayers, List <Participant> bluePlayers)
 {
     return(TrueSkillCalculator.CalculateMatchQuality(
                GameInfo.DefaultGameInfo,
                ConvertToMoserware(bluePlayers, redPlayers)));
 }
Exemple #9
0
 public static double GetRatingFor(IEnumerable <IDictionary <Player, Rating> > teams)
 {
     return(TrueSkillCalculator.CalculateMatchQuality(
                GameInfo.DefaultGameInfo,
                teams));
 }