Code cleaning: fix previous commit, simplify HistoryHelper creation

This commit is contained in:
Claude Brisson
2025-07-24 14:14:03 +02:00
parent ecec6556d1
commit f704f3adb2
12 changed files with 152 additions and 141 deletions

View File

@@ -27,7 +27,7 @@ fun Tournament<*>.getSortedPairables(round: Int, includePreliminary: Boolean = f
return ArrayList(frozen!!.map { it -> it as Json.Object })
}
val history = historyHelper(round)
val history = historyHelper(round + 1)
val neededCriteria = ArrayList(pairing.placementParams.criteria)
if (!neededCriteria.contains(Criterion.NBW)) neededCriteria.add(Criterion.NBW)
@@ -162,10 +162,8 @@ fun TeamTournament.getSortedTeamMembers(round: Int, includePreliminary: Boolean
val individualHistory = teamGames.map { roundTeamGames ->
roundTeamGames.flatMap { game -> individualGames[game.id]?.toList() ?: listOf() }
}
val historyHelper = HistoryHelper(individualHistory) {
pairables.mapValues {
Pair(0.0, wins[it.key] ?: 0.0)
}
val historyHelper = HistoryHelper(individualHistory).apply {
scoresFactory = { wins }
}
val neededCriteria = mutableListOf(Criterion.NBW, Criterion.RATING)
val criteria = neededCriteria.map { crit ->

View File

@@ -4,7 +4,8 @@ import com.republicate.kson.Json
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.MainCritParams.SeedMethod.SPLIT_AND_SLIP
import org.jeudego.pairgoth.model.PairingType.*
import org.jeudego.pairgoth.pairing.solver.BaseSolver
import org.jeudego.pairgoth.pairing.HistoryHelper
import org.jeudego.pairgoth.pairing.solver.Solver
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import org.jeudego.pairgoth.pairing.solver.SwissSolver
import kotlin.math.min
@@ -131,7 +132,7 @@ sealed class Pairing(
val pairingParams: PairingParams,
val placementParams: PlacementParams) {
companion object {}
abstract fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): BaseSolver
abstract fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): Solver
fun pair(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): List<Game> {
return solver(tournament, round, pairables).pair()
}
@@ -140,19 +141,6 @@ sealed class Pairing(
internal fun Tournament<*>.historyBefore(round: Int) =
(1 until min(round, lastRound() + 1)).map { games(it).values.toList() }
/*private fun Tournament<*>.historyBefore(round: Int) : List<List<Game>> {
println("Welcome to tournament.historyBefore !")
println("lastround and round = "+lastRound().toString()+" "+round.toString())
println((1 until round).map { it })
println((1 until round).map { games(it).values.toList() })
if (lastRound() == 1){
return emptyList()
}
else {
return (1 until round).map { games(it).values.toList() }
}
}*/
class Swiss(
pairingParams: PairingParams = PairingParams(
base = BaseCritParams(),
@@ -175,7 +163,7 @@ class Swiss(
): Pairing(SWISS, pairingParams, placementParams) {
companion object {}
override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>) =
SwissSolver(round, tournament.rounds, tournament.historyHelper(round), pairables, tournament.pairables, pairingParams, placementParams, tournament.usedTables(round))
SwissSolver(round, tournament.rounds, HistoryHelper(tournament.historyBefore(round)), pairables, tournament.pairables, pairingParams, placementParams, tournament.usedTables(round))
}
class MacMahon(
@@ -203,14 +191,14 @@ class MacMahon(
): Pairing(MAC_MAHON, pairingParams, placementParams) {
companion object {}
override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>) =
MacMahonSolver(round, tournament.rounds, tournament.historyHelper(round), pairables, tournament.pairables, pairingParams, placementParams, tournament.usedTables(round), mmFloor, mmBar)
MacMahonSolver(round, tournament.rounds, HistoryHelper(tournament.historyBefore(round)), pairables, tournament.pairables, pairingParams, placementParams, tournament.usedTables(round), mmFloor, mmBar)
}
class RoundRobin(
pairingParams: PairingParams = PairingParams(),
placementParams: PlacementParams = PlacementParams(Criterion.NBW, Criterion.RATING)
): Pairing(ROUND_ROBIN, pairingParams, placementParams) {
override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): BaseSolver {
override fun solver(tournament: Tournament<*>, round: Int, pairables: List<Pairable>): Solver {
TODO("not implemented")
}
}

View File

@@ -225,32 +225,7 @@ sealed class Tournament <P: Pairable>(
}
fun historyHelper(round: Int): HistoryHelper {
return HistoryHelper(historyBefore(round + 1)) {
if (pairing.type == PairingType.SWISS) {
pairables.mapValues {
// In a Swiss tournament the main criterion is the number of wins
Pair(0.0, wins[it.key] ?: 0.0)
}
}
else {
pairables.mapValues {
// In a MacMahon tournament the main criterion is the mms
it.value.let { pairable ->
val mmBase = pairable.mmBase()
val score = roundScore(mmBase +
(nbW(pairable) ?: 0.0) +
(1..round).sumOf { round ->
if (playersPerRound.getOrNull(round - 1)?.contains(pairable.id) == true) 0.0 else 1.0
} * pairing.pairingParams.main.mmsValueAbsent)
Pair(
if (pairing.pairingParams.main.sosValueAbsentUseBase) mmBase
else roundScore(mmBase + round/2),
score
)
}
}
}
}
return pairing.solver(this, round, emptyList()).history
}
}

View File

@@ -11,14 +11,11 @@ abstract class BasePairingHelper(
val placement: PlacementParams,
) {
val scores get() = history.scores
abstract val scoresX: Map<ID, Double>
// Extend pairables with members from all rounds
// The main criterion that will be used to define the groups should be defined by subclasses
// SOS and variants will be computed based on this score
val Pairable.main: Double get() = scores[id]?.second ?: 0.0
val Pairable.main: Double get() = score ?: 0.0
abstract val mainLimits: Pair<Double, Double>
// pairables sorted using overloadable sort function
@@ -89,9 +86,9 @@ abstract class BasePairingHelper(
protected val Pairable.nbBye: Int get() = history.nbPlayedWithBye(this) ?: 0
// score (number of wins)
val Pairable.score: Double get() = history.scores[id] ?: 0.0
val Pairable.scoreX: Double get() = history.scoresX[id] ?: 0.0
val Pairable.nbW: Double get() = history.nbW(this) ?: 0.0
val Pairable.sos: Double get() = history.sos[id] ?: 0.0
val Pairable.sosm1: Double get() = history.sosm1[id] ?: 0.0
val Pairable.sosm2: Double get() = history.sosm2[id] ?: 0.0

View File

@@ -2,22 +2,22 @@ package org.jeudego.pairgoth.pairing
import org.jeudego.pairgoth.model.*
import org.jeudego.pairgoth.model.Game.Result.*
import org.jeudego.pairgoth.model.TeamTournament.Team
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import kotlin.math.max
import kotlin.math.min
import org.jeudego.pairgoth.pairing.solver.Solver
/**
* Map from a pairable ID to a pair of (missed rounds increment, main score).
* The missed rounds increment is 0 for Swiss, and a function of the MMS base of the pairable for MacMahon.
* The main score is the NBW for the Swiss, the MMS for MacMahon.
*/
typealias ScoreMapBuilder = HistoryHelper.()-> Map<ID, Pair<Double, Double>>
typealias ScoreMap = Map<ID, Double>
typealias ScoreMapFactory = () -> ScoreMap
open class HistoryHelper(
protected val history: List<List<Game>>,
// scoresGetter() returns Pair(sos value for missed rounds, score) where score is nbw for Swiss, mms for MM, ...
scoresGetter: ScoreMapBuilder) {
protected val history: List<List<Game>>
) {
lateinit var scoresFactory: ScoreMapFactory
lateinit var scoresXFactory: ScoreMapFactory
lateinit var missedRoundsSosFactory: ScoreMapFactory
val scores by lazy { scoresFactory() }
val scoresX by lazy { scoresXFactory() }
val missedRoundsSos by lazy { missedRoundsSosFactory() }
private val Game.blackScore get() = when (result) {
BLACK, BOTHWIN -> 1.0
@@ -29,16 +29,6 @@ open class HistoryHelper(
else -> 0.0
}
val scores by lazy {
scoresGetter()
}
val scoresX by lazy {
scoresGetter().mapValues { entry ->
entry.value.first + (wins[entry.key] ?: 0.0)
}
}
// 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]
@@ -82,14 +72,14 @@ open class HistoryHelper(
}
}
// Set of all implied players for each round (warning: does comprise games with BIP)
// Set of all implied players for each round
val playersPerRound: List<Set<ID>> by lazy {
history.map {
it.fold(mutableSetOf<ID>()) { acc, next ->
if(next.white != 0) acc.add(next.white)
if (next.black != 0) acc.add(next.black)
acc
}
history.map { roundGames ->
roundGames.flatMap {
game -> listOf(game.white, game.black)
}.filter { id ->
id != ByePlayer.id
}.toSet()
}
}
@@ -110,67 +100,89 @@ open class HistoryHelper(
}
// define mms to be a synonym of scores
val mms by lazy { scores.mapValues { it -> it.value.second } }
val mms by lazy { scores }
val sos by lazy {
// SOS for played games against a real opponent or BIP
val historySos = (history.flatten().map { game ->
Pair(
game.black,
if (game.white == 0) scores[game.black]?.first ?: 0.0
else scores[game.white]?.second?.let { it - game.handicap } ?: 0.0
if (game.white == 0) missedRoundsSos[game.black] ?: 0.0
else scores[game.white]?.let { it - game.handicap } ?: 0.0
)
} + history.flatten().map { game ->
Pair(
game.white,
if (game.black == 0) scores[game.white]?.first ?: 0.0
else scores[game.black]?.second?.let { it + game.handicap } ?: 0.0
if (game.black == 0) missedRoundsSos[game.white] ?: 0.0
else scores[game.black]?.let { it + game.handicap } ?: 0.0
)
}).groupingBy {
it.first
}.fold(0.0) { acc, next ->
acc + next.second
}
scores.mapValues { (id, pair) ->
// plus SOS for missed rounds
missedRoundsSos.mapValues { (id, pseudoSos) ->
(historySos[id] ?: 0.0) + playersPerRound.sumOf {
if (it.contains(id)) 0.0 else pair.first
if (it.contains(id)) 0.0 else pseudoSos
}
}
}
// sos-1
val sosm1 by lazy {
// SOS for played games against a real opponent or BIP
(history.flatten().map { game ->
Pair(game.black, scores[game.white]?.second?.let { it - game.handicap } ?: 0.0)
Pair(
game.black,
if (game.white == 0) missedRoundsSos[game.black] ?: 0.0
else scores[game.white]?.let { it - game.handicap } ?: 0.0
)
} + history.flatten().map { game ->
Pair(game.white, scores[game.black]?.second?.let { it + game.handicap } ?: 0.0)
Pair(
game.white,
if (game.black == 0) missedRoundsSos[game.white] ?: 0.0
else scores[game.black]?.let { it + game.handicap } ?: 0.0
)
}).groupBy {
it.first
}.mapValues { (id, pairs) ->
val oppScores = pairs.map { it.second }.sortedDescending()
// minus greatest SOS
oppScores.sum() - (oppScores.firstOrNull() ?: 0.0) +
// plus SOS for missed rounds
playersPerRound.sumOf { players ->
if (players.contains(id)) 0.0
else scores[id]?.first ?: 0.0
else missedRoundsSos[id] ?: 0.0
}
}
}
// sos-2
val sosm2 by lazy {
// SOS for played games against a real opponent or BIP
(history.flatten().map { game ->
Pair(game.black, scores[game.white]?.second?.let { it - game.handicap } ?: 0.0)
Pair(
game.black,
if (game.white == 0) missedRoundsSos[game.black] ?: 0.0
else scores[game.white]?.let { it - game.handicap } ?: 0.0
)
} + history.flatten().map { game ->
Pair(game.white, scores[game.black]?.second?.let { it + game.handicap } ?: 0.0)
Pair(
game.white,
if (game.black == 0) missedRoundsSos[game.white] ?: 0.0
else scores[game.black]?.let { it + game.handicap } ?: 0.0
)
}).groupBy {
it.first
}.mapValues { (id, pairs) ->
val oppScores = pairs.map { it.second }.sorted()
val oppScores = pairs.map { it.second }.sortedDescending()
// minus two greatest SOS
oppScores.sum() - oppScores.getOrElse(0) { 0.0 } - oppScores.getOrElse(1) { 0.0 } +
// plus SOS for missed rounds
playersPerRound.sumOf { players ->
if (players.contains(id)) 0.0
else scores[id]?.first ?: 0.0
else missedRoundsSos[id] ?: 0.0
}
}
}
@@ -180,16 +192,17 @@ open class HistoryHelper(
(history.flatten().filter { game ->
game.white != 0 // Remove games against byePlayer
}.map { game ->
Pair(game.black, if (game.result == Game.Result.BLACK) scores[game.white]?.second?.let { it - game.handicap } ?: 0.0 else 0.0)
Pair(game.black, if (game.result == Game.Result.BLACK) scores[game.white]?.let { it - game.handicap } ?: 0.0 else 0.0)
} + history.flatten().filter { game ->
game.white != 0 // Remove games against byePlayer
}.map { game ->
Pair(game.white, if (game.result == Game.Result.WHITE) scores[game.black]?.second?.let { it + game.handicap } ?: 0.0 else 0.0)
Pair(game.white, if (game.result == Game.Result.WHITE) scores[game.black]?.let { it + game.handicap } ?: 0.0 else 0.0)
}).groupingBy { it.first }.fold(0.0) { acc, next ->
acc + next.second
}
}
// sosos
val sosos by lazy {
val currentRound = history.size
@@ -203,9 +216,9 @@ open class HistoryHelper(
acc + next.second
}
scores.mapValues { (id, pair) ->
missedRoundsSos.mapValues { (id, missedRoundSos) ->
(historySosos[id] ?: 0.0) + playersPerRound.sumOf {
if (it.contains(id)) 0.0 else pair.first * currentRound
if (it.contains(id)) 0.0 else missedRoundSos * currentRound
}
}

View File

@@ -1,7 +1,6 @@
package org.jeudego.pairgoth.pairing
import org.jeudego.pairgoth.model.Pairable
import org.jeudego.pairgoth.pairing.solver.BaseSolver
fun detRandom(max: Double, p1: Pairable, p2: Pairable, symmetric: Boolean): Double {
var inverse = false

View File

@@ -16,19 +16,31 @@ class MacMahonSolver(round: Int,
placementParams: PlacementParams,
usedTables: BitSet,
private val mmFloor: Int, private val mmBar: Int) :
BaseSolver(round, totalRounds, history, pairables, pairingParams, placementParams, usedTables) {
Solver(round, totalRounds, history, pairables, allPairablesMap, pairingParams, placementParams, usedTables) {
override val scoresX: Map<ID, Double> by lazy {
require (mmBar > mmFloor) { "MMFloor is higher than MMBar" }
allPairablesMap.mapValues {
it.value.let { pairable ->
override fun mainScoreMapFactory() =
allPairablesMap.mapValues { (id, pairable) ->
roundScore(pairable.mmBase +
pairable.nbW +
pairable.missedRounds() * pairing.main.mmsValueAbsent)
}
override fun scoreXMapFactory() =
allPairablesMap.mapValues { (id, pairable) ->
roundScore(pairable.mmBase + pairable.nbW)
}
override fun missedRoundSosMapFactory() =
allPairablesMap.mapValues { (id, pairable) ->
if (pairing.main.sosValueAbsentUseBase) {
pairable.mmBase
} else {
roundScore(pairable.mmBase + round/2)
}
}
override fun computeWeightForBye(p: Pairable): Double{
return 2*scores[p.id]!!.second
return 2 * p.score
}
override fun SecondaryCritParams.apply(p1: Pairable, p2: Pairable): Double {
@@ -69,8 +81,7 @@ class MacMahonSolver(round: Int,
// mmBase: starting Mac-Mahon score of the pairable
val Pairable.mmBase: Double get() = min(max(rank, mmFloor), mmBar) + mmsZero + mmsCorrection
// mms: current Mac-Mahon score of the pairable
val Pairable.mms: Double get() = scores[id]?.second ?: 0.0
val Pairable.scoreX: Double get() = scoresX[id] ?: 0.0
val Pairable.mms: Double get() = score
// CB TODO - configurable criteria
val mainScoreMin = mmFloor + PLA_SMMS_SCORE_MIN - Pairable.MIN_RANK

View File

@@ -19,11 +19,12 @@ import java.text.DecimalFormat
import java.util.*
import kotlin.math.*
sealed class BaseSolver(
sealed class Solver(
round: Int,
totalRounds: Int,
history: HistoryHelper, // History of all games played for each round
pairables: List<Pairable>, // All pairables for this round, it may include the bye player
history: HistoryHelper, // Digested history of all games played for each round
pairables: List<Pairable>, // Pairables to pair together
val allPairablesMap: Map<ID, Pairable>, // Map of all known pairables
pairing: PairingParams,
placement: PlacementParams,
val usedTables: BitSet
@@ -36,6 +37,27 @@ sealed class BaseSolver(
var legacy_mode = false
}
init {
history.scoresFactory = this::mainScoreMapFactory
history.scoresXFactory = this::scoreXMapFactory
history.missedRoundsSosFactory = this::missedRoundSosMapFactory
}
/**
* Main score map factory (NBW for Swiss, MMS for MacMahon, ...).
*/
abstract fun mainScoreMapFactory(): Map<ID, Double>
/**
* ScoreX map factory (NBW for Swiss, MMSBase + MMS for MacMahon, ...).
*/
abstract fun scoreXMapFactory(): Map<ID, Double>
/**
* SOS for missed rounds factory (0 for Swiss, mmBase or mmBase+rounds/2 for MacMahon depending on pairing option sosValueAbsentUseBase)
*/
abstract fun missedRoundSosMapFactory(): Map<ID, Double>
open fun openGothaWeight(p1: Pairable, p2: Pairable) =
1.0 + // 1 is minimum value because 0 means "no matching allowed"
pairing.base.apply(p1, p2) +
@@ -144,8 +166,8 @@ sealed class BaseSolver(
for (p in sortedPairables) {
logger.info(String.format("%-20s", p.name.substring(0, min(p.name.length, 18)))
+ " " + String.format("%-4s", p.id)
+ " " + String.format("%-4s", scores[p.id]?.first)
+ " " + String.format("%-4s", scores[p.id]?.second)
+ " " + String.format("%-4s", history.missedRoundsSos[p.id])
+ " " + String.format("%-4s", history.scores[p.id])
+ " " + String.format("%-4s", p.sos)
)
}

View File

@@ -8,18 +8,28 @@ class SwissSolver(round: Int,
totalRounds: Int,
history: HistoryHelper,
pairables: List<Pairable>,
pairablesMap: Map<ID, Pairable>,
allPairablesMap: Map<ID, Pairable>,
pairingParams: PairingParams,
placementParams: PlacementParams,
usedTables: BitSet
):
BaseSolver(round, totalRounds, history, pairables, pairingParams, placementParams, usedTables) {
Solver(round, totalRounds, history, pairables, allPairablesMap, pairingParams, placementParams, usedTables) {
override val scoresX: Map<ID, Double> get() = scores.mapValues { it.value.second }
override fun mainScoreMapFactory() =
allPairablesMap.mapValues { (id, pairable) ->
history.wins[id] ?: 0.0
}
override fun scoreXMapFactory() = mainScoreMapFactory()
override fun missedRoundSosMapFactory() =
allPairablesMap.mapValues { (id, pairable) ->
0.0
}
override val mainLimits = Pair(0.0, round - 1.0)
override fun computeWeightForBye(p: Pairable): Double{
return p.rank + 40*p.main
return p.rank + 40 * p.main
}
}

View File

@@ -1,14 +1,12 @@
package org.jeudego.pairgoth.test
import com.republicate.kson.Json
import org.jeudego.pairgoth.pairing.solver.BaseSolver
import org.jeudego.pairgoth.model.Game
import org.jeudego.pairgoth.pairing.solver.Solver
import org.jeudego.pairgoth.test.PairingTests.Companion.compare_weights
import org.junit.jupiter.api.Test
import java.io.FileWriter
import java.io.PrintWriter
import java.nio.charset.StandardCharsets
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@@ -22,16 +20,16 @@ class BOSP2024Test: TestBase() {
)!!.asObject()
val resp = TestAPI.post("/api/tour", tournament).asObject()
val tourId = resp.getInt("id")
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("bosp2024-weights.txt")))
Solver.weightsLogger = PrintWriter(FileWriter(getOutputFile("bosp2024-weights.txt")))
BaseSolver.legacy_mode = true
Solver.legacy_mode = true
TestAPI.post("/api/tour/$tourId/pair/3", Json.Array("all")).asArray()
// compare weights
assertTrue(compare_weights(getOutputFile("bosp2024-weights.txt"), getTestFile("opengotha/bosp2024/bosp2024_weights_R3.txt")), "Not matching opengotha weights for BOSP test")
TestAPI.delete("/api/tour/$tourId/pair/3", Json.Array("all"))
BaseSolver.legacy_mode = false
Solver.legacy_mode = false
val games = TestAPI.post("/api/tour/$tourId/pair/3", Json.Array("all")).asArray()
// Aksut Husrev is ID 18
val solved = games.map { it as Json.Object }.filter { game ->

View File

@@ -1,7 +1,7 @@
package org.jeudego.pairgoth.test
import com.republicate.kson.Json
import org.jeudego.pairgoth.pairing.solver.BaseSolver
import org.jeudego.pairgoth.pairing.solver.Solver
import org.jeudego.pairgoth.test.PairingTests.Companion.compare_weights
import org.junit.jupiter.api.Test
import java.io.FileWriter
@@ -19,7 +19,7 @@ class MalavasiTest: TestBase() {
)!!.asObject()
val resp = TestAPI.post("/api/tour", tournament).asObject()
val tourId = resp.getInt("id")
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("malavasi-weights.txt")))
Solver.weightsLogger = PrintWriter(FileWriter(getOutputFile("malavasi-weights.txt")))
val games = TestAPI.post("/api/tour/$tourId/pair/2", Json.Array("all")).asArray()
// Oceane is ID 548, Valentine 549
val buggy = games.map { it as Json.Object }.filter { game ->

View File

@@ -2,7 +2,7 @@ package org.jeudego.pairgoth.test
import com.republicate.kson.Json
import org.jeudego.pairgoth.model.*
import org.jeudego.pairgoth.pairing.solver.BaseSolver
import org.jeudego.pairgoth.pairing.solver.Solver
import org.jeudego.pairgoth.store.MemoryStore
import org.jeudego.pairgoth.store.lastPlayerId
import org.junit.jupiter.api.BeforeEach
@@ -59,7 +59,7 @@ class PairingTests: TestBase() {
}
fun compare_weights(file1: File, file2: File, skipSeeding: Boolean = false):Boolean {
BaseSolver.weightsLogger!!.flush()
Solver.weightsLogger!!.flush()
// Maps to store name pairs and costs
val map1 = create_weights_map(file1)
val map2 = create_weights_map(file2)
@@ -172,7 +172,7 @@ class PairingTests: TestBase() {
fun test_from_XML_internal(name: String, forcePairing:List<Int>, legacy: Boolean) {
// Let pairgoth use the legacy asymmetric detRandom()
BaseSolver.legacy_mode = legacy
Solver.legacy_mode = legacy
// read tournament with pairing
val file = getTestFile("opengotha/pairings/$name.xml")
logger.info("read from file $file")
@@ -203,7 +203,7 @@ class PairingTests: TestBase() {
for (round in 1..tournament.getInt("rounds")!!) {
val sumOfWeightsOG = compute_sumOfWeight_OG(getTestFile("opengotha/$name/$name" + "_weights_R$round.txt"), pairingsOG[round-1], players)
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
Solver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
// Call Pairgoth pairing solver to generate games
games = TestAPI.post("/api/tour/$id/pair/$round", Json.Array("all")).asArray()
logger.info("sumOfWeightOG = " + dec.format(sumOfWeightsOG))
@@ -273,7 +273,7 @@ class PairingTests: TestBase() {
@Test
fun `SwissTest simpleSwiss`() {
BaseSolver.legacy_mode = true
Solver.legacy_mode = true
// read tournament with pairing
var file = getTestFile("opengotha/pairings/simpleswiss.xml")
logger.info("read from file $file")
@@ -315,7 +315,7 @@ class PairingTests: TestBase() {
var firstGameID: Int
for (round in 1..7) {
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
Solver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
games = TestAPI.post("/api/tour/$id/pair/$round", Json.Array("all")).asArray()
logger.info("games for round $round: {}", games.toString().slice(0..50) + "...")
assertTrue(compare_weights(getOutputFile("weights.txt"), getTestFile("opengotha/simpleswiss/simpleswiss_weights_R$round.txt")), "Not matching opengotha weights for round $round")
@@ -354,7 +354,7 @@ class PairingTests: TestBase() {
@Test
fun `SwissTest KPMCSplitbug`() {
// Let pairgoth use the legacy asymmetric detRandom()
BaseSolver.legacy_mode = true
Solver.legacy_mode = true
// read tournament with pairing
val name = "20240921-KPMC-Splitbug"
val file = getTestFile("opengotha/pairings/$name.xml")
@@ -391,7 +391,7 @@ class PairingTests: TestBase() {
for (round in minRound..maxRound) {
val sumOfWeightsOG = compute_sumOfWeight_OG(getTestFile("opengotha/$name/$name" + "_weights_R$round.txt"), pairingsOG[round - minRound], players)
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
Solver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
// Call Pairgoth pairing solver to generate games
games = TestAPI.post("/api/tour/$id/pair/$round", Json.Array("all")).asArray()