Consistency checks on participations changes ; plus some code cleaning

This commit is contained in:
Claude Brisson
2025-01-26 11:51:22 +01:00
parent 169546ae66
commit 0ed9bfb5eb
5 changed files with 37 additions and 23 deletions

View File

@@ -4,6 +4,7 @@ import com.republicate.kson.Json
import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.Player
import org.jeudego.pairgoth.model.TeamTournament
import org.jeudego.pairgoth.model.fromJson
import org.jeudego.pairgoth.server.Event.*
import javax.servlet.http.HttpServletRequest
@@ -44,12 +45,25 @@ object PlayerHandler: PairgothApiHandler {
val leavingRounds = updated.skip.toSet().minus(player.skip.toSet())
leavingRounds.forEach { round ->
if (round <= tournament.lastRound()) {
val playing = tournament.games(round).values.flatMap { listOf(it.black, it.white) }
val playing = tournament.pairedPlayers(round)
if (playing.contains(id)) {
badRequest("player is playing in round #$round")
}
}
}
if (tournament is TeamTournament) {
// participations cannot be changed in an already paired team
val joiningRounds = player.skip.toSet().minus(updated.skip.toSet())
val changedRounds = leavingRounds.union(joiningRounds)
changedRounds.forEach { round ->
if (round <= tournament.lastRound()) {
val team = tournament.getPlayerTeam(id)
if (team != null && tournament.pairedTeams().contains(team.id)) {
badRequest("number of active players for team #${team.id} cannot be changed for round $round")
}
}
}
}
tournament.players[id] = updated
tournament.dispatchEvent(PlayerUpdated, request, player.toJson())
return Json.Object("success" to true)

View File

@@ -71,7 +71,7 @@ sealed class Tournament <P: Pairable>(
}
// games per id for each round
private val games = mutableListOf<MutableMap<ID, Game>>()
protected val games = mutableListOf<MutableMap<ID, Game>>()
fun games(round: Int) = games.getOrNull(round - 1) ?:
if (round > games.size + 1) throw Error("invalid round")
@@ -160,7 +160,10 @@ sealed class Tournament <P: Pairable>(
return changed
}
fun pairedPlayers() = games.flatMap { it.values }.flatMap { listOf(it.black, it.white) }.toSet()
open fun pairedPlayers() = games.flatMap { it.values }.flatMap { listOf(it.black, it.white) }.toSet()
open fun pairedPlayers(round: Int) = games(round).values.flatMap { listOf(it.black, it.white) }.filter { it != 0 }.toSet()
fun hasPlayer(dbId: DatabaseId, pId: String) = pId.isNotBlank() && players.values.filter { player -> pId == player.externalIds[dbId] }.isNotEmpty()
fun stats() = (0..rounds - 1).map { index ->
@@ -238,6 +241,12 @@ class TeamTournament(
override val players = mutableMapOf<ID, Player>()
val teams: MutableMap<ID, Team> = _pairables
fun pairedTeams() = super.pairedPlayers()
override fun pairedPlayers() = super.pairedPlayers().flatMap { pairables[it]!!.asTeam()!!.playerIds }.toSet()
override fun pairedPlayers(round: Int) = super.pairedPlayers(round).flatMap { pairables[it]!!.asTeam()!!.playerIds }.toSet()
private fun List<Int>.average(provider: (Player)->Int) = ((sumOf {id -> provider(players[id]!!)} - epsilon) / size).roundToInt()
inner class Team(id: ID, name: String, rating: Int, rank: Int, final: Boolean, mmsCorrection: Int = 0): Pairable(id, name, rating, rank, final, mmsCorrection) {
@@ -260,11 +269,11 @@ class TeamTournament(
}
val teamOfIndividuals: Boolean get() = type.individual
// override val skip get() = playerIds.map { players[it]!!.skip }.reduce { left, right -> (left union right) as MutableSet<Int> }
override fun canPlay(round: Int) = teamPlayers.filter { it.canPlay(round) }.size == type.playersNumber
}
fun getPlayerTeam(playerId: ID) = teams.values.filter { it.playerIds.contains(playerId) }.firstOrNull()
fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null): Team {
val teamPlayersIds = json.getArray("players")?.let { arr ->
arr.map {
@@ -287,6 +296,9 @@ class TeamTournament(
}
}
fun Pairable.asPlayer() = this as? Player
fun Pairable.asTeam() = this as? TeamTournament.Team
// Serialization
fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = null): Tournament<*> {

View File

@@ -2,6 +2,7 @@ package org.jeudego.pairgoth.pairing
import org.jeudego.pairgoth.model.*
import org.jeudego.pairgoth.model.Game.Result.*
import org.jeudego.pairgoth.model.TeamTournament.Team
open class HistoryHelper(
protected val history: List<List<Game>>,
@@ -247,18 +248,4 @@ open class HistoryHelper(
class TeamOfIndividualsHistoryHelper(history: List<List<Game>>, scoresGetter: () -> Map<ID, Pair<Double, Double>>):
HistoryHelper(history, { scoresGetter() }) {
private fun Pairable.asTeam() = this as TeamTournament.Team
override fun playedTogether(p1: Pairable, p2: Pairable) = paired.intersect(p1.asTeam().playerIds.first().let { id ->
(p2.asTeam()).playerIds.map {Pair(it, id) }
}.toSet()).isNotEmpty()
override fun nbW(p: Pairable) = p.asTeam().teamPlayers.map { super.nbW(it) ?: throw Error("unknown player id: #${it.id}") }.sum()
//override fun sos(p:Pairable) = p.asTeam().teamPlayers.map { super.sos(it) ?: throw Error("unknown player id: #${it.id}") }.sum()
//override fun sosos(p:Pairable) = p.asTeam().teamPlayers.map { super.sosos(it) ?: throw Error("unknown player id: #${it.id}") }.sum()
//override fun sodos(p:Pairable) = p.asTeam().teamPlayers.map { super.sodos(it) ?: throw Error("unknown player id: #${it.id}") }.sum()
// TODO CB - now that we've got the rounds in history helper, calculate virtual scores
// also - try to factorize a bit calculations
}