Moved the Glicko class to a separate file
Removed some unused 'custom upset' code
This commit is contained in:
parent
c8bdbaef86
commit
f35bb019cc
224
PepperBet/Glicko.vb
Executable file
224
PepperBet/Glicko.vb
Executable file
@ -0,0 +1,224 @@
|
||||
Public Class Glicko
|
||||
|
||||
'This constant defines how RD increases over time, higher=faster
|
||||
Private Const c = 0.6
|
||||
'Minimum RD (to ensure liquidity)
|
||||
Private Const RDmin = 30
|
||||
'Defined as part of the Glicko system
|
||||
Private Const q = 0.005756462732485
|
||||
|
||||
Enum Tiers
|
||||
Unknown
|
||||
Potato
|
||||
B
|
||||
A
|
||||
S
|
||||
X
|
||||
End Enum
|
||||
|
||||
Property K As Double
|
||||
Private _RD As Double
|
||||
Property RD As Double
|
||||
Set(value As Double)
|
||||
If value < RDmin Then
|
||||
_RD = RDmin
|
||||
Else
|
||||
_RD = value
|
||||
End If
|
||||
End Set
|
||||
Get
|
||||
Return _RD
|
||||
End Get
|
||||
End Property
|
||||
Property Name As String
|
||||
Property LastMatch As Long
|
||||
Property Tier As Tiers = Tiers.Unknown
|
||||
ReadOnly Property TierString As String
|
||||
Get
|
||||
Select Case Me.Tier
|
||||
Case Tiers.A
|
||||
Return " A "
|
||||
Case Tiers.B
|
||||
Return " B "
|
||||
Case Tiers.Potato
|
||||
Return " P "
|
||||
Case Tiers.S
|
||||
Return " S"
|
||||
Case Tiers.X
|
||||
Return " X "
|
||||
Case Tiers.Unknown
|
||||
Return "U "
|
||||
End Select
|
||||
Return ""
|
||||
End Get
|
||||
End Property
|
||||
ReadOnly Property TierLetter As String
|
||||
Get
|
||||
Select Case Me.Tier
|
||||
Case Tiers.A
|
||||
Return "A"
|
||||
Case Tiers.B
|
||||
Return "B"
|
||||
Case Tiers.Potato
|
||||
Return "P"
|
||||
Case Tiers.S
|
||||
Return "S"
|
||||
Case Tiers.X
|
||||
Return "X"
|
||||
Case Tiers.Unknown
|
||||
Return "U"
|
||||
End Select
|
||||
Return ""
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Updates this Glicko rating after a match. MAKE SURE TO COPY THE OPPONENT BEFORE UPDATING
|
||||
''' </summary>
|
||||
''' <param name="opp">Opponent that was faced</param>
|
||||
''' <param name="win">Did this Glicko win? Draw=0.5</param>
|
||||
''' <param name="t">Match number of this match</param>
|
||||
''' <remarks></remarks>
|
||||
Private Sub Update(opp() As Glicko, win() As Double, t As Long)
|
||||
Dim E As Double = 0
|
||||
Dim g As Double = 0
|
||||
Dim dsum As Double = 0
|
||||
Dim rsum As Double = 0
|
||||
|
||||
For i = 0 To opp.Count - 1
|
||||
g = 1 / Math.Sqrt(1 + (3 * Math.Pow(q, 2) * Math.Pow(opp(i).RD, 2)) / Math.Pow(Math.PI, 2))
|
||||
E = 1 / (1 + Math.Pow(10, (g * (Me.K - opp(i).K)) / -400))
|
||||
dsum += Math.Pow(g, 2) * E * (1 - E)
|
||||
rsum += g * (win(i) - E)
|
||||
Next
|
||||
|
||||
Dim dsq As Double = Math.Pow(Math.Pow(q, 2) * dsum, -1)
|
||||
|
||||
Me.K = Me.K + (q / ((1 / Math.Pow(Me.RD, 2)) + (1 / dsq))) * rsum
|
||||
Me.RD = Math.Max(Math.Sqrt(Math.Pow((1 / Math.Pow(Me.RD, 2)) + (1 / dsq), -1)), 30)
|
||||
Me.LastMatch = t
|
||||
End Sub
|
||||
|
||||
Public Shared Sub UpdateBatch(a As Glicko, b As Glicko, Acount As Integer, Bcount As Integer, t As Long, Optional Dcount As Integer = 0)
|
||||
Dim total As Integer = Acount + Bcount + Dcount
|
||||
Dim Aresults(total - 1) As Double
|
||||
Dim aopps(total - 1) As Glicko
|
||||
Dim Bresults(total - 1) As Double
|
||||
Dim bopps(total - 1) As Glicko
|
||||
Dim upset As Boolean = False
|
||||
Dim confidence As Double = Conf(a, b)
|
||||
|
||||
Dim tempb As New Glicko("", -1)
|
||||
tempb.K = b.K
|
||||
tempb.RD = b.RD
|
||||
|
||||
For i = 0 To total - 1
|
||||
aopps(i) = tempb
|
||||
bopps(i) = a
|
||||
Next
|
||||
For i = 0 To Acount - 1
|
||||
Aresults(i) = 1
|
||||
Next
|
||||
|
||||
For i = Acount To Acount + Bcount - 1
|
||||
Bresults(i) = 1
|
||||
Next
|
||||
|
||||
For i = Acount + Bcount To total - 1
|
||||
Aresults(i) = 0.5
|
||||
Bresults(i) = 0.5
|
||||
Next
|
||||
|
||||
If (Aresults.Average > 0.5 And b.K > a.K) Or (Bresults.Average > 0.5 And a.K > b.K) Then
|
||||
upset = True
|
||||
End If
|
||||
|
||||
b.Update(bopps, Bresults, t)
|
||||
a.Update(aopps, Aresults, t)
|
||||
|
||||
'My custom RD-increasing function in case of upsets
|
||||
'Note this increases after Glicko's decrease, so they oppose each other
|
||||
'If upset = True Then
|
||||
' 'U-factor is upset factor, the maximum possible increase in RD for a character if we trusted the results 100% accurately
|
||||
' Dim aUfactor As Double = u * a.RD * (confidence ^ e)
|
||||
' Dim bUfactor As Double = u * b.RD * (confidence ^ e)
|
||||
' 'F-factor is the fluke factor, more rounds means it's less of a fluke and we should increase more
|
||||
' Dim Ffactor As Double = 1 - (1 / (Aresults.Count + f))
|
||||
' 'C-factor is the closeness factor, close matches are weighted less (5-0 more increase than 5-4)
|
||||
' Dim Cfactor As Double = (Math.Max(Aresults.Average, Bresults.Average) - 0.5) * 2
|
||||
' a.RD = Math.Min(350, a.RD + (aUfactor * Ffactor * Cfactor))
|
||||
' b.RD = Math.Min(350, b.RD + (bUfactor * Ffactor * Cfactor))
|
||||
'End If
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Time-decays RD in preperation for a match
|
||||
''' </summary>
|
||||
''' <param name="t">Current match number</param>
|
||||
''' <remarks></remarks>
|
||||
Public Sub Prep(t As Long)
|
||||
Me.RD = Math.Min(350, Math.Sqrt(Math.Pow(Me.RD, 2) + Math.Pow(c, 2) * (t - Me.LastMatch)))
|
||||
End Sub
|
||||
|
||||
Public Sub New(name As String, t As Long)
|
||||
Me.K = 1500
|
||||
Me.RD = 350
|
||||
Me.Name = name
|
||||
Me.LastMatch = t
|
||||
End Sub
|
||||
|
||||
Public Function GenerateXMLItem() As XElement
|
||||
Dim ret As New XElement("glicko")
|
||||
ret.SetAttributeValue("name", Me.Name)
|
||||
ret.SetAttributeValue("k", Me.K)
|
||||
ret.SetAttributeValue("rd", Me.RD)
|
||||
ret.SetAttributeValue("lastmatch", Me.LastMatch)
|
||||
ret.SetAttributeValue("tier", CInt(Me.Tier))
|
||||
Return ret
|
||||
End Function
|
||||
|
||||
Private Shared Function erf(x As Double) As Double
|
||||
'Erf(x) approximation, max error 3e-7
|
||||
Dim a1 As Double = 0.0705230784
|
||||
Dim a2 As Double = 0.0422820123
|
||||
Dim a3 As Double = 0.0092705272
|
||||
Dim a4 As Double = 0.0001520143
|
||||
Dim a5 As Double = 0.0002765672
|
||||
Dim a6 As Double = 0.0000430638
|
||||
|
||||
a1 = a1 * x
|
||||
a2 = a2 * (x ^ 2)
|
||||
a3 = a3 * (x ^ 3)
|
||||
a4 = a4 * (x ^ 4)
|
||||
a5 = a5 * (x ^ 5)
|
||||
a6 = a6 * (x ^ 6)
|
||||
Return 1 - (1 / ((1 + a1 + a2 + a3 + a4 + a5 + a6) ^ 16))
|
||||
End Function
|
||||
|
||||
Private Shared Function CDF(x As Double, mu As Double, sigma As Double) As Double
|
||||
Return 0.5 * (1 + erf((x - mu) / (sigma * Math.Sqrt(2))))
|
||||
End Function
|
||||
|
||||
Private Shared Function StdNorm(x As Double) As Double
|
||||
Return Math.Exp(-0.5 * (x ^ 2)) / (Math.Sqrt(2 * Math.PI))
|
||||
End Function
|
||||
|
||||
Private Shared Function Norm(x As Double, mu As Double, sigma As Double) As Double
|
||||
Return (1 / sigma) * StdNorm((x - mu) / sigma)
|
||||
End Function
|
||||
|
||||
Public Shared Function Conf(a As Glicko, b As Glicko) As Double
|
||||
Dim sum As Double
|
||||
For i = 0 To 3000 Step 1
|
||||
sum += Math.Max(Norm(i, a.K, a.RD) - Norm(i, b.K, b.RD), 0)
|
||||
Next
|
||||
Return sum
|
||||
End Function
|
||||
|
||||
End Class
|
||||
|
||||
|
@ -1,19 +1,7 @@
|
||||
Module Pepperbet
|
||||
|
||||
'This constant defines how RD increases over time, higher=faster
|
||||
Const c = 0.6
|
||||
'Minimum RD (to ensure liquidity)
|
||||
Const RDmin = 30
|
||||
'Defined as part of the Glicko system
|
||||
Const q = 0.005756462732485
|
||||
'Seconds between updates
|
||||
Const updatedelay = 2
|
||||
'Upset RD maximum increase factor (infinite matches, as a fraction of RD)
|
||||
Const u = 0.5
|
||||
'Upset RD increase fluke-factor, more matches creates less chance of a fluke
|
||||
Const f = 0.5
|
||||
'Upset RD exponent, steepens modification curve with confidence
|
||||
Const e = 1.5
|
||||
Const version As String = "1.9.12"
|
||||
Const downloadurl As String = "https://long-cat.net/projects/pepperbet/pepperbet.exe?v=" & version
|
||||
Const versionurl As String = "https://long-cat.net/projects/pepperbet/version.txt?v=" & version
|
||||
@ -24,6 +12,10 @@
|
||||
Dim watching As Boolean = True
|
||||
Dim autoupdate As Boolean = False
|
||||
Dim lastupdatecheck As New DateTime(0)
|
||||
Dim accuracies(10) As Double
|
||||
'These are the time constants for the exponentially weighted falloff
|
||||
Dim accuracytimeconstants() As Double = {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000}
|
||||
|
||||
Enum ModeTypes
|
||||
Matchmaking
|
||||
Tournament
|
||||
@ -888,242 +880,6 @@
|
||||
End Function
|
||||
|
||||
|
||||
Private Class Glicko
|
||||
Enum Tiers
|
||||
Unknown
|
||||
Potato
|
||||
B
|
||||
A
|
||||
S
|
||||
X
|
||||
End Enum
|
||||
|
||||
Property K As Double
|
||||
Private _RD As Double
|
||||
Property RD As Double
|
||||
Set(value As Double)
|
||||
If value < RDmin Then
|
||||
_RD = RDmin
|
||||
Else
|
||||
_RD = value
|
||||
End If
|
||||
End Set
|
||||
Get
|
||||
Return _RD
|
||||
End Get
|
||||
End Property
|
||||
Property Name As String
|
||||
Property LastMatch As Long
|
||||
Property Tier As Tiers = Tiers.Unknown
|
||||
ReadOnly Property TierString As String
|
||||
Get
|
||||
Select Case Me.Tier
|
||||
Case Tiers.A
|
||||
Return " A "
|
||||
Case Tiers.B
|
||||
Return " B "
|
||||
Case Tiers.Potato
|
||||
Return " P "
|
||||
Case Tiers.S
|
||||
Return " S"
|
||||
Case Tiers.X
|
||||
Return " X "
|
||||
Case Tiers.Unknown
|
||||
Return "U "
|
||||
End Select
|
||||
Return ""
|
||||
End Get
|
||||
End Property
|
||||
ReadOnly Property TierLetter As String
|
||||
Get
|
||||
Select Case Me.Tier
|
||||
Case Tiers.A
|
||||
Return "A"
|
||||
Case Tiers.B
|
||||
Return "B"
|
||||
Case Tiers.Potato
|
||||
Return "P"
|
||||
Case Tiers.S
|
||||
Return "S"
|
||||
Case Tiers.X
|
||||
Return "X"
|
||||
Case Tiers.Unknown
|
||||
Return "U"
|
||||
End Select
|
||||
Return ""
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Updates this Glicko rating after a match. MAKE SURE TO COPY THE OPPONENT BEFORE UPDATING
|
||||
''' </summary>
|
||||
''' <param name="opp">Opponent that was faced</param>
|
||||
''' <param name="win">Did this Glicko win? Draw=0.5</param>
|
||||
''' <param name="t">Match number of this match</param>
|
||||
''' <remarks></remarks>
|
||||
Private Sub Update(opp() As Glicko, win() As Double, t As Long)
|
||||
Dim E As Double = 0
|
||||
Dim g As Double = 0
|
||||
Dim dsum As Double = 0
|
||||
Dim rsum As Double = 0
|
||||
|
||||
For i = 0 To opp.Count - 1
|
||||
g = 1 / Math.Sqrt(1 + (3 * Math.Pow(q, 2) * Math.Pow(opp(i).RD, 2)) / Math.Pow(Math.PI, 2))
|
||||
E = 1 / (1 + Math.Pow(10, (g * (Me.K - opp(i).K)) / -400))
|
||||
dsum += Math.Pow(g, 2) * E * (1 - E)
|
||||
rsum += g * (win(i) - E)
|
||||
Next
|
||||
|
||||
Dim dsq As Double = Math.Pow(Math.Pow(q, 2) * dsum, -1)
|
||||
|
||||
Me.K = Me.K + (q / ((1 / Math.Pow(Me.RD, 2)) + (1 / dsq))) * rsum
|
||||
Me.RD = Math.Max(Math.Sqrt(Math.Pow((1 / Math.Pow(Me.RD, 2)) + (1 / dsq), -1)), 30)
|
||||
Me.LastMatch = t
|
||||
End Sub
|
||||
|
||||
Public Shared Sub UpdateBatch(a As Glicko, b As Glicko, Acount As Integer, Bcount As Integer, t As Long, Optional Dcount As Integer = 0)
|
||||
Dim total As Integer = Acount + Bcount + Dcount
|
||||
Dim Aresults(total - 1) As Double
|
||||
Dim aopps(total - 1) As Glicko
|
||||
Dim Bresults(total - 1) As Double
|
||||
Dim bopps(total - 1) As Glicko
|
||||
Dim upset As Boolean = False
|
||||
Dim confidence As Double = Conf(a, b)
|
||||
|
||||
Dim tempb As New Glicko("", -1)
|
||||
tempb.K = b.K
|
||||
tempb.RD = b.RD
|
||||
|
||||
For i = 0 To total - 1
|
||||
aopps(i) = tempb
|
||||
bopps(i) = a
|
||||
Next
|
||||
For i = 0 To Acount - 1
|
||||
Aresults(i) = 1
|
||||
Next
|
||||
|
||||
For i = Acount To Acount + Bcount - 1
|
||||
Bresults(i) = 1
|
||||
Next
|
||||
|
||||
For i = Acount + Bcount To total - 1
|
||||
Aresults(i) = 0.5
|
||||
Bresults(i) = 0.5
|
||||
Next
|
||||
|
||||
If (Aresults.Average > 0.5 And b.K > a.K) Or (Bresults.Average > 0.5 And a.K > b.K) Then
|
||||
upset = True
|
||||
End If
|
||||
|
||||
b.Update(bopps, Bresults, t)
|
||||
a.Update(aopps, Aresults, t)
|
||||
|
||||
'My custom RD-increasing function in case of upsets
|
||||
'Note this increases after Glicko's decrease, so they oppose each other
|
||||
'If upset = True Then
|
||||
' 'U-factor is upset factor, the maximum possible increase in RD for a character if we trusted the results 100% accurately
|
||||
' Dim aUfactor As Double = u * a.RD * (confidence ^ e)
|
||||
' Dim bUfactor As Double = u * b.RD * (confidence ^ e)
|
||||
' 'F-factor is the fluke factor, more rounds means it's less of a fluke and we should increase more
|
||||
' Dim Ffactor As Double = 1 - (1 / (Aresults.Count + f))
|
||||
' 'C-factor is the closeness factor, close matches are weighted less (5-0 more increase than 5-4)
|
||||
' Dim Cfactor As Double = (Math.Max(Aresults.Average, Bresults.Average) - 0.5) * 2
|
||||
' a.RD = Math.Min(350, a.RD + (aUfactor * Ffactor * Cfactor))
|
||||
' b.RD = Math.Min(350, b.RD + (bUfactor * Ffactor * Cfactor))
|
||||
'End If
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
Public Shared Sub UpdateTiers(a As Glicko, b As Glicko)
|
||||
If Now.DayOfWeek = DayOfWeek.Thursday And Now.Hour >= 18 And Now.Hour < 21 Then
|
||||
'shaker classic
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
If a.Tier = Tiers.Unknown And b.Tier = Tiers.Unknown Then
|
||||
Exit Sub
|
||||
ElseIf a.Tier = Tiers.Unknown Then
|
||||
a.Tier = b.Tier
|
||||
ElseIf b.Tier = Tiers.Unknown Then
|
||||
b.Tier = a.Tier
|
||||
ElseIf b.Tier = a.Tier Then
|
||||
Exit Sub
|
||||
Else
|
||||
a.Tier = Tiers.Unknown
|
||||
b.Tier = Tiers.Unknown
|
||||
|
||||
End If
|
||||
Save()
|
||||
End Sub
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Time-decays RD in preperation for a match
|
||||
''' </summary>
|
||||
''' <param name="t">Current match number</param>
|
||||
''' <remarks></remarks>
|
||||
Public Sub Prep(t As Long)
|
||||
Me.RD = Math.Min(350, Math.Sqrt(Math.Pow(Me.RD, 2) + Math.Pow(c, 2) * (t - Me.LastMatch)))
|
||||
End Sub
|
||||
|
||||
Public Sub New(name As String, t As Long)
|
||||
Me.K = 1500
|
||||
Me.RD = 350
|
||||
Me.Name = name
|
||||
Me.LastMatch = t
|
||||
End Sub
|
||||
|
||||
Public Function GenerateXMLItem() As XElement
|
||||
Dim ret As New XElement("glicko")
|
||||
ret.SetAttributeValue("name", Me.Name)
|
||||
ret.SetAttributeValue("k", Me.K)
|
||||
ret.SetAttributeValue("rd", Me.RD)
|
||||
ret.SetAttributeValue("lastmatch", Me.LastMatch)
|
||||
ret.SetAttributeValue("tier", CInt(Me.Tier))
|
||||
Return ret
|
||||
End Function
|
||||
|
||||
Private Shared Function erf(x As Double) As Double
|
||||
'Erf(x) approximation, max error 3e-7
|
||||
Dim a1 As Double = 0.0705230784
|
||||
Dim a2 As Double = 0.0422820123
|
||||
Dim a3 As Double = 0.0092705272
|
||||
Dim a4 As Double = 0.0001520143
|
||||
Dim a5 As Double = 0.0002765672
|
||||
Dim a6 As Double = 0.0000430638
|
||||
|
||||
a1 = a1 * x
|
||||
a2 = a2 * (x ^ 2)
|
||||
a3 = a3 * (x ^ 3)
|
||||
a4 = a4 * (x ^ 4)
|
||||
a5 = a5 * (x ^ 5)
|
||||
a6 = a6 * (x ^ 6)
|
||||
Return 1 - (1 / ((1 + a1 + a2 + a3 + a4 + a5 + a6) ^ 16))
|
||||
End Function
|
||||
|
||||
Private Shared Function CDF(x As Double, mu As Double, sigma As Double) As Double
|
||||
Return 0.5 * (1 + erf((x - mu) / (sigma * Math.Sqrt(2))))
|
||||
End Function
|
||||
|
||||
Private Shared Function StdNorm(x As Double) As Double
|
||||
Return Math.Exp(-0.5 * (x ^ 2)) / (Math.Sqrt(2 * Math.PI))
|
||||
End Function
|
||||
|
||||
Private Shared Function Norm(x As Double, mu As Double, sigma As Double) As Double
|
||||
Return (1 / sigma) * StdNorm((x - mu) / sigma)
|
||||
End Function
|
||||
|
||||
Public Shared Function Conf(a As Glicko, b As Glicko) As Double
|
||||
Dim sum As Double
|
||||
For i = 0 To 3000 Step 1
|
||||
sum += Math.Max(Norm(i, a.K, a.RD) - Norm(i, b.K, b.RD), 0)
|
||||
Next
|
||||
Return sum
|
||||
End Function
|
||||
|
||||
End Class
|
||||
|
||||
Private Sub Save()
|
||||
Dim thr As New Threading.Thread(AddressOf SaveDelegate)
|
||||
thr.Start()
|
||||
|
@ -97,6 +97,7 @@
|
||||
<Import Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Glicko.vb" />
|
||||
<Compile Include="PepperBet.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
|
Loading…
x
Reference in New Issue
Block a user