func TwoOnTwoUnbalancedDrawTest(t *testing.T, calc skills.Calc) { gameInfo := skills.DefaultGameInfo team1 := skills.NewTeam() team1.AddPlayer(1, skills.NewRating(15, 8)) team1.AddPlayer(2, skills.NewRating(20, 6)) team2 := skills.NewTeam() team2.AddPlayer(3, skills.NewRating(25, 4)) team2.AddPlayer(4, skills.NewRating(30, 3)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 1) // Winners AssertRating(t, 21.570, 6.556, newRatings[1]) AssertRating(t, 23.696, 5.418, newRatings[2]) // Losers AssertRating(t, 23.357, 3.833, newRatings[3]) AssertRating(t, 29.075, 2.931, newRatings[4]) AssertMatchQuality(t, 0.214, calc.CalcMatchQual(gameInfo, teams)) }
func TwoOnTwoUpsetTest(t *testing.T, calc skills.Calc) { gameInfo := skills.DefaultGameInfo team1 := skills.NewTeam() team1.AddPlayer(1, skills.NewRating(20, 8)) team1.AddPlayer(2, skills.NewRating(25, 6)) team2 := skills.NewTeam() team2.AddPlayer(3, skills.NewRating(35, 7)) team2.AddPlayer(4, skills.NewRating(40, 5)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 2) // Winners AssertRating(t, 29.698, 7.008, newRatings[1]) AssertRating(t, 30.455, 5.594, newRatings[2]) // Losers AssertRating(t, 27.575, 6.346, newRatings[3]) AssertRating(t, 36.211, 4.768, newRatings[4]) AssertMatchQuality(t, 0.084, calc.CalcMatchQual(gameInfo, teams)) }
func TwoPlayerChessTestNotDrawn(t *testing.T, calc skills.Calc) { // Inspired by a real bug :-) gameInfo := &skills.GameInfo{ InitialMean: 1200, InitialStddev: 1200 / 3, Beta: 200, DynamicsFactor: 1200 / 300, DrawProbability: 0.03, } team1 := skills.NewTeam() team1.AddPlayer(1, skills.NewRating(1301.0007, 42.9232)) team2 := skills.NewTeam() team2.AddPlayer(2, skills.NewRating(1188.7560, 42.5570)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 2) player1NewRating := newRatings[1] AssertRating(t, 1304.7820836053318, 42.843513887848658, player1NewRating) player2NewRating := newRatings[2] AssertRating(t, 1185.0383099003536, 42.485604606897752, player2NewRating) }
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 ThreeOnTwoTests(t *testing.T, calc skills.Calc) { gameInfo := skills.DefaultGameInfo team1 := skills.NewTeam() team1.AddPlayer(1, skills.NewRating(28, 7)) team1.AddPlayer(2, skills.NewRating(27, 6)) team1.AddPlayer(3, skills.NewRating(26, 5)) team2 := skills.NewTeam() team2.AddPlayer(4, skills.NewRating(30, 4)) team2.AddPlayer(5, skills.NewRating(31, 3)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 2) // Winners AssertRating(t, 28.658, 6.770, newRatings[1]) AssertRating(t, 27.484, 5.856, newRatings[2]) AssertRating(t, 26.336, 4.917, newRatings[3]) // Losers AssertRating(t, 29.785, 3.958, newRatings[4]) AssertRating(t, 30.879, 2.983, newRatings[5]) newRatings = calc.CalcNewRatings(gameInfo, teams, 2, 1) // Losers AssertRating(t, 21.840, 6.314, newRatings[1]) AssertRating(t, 22.474, 5.575, newRatings[2]) AssertRating(t, 22.857, 4.757, newRatings[3]) // Winners AssertRating(t, 32.012, 3.877, newRatings[4]) AssertRating(t, 32.132, 2.949, newRatings[5]) AssertMatchQuality(t, 0.254, calc.CalcMatchQual(gameInfo, teams)) }
func OneOnTwoSomewhatBalanced(t *testing.T, calc skills.Calc) { gameInfo := skills.DefaultGameInfo team1 := skills.NewTeam() team1.AddPlayer(1, skills.NewRating(40, 6)) team2 := skills.NewTeam() team2.AddPlayer(2, skills.NewRating(20, 7)) team2.AddPlayer(3, skills.NewRating(25, 8)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 2) // Winners AssertRating(t, 42.744, 5.602, newRatings[1]) // Losers AssertRating(t, 16.266, 6.359, newRatings[2]) AssertRating(t, 20.123, 7.028, newRatings[3]) AssertMatchQuality(t, 0.478, calc.CalcMatchQual(gameInfo, teams)) }
func twoTeamUpdateRatings(gi *skills.GameInfo, newSkills skills.PlayerRatings, selfTeam, otherTeam skills.Team, comparison int) { drawMargin := drawMarginFromDrawProbability(gi.DrawProbability, gi.Beta) betaSqr := numerics.Sqr(gi.Beta) tauSqr := numerics.Sqr(gi.DynamicsFactor) totalPlayers := selfTeam.PlayerCount() + otherTeam.PlayerCount() selfMeanSum := selfTeam.Accum(skills.MeanSum) otherMeanSum := otherTeam.Accum(skills.MeanSum) c := math.Sqrt(selfTeam.Accum(skills.VarianceSum) + otherTeam.Accum(skills.VarianceSum) + float64(totalPlayers)*betaSqr) winningMean := selfMeanSum losingMean := otherMeanSum if comparison == skills.Lose { winningMean, losingMean = losingMean, winningMean } meanDelta := winningMean - losingMean var v, w, rankMultiplier float64 if comparison != skills.Draw { v = vExceedsMarginC(meanDelta, drawMargin, c) w = wExceedsMarginC(meanDelta, drawMargin, c) rankMultiplier = float64(comparison) } else { v = vWithinMarginC(meanDelta, drawMargin, c) w = wWithinMarginC(meanDelta, drawMargin, c) rankMultiplier = 1 } for p, r := range selfTeam.PlayerRatings { prevPlayerRating := r meanMultiplier := (prevPlayerRating.Variance() + tauSqr) / c stdDevMultiplier := (prevPlayerRating.Variance() + tauSqr) / numerics.Sqr(c) playerMeanDelta := rankMultiplier * meanMultiplier * v newMean := prevPlayerRating.Mean() + playerMeanDelta newStdDev := math.Sqrt((prevPlayerRating.Variance() + tauSqr) * (1 - w*stdDevMultiplier)) newSkills[p] = skills.NewRating(newMean, newStdDev) } }
func OneOnOneMassiveUpsetDrawTest(t *testing.T, calc skills.Calc) { gameInfo := skills.DefaultGameInfo team1 := skills.NewTeam() team1.AddPlayer(1, gameInfo.DefaultRating()) team2 := skills.NewTeam() team2.AddPlayer(2, skills.NewRating(50, 12.5)) teams := []skills.Team{team1, team2} newRatings := calc.CalcNewRatings(gameInfo, teams, 1, 1) player1NewRating := newRatings[1] AssertRating(t, 31.662, 7.137, player1NewRating) player2NewRating := newRatings[2] AssertRating(t, 35.010, 7.910, player2NewRating) AssertMatchQuality(t, 0.110, calc.CalcMatchQual(gameInfo, teams)) }
func NewMatchmakerParticipant(connection *ClientConnection) *MatchmakerParticipant { // TrueSkill stuff team := skills.NewTeam() team.AddPlayer(connection.client.Id, skills.NewRating(connection.client.RatingMean, connection.client.RatingStdDev)) return &MatchmakerParticipant{ connection: connection, client: connection.client, enrollTime: time.Now(), team: team, points: connection.client.LadderPoints, rating: connection.client.RatingMean, radius: connection.client.LadderSearchRadius, regions: connection.client.LadderSearchRegions, matching: false, abort: make(chan bool), match: make(chan *MatchmakerMatch), } }
func twoPlayerCalcNewRating(gi *skills.GameInfo, selfRating, oppRating skills.Rating, comparison int) skills.Rating { drawMargin := drawMarginFromDrawProbability(gi.DrawProbability, gi.Beta) c := math.Sqrt(numerics.Sqr(selfRating.Stddev()) + numerics.Sqr(oppRating.Stddev()) + 2*numerics.Sqr(gi.Beta)) winningMean := selfRating.Mean() losingMean := oppRating.Mean() if comparison == skills.Lose { winningMean = oppRating.Mean() losingMean = selfRating.Mean() } meanDelta := winningMean - losingMean var v, w, rankMultiplier float64 if comparison != skills.Draw { v = vExceedsMarginC(meanDelta, drawMargin, c) w = wExceedsMarginC(meanDelta, drawMargin, c) rankMultiplier = float64(comparison) } else { v = vWithinMarginC(meanDelta, drawMargin, c) w = wWithinMarginC(meanDelta, drawMargin, c) rankMultiplier = 1 } meanMultiplier := (numerics.Sqr(selfRating.Stddev()) + numerics.Sqr(gi.DynamicsFactor)) / c varianceWithDynamics := numerics.Sqr(selfRating.Stddev()) + numerics.Sqr(gi.DynamicsFactor) stdDevMultiplier := varianceWithDynamics / numerics.Sqr(c) newMean := selfRating.Mean() + (rankMultiplier * meanMultiplier * v) newStdDev := math.Sqrt(varianceWithDynamics * (1 - w*stdDevMultiplier)) return skills.NewRating(newMean, newStdDev) }
func rating2srating(r Rating) skills.Rating { return skills.NewRating(r.Mean, r.Stddev) }