Skip to content

Commit

Permalink
fixes #9 games are processed in reverse order (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
wakingrufus authored Jan 8, 2018
1 parent 73ec3d3 commit 036e613
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 9 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Library for ELO calculations for game leagues
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.wakingrufus/lib-elo/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.wakingrufus/lib-elo)

## 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.

Expand All @@ -14,7 +15,7 @@ Library for ELO calculations for game leagues
First, start a league by creating a league object with the configuration for the league:

```kotlin
val league = League(teamSize = 1, kFactorBase = 32, trialKFactorMultiplier = 1)
val league = League(kFactorBase = 32, trialKFactorMultiplier = 2)
```

You will probably want to persist this information within your application so that you can re-create this object at anytime
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ext {
isReleaseVersion = !(project.version =~ /-SNAPSHOT$/)
}

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

dependencies {
Expand Down
3 changes: 1 addition & 2 deletions src/main/kotlin/com/github/wakingrufus/elo/BigDecimal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.github.wakingrufus.elo

import java.math.BigDecimal
import java.math.MathContext
import java.math.RoundingMode

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

// Perform X^(A+B)=X^A*X^B (B = remainder)
Expand Down
12 changes: 7 additions & 5 deletions src/main/kotlin/com/github/wakingrufus/elo/EloLeague.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.github.wakingrufus.elo

import java.util.*

fun calculateNewLeague(league: League, games: List<Game>): LeagueState {
var leagueState = LeagueState(league = league)
games.stream()
.sorted({ g1: Game, g2: Game -> (g2.entryDate.epochSecond - g1.entryDate.epochSecond).toInt() })
.forEach { leagueState = addGameToLeague(leagueState, it) }
return leagueState
return games.toList()
.sortedWith(Comparator.comparing(Game::entryDate))
.fold(initial = LeagueState(league = league)) { leagueState, game ->
addGameToLeague(leagueState, game)
}
}

fun addGameToLeague(leagueState: LeagueState, game: Game): LeagueState {
Expand Down
59 changes: 59 additions & 0 deletions src/test/kotlin/com/github/wakingrufus/elo/EloLeagueKtTest.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,71 @@
package com.github.wakingrufus.elo

import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import java.time.Instant
import java.util.*


class EloLeagueKtTest {

@Test
fun `calculateNewLeague processes games in time order`() {
// data
val player1Id = UUID.randomUUID().toString()
val player2Id = UUID.randomUUID().toString()
val league = League(kFactorBase = 32, trialKFactorMultiplier = 1)
val game1 = Game(
id = UUID.randomUUID().toString(),
team1Score = 10,
team2Score = 0,
team1PlayerIds = listOf(player1Id),
team2PlayerIds = listOf(player2Id),
entryDate = Instant.now())
val game2 = Game(
id = UUID.randomUUID().toString(),
team1Score = 10,
team2Score = 0,
team1PlayerIds = listOf(player1Id),
team2PlayerIds = listOf(player2Id),
entryDate = Instant.now().plusSeconds(1))


val actual = calculateNewLeague(league = league, games = listOf(game1, game2))

// assertions
assertTrue("results for first game have starting rating of the league starting rating",
actual.history
.filter { game1.id == it.gameId }
.all { league.startingRating == it.startingRating })
assertTrue("", actual.history
.filter { game2.id == it.gameId }
.filter { player1Id == it.playerId }
.all {
league.startingRating + actual.history
.filter { game1.id == it.gameId }
.first { player1Id == it.playerId }.ratingAdjustment == it.startingRating
})
assertTrue("", actual.history
.filter { game2.id == it.gameId }
.filter { player2Id == it.playerId }
.all {
league.startingRating + actual.history
.filter { game1.id == it.gameId }
.first { player2Id == it.playerId }.ratingAdjustment == it.startingRating
})
assertEquals(game1.id, actual.history[0].gameId)
assertEquals(1500, actual.history[0].startingRating)
assertEquals(game1.id, actual.history[1].gameId)
assertEquals(1500, actual.history[1].startingRating)
assertEquals(game2.id, actual.history[2].gameId)
assertEquals(1500 + actual.history[0].ratingAdjustment, actual.history[2].startingRating)
assertEquals(game2.id, actual.history[3].gameId)
assertEquals(1500 + actual.history[1].ratingAdjustment, actual.history[3].startingRating)


}

@Test
fun calculateNewLeague() {
// data
Expand Down

0 comments on commit 036e613

Please sign in to comment.