func calculateNewRating(winnerId, loserId int64, winnerRating, winnerStdDev, loserRating, loserStdDev float64) (winnerNewRating, winnerNewStdDev, loserNewRating, loserNewStdDev, quality float64) { team1 := skills.NewTeam() team2 := skills.NewTeam() team1.AddPlayer(winnerId, skills.NewRating(winnerRating, winnerStdDev)) team2.AddPlayer(loserId, skills.NewRating(loserRating, loserStdDev)) teams := []skills.Team{team1, team2} var calc trueskill.TwoPlayerCalc ratings := calc.CalcNewRatings(skills.DefaultGameInfo, teams, 1, 2) quality = calc.CalcMatchQual(skills.DefaultGameInfo, teams) return ratings[winnerId].Mean(), ratings[winnerId].Stddev(), ratings[loserId].Mean(), ratings[loserId].Stddev(), quality }
func RateGames(players []int64, games []Result) (Rankings, error) { // TODO(dm): this function is messy because the API we are depending on // (GoSkills) is pretty weird. Could be cleaned up by just moving the // calculation logic into our own impl if err := checkGameParticipantsArePlayers(players, games); err != nil { return nil, err } ratings := DefaultRatings(players) for _, r := range games { whiteTeam := skills.NewTeam() whiteTeam.AddPlayer(r.WhiteID, rating2srating(ratings[r.WhiteID])) blackTeam := skills.NewTeam() blackTeam.AddPlayer(r.BlackID, rating2srating(ratings[r.BlackID])) var twoPlayerCalc trueskill.TwoPlayerCalc ranks, err := outcomeToRanks(r.Outcome) if err != nil { return nil, err } newSkills := twoPlayerCalc.CalcNewRatings(gameInfo, []skills.Team{whiteTeam, blackTeam}, ranks...) ratings[r.WhiteID] = srating2rating(newSkills[r.WhiteID]) ratings[r.BlackID] = srating2rating(newSkills[r.BlackID]) } ranks := make(Rankings, 0) for id, rating := range ratings { ranks = append(ranks, Ranking{PlayerID: id, Rating: rating, Rank: -1}) } sort.Sort(ranks) var prevRating Rating for i, _ := range ranks { if prevRating == ranks[i].Rating { ranks[i].Rank = ranks[i-1].Rank } else { ranks[i].Rank = i + 1 } prevRating = ranks[i].Rating } return ranks, nil }