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 dupWeight: Double = MAX_AVOIDDUPGAME,
|
||||||
val random: Double = 0.0,
|
val random: Double = 0.0,
|
||||||
val deterministic: Boolean = true,
|
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 {
|
init {
|
||||||
if (nx1 < 0.0 || nx1 > 1.0) throw Error("invalid standardNX1Factor")
|
if (nx1 < 0.0 || nx1 > 1.0) throw Error("invalid standardNX1Factor")
|
||||||
@@ -25,6 +26,7 @@ data class BaseCritParams(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_AVOIDDUPGAME = 500000000000000.0 // 5e14
|
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_RANDOM = 1000000000.0 // 1e9
|
||||||
const val MAX_COLOR_BALANCE = 1000000.0 // 1e6
|
const val MAX_COLOR_BALANCE = 1000000.0 // 1e6
|
||||||
val default = BaseCritParams()
|
val default = BaseCritParams()
|
||||||
|
@@ -75,6 +75,8 @@ abstract class BasePairingHelper(
|
|||||||
|
|
||||||
protected val Pairable.group: Int get() = _groups[id]!!
|
protected val Pairable.group: Int get() = _groups[id]!!
|
||||||
|
|
||||||
|
protected val Pairable.nbBye: Int get() = historyHelper.nbPlayedWithBye(this) ?: 0
|
||||||
|
|
||||||
// score (number of wins)
|
// score (number of wins)
|
||||||
val Pairable.nbW: Double get() = historyHelper.nbW(this) ?: 0.0
|
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
|
// Generic helper functions
|
||||||
open fun playedTogether(p1: Pairable, p2: Pairable) = paired.contains(Pair(p1.id, p2.id))
|
open fun playedTogether(p1: Pairable, p2: Pairable) = paired.contains(Pair(p1.id, p2.id))
|
||||||
open fun colorBalance(p: Pairable) = colorBalance[p.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]
|
open fun nbW(p: Pairable) = wins[p.id]
|
||||||
|
|
||||||
fun drawnUpDown(p: Pairable) = drawnUpDown[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 {
|
val wins: Map<ID, Double> by lazy {
|
||||||
mutableMapOf<ID, Double>().apply {
|
mutableMapOf<ID, Double>().apply {
|
||||||
history.flatten().forEach { game ->
|
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
|
pairables: List<Pairable>, // All pairables for this round, it may include the bye player
|
||||||
pairing: PairingParams,
|
pairing: PairingParams,
|
||||||
placement: PlacementParams,
|
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) {
|
) : BasePairingHelper(history, pairables, pairing, placement) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -41,25 +40,12 @@ sealed class BaseSolver(
|
|||||||
|
|
||||||
open fun weight(p1: Pairable, p2: Pairable) =
|
open fun weight(p1: Pairable, p2: Pairable) =
|
||||||
openGothaWeight(p1, p2) +
|
openGothaWeight(p1, p2) +
|
||||||
|
pairing.base.applyByeWeight(p1, p2) +
|
||||||
pairing.handicap.color(p1, p2)
|
pairing.handicap.color(p1, p2)
|
||||||
|
|
||||||
fun pair(): List<Game> {
|
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
|
// 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")
|
if (pairables.size % 2 != 0) throw Error("expecting an even number of pairables")
|
||||||
val builder = GraphBuilder(SimpleDirectedWeightedGraph<Pairable, DefaultWeightedEdge>(DefaultWeightedEdge::class.java))
|
val builder = GraphBuilder(SimpleDirectedWeightedGraph<Pairable, DefaultWeightedEdge>(DefaultWeightedEdge::class.java))
|
||||||
|
|
||||||
@@ -115,12 +101,6 @@ sealed class BaseSolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun chooseByePlayer(): Pairable {
|
|
||||||
// TODO https://github.com/lucvannier/opengotha/blob/master/src/info/vannier/gotha/Tournament.java#L1471
|
|
||||||
return ByePlayer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base criteria
|
// Base criteria
|
||||||
@@ -164,6 +144,17 @@ sealed class BaseSolver(
|
|||||||
return score
|
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
|
// Main criteria
|
||||||
open fun MainCritParams.apply(p1: Pairable, p2: Pairable): Double {
|
open fun MainCritParams.apply(p1: Pairable, p2: Pairable): Double {
|
||||||
var score = 0.0
|
var score = 0.0
|
||||||
|
Reference in New Issue
Block a user