Merge branch 'pairing2' of gitlab.jeudego.org:tournois/pairgoth into pairing2
This commit is contained in:
@@ -14,7 +14,8 @@ data class BaseCritParams(
|
||||
val dupWeight: Double = MAX_AVOIDDUPGAME,
|
||||
val random: Double = 0.0,
|
||||
val deterministic: Boolean = true,
|
||||
val colorBalanceWeight: Double = MAX_COLOR_BALANCE
|
||||
val colorBalanceWeight: Double = MAX_COLOR_BALANCE,
|
||||
val byeWeight: Double = MAX_BYE_WEIGHT // This weight is not in opengotha
|
||||
) {
|
||||
init {
|
||||
if (nx1 < 0.0 || nx1 > 1.0) throw Error("invalid standardNX1Factor")
|
||||
@@ -25,6 +26,7 @@ data class BaseCritParams(
|
||||
|
||||
companion object {
|
||||
const val MAX_AVOIDDUPGAME = 500000000000000.0 // 5e14
|
||||
const val MAX_BYE_WEIGHT = 100000000000.0 // 1e11
|
||||
const val MAX_RANDOM = 1000000000.0 // 1e9
|
||||
const val MAX_COLOR_BALANCE = 1000000.0 // 1e6
|
||||
val default = BaseCritParams()
|
||||
|
@@ -75,6 +75,8 @@ abstract class BasePairingHelper(
|
||||
|
||||
protected val Pairable.group: Int get() = _groups[id]!!
|
||||
|
||||
protected val Pairable.nbBye: Int get() = historyHelper.nbPlayedWithBye(this) ?: 0
|
||||
|
||||
// score (number of wins)
|
||||
val Pairable.nbW: Double get() = historyHelper.nbW(this) ?: 0.0
|
||||
|
||||
|
@@ -20,6 +20,7 @@ open class HistoryHelper(protected val history: List<List<Game>>, scoresGetter:
|
||||
// Generic helper functions
|
||||
open fun playedTogether(p1: Pairable, p2: Pairable) = paired.contains(Pair(p1.id, p2.id))
|
||||
open fun colorBalance(p: Pairable) = colorBalance[p.id]
|
||||
open fun nbPlayedWithBye(p: Pairable) = nbPlayedWithBye[p.id]
|
||||
open fun nbW(p: Pairable) = wins[p.id]
|
||||
|
||||
fun drawnUpDown(p: Pairable) = drawnUpDown[p.id]
|
||||
@@ -46,6 +47,17 @@ open class HistoryHelper(protected val history: List<List<Game>>, scoresGetter:
|
||||
}
|
||||
}
|
||||
|
||||
private val nbPlayedWithBye: Map<ID, Int> by lazy {
|
||||
history.flatten().flatMap { game ->
|
||||
// Duplicates (white, black) into (white, black) and (black, white)
|
||||
listOf(Pair(game.white, game.black), Pair(game.black, game.white))
|
||||
}.groupingBy {
|
||||
it.first
|
||||
}.fold(0) { acc, next ->
|
||||
acc + if (next.second == ByePlayer.id) 1 else 0
|
||||
}
|
||||
}
|
||||
|
||||
val wins: Map<ID, Double> by lazy {
|
||||
mutableMapOf<ID, Double>().apply {
|
||||
history.flatten().forEach { game ->
|
||||
|
@@ -24,7 +24,6 @@ sealed class BaseSolver(
|
||||
pairables: List<Pairable>, // All pairables for this round, it may include the bye player
|
||||
pairing: PairingParams,
|
||||
placement: PlacementParams,
|
||||
val forcedBye: Pairable? = null, // This parameter is non-null to force the given pairable to be chosen as a bye player.
|
||||
) : BasePairingHelper(history, pairables, pairing, placement) {
|
||||
|
||||
companion object {
|
||||
@@ -41,25 +40,12 @@ sealed class BaseSolver(
|
||||
|
||||
open fun weight(p1: Pairable, p2: Pairable) =
|
||||
openGothaWeight(p1, p2) +
|
||||
pairing.base.applyByeWeight(p1, p2) +
|
||||
pairing.handicap.color(p1, p2)
|
||||
|
||||
fun pair(): List<Game> {
|
||||
// The byeGame is a list of one game with the bye player or an empty list
|
||||
val byeGame: List<Game> = if (pairables.size % 2 != 0) {
|
||||
// We must choose a bye player
|
||||
val physicalByePlayer = forcedBye ?: chooseByePlayer()
|
||||
// Remove the bye from the pairables
|
||||
pairables = pairables.filterNot { it == physicalByePlayer }
|
||||
// Assign a special game to the bye player
|
||||
listOf( Game(Store.nextGameId, physicalByePlayer.id, ByePlayer.id) )
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
|
||||
return listOf(pairEvenNumberOfPlayers(), byeGame).flatten() // Add the bye game to the actual paired games
|
||||
}
|
||||
fun pairEvenNumberOfPlayers(): List<Game> {
|
||||
// check that at this stage, we have an even number of pairables
|
||||
// The BYE player should have been added beforehand to make a number of pairables even.
|
||||
if (pairables.size % 2 != 0) throw Error("expecting an even number of pairables")
|
||||
val builder = GraphBuilder(SimpleDirectedWeightedGraph<Pairable, DefaultWeightedEdge>(DefaultWeightedEdge::class.java))
|
||||
|
||||
@@ -115,12 +101,6 @@ sealed class BaseSolver(
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
fun chooseByePlayer(): Pairable {
|
||||
// TODO https://github.com/lucvannier/opengotha/blob/master/src/info/vannier/gotha/Tournament.java#L1471
|
||||
return ByePlayer
|
||||
}
|
||||
|
||||
// Base criteria
|
||||
@@ -164,6 +144,17 @@ sealed class BaseSolver(
|
||||
return score
|
||||
}
|
||||
|
||||
open fun BaseCritParams.applyByeWeight(p1: Pairable, p2: Pairable): Double {
|
||||
// The weight is applied if one of p1 or p2 is the BYE player
|
||||
return if (p1.id == ByePlayer.id || p2.id == ByePlayer.id) {
|
||||
val actualPlayer = if (p1.id == ByePlayer.id) p2 else p1
|
||||
// TODO maybe use a different formula than opengotha
|
||||
BaseCritParams.MAX_BYE_WEIGHT - (1000 * actualPlayer.nbBye + actualPlayer.rank + 2*actualPlayer.main)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
// Main criteria
|
||||
open fun MainCritParams.apply(p1: Pairable, p2: Pairable): Double {
|
||||
var score = 0.0
|
||||
|
Reference in New Issue
Block a user