Reeng of solver classes for main crit, start MM
This commit is contained in:
@@ -3,7 +3,7 @@ package org.jeudego.pairgoth.pairing
|
|||||||
import org.jeudego.pairgoth.model.*
|
import org.jeudego.pairgoth.model.*
|
||||||
import org.jeudego.pairgoth.model.Game.Result.*
|
import org.jeudego.pairgoth.model.Game.Result.*
|
||||||
|
|
||||||
open class HistoryHelper(protected val history: List<List<Game>>, computeScore: () -> Map<ID, Double>) {
|
open class HistoryHelper(protected val history: List<List<Game>>, private val scores: Map<ID, Double>) {
|
||||||
|
|
||||||
private val Game.blackScore get() = when (result) {
|
private val Game.blackScore get() = when (result) {
|
||||||
BLACK, BOTHWIN -> 1.0
|
BLACK, BOTHWIN -> 1.0
|
||||||
@@ -58,17 +58,12 @@ open class HistoryHelper(protected val history: List<List<Game>>, computeScore:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has to be set after construction
|
|
||||||
private val score by lazy {
|
|
||||||
computeScore()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SOS related functions given a score function
|
// SOS related functions given a score function
|
||||||
val sos by lazy {
|
val sos by lazy {
|
||||||
(history.flatten().map { game ->
|
(history.flatten().map { game ->
|
||||||
Pair(game.black, score[game.white] ?: 0.0)
|
Pair(game.black, scores[game.white] ?: 0.0)
|
||||||
} + history.flatten().map { game ->
|
} + 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 ->
|
}).groupingBy { it.first }.fold(0.0) { acc, next ->
|
||||||
acc + next.second
|
acc + next.second
|
||||||
}
|
}
|
||||||
@@ -77,9 +72,9 @@ open class HistoryHelper(protected val history: List<List<Game>>, computeScore:
|
|||||||
// sos-1
|
// sos-1
|
||||||
val sosm1 by lazy {
|
val sosm1 by lazy {
|
||||||
(history.flatten().map { game ->
|
(history.flatten().map { game ->
|
||||||
Pair(game.black, score[game.white] ?: 0.0)
|
Pair(game.black, scores[game.white] ?: 0.0)
|
||||||
} + history.flatten().map { game ->
|
} + history.flatten().map { game ->
|
||||||
Pair(game.white, score[game.black] ?: 0.0)
|
Pair(game.white, scores[game.black] ?: 0.0)
|
||||||
}).groupBy {
|
}).groupBy {
|
||||||
it.first
|
it.first
|
||||||
}.mapValues {
|
}.mapValues {
|
||||||
@@ -91,9 +86,9 @@ open class HistoryHelper(protected val history: List<List<Game>>, computeScore:
|
|||||||
// sos-2
|
// sos-2
|
||||||
val sosm2 by lazy {
|
val sosm2 by lazy {
|
||||||
(history.flatten().map { game ->
|
(history.flatten().map { game ->
|
||||||
Pair(game.black, score[game.white] ?: 0.0)
|
Pair(game.black, scores[game.white] ?: 0.0)
|
||||||
} + history.flatten().map { game ->
|
} + history.flatten().map { game ->
|
||||||
Pair(game.white, score[game.black] ?: 0.0)
|
Pair(game.white, scores[game.black] ?: 0.0)
|
||||||
}).groupBy {
|
}).groupBy {
|
||||||
it.first
|
it.first
|
||||||
}.mapValues {
|
}.mapValues {
|
||||||
@@ -105,9 +100,9 @@ open class HistoryHelper(protected val history: List<List<Game>>, computeScore:
|
|||||||
// sodos
|
// sodos
|
||||||
val sodos by lazy {
|
val sodos by lazy {
|
||||||
(history.flatten().map { game ->
|
(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 ->
|
} + 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 ->
|
}).groupingBy { it.first }.fold(0.0) { acc, next ->
|
||||||
acc + next.second
|
acc + next.second
|
||||||
}
|
}
|
||||||
@@ -134,17 +129,16 @@ open class HistoryHelper(protected val history: List<List<Game>>, computeScore:
|
|||||||
acc + next.whiteScore
|
acc + next.whiteScore
|
||||||
})
|
})
|
||||||
}.reduce { acc, map ->
|
}.reduce { acc, map ->
|
||||||
(acc.keys + map.keys).associate<ID, ID, Double> { id ->
|
(acc.keys + map.keys).associateWith { id -> acc.getOrDefault(id, 0.0) + acc.getOrDefault(id, 0.0) + map.getOrDefault(id, 0.0) }
|
||||||
Pair(id, acc.getOrDefault(id, 0.0) + acc.getOrDefault(id, 0.0) + map.getOrDefault(id, 0.0))
|
.toMap()
|
||||||
}.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
|
// 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<List<Game>>, computeScore: () -> Map<ID, Double>):
|
class TeamOfIndividualsHistoryHelper(history: List<List<Game>>, scores: Map<ID, Double>):
|
||||||
HistoryHelper(history, computeScore) {
|
HistoryHelper(history, scores) {
|
||||||
|
|
||||||
private fun Pairable.asTeam() = this as TeamTournament.Team
|
private fun Pairable.asTeam() = this as TeamTournament.Team
|
||||||
|
|
||||||
@@ -156,4 +150,7 @@ class TeamOfIndividualsHistoryHelper(history: List<List<Game>>, computeScore: ()
|
|||||||
//override fun sos(p:Pairable) = p.asTeam().teamPlayers.map { super.sos(it) ?: throw Error("unknown player id: #${it.id}") }.sum()
|
//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 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()
|
//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
|
||||||
}
|
}
|
||||||
|
@@ -9,16 +9,18 @@ class MacMahonSolver(round: Int,
|
|||||||
placementParams: PlacementParams):
|
placementParams: PlacementParams):
|
||||||
Solver(round, history, pairables, pairingParams, placementParams) {
|
Solver(round, history, pairables, pairingParams, placementParams) {
|
||||||
|
|
||||||
val Pairable.mmBase: Double get() = rank + 30.0 // TODO use params
|
override val scores: Map<ID, Double> by lazy {
|
||||||
val Pairable.mms: Double get() = mmBase + nbW // TODO real calculation
|
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
|
// CB TODO - configurable criteria
|
||||||
override val Pairable.main get() = mms
|
|
||||||
override val mainLimits get() = TODO()
|
override val mainLimits get() = TODO()
|
||||||
override fun computeStandingScore(): Map<ID, Double> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun evalCriterion(pairable: Pairable, criterion: Criterion) = when (criterion) {
|
override fun evalCriterion(pairable: Pairable, criterion: Criterion) = when (criterion) {
|
||||||
Criterion.MMS -> pairable.mms
|
Criterion.MMS -> pairable.mms
|
||||||
else -> super.evalCriterion(pairable, criterion)
|
else -> super.evalCriterion(pairable, criterion)
|
||||||
|
@@ -47,8 +47,18 @@ sealed class Solver(
|
|||||||
val rand = Random(/* seed from properties - TODO */)
|
val rand = Random(/* seed from properties - TODO */)
|
||||||
}
|
}
|
||||||
|
|
||||||
val historyHelper = if (pairables.first().let { it is TeamTournament.Team && it.teamOfIndividuals }) TeamOfIndividualsHistoryHelper(history, ::computeStandingScore)
|
abstract val scores: Map<ID, Double>
|
||||||
else HistoryHelper(history, ::computeStandingScore)
|
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 {
|
open fun sort(p: Pairable, q: Pairable): Int {
|
||||||
for (criterion in placement.criteria) {
|
for (criterion in placement.criteria) {
|
||||||
@@ -68,11 +78,9 @@ sealed class Solver(
|
|||||||
pairing.geo.apply(p1, p2)
|
pairing.geo.apply(p1, p2)
|
||||||
|
|
||||||
// The main criterion that will be used to define the groups should be defined by subclasses
|
// 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<Double, Double>
|
abstract val mainLimits: Pair<Double, Double>
|
||||||
// SOS and variants will be computed based on this score
|
// SOS and variants will be computed based on this score
|
||||||
abstract fun computeStandingScore(): Map<ID, Double>
|
|
||||||
|
|
||||||
fun pair(): List<Game> {
|
fun pair(): List<Game> {
|
||||||
// check that at this stage, we have an even number of pairables
|
// 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")
|
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.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)
|
// place (among sorted pairables)
|
||||||
val Pairable.place: Int get() = _place[id]!!
|
val Pairable.place: Int get() = _place[id]!!
|
||||||
private val _place by lazy {
|
private val _place by lazy {
|
||||||
|
@@ -10,10 +10,9 @@ class SwissSolver(round: Int,
|
|||||||
Solver(round, history, pairables, pairingParams, placementParams) {
|
Solver(round, history, pairables, pairingParams, placementParams) {
|
||||||
|
|
||||||
// In a Swiss tournament the main criterion is the number of wins and already computed
|
// 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<ID, Double> {
|
override val scores: Map<ID, Double>
|
||||||
return historyHelper.wins
|
get() = historyHelper.wins
|
||||||
}
|
|
||||||
|
override val mainLimits = Pair(0.0, round - 1.0)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user