diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt index a0e63c8..7a02948 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt @@ -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) diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt index c92a7ff..b517d37 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt @@ -71,7 +71,7 @@ sealed class Tournament ( } // games per id for each round - private val games = mutableListOf>() + protected val games = mutableListOf>() fun games(round: Int) = games.getOrNull(round - 1) ?: if (round > games.size + 1) throw Error("invalid round") @@ -160,7 +160,10 @@ sealed class Tournament ( 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() val teams: MutableMap = _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.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 } - 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<*> { diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt index 7505bcc..11b3e54 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/HistoryHelper.kt @@ -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>, @@ -247,18 +248,4 @@ open class HistoryHelper( class TeamOfIndividualsHistoryHelper(history: List>, scoresGetter: () -> Map>): 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 } diff --git a/view-webapp/src/main/webapp/js/tour-teams.inc.js b/view-webapp/src/main/webapp/js/tour-teams.inc.js index d21fa28..1875ae5 100644 --- a/view-webapp/src/main/webapp/js/tour-teams.inc.js +++ b/view-webapp/src/main/webapp/js/tour-teams.inc.js @@ -40,9 +40,10 @@ function leave(teamId, playerId) { let team = teams.get(teamId); let index = team.players.indexOf(playerId); if (index > -1) { - team.players.splice(index, 1); + let newPlayers = team.players.slice(); + newPlayers.splice(index, 1); api.putJson(`tour/${tour_id}/team/${teamId}`, { - "players": team.players + "players": newPlayers }).then(rst => { if (rst !== 'error') { document.location.reload(); diff --git a/view-webapp/src/main/webapp/tour-pairing.inc.html b/view-webapp/src/main/webapp/tour-pairing.inc.html index b257786..1933c4b 100644 --- a/view-webapp/src/main/webapp/tour-pairing.inc.html +++ b/view-webapp/src/main/webapp/tour-pairing.inc.html @@ -99,8 +99,8 @@ #set($black = $pmap[$game.b]) ${game.t} - #if($white)${white.name} ${white.firstname} (#rank($white.rank), $white.country $white.club)#{else}BIP#end - #if($black)${black.name} ${black.firstname} (#rank($black.rank), $black.country $black.club)#{else}BIP#end + #if($white)${white.name} $!{white.firstname} (#rank($white.rank) $!white.country $!white.club)#{else}BIP#end + #if($black)${black.name} $!{black.firstname} (#rank($black.rank) $!black.country $!black.club)#{else}BIP#end ${game.h} #end