Skip to content

Commit

Permalink
change trial period to apply inverse multiplier to all non-new players (
Browse files Browse the repository at this point in the history
#11)

update kotlin version
refactor BigDecimal.pow
  • Loading branch information
wakingrufus authored Feb 28, 2019
1 parent 036e613 commit e7e5676
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 52 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ Library for ELO calculations for game leagues
## Features
- Fully configurable _starting rating_, _k-factor_, and _xi_ values
- Support for _n_-sized teams
- "Exhibition" period: first _n_ games can have and adjustment multiplier in order to move a player to their proper rating faster. Their opponents will get an inverse multiplier.
- "Exhibition" period: first _n_ games can have and adjustment multiplier in order to move a player to their proper rating faster.
Other players will get an inverse multiplier.

## Usage

Expand Down
32 changes: 11 additions & 21 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
buildscript {
ext.kotlin_version = '1.2.0'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
repositories {
mavenCentral()
}
}

plugins {
id 'java'
id 'idea'
id "org.jetbrains.kotlin.jvm" version "1.2.0"
id "org.jetbrains.kotlin.jvm" version "1.3.21"
id 'jacoco'
id 'maven'
id 'signing'
Expand All @@ -27,23 +17,23 @@ ext {
isReleaseVersion = !(project.version =~ /-SNAPSHOT$/)
}

version = "0.3.1"
version = "0.4.0"
project.group = "com.github.wakingrufus"

dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
compile 'org.projectlombok:lombok:1.16.18'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile 'org.slf4j:slf4j-api:1.7.25'
compile 'io.github.microutils:kotlin-logging:1.4.4'
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile("io.github.microutils:kotlin-logging:1.6.23")
compile "org.jetbrains.kotlin:kotlin-reflect"
compile "org.jsoup:jsoup:1.10.3"

testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"
testCompile 'org.mockito:mockito-core:2.8.9'
testCompile 'junit:junit:4.12'
testCompile 'junit:junit:4.12'
testCompile "com.nhaarman:mockito-kotlin-kt1.1:1.5.0"
testCompile 'org.slf4j:slf4j-log4j12:1.7.25'
testCompile "org.assertj:assertj-core:3.11.1"
}

idea {
Expand All @@ -52,8 +42,8 @@ idea {
}
}

task wrapper(type: Wrapper) {
gradleVersion = '4.2.1'
wrapper {
gradleVersion = '5.2'
}

jacocoTestReport {
Expand Down
35 changes: 17 additions & 18 deletions src/main/kotlin/com/github/wakingrufus/elo/BigDecimal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ package com.github.wakingrufus.elo
import java.math.BigDecimal
import java.math.MathContext

fun BigDecimal.pow(exponent: BigDecimal): BigDecimal {
val signOf2 = exponent.signum()

fun BigDecimal.pow(exponent: BigDecimal, mathContext: MathContext = MathContext.DECIMAL64): BigDecimal {
// Perform X^(A+B)=X^A*X^B (B = remainder)
val dn1 = this.toDouble()
// Compare the same row of digits according to context
val n2 = exponent.multiply(BigDecimal(signOf2)) // n2 is now positive
val remainderOf2 = n2.remainder(BigDecimal.ONE)
val n2IntPart = n2.subtract(remainderOf2)
// Calculate big part of the power using context -
// bigger range and performance but lower accuracy
val intPow = this.pow(n2IntPart.intValueExact())
val doublePow = BigDecimal(Math.pow(dn1, remainderOf2.toDouble()))
var result = intPow.multiply(doublePow)

// Fix negative power
if (signOf2 == -1)
result = BigDecimal.ONE.divide(result, MathContext.DECIMAL64)
return result
return exponent.signum().let { signOfExponent ->
// Compare the same row of digits according to context
exponent.multiply(BigDecimal(signOfExponent)).let { n2 ->
n2.remainder(BigDecimal.ONE).let { remainderOfExponent ->
// Calculate big part of the power using context -
// bigger range and performance but lower accuracy
this.pow(n2.subtract(remainderOfExponent).intValueExact()).let { intPow ->
intPow.multiply(BigDecimal(Math.pow(this.toDouble(), remainderOfExponent.toDouble()))).let {
// Fix negative power
if (signOfExponent == -1)
return BigDecimal.ONE.divide(it, mathContext) else it
}
}
}
}
}
}
15 changes: 5 additions & 10 deletions src/main/kotlin/com/github/wakingrufus/elo/EloCalculator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,10 @@ fun calculateKfactor(kfactorBase: Int,
trialPeriod: Int,
trialMultiplier: Int,
playerGamesPlayed: Int,
otherPlayerGamesPlayed: Int): Int {
var kFactor = kfactorBase

if (playerGamesPlayed < trialPeriod) {
kFactor *= trialMultiplier

}
if (otherPlayerGamesPlayed < trialPeriod) {
kFactor /= trialMultiplier
allPlayers: List<Player>): Int {
return when {
playerGamesPlayed < trialPeriod -> kfactorBase * trialMultiplier
allPlayers.any { it.gamesPlayed < trialPeriod } -> kfactorBase / trialMultiplier
else -> kfactorBase
}
return kFactor
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ fun calculateChanges(league: League, players: Map<String, Player>, game: Game):
logger.debug("team1ActualScore: " + team1ActualScore.toPlainString())
logger.debug("team2ActualScore: " + team2ActualScore.toPlainString())

val newPlayerPresent = team1Players.plus(team2Players).any { it.gamesPlayed < league.trialPeriod }

return team1Players.map { player ->
RatingHistoryItem(
gameId = game.id,
Expand All @@ -36,7 +38,7 @@ fun calculateChanges(league: League, players: Map<String, Player>, game: Game):
trialPeriod = league.trialPeriod,
trialMultiplier = league.trialKFactorMultiplier,
playerGamesPlayed = player.gamesPlayed,
otherPlayerGamesPlayed = calculateTeamGamesPlayed(team2Players)
allPlayers = team1Players + team2Players
),
score = team1ActualScore,
expectedScore = team1ExpectedScoreRatio
Expand All @@ -54,7 +56,7 @@ fun calculateChanges(league: League, players: Map<String, Player>, game: Game):
trialPeriod = league.trialPeriod,
trialMultiplier = league.trialKFactorMultiplier,
playerGamesPlayed = player.gamesPlayed,
otherPlayerGamesPlayed = calculateTeamGamesPlayed(team1Players)
allPlayers = team1Players + team2Players
),
score = team2ActualScore,
expectedScore = team2ExpectedScoreRatio
Expand Down
27 changes: 27 additions & 0 deletions src/test/kotlin/com/github/wakingrufus/elo/EloCalculatorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.wakingrufus.elo

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.util.*

class EloCalculatorTest {
val newPlayer = Player(id = UUID.randomUUID().toString(), gamesPlayed = 9, currentRating = 1500)
val oldPlayer = Player(id = UUID.randomUUID().toString(), gamesPlayed = 11, currentRating = 1500)
@Test
fun `test calculateKfactor new player`() {
assertThat(calculateKfactor(32, 10, 2, 9, listOf(oldPlayer, newPlayer)))
.isEqualTo(64)
}

@Test
fun `test calculateKfactor playing against new player`() {
assertThat(calculateKfactor(32, 10, 2, 11, listOf(oldPlayer, newPlayer)))
.isEqualTo(16)
}

@Test
fun `test calculateKfactor`() {
assertThat(calculateKfactor(32, 10, 2, 11, listOf(oldPlayer)))
.isEqualTo(32)
}
}

0 comments on commit e7e5676

Please sign in to comment.