public async Task Update(ulong winner, ulong loser, bool draw) { var winnerRank = (await GetRank(winner))?.Rating ?? new Trueskill.TrueskillRating(_gameinfo.DefaultRating.Mean, _gameinfo.DefaultRating.StandardDeviation); var loserRank = (await GetRank(loser))?.Rating ?? new Trueskill.TrueskillRating(_gameinfo.DefaultRating.Mean, _gameinfo.DefaultRating.StandardDeviation); var teams = new[] { new Dictionary <ulong, Rating> { { winner, new Rating(winnerRank.Mean, winnerRank.StdDev) } }, new Dictionary <ulong, Rating> { { loser, new Rating(loserRank.Mean, loserRank.StdDev) } }, }; var results = TrueSkillCalculator.CalculateNewRatings( _gameinfo, teams, draw ? new[] { 0, 0 } : new[] { 0, 1 } ); var winnerResult = results[winner]; var loserResult = results[loser]; await SetRank(winner, winnerResult.Mean, winnerResult.StandardDeviation); await SetRank(loser, loserResult.Mean, loserResult.StandardDeviation); }
public IDictionary <Player, Rating> GetNewRatings() { var redTeam = new Team <Player>(); var blueTeam = new Team <Player>(); foreach (PlayerGameStats p in playerStats) { if (p.Team == HqmTeam.red) { redTeam.AddPlayer(p.Player, new Moserware.Skills.Rating(p.RatingMean, p.RatingStandardDeviation)); } else if (p.Team == HqmTeam.blue) { blueTeam.AddPlayer(p.Player, new Moserware.Skills.Rating(p.RatingMean, p.RatingStandardDeviation)); } } int redrank = winner == HqmTeam.red ? 1 : 2; int bluerank = winner == HqmTeam.blue ? 1 : 2; var newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(redTeam, blueTeam), redrank, bluerank); return(newRatings.ToDictionary(x => x.Key, x => new Rating() { Mean = x.Value.Mean, StandardDeviation = x.Value.StandardDeviation })); }
private int AdjustRatings(int kills, bool firstTeamWon, GameInfo gameInfo, IEnumerable <IDictionary <Player, Rating> > teams, string name1, string name2) { if (kills > 0) { const int team1 = 1; const int team2 = 2; int winner = firstTeamWon ? team1 : team2; int loser = firstTeamWon ? team2 : team1; string killerName = firstTeamWon ? name1 : name2; string victimName = firstTeamWon ? name2 : name1; var killer = GetPlayerData(killerName); var victim = GetPlayerData(victimName); killer.Kills++; victim.Deaths++; var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, winner, loser); foreach (var pair in newRatings) { string name = (string)pair.Key.Id; var playerData = _PlayerData[name]; playerData.Rating = pair.Value; } kills--; } return(kills); }
public async Task <IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return(Page()); } MatchPeople = MatchPeople.Where(x => x.Person.PersonName != null).ToList(); MatchPeople.ForEach(x => x.Person.PersonName = FirstCharToUpper(x.Person.PersonName)); _context.MatchPeople.AttachRange(MatchPeople); MatchPeople.ForEach(x => x.Person.GetData(_context)); //abstract this, this is used in Leaderboard var newSkills = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, GetTeams(MatchPeople), (int)Result.Win, (int)Result.Loss); for (int i = 0; i < MatchPeople.Count(); i++) { double oldRating = MatchPeople[i].Person.Rating.ConservativeRating; MatchPeople[i].Person.Rating = newSkills[MatchPeople[i].Person]; MatchPeople[i].RatingChange = MatchPeople[i].Person.Rating.ConservativeRating - oldRating; MatchPeople[i].Match = Match; MatchPeople[i].MatchResult = (i % 2) + 1; } await _context.SaveChangesAsync(); return(RedirectToPage("./Result")); }
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); }
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); }
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)); }
private void SetRating(GameInfo info, Team[] teamArray, int[] rankArray) { var teams = Teams.Concat(teamArray); var newRatings = TrueSkillCalculator.CalculateNewRatings(info, teams, rankArray); foreach (var newRating in newRatings) { var key = playerIdToRiderIdDic[(int)newRating.Key.Id]; KyoteiTrueSkillDic[key].Rating = newRating.Value; } }
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)); }
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); }
public static MMgame RateGame(List <MMplayer> t1, List <MMplayer> t2) { int i = 0; var team1 = new Team(); var team2 = new Team(); foreach (var pl in t1) { team1.AddPlayer(new Player(i), new Rating(pl.MU, pl.SIGMA)); pl.Games++; i++; } foreach (var pl in t2) { team2.AddPlayer(new Player(i), new Rating(pl.MU, pl.SIGMA)); pl.Games++; i++; } var gameInfo = GameInfo.DefaultGameInfo; var teams = Teams.Concat(team1, team2); var newRatingsWinLoseExpected = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2); MMgame game = new MMgame(); i = 0; foreach (var pl in team1.AsDictionary().Keys) { var res = newRatingsWinLoseExpected[pl]; t1[i].EXP = res.ConservativeRating; t1[i].MU = res.Mean; t1[i].SIGMA = res.StandardDeviation; game.Team1.Add(new BasePlayer(t1[i])); i++; } i = 0; foreach (var pl in team2.AsDictionary().Keys) { var res = newRatingsWinLoseExpected[pl]; t2[i].EXP = res.ConservativeRating; t2[i].MU = res.Mean; t2[i].SIGMA = res.StandardDeviation; game.Team2.Add(new BasePlayer(t2[i])); i++; } return(game); }
public override bool Call(string[] arguments) { if (arguments.Length != 1) { return(false); } TeamColor?color = TeamColorExtensions.FromString(arguments[0]); if (!color.HasValue) { Console.WriteLine("Color not found"); return(false); } IDictionary <Player, Rating> newRating = TrueSkillCalculator.CalculateNewRatings( GameInfo.DefaultGameInfo, Matchmaker.Logic.Teams.ConvertToMoserware(), color.Value is TeamColor.Blue ? 1 : 2, color.Value is TeamColor.Red ? 1 : 2); using (Context context = new Context()) { foreach (KeyValuePair <Player, Rating> player in newRating) { Participant participant = context.Participants.Find(player.Key.Id); if (participant == null) { Console.WriteLine($"Failed to find player {player.Key.Id.ToString()}"); continue; } participant.Mean = player.Value.Mean; participant.StandardDeviation = player.Value.StandardDeviation; participant.Rating = player.Value.ConservativeRating; } context.SaveChanges(); } Console.WriteLine("Updated rating for all players"); return(true); }
public IActionResult Update(Match match) { // Lookup Gameinfo var game = _gameService.Get(match.GameId); if (game == null) { return(NotFound()); } GameInfo gameInfo = new GameInfo(game.InitialMean, game.InitialStd, game.Beta, game.DynamicsFactor, game.DrawProbability); Dictionary <string, APIPlayer> apiPlayers = new Dictionary <string, APIPlayer>(); List <Team> moserTeams = new List <Team>(); List <int> moserTeamRanks = new List <int>(); match.Teams.ForEach(apiteam => { var moserTeam = new Team(); apiteam.Players.ForEach(playerId => { var apiplayer = _playerService.Get(playerId); apiPlayers.Add(playerId, apiplayer); moserTeam.AddPlayer(new Player(apiplayer.Id), new Rating(apiplayer.Rating.Mean, apiplayer.Rating.Std)); }); moserTeams.Add(moserTeam); moserTeamRanks.Add(apiteam.MatchRank); }); var teams = Teams.Concat(moserTeams.ToArray()); var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, moserTeamRanks.ToArray()); foreach (KeyValuePair <Player, Rating> newRating in newRatings) { APIPlayer player; apiPlayers.TryGetValue(newRating.Key.Id.ToString(), out player); player.Rating = new APIRating { Mean = newRating.Value.Mean, Std = newRating.Value.StandardDeviation, Multiplier = newRating.Value.ConservativeRating }; _playerService.Update(player.Id, player); } return(NoContent()); }
public async Task ApplyChallengeResults(ulong challengeId) { // Convert all solutions for the current challenge into a set of relevant data var teamRanks = await _solutions.GetSolutions(challengeId, uint.MaxValue) .AsAsyncEnumerable() .OrderBy(a => a.Rank) .SelectAwait(async a => new { player = a.Solution.UserId, rank = a.Rank, rating = Convert(await GetOrAddRating(a.Solution.UserId)), }) .Select(a => new { team = new Dictionary <ulong, Rating> { { a.player, a.rating } }, a.rank }).ToArrayAsync(); // Trueskill can't be applied if there were less than 2 entrants if (teamRanks.Length > 1) { // Extract the data out of that into separate collections var teams = teamRanks.Select(a => a.team).ToArray(); var ranks = teamRanks.Select(a => (int)a.rank).ToArray(); // Calculate trueskill ratings var results = TrueSkillCalculator.CalculateNewRatings( GameInfo.DefaultGameInfo, teams, ranks ); // Update database with new ratings foreach (var(key, rating) in results) { await _ratings.SetRating(key, rating.Mean, rating.StandardDeviation); } } // Decay rank of all players who did not participate in this challenge await _ratings.Decay(4); }
public async Task <IActionResult> PutPlayerInt([FromBody] TeamListModel TeamList) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var gameInfo = GameInfo.DefaultGameInfo; List <Team> teamList = new List <Team>(); List <int> positions = new List <int>(); foreach (ResultTeam team in TeamList.TeamList) { var team1 = new Team(); foreach (string ID in team.PlayerIds) { var player = await _context.Player.Include(e => e.Rating) .FirstOrDefaultAsync(e => e.PlayfabId == ID); team1.AddPlayer(player, player.Rating); } teamList.Add(team1); positions.Add(team.Place); } var teams = Teams.Concat(teamList.ToArray()); var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, positions); foreach (KeyValuePair <Player, Rating> item in newRatings) { item.Key.Rating = item.Value; _context.Entry(item.Key).State = EntityState.Modified; } try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { return(NotFound()); } return(Ok(newRatings)); }
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; })); }
public void Play(ColdBot.Models.Magic.Command command, String channel) { var teams = new List <Team>(); var decks = command.Decks; var gameMode = command.GameMode; var ratings = getRatings(decks, gameMode, channel); int playersPerTeam = command.GameMode.ShortName.Equals("ffa") ? 1 : 2; if (ratings == null) { slackService.SendMessage("Rating were not properly fetched. The game was not recorded.", channel); return; } if (decks.Count % playersPerTeam != 0) { slackService.SendMessage("Actual numbers players are not divisible by players per team. The game was not recorded.", channel); return; } var playersWithRating = new List <Tuple <Player, Rating> >(); // Player names and their rating from the database to TrueSkill objects for (int i = 0; i < decks.Count; i++) { var player = new Player(decks[i].Player.Name); var rating = new Rating(ratings[i].Mean, ratings[i].StandardDeviation); playersWithRating.Add((new Tuple <Player, Rating>(player, rating))); } // Divide players to teams while (playersWithRating.Count > 0) { var playersInTeam = new List <Tuple <Player, Rating> >(); for (int i = 0; i < playersPerTeam; i++) { playersInTeam.Add(new Tuple <Player, Rating>(playersWithRating[0].Item1, playersWithRating[0].Item2)); playersWithRating.RemoveAt(0); } var team = new Team(); foreach (var player in playersInTeam) { team.AddPlayer(player.Item1, player.Item2); } teams.Add(team); } // Calculate new rating var newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(teams.ToArray()), generateRanking(teams.Count).ToArray()); // For each new rating match with fetched ratings and update values in DB foreach (var playerWithRating in newRatings) { var rating = ratings .Where(x => x.Player.Name.ToLower().Equals(playerWithRating.Key.Id.ToString().ToLower())) .Where(x => x.GameMode.Equals(gameMode)) .FirstOrDefault(); rating.Mean = playerWithRating.Value.Mean; rating.StandardDeviation = playerWithRating.Value.StandardDeviation; rating.ConservativeRating = playerWithRating.Value.ConservativeRating; } context.SaveChanges(); }
/// <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); }
public void UpdateMetrics(Models.Team Team1, Models.Team Team2, int Score1, int Score2) { using (var dbContext = new Foostats2.Models.FoostatsContext()){ Team1 = dbContext.Teams.Include(x => x.Player1).Include(x => x.Player2).SingleOrDefault(x => x.Id == Team1.Id); Team2 = dbContext.Teams.Include(x => x.Player1).Include(x => x.Player2).SingleOrDefault(x => x.Id == Team2.Id); // reload var gameInfo = GameInfo.DefaultGameInfo; var t1p1Trueskill = dbContext.Trueskill. Include(x => x.Player). FirstOrDefault(x => x.Player.Id == Team1.Player1.Id); var t1p2Trueskill = Team1.Player2 == null ? null : dbContext.Trueskill. Include(x => x.Player). FirstOrDefault(x => x.Player.Id == Team1.Player2.Id); var t2p1Trueskill = dbContext.Trueskill. Include(x => x.Player). FirstOrDefault(x => x.Player.Id == Team2.Player1.Id); var t2p2Trueskill = Team2.Player2 == null ? null : dbContext.Trueskill. Include(x => x.Player). FirstOrDefault(x => x.Player.Id == Team2.Player2.Id); Rating t1p1, t1p2, t2p1, t2p2; t1p1 = t1p1Trueskill != null ? new Rating(t1p1Trueskill.Mean, t1p1Trueskill.StandardDeviation) : gameInfo.DefaultRating; t1p2 = t1p2Trueskill != null ? new Rating(t1p2Trueskill.Mean, t1p2Trueskill.StandardDeviation) : gameInfo.DefaultRating; t2p1 = t2p1Trueskill != null ? new Rating(t2p1Trueskill.Mean, t2p1Trueskill.StandardDeviation) : gameInfo.DefaultRating; t2p2 = t2p2Trueskill != null ? new Rating(t2p2Trueskill.Mean, t2p2Trueskill.StandardDeviation) : gameInfo.DefaultRating; var team1player1 = new Player(Team1.Player1.Id); var team1player2 = Team1.Player2 == null ? null : new Player(Team1.Player2.Id); var team2player1 = new Player(Team2.Player1.Id); var team2player2 = Team2.Player2 == null ? null : new Player(Team2.Player2.Id); var team1 = new Team(); team1.AddPlayer(team1player1, t1p1); if (team1player2 != null) { team1.AddPlayer(team1player2, t1p2); } var team2 = new Team(); team2.AddPlayer(team2player1, t2p1); if (team2player2 != null) { team2.AddPlayer(team2player2, t2p2); } var teams = Teams.Concat(team1, team2); var team1Place = Score1 >= Score2 ? 1 : 2; var team2Place = Score2 >= Score1 ? 1 : 2; var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, team1Place, team2Place); var team1player1NewRating = newRatings[team1player1]; Rating team1player2NewRating = team1player2 == null ? null : newRatings[team1player2]; var team2player1NewRating = newRatings[team2player1]; Rating team2player2NewRating = team2player2 == null ? null : newRatings[team2player2]; if (t1p1Trueskill != null) { t1p1Trueskill.Mean = team1player1NewRating.Mean; t1p1Trueskill.StandardDeviation = team1player1NewRating.StandardDeviation; t1p1Trueskill.ConservativeRating = team1player1NewRating.ConservativeRating; } else { dbContext.Trueskill.Add(new Models.Trueskill() { Player = Team1.Player1, Mean = team1player1NewRating.Mean, StandardDeviation = team1player1NewRating.StandardDeviation, ConservativeRating = team1player1NewRating.ConservativeRating }); } if (team1player2 != null) { if (t1p2Trueskill != null) { t1p2Trueskill.Mean = team1player2NewRating.Mean; t1p2Trueskill.StandardDeviation = team1player2NewRating.StandardDeviation; t1p2Trueskill.ConservativeRating = team1player2NewRating.ConservativeRating; } else { dbContext.Trueskill.Add(new Models.Trueskill() { Player = Team1.Player2, Mean = team1player2NewRating.Mean, StandardDeviation = team1player2NewRating.StandardDeviation, ConservativeRating = team1player2NewRating.ConservativeRating }); } } if (t2p1Trueskill != null) { t2p1Trueskill.Mean = team2player1NewRating.Mean; t2p1Trueskill.StandardDeviation = team2player1NewRating.StandardDeviation; t2p1Trueskill.ConservativeRating = team2player1NewRating.ConservativeRating; } else { dbContext.Trueskill.Add(new Models.Trueskill() { Player = Team2.Player1, Mean = team2player1NewRating.Mean, StandardDeviation = team2player1NewRating.StandardDeviation, ConservativeRating = team2player1NewRating.ConservativeRating }); } if (team2player2 != null) { if (t2p2Trueskill != null) { t2p2Trueskill.Mean = team2player2NewRating.Mean; t2p2Trueskill.StandardDeviation = team2player2NewRating.StandardDeviation; t2p2Trueskill.ConservativeRating = team2player2NewRating.ConservativeRating; } else { dbContext.Trueskill.Add(new Models.Trueskill() { Player = Team2.Player2, Mean = team2player2NewRating.Mean, StandardDeviation = team2player2NewRating.StandardDeviation, ConservativeRating = team2player2NewRating.ConservativeRating }); } } dbContext.SaveChanges(); } }
public static void recalcMatches(List <Person> playerList, List <Match> matchList, Double startMu, Double startSigma, Double multiplier, UInt16 decay, UInt32 decayValue, DateTime lastDate, ProgressBar progress) { lastDate += new TimeSpan(23, 59, 59); Dictionary <String, Person> playerMap = new Dictionary <string, Person>(); DateTime latestMatch = DateTime.MinValue; int matchTotal = matchList.Count; int counted = 0; if (progress != null) { progress.Value = 0; progress.Refresh(); } foreach (Person person in playerList) { person.Mu = startMu; person.Sigma = startSigma; person.Wins = 0; person.Losses = 0; person.Draws = 0; person.Multiplier = multiplier; person.DecayDays = 0; person.DecayMonths = 0; playerMap.Add(person.Name, person); } foreach (Match match in matchList) { if (progress != null) { counted++; progress.Value = (counted * 100) / matchTotal; progress.PerformStep(); } if (match.Timestamp <= lastDate) { Person p1 = playerMap[match.Player1]; Person p2 = playerMap[match.Player2]; if (decay > 0) { uint i = 0; if (decay < 3) { while (p1.LastMatch.AddDays(i).CompareTo(match.Timestamp) < 0) { i++; } p1.DecayDays += i; i = 0; while (p2.LastMatch.AddDays(i).CompareTo(match.Timestamp) < 0) { i++; } p2.DecayDays += i; } else { i = 0; while (p1.LastMatch.AddMonths((int)i).CompareTo(match.Timestamp) < 0) { i++; } p1.DecayMonths += i; i = 0; while (p2.LastMatch.AddMonths((int)i).CompareTo(match.Timestamp) < 0) { i++; } p2.DecayMonths += i; } switch (decay) { case 1: while (p1.DecayDays > decayValue - 1) { p1.decayScore(startSigma); p1.DecayDays -= decayValue; } while (p2.DecayDays > decayValue - 1) { p2.decayScore(startSigma); p2.DecayDays -= decayValue; } break; case 2: while (p1.DecayDays > (7 * decayValue) - 1) { p1.decayScore(startSigma); p1.DecayDays -= 7 * decayValue; } while (p2.DecayDays > (7 * decayValue) - 1) { p2.decayScore(startSigma); p2.DecayDays -= 7 * decayValue; } break; case 3: while (p1.DecayMonths > decayValue - 1) { p1.decayScore(startSigma); p1.DecayMonths -= decayValue; } while (p2.DecayMonths > decayValue - 1) { p2.decayScore(startSigma); p2.DecayMonths -= decayValue; } break; case 4: while (p1.DecayMonths > (12 * decayValue) - 1) { p1.decayScore(startSigma); p1.DecayMonths -= 12 * decayValue; } while (p2.DecayMonths > (12 * decayValue) - 1) { p2.decayScore(startSigma); p2.DecayMonths -= 12 * decayValue; } break; } } match.P1Score = p1.Score; match.P2Score = p2.Score; Player p1s = new Player(1); Player p2s = new Player(2); Rating p1r = new Rating(p1.Mu, p1.Sigma); Rating p2r = new Rating(p2.Mu, p2.Sigma); Team t1 = new Team(p1s, p1r); Team t2 = new Team(p2s, p2r); IDictionary <Player, Rating> newRatings = null; if (match.Winner == 0) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 1, 1); } else if (match.Winner == 1) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 1, 2); } else if (match.Winner == 2) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 2, 1); } p1.Mu = newRatings[p1s].Mean; p1.Sigma = newRatings[p1s].StandardDeviation; p2.Mu = newRatings[p2s].Mean; p2.Sigma = newRatings[p2s].StandardDeviation; match.P1Score2 = p1.Score; match.P2Score2 = p2.Score; p1.LastMatch = match.Timestamp; p2.LastMatch = match.Timestamp; if (latestMatch < match.Timestamp) { latestMatch = match.Timestamp; } if (match.Winner == 0) { p1.Draws++; p2.Draws++; } else if (match.Winner == 1) { p1.Wins++; p2.Losses++; } else if (match.Winner == 2) { p1.Losses++; p2.Wins++; } } else { break; } } foreach (Person p in playerList) { if (decay > 0) { uint i = 0; while (p.LastMatch.AddDays(i).CompareTo(latestMatch) < 0) { i++; } p.DecayDays += i; i = 0; while (p.LastMatch.AddMonths((int)i).CompareTo(latestMatch) < 0) { i++; } p.DecayMonths += i; switch (decay) { case 1: while (p.DecayDays > 0) { p.decayScore(startSigma); p.DecayDays--; } break; case 2: while (p.DecayDays > 6) { p.decayScore(startSigma); p.DecayDays -= 7; } break; case 3: while (p.DecayMonths > 0) { p.decayScore(startSigma); p.DecayMonths--; } break; case 4: while (p.DecayMonths > 11) { p.decayScore(startSigma); p.DecayMonths -= 12; } break; } } } }
public static double GetRatingFor(List <Participant> redPlayers, List <Participant> bluePlayers) { return(TrueSkillCalculator.CalculateMatchQuality( GameInfo.DefaultGameInfo, ConvertToMoserware(bluePlayers, redPlayers))); }
public static double GetRatingFor(IEnumerable <IDictionary <Player, Rating> > teams) { return(TrueSkillCalculator.CalculateMatchQuality( GameInfo.DefaultGameInfo, teams)); }
public static void recalcMatches(List <Person> playerList, List <Match> matchList, Double startMu, Double startSigma, Double multiplier, UInt16 decay, UInt32 decayValue, DateTime lastDate, ProgressBar progress) { lastDate += new TimeSpan(23, 59, 59); Dictionary <String, Person> playerMap = new Dictionary <string, Person>(); DateTime latestMatch = DateTime.MinValue; int matchTotal = matchList.Count; int counted = 0; if (progress != null) { progress.Value = 0; progress.Refresh(); } foreach (Person person in playerList) { person.Mu = startMu; person.Sigma = startSigma; person.Wins = 0; person.Losses = 0; person.Draws = 0; person.Multiplier = multiplier; person.DecayDays = 0; person.DecayMonths = 0; playerMap.Add(person.Name, person); } foreach (Match match in matchList) { if (progress != null) { counted++; progress.Value = (counted * 100) / matchTotal; progress.PerformStep(); } if (match.Timestamp <= lastDate) { Person p1 = playerMap[match.Player1]; Person p2 = playerMap[match.Player2]; //Explained on line 177 p1.DecayDays = 0; p2.DecayDays = 0; p1.DecayMonths = 0; p2.DecayMonths = 0; if (decay > 0) { uint i = 0; if (decay < 3) { while (p1.LastMatch.AddDays(i).CompareTo(match.Timestamp) < 0) { i++; } p1.DecayDays += i; i = 0; while (p2.LastMatch.AddDays(i).CompareTo(match.Timestamp) < 0) { i++; } p2.DecayDays += i; } else { i = 0; while (p1.LastMatch.AddMonths((int)i).CompareTo(match.Timestamp) < 0) { i++; } p1.DecayMonths += i; i = 0; while (p2.LastMatch.AddMonths((int)i).CompareTo(match.Timestamp) < 0) { i++; } p2.DecayMonths += i; } switch (decay) { case 1: while (p1.DecayDays > decayValue - 1) { p1.decayScore(startSigma); p1.DecayDays -= decayValue; } while (p2.DecayDays > decayValue - 1) { p2.decayScore(startSigma); p2.DecayDays -= decayValue; } break; case 2: while (p1.DecayDays > (7 * decayValue) - 1) { p1.decayScore(startSigma); p1.DecayDays -= 7 * decayValue; } while (p2.DecayDays > (7 * decayValue) - 1) { p2.decayScore(startSigma); p2.DecayDays -= 7 * decayValue; } break; case 3: while (p1.DecayMonths > decayValue - 1) { p1.decayScore(startSigma); p1.DecayMonths -= decayValue; } while (p2.DecayMonths > decayValue - 1) { p2.decayScore(startSigma); p2.DecayMonths -= decayValue; } break; case 4: while (p1.DecayMonths > (12 * decayValue) - 1) { p1.decayScore(startSigma); p1.DecayMonths -= 12 * decayValue; } while (p2.DecayMonths > (12 * decayValue) - 1) { p2.decayScore(startSigma); p2.DecayMonths -= 12 * decayValue; } break; } } /* * Correction to v1.0.1.6: * While decayDays/Months can be removed if they exceed the decayInterval, * if they do not they remain in the players cummulative decayDays/Months. * This means that players that would ordinarily not receive decay would. * * Ex. 6 Days between Matches with a week decayInterval. * Day 0 | Match 1 : No decayDays; No decay * DecayDays for player: 0 * Day 6 | Match 2 : +6 decayDays; 6 > 7 days for week interval? No; No decay * DecayDays for player: 6 * Day 12 | Match 3 : +6 decayDays; 12 > 7? Yes; unexpected decay * DecayDays for player: 5 * * To correct this after each player is selected from the match they will have * the decayDays/Months reset on line 85 and 246. */ match.P1Score = p1.Score; match.P2Score = p2.Score; Player p1s = new Player(1); Player p2s = new Player(2); Rating p1r = new Rating(p1.Mu, p1.Sigma); Rating p2r = new Rating(p2.Mu, p2.Sigma); Team t1 = new Team(p1s, p1r); Team t2 = new Team(p2s, p2r); IDictionary <Player, Rating> newRatings = null; if (match.Winner == 0) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 1, 1); } else if (match.Winner == 1) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 1, 2); } else if (match.Winner == 2) { newRatings = TrueSkillCalculator.CalculateNewRatings(GameInfo.DefaultGameInfo, Teams.Concat(t1, t2), 2, 1); } p1.Mu = newRatings[p1s].Mean; p1.Sigma = newRatings[p1s].StandardDeviation; p2.Mu = newRatings[p2s].Mean; p2.Sigma = newRatings[p2s].StandardDeviation; match.P1Score2 = p1.Score; match.P2Score2 = p2.Score; p1.LastMatch = match.Timestamp; p2.LastMatch = match.Timestamp; if (latestMatch < match.Timestamp) { latestMatch = match.Timestamp; } if (match.Winner == 0) { p1.Draws++; p2.Draws++; } else if (match.Winner == 1) { p1.Wins++; p2.Losses++; } else if (match.Winner == 2) { p1.Losses++; p2.Wins++; } } else { break; } } foreach (Person p in playerList) { //Explained on line 177 p.DecayDays = 0; p.DecayMonths = 0; if (decay > 0) { uint i = 0; while (p.LastMatch.AddDays(i).CompareTo(latestMatch) < 0) { i++; } p.DecayDays += i; i = 0; while (p.LastMatch.AddMonths((int)i).CompareTo(latestMatch) < 0) { i++; } p.DecayMonths += i; switch (decay) { /* * Correction to v1.0.1.6: * To correct 7 days and 1 week decayIntervals not yielding the same score, * it was found that the final player score adjustment did not take into * account the decayValue like in the match-to-match decay. This was added. */ case 1: while (p.DecayDays > decayValue - 1) { p.decayScore(startSigma); p.DecayDays -= decayValue; } break; case 2: while (p.DecayDays > (7 * decayValue) - 1) { p.decayScore(startSigma); p.DecayDays -= 7 * decayValue; } break; case 3: while (p.DecayMonths > decayValue - 1) { p.decayScore(startSigma); p.DecayMonths -= decayValue; } break; case 4: while (p.DecayMonths > (12 * decayValue) - 1) { p.decayScore(startSigma); p.DecayMonths -= 12 * decayValue; } break; } } } }
public static MMgameNG RateGame(Team team1, Team team2, string lobby, StartUp _mm, bool cmdr = false) { var gameInfo = GameInfo.DefaultGameInfo; var teams = Teams.Concat(team1, team2); var newRatingsWinLoseExpected = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, 1, 2); MMgameNG game = new MMgameNG(); game.Lobby = lobby; int i = 0; foreach (var pl in team1.AsDictionary().Keys) { var res = newRatingsWinLoseExpected[pl]; string name = pl.Id.ToString(); MMplayerNG mpl = new MMplayerNG(); MMPlRating plrat = new MMPlRating(); if (_mm.MMplayers.ContainsKey(name)) { mpl = _mm.MMplayers[name]; plrat = mpl.Rating[lobby].LastOrDefault().ShallowCopy(); plrat.Db = false; } else { mpl.Name = "Dummy" + i; } if (cmdr == true) { mpl = _mm.MMraces[name]; plrat = mpl.Rating[lobby].LastOrDefault().ShallowCopy(); plrat.Db = false; } double temp = plrat.EXP; plrat.EXP = res.ConservativeRating; mpl.ExpChange = plrat.EXP - temp; plrat.MU = res.Mean; plrat.SIGMA = res.StandardDeviation; plrat.Games++; plrat.Time = DateTime.UtcNow; mpl.Rating[lobby].Add(plrat); game.Team1.Add(mpl); i++; } foreach (var pl in team2.AsDictionary().Keys) { var res = newRatingsWinLoseExpected[pl]; string name = pl.Id.ToString(); MMplayerNG mpl = new MMplayerNG(); MMPlRating plrat = new MMPlRating(); if (_mm.MMplayers.ContainsKey(name)) { mpl = _mm.MMplayers[name]; plrat = mpl.Rating[lobby].LastOrDefault().ShallowCopy(); plrat.Db = false; } else { mpl.Name = "Dummy" + i; } if (cmdr == true) { mpl = _mm.MMraces[name]; plrat = mpl.Rating[lobby].LastOrDefault().ShallowCopy(); plrat.Db = false; } double temp = plrat.EXP; plrat.EXP = res.ConservativeRating; mpl.ExpChange = plrat.EXP - temp; plrat.MU = res.Mean; plrat.SIGMA = res.StandardDeviation; plrat.Games++; plrat.Time = DateTime.UtcNow; mpl.Rating[lobby].Add(plrat); game.Team2.Add(mpl); i++; } return(game); }
public async Task <ReplayData> TwoPlayerTestNotDrawn(ReplayData data, string type, Dictionary <string, uint> mmrIds, Dictionary <string, string> role) { // 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; // 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 var playerRatings = new Rating[10]; for (var i = 0; i < 10; i++) { _playerMmRs[i] = 0; _playerConserv[i] = 0; playerRatings[i] = gameInfo.DefaultRating; } for (var i = 0; i < 10; i++) { _typeId = type switch { "player" => mmrIds["player"], "hero" => mmrIds[data.ReplayPlayer[i].Hero], "role" => mmrIds[role[data.ReplayPlayer[i].Hero]], _ => _typeId }; var masterMmrData = await _context.MasterMmrData.Where(x => x.TypeValue == _typeId && x.GameType.ToString() == data.GameTypeId && x.BlizzId == data.ReplayPlayer[i].BlizzId && x.Region == data.Region).ToListAsync(); var count = 0; foreach (var mmrData in masterMmrData) { _playerConserv[count] = mmrData.ConservativeRating; playerRatings[count] = new Rating(mmrData.Mean, mmrData.StandardDeviation); count++; } } _teamOneWinner = data.ReplayPlayer[0].Winner; _teamTwoWinner = data.ReplayPlayer[9].Winner; var players = new Player[10]; for (var i = 0; i < 10; i++) { players[i] = new Player(i); } var team1 = new Team() .AddPlayer(players[0], playerRatings[0]) .AddPlayer(players[1], playerRatings[1]) .AddPlayer(players[2], playerRatings[2]) .AddPlayer(players[3], playerRatings[3]) .AddPlayer(players[4], playerRatings[4]); var team2 = new Team() .AddPlayer(players[5], playerRatings[5]) .AddPlayer(players[6], playerRatings[6]) .AddPlayer(players[7], playerRatings[7]) .AddPlayer(players[8], playerRatings[8]) .AddPlayer(players[9], playerRatings[9]); // 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. //Rating r1 = new Rating(); // 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 teamOneValue = 2; var teamTwoValue = 2; if (_teamOneWinner) { teamOneValue = 1; } else if (_teamTwoWinner) { teamTwoValue = 1; } var newRatings = TrueSkillCalculator.CalculateNewRatings(gameInfo, teams, teamOneValue, teamTwoValue); // 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 playerNewRatings = new Rating[10]; for (var i = 0; i < 10; i++) { playerNewRatings[i] = newRatings[players[i]]; switch (type) { case "player": data.ReplayPlayer[i].PlayerConservativeRating = playerNewRatings[i].ConservativeRating; data.ReplayPlayer[i].PlayerMean = playerNewRatings[i].Mean; data.ReplayPlayer[i].PlayerStandardDeviation = playerNewRatings[i].StandardDeviation; break; case "role": data.ReplayPlayer[i].RoleConservativeRating = playerNewRatings[i].ConservativeRating; data.ReplayPlayer[i].RoleMean = playerNewRatings[i].Mean; data.ReplayPlayer[i].RoleStandardDeviation = playerNewRatings[i].StandardDeviation; break; case "hero": data.ReplayPlayer[i].HeroConservativeRating = playerNewRatings[i].ConservativeRating; data.ReplayPlayer[i].HeroMean = playerNewRatings[i].Mean; data.ReplayPlayer[i].HeroStandardDeviation = playerNewRatings[i].StandardDeviation; break; } } return(data); } }