From b69b5cc0a645425994d4af15de2ff61dbc274532 Mon Sep 17 00:00:00 2001 From: Claude Brisson Date: Tue, 26 Dec 2023 11:04:54 +0100 Subject: [PATCH] Handling of half MMS point for missed rounds --- .../org/jeudego/pairgoth/ext/OpenGotha.kt | 17 +++++++++++++++-- .../org/jeudego/pairgoth/model/Pairing.kt | 12 ++++++++++-- .../pairgoth/pairing/BasePairingHelper.kt | 4 +++- .../jeudego/pairgoth/pairing/HistoryHelper.kt | 9 +++++++++ .../pairgoth/pairing/solver/MacMahonSolver.kt | 4 +++- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt index b1a81b7..4c7186d 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt @@ -10,6 +10,7 @@ import org.jeudego.pairgoth.store.Store import org.w3c.dom.Element import java.util.* import javax.xml.datatype.XMLGregorianCalendar +import kotlin.math.roundToInt private const val MILLISECONDS_PER_DAY = 86400000 fun XMLGregorianCalendar.toLocalDate() = LocalDate(year, month, day) @@ -67,7 +68,11 @@ object OpenGotha { seedSystem1 = parseSeedSystem(pairParams.paiMaSeedSystem1), seedSystem2 = parseSeedSystem(pairParams.paiMaSeedSystem2 ?: "SPLITANDSLIP"), additionalPlacementCritSystem1 = Criterion.valueOf(pairParams.paiMaAdditionalPlacementCritSystem1.uppercase()), - additionalPlacementCritSystem2 = Criterion.valueOf(pairParams.paiMaAdditionalPlacementCritSystem2.uppercase().replace("NULL", "NONE")) + additionalPlacementCritSystem2 = Criterion.valueOf(pairParams.paiMaAdditionalPlacementCritSystem2.uppercase().replace("NULL", "NONE")), + nbwValueAbsent = genParams.genNBW2ValueAbsent.toDouble() / 2.0, + nbwValueBye = genParams.genNBW2ValueBye.toDouble() / 2.0, + mmsValueAbsent = genParams.genMMS2ValueAbsent.toDouble() / 2.0, + mmsValueBye = genParams.genMMS2ValueBye.toDouble() / 2.0, ), secondary = SecondaryCritParams( barThresholdActive = pairParams.paiSeBarThresholdActive.toBoolean(), @@ -262,7 +267,15 @@ object OpenGotha { displayRank( if (tournament.pairing is MacMahon) tournament.pairing.mmFloor else -30 ).uppercase(Locale.ROOT) - }" genMMS2ValueAbsent="1" genMMS2ValueBye="2" genMMZero="30K" genNBW2ValueAbsent="0" genNBW2ValueBye="2" genRoundDownNBWMMS="true" komi="${tournament.komi}" location="${tournament.location}" name="${tournament.name}" nbMovesCanTime="${tournament.timeSystem.stones}" numberOfCategories="1" numberOfRounds="${tournament.rounds}" shortName="${tournament.shortName}" size="${tournament.gobanSize}" stdByoYomiTime="${tournament.timeSystem.byoyomi}"/> + }" genMMS2ValueAbsent="${ + (tournament.pairing.pairingParams.main.mmsValueAbsent * 2).roundToInt() + }" genMMS2ValueBye="${ + (tournament.pairing.pairingParams.main.mmsValueBye * 2).roundToInt() + }" genMMZero="30K" genNBW2ValueAbsent="${ + (tournament.pairing.pairingParams.main.nbwValueAbsent * 2).roundToInt() + }" genNBW2ValueBye="${ + (tournament.pairing.pairingParams.main.nbwValueBye * 2).roundToInt() + }" genRoundDownNBWMMS="true" komi="${tournament.komi}" location="${tournament.location}" name="${tournament.name}" nbMovesCanTime="${tournament.timeSystem.stones}" numberOfCategories="1" numberOfRounds="${tournament.rounds}" shortName="${tournament.shortName}" size="${tournament.gobanSize}" stdByoYomiTime="${tournament.timeSystem.byoyomi}"/> diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairing.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairing.kt index 0cf8fbe..9f52d14 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairing.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairing.kt @@ -48,6 +48,10 @@ data class MainCritParams( val seedSystem2: SeedMethod = SeedMethod.SPLIT_AND_FOLD, val additionalPlacementCritSystem1: Criterion = Criterion.RATING, val additionalPlacementCritSystem2: Criterion = Criterion.NONE, + val nbwValueAbsent: Double = 0.0, + val nbwValueBye: Double = 1.0, + val mmsValueAbsent: Double = 0.5, + val mmsValueBye: Double = 1.0 ) { enum class DrawUpDown { TOP, MIDDLE, BOTTOM } enum class SeedMethod { SPLIT_AND_FOLD, SPLIT_AND_RANDOM, SPLIT_AND_SLIP } @@ -239,8 +243,12 @@ fun MainCritParams.Companion.fromJson(json: Json.Object, localDefault: MainCritP seedSystem1 = json.getString("firstSeed")?.let { MainCritParams.SeedMethod.valueOf(it) } ?: localDefault?.seedSystem1 ?: default.seedSystem1, seedSystem2 = json.getString("secondSeed")?.let { MainCritParams.SeedMethod.valueOf(it) } ?: localDefault?.seedSystem2 ?: default.seedSystem2, additionalPlacementCritSystem1 = json.getString("firstSeedAddCrit")?.let { Criterion.valueOf(it) } ?: localDefault?.additionalPlacementCritSystem1 ?: default.additionalPlacementCritSystem1, - additionalPlacementCritSystem2 = json.getString("secondSeedAddCrit")?.let { Criterion.valueOf(it) } ?: localDefault?.additionalPlacementCritSystem2 ?: default.additionalPlacementCritSystem2 -) + additionalPlacementCritSystem2 = json.getString("secondSeedAddCrit")?.let { Criterion.valueOf(it) } ?: localDefault?.additionalPlacementCritSystem2 ?: default.additionalPlacementCritSystem2, + nbwValueAbsent = json.getDouble("nbwValueAbsent") ?: localDefault?.nbwValueAbsent ?: default.nbwValueAbsent, + nbwValueBye = json.getDouble("nbwValueBye") ?: localDefault?.nbwValueBye ?: default.nbwValueBye, + mmsValueAbsent = json.getDouble("mmsValueAbsent") ?: localDefault?.mmsValueAbsent ?: default.mmsValueAbsent, + mmsValueBye = json.getDouble("mmsValueBye") ?: localDefault?.mmsValueBye ?: default.mmsValueBye + ) fun MainCritParams.toJson() = Json.Object( "catWeight" to categoriesWeight, diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/BasePairingHelper.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/BasePairingHelper.kt index dcc0e6e..76e4f43 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/BasePairingHelper.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/BasePairingHelper.kt @@ -89,7 +89,9 @@ abstract class BasePairingHelper( val Pairable.sosos: Double get() = historyHelper.sosos[id] ?: 0.0 val Pairable.sodos: Double get() = historyHelper.sodos[id] ?: 0.0 val Pairable.cums: Double get() = historyHelper.cumScore[id] ?: 0.0 - + fun Pairable.missedRounds(upToRound: Int): Int = (1..upToRound).map { round -> + if (historyHelper.playersPerRound.getOrNull(round)?.contains(id) == true) 0 else 1 + }.sum() fun Pairable.eval(criterion: Criterion) = evalCriterion(this, criterion) open fun evalCriterion(pairable: Pairable, criterion: Criterion) = when (criterion) { Criterion.NONE -> 0.0 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 a97e8f5..44de378 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 @@ -60,6 +60,15 @@ open class HistoryHelper(protected val history: List>, scoresGetter: } } + // Set of all implied players for each round + val playersPerRound = history.map { + it.fold(mutableSetOf()) { acc, next -> + acc.add(next.white) + acc.add(next.black) + acc + } + } + val wins: Map by lazy { mutableMapOf().apply { history.flatten().forEach { game -> diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/solver/MacMahonSolver.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/solver/MacMahonSolver.kt index a6265b3..4bee2ff 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/solver/MacMahonSolver.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/solver/MacMahonSolver.kt @@ -15,7 +15,9 @@ class MacMahonSolver(round: Int, override val scores: Map by lazy { pairablesMap.mapValues { it.value.let { - pairable -> pairable.mmBase + pairable.nbW // TODO take tournament parameter into account + pairable -> pairable.mmBase + + pairable.nbW + // TODO take tournament parameter into account + pairable.missedRounds(round) * pairingParams.main.mmsValueAbsent } } }