Recompute DUDD at import (plus some code cleaning)

This commit is contained in:
Claude Brisson
2024-05-28 12:29:49 +02:00
parent 8636f939e4
commit 6dc634df7e
4 changed files with 44 additions and 21 deletions

View File

@@ -75,14 +75,14 @@ object PairingHandler: PairgothApiHandler {
listOf(it.black, it.white) listOf(it.black, it.white)
}.toSet() }.toSet()
if (game.result != Game.Result.UNKNOWN && ( if (game.result != Game.Result.UNKNOWN && (
game.black != payload.getInt("b") || game.black != payload.getInt("b") ||
game.white != payload.getInt("w") || game.white != payload.getInt("w") ||
game.handicap != payload.getInt("h") game.handicap != payload.getInt("h")
)) badRequest("Game already has a result") )) badRequest("Game already has a result")
game.black = payload.getID("b") ?: badRequest("missing black player id") game.black = payload.getID("b") ?: badRequest("missing black player id")
game.white = payload.getID("w") ?: badRequest("missing white player id") game.white = payload.getID("w") ?: badRequest("missing white player id")
tournament.recomputeHdAndDUDD(round, game.id) tournament.recomputeDUDD(round, game.id)
val previousTable = game.table; val previousTable = game.table;
// temporary // temporary
//payload.getInt("dudd")?.let { game.drawnUpDown = it } //payload.getInt("dudd")?.let { game.drawnUpDown = it }

View File

@@ -55,6 +55,7 @@ object TournamentHandler: PairgothApiHandler {
is Element -> OpenGotha.import(payload) is Element -> OpenGotha.import(payload)
else -> badRequest("missing or invalid payload") else -> badRequest("missing or invalid payload")
} }
tournament.recomputeDUDD()
getStore(request).addTournament(tournament) getStore(request).addTournament(tournament)
tournament.dispatchEvent(TournamentAdded, request, tournament.toJson()) tournament.dispatchEvent(TournamentAdded, request, tournament.toJson())
return Json.Object("success" to true, "id" to tournament.id) return Json.Object("success" to true, "id" to tournament.id)

View File

@@ -4,6 +4,7 @@ import com.republicate.kson.Json
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.MainCritParams.SeedMethod.SPLIT_AND_SLIP import org.jeudego.pairgoth.model.MainCritParams.SeedMethod.SPLIT_AND_SLIP
import org.jeudego.pairgoth.model.PairingType.* import org.jeudego.pairgoth.model.PairingType.*
import org.jeudego.pairgoth.pairing.solver.BaseSolver
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import org.jeudego.pairgoth.pairing.solver.SwissSolver import org.jeudego.pairgoth.pairing.solver.SwissSolver
import kotlin.math.min import kotlin.math.min
@@ -129,7 +130,10 @@ sealed class Pairing(
val pairingParams: PairingParams, val pairingParams: PairingParams,
val placementParams: PlacementParams) { val placementParams: PlacementParams) {
companion object {} companion object {}
abstract fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> abstract fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): BaseSolver
fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> {
return solver(tournament, round, pairables).pair()
}
} }
internal fun Tournament<*>.historyBefore(round: Int) = internal fun Tournament<*>.historyBefore(round: Int) =
@@ -169,9 +173,8 @@ class Swiss(
) )
): Pairing(SWISS, pairingParams, placementParams) { ): Pairing(SWISS, pairingParams, placementParams) {
companion object {} companion object {}
override fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> { override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>) =
return SwissSolver(round, tournament.rounds, tournament.historyBefore(round), pairables, pairingParams, placementParams, tournament.usedTables(round)).pair() SwissSolver(round, tournament.rounds, tournament.historyBefore(round), pairables, pairingParams, placementParams, tournament.usedTables(round))
}
} }
class MacMahon( class MacMahon(
@@ -198,17 +201,16 @@ class MacMahon(
var mmBar: Int = 0 // 1D var mmBar: Int = 0 // 1D
): Pairing(MAC_MAHON, pairingParams, placementParams) { ): Pairing(MAC_MAHON, pairingParams, placementParams) {
companion object {} companion object {}
override fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> { override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>) =
return MacMahonSolver(round, tournament.rounds, tournament.historyBefore(round), pairables, pairingParams, placementParams, tournament.usedTables(round), mmFloor, mmBar).pair() MacMahonSolver(round, tournament.rounds, tournament.historyBefore(round), pairables, pairingParams, placementParams, tournament.usedTables(round), mmFloor, mmBar)
}
} }
class RoundRobin( class RoundRobin(
pairingParams: PairingParams = PairingParams(), pairingParams: PairingParams = PairingParams(),
placementParams: PlacementParams = PlacementParams(Criterion.NBW, Criterion.RATING) placementParams: PlacementParams = PlacementParams(Criterion.NBW, Criterion.RATING)
): Pairing(ROUND_ROBIN, pairingParams, placementParams) { ): Pairing(ROUND_ROBIN, pairingParams, placementParams) {
override fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> { override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): BaseSolver {
TODO() TODO("not implemented")
} }
} }

View File

@@ -74,15 +74,10 @@ sealed class Tournament <P: Pairable>(
else mutableMapOf<ID, Game>().also { games.add(it) } else mutableMapOf<ID, Game>().also { games.add(it) }
fun lastRound() = max(1, games.size) fun lastRound() = max(1, games.size)
fun recomputeHdAndDUDD(round: Int, gameID: ID) { fun recomputeDUDD(round: Int, gameID: ID) {
// Instantiate solver with game history // Instantiate solver with game history
// TODO cleaner solver instantiation
val history = historyBefore(round) val history = historyBefore(round)
val solver = if (pairing is Swiss) { val solver = pairing.solver(this, round, pairables.values.toList())
SwissSolver(round, rounds, history, pairables.values.toList(), pairing.pairingParams, pairing.placementParams, usedTables(round))
} else if (pairing is MacMahon) {
MacMahonSolver(round, rounds, history, pairables.values.toList(), pairing.pairingParams, pairing.placementParams, usedTables(round), pairing.mmFloor, pairing.mmBar)
} else throw Exception("Invalid tournament type")
// Recomputes DUDD and hd // Recomputes DUDD and hd
val game = games(round)[gameID]!! val game = games(round)[gameID]!!
@@ -92,6 +87,31 @@ sealed class Tournament <P: Pairable>(
game.handicap = solver.hd(white = white, black = black) game.handicap = solver.hd(white = white, black = black)
} }
/**
* Recompute DUDD for the specified round
*/
fun recomputeDUDD(round: Int) {
// Instantiate solver with game history
val history = historyBefore(round)
val solver = pairing.solver(this, round, pairables.values.toList())
for (game in games(round).values) {
val white = solver.pairables.find { p-> p.id == game.white }!!
val black = solver.pairables.find { p-> p.id == game.black }!!
game.drawnUpDown = solver.dudd(black, white)
}
}
/**
* Recompute DUDD for all rounds
*/
fun recomputeDUDD() {
for (round in 1..rounds) {
recomputeDUDD(round)
}
}
fun usedTables(round: Int): BitSet = fun usedTables(round: Int): BitSet =
games(round).values.map { it.table }.fold(BitSet()) { acc, table -> games(round).values.map { it.table }.fold(BitSet()) { acc, table ->
acc.set(table) acc.set(table)