You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-elo/strategy.go

96 lines
2.5 KiB

package elo
import (
"math"
)
type StrategyFunc func(input *CalculatorInput) (r1 float64, r2 float64)
// Calculates elo based on a Win/Loss system.
func StrategyDefault(input *CalculatorInput) (float64, float64) {
R1 := math.Pow(10, input.PlayerOne/input.Deviation)
R2 := math.Pow(10, input.PlayerTwo/input.Deviation)
E1 := R1 / (R1 + R2)
E2 := R2 / (R1 + R2)
var S1, S2 float64
switch input.Outcome {
case OutcomePlayerOneWin:
S1 = 1.0
S2 = 0.0
case OutcomePlayerTwoWin:
S1 = 0.0
S2 = 1.0
case OutcomeDraw:
S1 = 0.5
S2 = 0.5
}
NewP1 := input.PlayerOne + input.K*(S1-E1)
NewP2 := input.PlayerTwo + input.K*(S2-E2)
return NewP1, NewP2
}
func determineWeightedSValues(winnerScore, loserScore, winnerE, loserE, weight float64) (S1, S2 float64) {
// determine the domination factor
D := winnerScore / (winnerScore + loserScore)
// calculate the amount of elo to be gained or lost, based on the domination factor and the expected chance
// for the winner of the match to win
// in general, G is smaller if the winner was heavily favored, and larger if the winner was not favored
G := (1.0 - winnerE) * D
// apply the score weight multiplier
G = G * math.Exp((-1*weight)*winnerE)
// add the weight to the expected chance to win to get a value between winnerE and 1.0 that
// is weighted based on the domination factor, and will be multiplied by K to get actual elo gained
S1 = G + winnerE
// and subtract G from E2 to get a value between 0 and loserE that will be multiplied by K to get actual elo lost
S2 = loserE - G
return S1, S2
}
// Calculates elo weighted by the final score.
// A more dominant score means greater elo gained.
func StrategyScored(input *CalculatorInput) (float64, float64) {
R1 := math.Pow(10, input.PlayerOne/input.Deviation)
R2 := math.Pow(10, input.PlayerTwo/input.Deviation)
E1 := R1 / (R1 + R2)
E2 := R2 / (R1 + R2)
var S1, S2 float64
if input.PlayerOneScore == 0 {
S1 = 0
S2 = 1
} else if input.PlayerTwoScore == 0 {
S1 = 1
S2 = 0
} else if input.PlayerOneScore > input.PlayerTwoScore { // P1 win
S1, S2 = determineWeightedSValues(
float64(input.PlayerOneScore),
float64(input.PlayerTwoScore),
E1,
E2,
input.ScoreWeight,
)
} else if input.PlayerOneScore < input.PlayerTwoScore { // P2 win
S2, S1 = determineWeightedSValues(
float64(input.PlayerTwoScore),
float64(input.PlayerOneScore),
E2,
E1,
input.ScoreWeight,
)
} else {
S1 = 0.5
S2 = 0.5
}
NewP1 := input.PlayerOne + input.K*(S1-E1)
NewP2 := input.PlayerTwo + input.K*(S2-E2)
return NewP1, NewP2
}