diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt index b4df064..372cb0e 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt @@ -3,7 +3,7 @@ package org.jeudego.pairgoth.pairing import org.jeudego.pairgoth.model.* import org.jeudego.pairgoth.model.Game.Result.* -open class HistoryHelper(protected val history: List>, computeScore: () -> Map) { +open class HistoryHelper(protected val history: List>, private val scores: Map) { private val Game.blackScore get() = when (result) { BLACK, BOTHWIN -> 1.0 @@ -58,17 +58,12 @@ open class HistoryHelper(protected val history: List>, computeScore: } } - // Has to be set after construction - private val score by lazy { - computeScore() - } - // SOS related functions given a score function val sos by lazy { (history.flatten().map { game -> - Pair(game.black, score[game.white] ?: 0.0) + Pair(game.black, scores[game.white] ?: 0.0) } + history.flatten().map { game -> - Pair(game.white, score[game.black] ?: 0.0) + Pair(game.white, scores[game.black] ?: 0.0) }).groupingBy { it.first }.fold(0.0) { acc, next -> acc + next.second } @@ -77,9 +72,9 @@ open class HistoryHelper(protected val history: List>, computeScore: // sos-1 val sosm1 by lazy { (history.flatten().map { game -> - Pair(game.black, score[game.white] ?: 0.0) + Pair(game.black, scores[game.white] ?: 0.0) } + history.flatten().map { game -> - Pair(game.white, score[game.black] ?: 0.0) + Pair(game.white, scores[game.black] ?: 0.0) }).groupBy { it.first }.mapValues { @@ -91,9 +86,9 @@ open class HistoryHelper(protected val history: List>, computeScore: // sos-2 val sosm2 by lazy { (history.flatten().map { game -> - Pair(game.black, score[game.white] ?: 0.0) + Pair(game.black, scores[game.white] ?: 0.0) } + history.flatten().map { game -> - Pair(game.white, score[game.black] ?: 0.0) + Pair(game.white, scores[game.black] ?: 0.0) }).groupBy { it.first }.mapValues { @@ -105,9 +100,9 @@ open class HistoryHelper(protected val history: List>, computeScore: // sodos val sodos by lazy { (history.flatten().map { game -> - Pair(game.black, if (game.result == Game.Result.BLACK) score[game.white] ?: 0.0 else 0.0) + Pair(game.black, if (game.result == Game.Result.BLACK) scores[game.white] ?: 0.0 else 0.0) } + history.flatten().map { game -> - Pair(game.white, if (game.result == Game.Result.WHITE) score[game.black] ?: 0.0 else 0.0) + Pair(game.white, if (game.result == Game.Result.WHITE) scores[game.black] ?: 0.0 else 0.0) }).groupingBy { it.first }.fold(0.0) { acc, next -> acc + next.second } @@ -134,17 +129,16 @@ open class HistoryHelper(protected val history: List>, computeScore: acc + next.whiteScore }) }.reduce { acc, map -> - (acc.keys + map.keys).associate { id -> - Pair(id, acc.getOrDefault(id, 0.0) + acc.getOrDefault(id, 0.0) + map.getOrDefault(id, 0.0)) - }.toMap() + (acc.keys + map.keys).associateWith { id -> acc.getOrDefault(id, 0.0) + acc.getOrDefault(id, 0.0) + map.getOrDefault(id, 0.0) } + .toMap() } } } // CB TODO - a big problem with the current naive implementation is that the team score is -for now- the sum of team members individual scores -class TeamOfIndividualsHistoryHelper(history: List>, computeScore: () -> Map): - HistoryHelper(history, computeScore) { +class TeamOfIndividualsHistoryHelper(history: List>, scores: Map): + HistoryHelper(history, scores) { private fun Pairable.asTeam() = this as TeamTournament.Team @@ -156,4 +150,7 @@ class TeamOfIndividualsHistoryHelper(history: List>, computeScore: () //override fun sos(p:Pairable) = p.asTeam().teamPlayers.map { super.sos(it) ?: throw Error("unknown player id: #${it.id}") }.sum() //override fun sosos(p:Pairable) = p.asTeam().teamPlayers.map { super.sosos(it) ?: throw Error("unknown player id: #${it.id}") }.sum() //override fun sodos(p:Pairable) = p.asTeam().teamPlayers.map { super.sodos(it) ?: throw Error("unknown player id: #${it.id}") }.sum() + + // TODO CB - now that we've got the rounds in history helper, calculate virtual scores + // also - try to factorize a bit calculations } diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/MacMahonSolver.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/MacMahonSolver.kt index dbcfd26..962b79d 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/MacMahonSolver.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/MacMahonSolver.kt @@ -9,16 +9,18 @@ class MacMahonSolver(round: Int, placementParams: PlacementParams): Solver(round, history, pairables, pairingParams, placementParams) { - val Pairable.mmBase: Double get() = rank + 30.0 // TODO use params - val Pairable.mms: Double get() = mmBase + nbW // TODO real calculation + override val scores: Map by lazy { + historyHelper.wins.mapValues { + pairablesMap[it.key]!!.let { pairable -> + pairable.mmBase + pairable.nbW + } + } + } + val Pairable.mmBase: Double get() = rank + 30.0 // TODO use params + val Pairable.mms: Double get() = scores[id] ?: 0.0 // CB TODO - configurable criteria - override val Pairable.main get() = mms override val mainLimits get() = TODO() - override fun computeStandingScore(): Map { - TODO("Not yet implemented") - } - override fun evalCriterion(pairable: Pairable, criterion: Criterion) = when (criterion) { Criterion.MMS -> pairable.mms else -> super.evalCriterion(pairable, criterion) diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/Solver.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/Solver.kt index f1419d7..664c01a 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/Solver.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/Solver.kt @@ -47,8 +47,18 @@ sealed class Solver( val rand = Random(/* seed from properties - TODO */) } - val historyHelper = if (pairables.first().let { it is TeamTournament.Team && it.teamOfIndividuals }) TeamOfIndividualsHistoryHelper(history, ::computeStandingScore) - else HistoryHelper(history, ::computeStandingScore) + abstract val scores: Map + val historyHelper = if (pairables.first().let { it is TeamTournament.Team && it.teamOfIndividuals }) TeamOfIndividualsHistoryHelper(history, scores) + else HistoryHelper(history, scores) + + // pairables sorted using overloadable sort function + private val sortedPairables by lazy { + pairables.sortedWith(::sort) + } + + protected val pairablesMap by lazy { + pairables.associateBy { it.id } + } open fun sort(p: Pairable, q: Pairable): Int { for (criterion in placement.criteria) { @@ -68,11 +78,9 @@ sealed class Solver( pairing.geo.apply(p1, p2) // The main criterion that will be used to define the groups should be defined by subclasses - abstract val Pairable.main: Double + val Pairable.main: Double get() = scores[id] ?: 0.0 abstract val mainLimits: Pair // SOS and variants will be computed based on this score - abstract fun computeStandingScore(): Map - fun pair(): List { // check that at this stage, we have an even number of pairables if (pairables.size % 2 != 0) throw Error("expecting an even number of pairables") @@ -314,11 +322,6 @@ sealed class Solver( pairables.associate { pairable -> Pair(pairable.id, pairable.main.toInt()) } } - // pairables sorted using overloadable sort function - private val sortedPairables by lazy { - pairables.sortedWith(::sort) - } - // place (among sorted pairables) val Pairable.place: Int get() = _place[id]!! private val _place by lazy { diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/SwissSolver.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/SwissSolver.kt index eb0f2b1..8b75346 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/SwissSolver.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/SwissSolver.kt @@ -10,10 +10,9 @@ class SwissSolver(round: Int, Solver(round, history, pairables, pairingParams, placementParams) { // In a Swiss tournament the main criterion is the number of wins and already computed - override val Pairable.main: Double get() = nbW // Rounded Down TODO make it a parameter ? - override val mainLimits = Pair(0.0, round - 1.0) - override fun computeStandingScore(): Map { - return historyHelper.wins - } + override val scores: Map + get() = historyHelper.wins + + override val mainLimits = Pair(0.0, round - 1.0) }