MMS up to round 4 out of 5 (bug with BWbalance)
This commit is contained in:
@@ -73,9 +73,10 @@ object PairingHandler: PairgothApiHandler {
|
|||||||
}.toSet()
|
}.toSet()
|
||||||
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.recomputeDUDD(round, game.id)
|
|
||||||
|
tournament.recomputeHdAndDUDD(round, game.id)
|
||||||
// temporary
|
// temporary
|
||||||
payload.getInt("dudd")?.let { game.drawnUpDown = it }
|
//payload.getInt("dudd")?.let { game.drawnUpDown = it }
|
||||||
val black = tournament.pairables[game.black] ?: badRequest("invalid black player id")
|
val black = tournament.pairables[game.black] ?: badRequest("invalid black player id")
|
||||||
val white = tournament.pairables[game.black] ?: badRequest("invalid white player id")
|
val white = tournament.pairables[game.black] ?: badRequest("invalid white player id")
|
||||||
if (black.skip.contains(round)) badRequest("black is not playing this round")
|
if (black.skip.contains(round)) badRequest("black is not playing this round")
|
||||||
|
@@ -71,7 +71,7 @@ sealed class Tournament <P: Pairable>(
|
|||||||
else mutableMapOf<ID, Game>().also { games.add(it) }
|
else mutableMapOf<ID, Game>().also { games.add(it) }
|
||||||
fun lastRound() = games.size
|
fun lastRound() = games.size
|
||||||
|
|
||||||
fun recomputeDUDD(round: Int, gameID: ID) {
|
fun recomputeHdAndDUDD(round: Int, gameID: ID) {
|
||||||
// Instantiate solver with game history
|
// Instantiate solver with game history
|
||||||
// TODO cleaner solver instantiation
|
// TODO cleaner solver instantiation
|
||||||
val history = historyBefore(round)
|
val history = historyBefore(round)
|
||||||
@@ -81,11 +81,12 @@ sealed class Tournament <P: Pairable>(
|
|||||||
MacMahonSolver(round, history, pairables.values.toList(), pairing.pairingParams, pairing.placementParams, pairing.mmFloor, pairing.mmBar)
|
MacMahonSolver(round, history, pairables.values.toList(), pairing.pairingParams, pairing.placementParams, pairing.mmFloor, pairing.mmBar)
|
||||||
} else throw Exception("Invalid tournament type")
|
} else throw Exception("Invalid tournament type")
|
||||||
|
|
||||||
// Recomputes DUDD
|
// Recomputes DUDD and hd
|
||||||
val game = games(round)[gameID]!!
|
val game = games(round)[gameID]!!
|
||||||
val whiteplayer = solver.pairables.find { p-> p.id == game.white }!!
|
val white = solver.pairables.find { p-> p.id == game.white }!!
|
||||||
val blackplayer = solver.pairables.find { p-> p.id == game.black }!!
|
val black = solver.pairables.find { p-> p.id == game.black }!!
|
||||||
game.drawnUpDown = solver.dudd(blackplayer, whiteplayer)
|
game.drawnUpDown = solver.dudd(black, white)
|
||||||
|
game.handicap = solver.hd(black, white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ open class HistoryHelper(protected val history: List<List<Game>>, scoresGetter:
|
|||||||
history.flatten().filter { game ->
|
history.flatten().filter { game ->
|
||||||
game.handicap == 0
|
game.handicap == 0
|
||||||
}.filter { game ->
|
}.filter { game ->
|
||||||
game.white != 0 // Remove games against byePlayer
|
game.white != ByePlayer.id // Remove games against byePlayer
|
||||||
}.flatMap { game ->
|
}.flatMap { game ->
|
||||||
listOf(Pair(game.white, +1), Pair(game.black, -1))
|
listOf(Pair(game.white, +1), Pair(game.black, -1))
|
||||||
}.groupingBy {
|
}.groupingBy {
|
||||||
|
@@ -184,6 +184,9 @@ sealed class BaseSolver(
|
|||||||
// This cost is never applied if potential Handicap != 0
|
// This cost is never applied if potential Handicap != 0
|
||||||
// It is fully applied if wbBalance(sP1) and wbBalance(sP2) are strictly of different signs
|
// It is fully applied if wbBalance(sP1) and wbBalance(sP2) are strictly of different signs
|
||||||
// It is half applied if one of wbBalance is 0 and the other is >=2
|
// It is half applied if one of wbBalance is 0 and the other is >=2
|
||||||
|
if (p1.name == "Marechal" && p2.name == "Goloubkov") {
|
||||||
|
println("coucou ${p1.colorBalance} ${p2.colorBalance}")
|
||||||
|
}
|
||||||
val hd1 = pairing.handicap.handicap(p1, p2)
|
val hd1 = pairing.handicap.handicap(p1, p2)
|
||||||
val hd2 = pairing.handicap.handicap(p2, p1)
|
val hd2 = pairing.handicap.handicap(p2, p1)
|
||||||
val potentialHd: Int = max(hd1, hd2)
|
val potentialHd: Int = max(hd1, hd2)
|
||||||
@@ -331,7 +334,7 @@ sealed class BaseSolver(
|
|||||||
score += 4 * duddWeight
|
score += 4 * duddWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if(true) {
|
/*if(p1.name == "Durand" && p2.name == "Aim") {
|
||||||
println("Names DU DD "+p1.nameSeed()+" "+p1_DU+" "+p1_DD+" "+p2.nameSeed()+" "+p2_DU+" "+p2_DD)
|
println("Names DU DD "+p1.nameSeed()+" "+p1_DU+" "+p1_DD+" "+p2.nameSeed()+" "+p2_DU+" "+p2_DD)
|
||||||
println("Names "+upperSP.nameSeed()+" "+upperSP.group+" "+lowerSP.nameSeed()+" "+lowerSP.group)
|
println("Names "+upperSP.nameSeed()+" "+upperSP.group+" "+lowerSP.nameSeed()+" "+lowerSP.group)
|
||||||
println("DUDD scenario, GroupDiff = "+scenario.toString()+" "+(upperSP.group-lowerSP.group).toString())
|
println("DUDD scenario, GroupDiff = "+scenario.toString()+" "+(upperSP.group-lowerSP.group).toString())
|
||||||
@@ -526,13 +529,23 @@ sealed class BaseSolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dudd(black: Pairable, white: Pairable): Int {
|
fun dudd(black: Pairable, white: Pairable): Int {
|
||||||
return white.group - black.group
|
return if (white.main > black.main) {
|
||||||
|
1
|
||||||
|
} else if (white.main < black.main) {
|
||||||
|
-1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
//return white.group - black.group
|
||||||
|
}
|
||||||
|
fun hd(black: Pairable, white: Pairable): Int {
|
||||||
|
return pairing.handicap.handicap(white, black)
|
||||||
}
|
}
|
||||||
open fun games(black: Pairable, white: Pairable): List<Game> {
|
open fun games(black: Pairable, white: Pairable): List<Game> {
|
||||||
// CB TODO team of individuals pairing
|
// CB TODO team of individuals pairing
|
||||||
val usedTables = tables.getOrNull(round - 1) ?: BitSet().also { tables.add(it) }
|
val usedTables = tables.getOrNull(round - 1) ?: BitSet().also { tables.add(it) }
|
||||||
val table = if (black.id == 0 || white.id == 0) 0 else usedTables.nextClearBit(1)
|
val table = if (black.id == 0 || white.id == 0) 0 else usedTables.nextClearBit(1)
|
||||||
usedTables.set(table)
|
usedTables.set(table)
|
||||||
return listOf(Game(id = Store.nextGameId, table = table, black = black.id, white = white.id, handicap = pairing.handicap.handicap(white, black), drawnUpDown = dudd(black, white)))
|
return listOf(Game(id = Store.nextGameId, table = table, black = black.id, white = white.id, handicap = hd(white, black), drawnUpDown = dudd(black, white)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,8 @@ import java.io.FileWriter
|
|||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@@ -93,7 +95,7 @@ class PairingTests: TestBase() {
|
|||||||
return identical
|
return identical
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compare_games(games:Json.Array, opengotha:Json.Array): Boolean{
|
fun compare_games(games:Json.Array, opengotha:Json.Array, skipColor: Boolean = false): Boolean{
|
||||||
if (games.size != opengotha.size) {
|
if (games.size != opengotha.size) {
|
||||||
val tmp = Game.fromJson(games.getJson(games.size-1)!!.asObject())
|
val tmp = Game.fromJson(games.getJson(games.size-1)!!.asObject())
|
||||||
if ((tmp.white != 0) and (tmp.black != 0)) {return false}
|
if ((tmp.white != 0) and (tmp.black != 0)) {return false}
|
||||||
@@ -104,11 +106,16 @@ class PairingTests: TestBase() {
|
|||||||
val tmp = Game.fromJson(games.getJson(i)!!.asObject().let {
|
val tmp = Game.fromJson(games.getJson(i)!!.asObject().let {
|
||||||
Json.MutableObject(it).set("t", 0) // hack to fill the table to make fromJson() happy
|
Json.MutableObject(it).set("t", 0) // hack to fill the table to make fromJson() happy
|
||||||
})
|
})
|
||||||
gamesPair.add(Pair(tmp.white, tmp.black))
|
|
||||||
val tmpOG = Game.fromJson(opengotha.getJson(i)!!.asObject().let {
|
val tmpOG = Game.fromJson(opengotha.getJson(i)!!.asObject().let {
|
||||||
Json.MutableObject(it).set("t", 0) // hack to fill the table to make fromJson() happy
|
Json.MutableObject(it).set("t", 0) // hack to fill the table to make fromJson() happy
|
||||||
})
|
})
|
||||||
openGothaPair.add(Pair(tmpOG.white, tmpOG.black))
|
if (skipColor) {
|
||||||
|
gamesPair.add(Pair(min(tmp.white, tmp.black), max(tmp.white, tmp.black)))
|
||||||
|
openGothaPair.add(Pair(min(tmpOG.white, tmpOG.black), max(tmpOG.white, tmpOG.black)))
|
||||||
|
} else {
|
||||||
|
gamesPair.add(Pair(tmp.white, tmp.black))
|
||||||
|
openGothaPair.add(Pair(tmpOG.white, tmpOG.black))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return gamesPair==openGothaPair
|
return gamesPair==openGothaPair
|
||||||
}
|
}
|
||||||
@@ -300,17 +307,20 @@ class PairingTests: TestBase() {
|
|||||||
val respOG = TestAPI.post("/api/tour", resourceOG)
|
val respOG = TestAPI.post("/api/tour", resourceOG)
|
||||||
val idOG = respOG.asObject().getInt("id")
|
val idOG = respOG.asObject().getInt("id")
|
||||||
val tournamentOG = TestAPI.get("/api/tour/$idOG").asObject()
|
val tournamentOG = TestAPI.get("/api/tour/$idOG").asObject()
|
||||||
logger.info(tournamentOG.toString().slice(0..50) + "...")
|
//logger.info(tournamentOG.toString().slice(0..50) + "...")
|
||||||
val playersOG = TestAPI.get("/api/tour/$idOG/part").asArray()
|
val playersOG = TestAPI.get("/api/tour/$idOG/part").asArray()
|
||||||
//logger.info(players.toString().slice(0..50) + "...")
|
//logger.info(players.toString().slice(0..50) + "...")
|
||||||
//logger.info(playersOG.toString())
|
logger.info(playersOG.toString())
|
||||||
|
|
||||||
val pairingsOG = mutableListOf<String>()
|
val pairingsOG = mutableListOf<Json.Array>()
|
||||||
for (round in 1..tournamentOG.getInt("rounds")!!) {
|
for (round in 1..tournamentOG.getInt("rounds")!!) {
|
||||||
val games = TestAPI.get("/api/tour/$idOG/res/$round").asArray()
|
val games = TestAPI.get("/api/tour/$idOG/res/$round").asArray()
|
||||||
logger.info("games for round $round: {}", games.toString())
|
logger.info("games for round $round: {}", games.toString())
|
||||||
pairingsOG.add(games.toString())
|
pairingsOG.add(games)
|
||||||
}*/
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//assert(false)
|
||||||
|
|
||||||
|
|
||||||
val pairingsR1 = """[{"id":1,"w":3,"b":5,"h":0,"r":"w","dd":0},{"id":2,"w":12,"b":10,"h":0,"r":"b","dd":0},{"id":3,"w":9,"b":14,"h":0,"r":"b","dd":0},{"id":4,"w":11,"b":6,"h":0,"r":"b","dd":0},{"id":5,"w":13,"b":15,"h":0,"r":"b","dd":0},{"id":6,"w":2,"b":16,"h":1,"r":"w","dd":0},{"id":7,"w":8,"b":4,"h":5,"r":"b","dd":0},{"id":8,"w":7,"b":1,"h":2,"r":"w","dd":0}]"""
|
val pairingsR1 = """[{"id":1,"w":3,"b":5,"h":0,"r":"w","dd":0},{"id":2,"w":12,"b":10,"h":0,"r":"b","dd":0},{"id":3,"w":9,"b":14,"h":0,"r":"b","dd":0},{"id":4,"w":11,"b":6,"h":0,"r":"b","dd":0},{"id":5,"w":13,"b":15,"h":0,"r":"b","dd":0},{"id":6,"w":2,"b":16,"h":1,"r":"w","dd":0},{"id":7,"w":8,"b":4,"h":5,"r":"b","dd":0},{"id":8,"w":7,"b":1,"h":2,"r":"w","dd":0}]"""
|
||||||
@@ -346,16 +356,22 @@ class PairingTests: TestBase() {
|
|||||||
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
|
BaseSolver.weightsLogger = PrintWriter(FileWriter(getOutputFile("weights.txt")))
|
||||||
// games must be created and then modified by PUT
|
// games must be created and then modified by PUT
|
||||||
games = TestAPI.post("/api/tour/$id/pair/$round", Json.Array("all")).asArray()
|
games = TestAPI.post("/api/tour/$id/pair/$round", Json.Array("all")).asArray()
|
||||||
|
logger.info(games.toString())
|
||||||
val skipSeeding = round <= 2
|
val skipSeeding = round <= 2
|
||||||
assertTrue(compare_weights(getOutputFile("weights.txt"), getTestFile("opengotha/simplemm/simplemm_weights_R$round.txt"), skipSeeding), "Not matching opengotha weights for round $round")
|
assertTrue(compare_weights(getOutputFile("weights.txt"), getTestFile("opengotha/simplemm/simplemm_weights_R$round.txt"), skipSeeding), "Not matching opengotha weights for round $round")
|
||||||
logger.info("Weights for round $round match OpenGotha")
|
logger.info("Weights for round $round match OpenGotha")
|
||||||
|
assertTrue(compare_games(games, Json.parse(pairings[round - 1])!!.asArray(), skipColor=true),"pairings for round $round differ")
|
||||||
|
logger.info("Pairing for round $round match OpenGotha")
|
||||||
|
|
||||||
forcedGames = Json.parse(pairings[round-1])!!.asArray()
|
forcedGames = Json.parse(pairings[round-1])!!.asArray()
|
||||||
|
//forcedGames = pairingsOG[round-1]
|
||||||
|
|
||||||
for (j in 0..forcedGames.size-1) {
|
for (j in 0..forcedGames.size-1) {
|
||||||
game = forcedGames.getJson(j)!!.asObject()
|
game = forcedGames.getJson(j)!!.asObject()
|
||||||
TestAPI.put("/api/tour/$id/pair/$round", game)
|
TestAPI.put("/api/tour/$id/pair/$round", game)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Enter results
|
// Enter results
|
||||||
firstGameID = (games.getJson(0)!!.asObject()["id"] as Long?)!!.toInt()
|
firstGameID = (games.getJson(0)!!.asObject()["id"] as Long?)!!.toInt()
|
||||||
// Extract results
|
// Extract results
|
||||||
|
Reference in New Issue
Block a user