Table renumbering ; various bugfixes and enhancements

This commit is contained in:
Claude Brisson
2024-01-22 11:25:20 +01:00
parent fdf39612ff
commit 354c7cc748
13 changed files with 88 additions and 39 deletions

View File

@@ -16,7 +16,7 @@ interface PairgothApiHandler: ApiHandler {
fun Tournament<*>.dispatchEvent(event: Event, data: Json? = null) {
Event.dispatch(event, Json.Object("tournament" to id, "data" to data))
// when storage is not in memory, the tournament has to be persisted
if (event != Event.tournamentAdded && event != Event.tournamentDeleted)
if (event != Event.TournamentAdded && event != Event.TournamentDeleted)
Store.replaceTournament(this)
}

View File

@@ -7,7 +7,6 @@ import org.jeudego.pairgoth.model.Game
import org.jeudego.pairgoth.model.getID
import org.jeudego.pairgoth.model.toID
import org.jeudego.pairgoth.model.toJson
import org.jeudego.pairgoth.server.Event
import org.jeudego.pairgoth.server.Event.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@@ -59,7 +58,7 @@ object PairingHandler: PairgothApiHandler {
}
val games = tournament.pair(round, pairables)
val ret = games.map { it.toJson() }.toJsonArray()
tournament.dispatchEvent(gamesAdded, Json.Object("round" to round, "games" to ret))
tournament.dispatchEvent(GamesAdded, Json.Object("round" to round, "games" to ret))
return ret
}
@@ -78,6 +77,7 @@ object PairingHandler: PairgothApiHandler {
game.black = payload.getID("b") ?: badRequest("missing black player id")
game.white = payload.getID("w") ?: badRequest("missing white player id")
tournament.recomputeDUDD(round, game.id)
val previousTable = game.table;
// temporary
payload.getInt("dudd")?.let { game.drawnUpDown = it }
val black = tournament.pairables[game.black] ?: badRequest("invalid black player id")
@@ -90,10 +90,15 @@ object PairingHandler: PairgothApiHandler {
if (playing.contains(white.id)) badRequest("white is already in another game")
if (payload.containsKey("h")) game.handicap = payload.getString("h")?.toIntOrNull() ?: badRequest("invalid handicap")
if (payload.containsKey("t")) {
// TODO CB - update *all* tables numbers accordingly
game.table = payload.getString("t")?.toIntOrNull() ?: badRequest("invalid table number")
}
tournament.dispatchEvent(gameUpdated, Json.Object("round" to round, "game" to game.toJson()))
tournament.dispatchEvent(GameUpdated, Json.Object("round" to round, "game" to game.toJson()))
if (game.table != previousTable && tournament.renumberTables(round, game)) {
val games = tournament.games(round).values.sortedBy {
if (it.table == 0) Int.MAX_VALUE else it.table
}
tournament.dispatchEvent(TablesRenumbered, Json.Object("round" to round, "games" to games.map { it.toJson() }.toCollection(Json.MutableArray())))
}
return Json.Object("success" to true)
}
@@ -111,7 +116,7 @@ object PairingHandler: PairgothApiHandler {
payload.forEach {
val id = (it as Number).toInt()
val game = tournament.games(round)[id] ?: throw Error("invalid game id")
if (game.result != Game.Result.UNKNOWN) {
if (game.result != Game.Result.UNKNOWN && game.black != 0 && game.white != 0) {
ApiHandler.logger.error("cannot unpair game id ${game.id}: it has a result")
// we'll only skip it
// throw Error("cannot unpair ")
@@ -120,7 +125,7 @@ object PairingHandler: PairgothApiHandler {
}
}
}
tournament.dispatchEvent(gamesDeleted, Json.Object("round" to round, "games" to payload))
tournament.dispatchEvent(GamesDeleted, Json.Object("round" to round, "games" to payload))
return Json.Object("success" to true)
}
}

View File

@@ -5,7 +5,6 @@ import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.Player
import org.jeudego.pairgoth.model.fromJson
import org.jeudego.pairgoth.server.Event
import org.jeudego.pairgoth.server.Event.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@@ -25,7 +24,7 @@ object PlayerHandler: PairgothApiHandler {
val payload = getObjectPayload(request)
val player = Player.fromJson(payload)
tournament.players[player.id] = player
tournament.dispatchEvent(playerAdded, player.toJson())
tournament.dispatchEvent(PlayerAdded, player.toJson())
return Json.Object("success" to true, "id" to player.id)
}
@@ -36,7 +35,7 @@ object PlayerHandler: PairgothApiHandler {
val payload = getObjectPayload(request)
val updated = Player.fromJson(payload, player)
tournament.players[updated.id] = updated
tournament.dispatchEvent(playerUpdated, player.toJson())
tournament.dispatchEvent(PlayerUpdated, player.toJson())
return Json.Object("success" to true)
}
@@ -44,7 +43,7 @@ object PlayerHandler: PairgothApiHandler {
val tournament = getTournament(request)
val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector")
tournament.players.remove(id) ?: badRequest("invalid player id")
tournament.dispatchEvent(playerDeleted, Json.Object("id" to id))
tournament.dispatchEvent(PlayerDeleted, Json.Object("id" to id))
return Json.Object("success" to true)
}
}

View File

@@ -24,7 +24,7 @@ object ResultsHandler: PairgothApiHandler {
val payload = getObjectPayload(request)
val game = tournament.games(round)[payload.getInt("id")] ?: badRequest("invalid game id")
game.result = Game.Result.fromSymbol(payload.getChar("result") ?: badRequest("missing result"))
tournament.dispatchEvent(Event.resultUpdated, Json.Object("round" to round, "data" to game))
tournament.dispatchEvent(Event.ResultUpdated, Json.Object("round" to round, "data" to game))
return Json.Object("success" to true)
}
}

View File

@@ -4,7 +4,6 @@ import com.republicate.kson.Json
import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.TeamTournament
import org.jeudego.pairgoth.server.Event
import org.jeudego.pairgoth.server.Event.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@@ -26,7 +25,7 @@ object TeamHandler: PairgothApiHandler {
val payload = getObjectPayload(request)
val team = tournament.teamFromJson(payload)
tournament.teams[team.id] = team
tournament.dispatchEvent(teamAdded, team.toJson())
tournament.dispatchEvent(TeamAdded, team.toJson())
return Json.Object("success" to true, "id" to team.id)
}
@@ -38,7 +37,7 @@ object TeamHandler: PairgothApiHandler {
val payload = getObjectPayload(request)
val updated = tournament.teamFromJson(payload, team)
tournament.teams[updated.id] = updated
tournament.dispatchEvent(teamUpdated, team.toJson())
tournament.dispatchEvent(TeamUpdated, team.toJson())
return Json.Object("success" to true)
}
@@ -47,7 +46,7 @@ object TeamHandler: PairgothApiHandler {
if (tournament !is TeamTournament) badRequest("tournament is not a team tournament")
val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid team selector")
tournament.teams.remove(id) ?: badRequest("invalid team id")
tournament.dispatchEvent(teamDeleted, Json.Object("id" to id))
tournament.dispatchEvent(TeamDeleted, Json.Object("id" to id))
return Json.Object("success" to true)
}
}

View File

@@ -11,7 +11,6 @@ import org.jeudego.pairgoth.model.fromJson
import org.jeudego.pairgoth.model.toJson
import org.jeudego.pairgoth.store.Store
import org.jeudego.pairgoth.server.ApiServlet
import org.jeudego.pairgoth.server.Event
import org.jeudego.pairgoth.server.Event.*
import org.w3c.dom.Element
import javax.servlet.http.HttpServletRequest
@@ -44,7 +43,7 @@ object TournamentHandler: PairgothApiHandler {
else -> badRequest("missing or invalid payload")
}
Store.addTournament(tournament)
tournament.dispatchEvent(tournamentAdded, tournament.toJson())
tournament.dispatchEvent(TournamentAdded, tournament.toJson())
return Json.Object("success" to true, "id" to tournament.id)
}
@@ -64,14 +63,14 @@ object TournamentHandler: PairgothApiHandler {
clear()
putAll(tournament.games(round))
}
updated.dispatchEvent(tournamentUpdated, updated.toJson())
updated.dispatchEvent(TournamentUpdated, updated.toJson())
return Json.Object("success" to true)
}
override fun delete(request: HttpServletRequest): Json {
val tournament = getTournament(request)
Store.deleteTournament(tournament)
tournament.dispatchEvent(tournamentDeleted, Json.Object("id" to tournament.id))
tournament.dispatchEvent(TournamentDeleted, Json.Object("id" to tournament.id))
return Json.Object("success" to true)
}
}

View File

@@ -90,6 +90,23 @@ sealed class Tournament <P: Pairable>(
val blackplayer = solver.pairables.find { p-> p.id == game.black }!!
game.drawnUpDown = solver.dudd(blackplayer, whiteplayer)
}
fun renumberTables(round: Int, pivot: Game? = null): Boolean {
var changed = false
var nextTable = 1
games(round).values.filter{ game -> pivot?.let { pivot.id != game.id } ?: true }.sortedBy { game ->
val whiteRank = pairables[game.white]?.rating ?: Int.MIN_VALUE
val blackRank = pairables[game.black]?.rating ?: Int.MIN_VALUE
-(2 * whiteRank + 2 * blackRank) / 2
}.forEach { game ->
if (pivot != null && nextTable == pivot.table) {
++nextTable
}
changed = changed || game.table != nextTable
game.table = nextTable++
}
return changed
}
}
// standard tournament of individuals

View File

@@ -4,19 +4,20 @@ import info.macias.sse.events.MessageEvent
import java.util.concurrent.atomic.AtomicLong
enum class Event {
tournamentAdded,
tournamentUpdated,
tournamentDeleted,
playerAdded,
playerUpdated,
playerDeleted,
teamAdded,
teamUpdated,
teamDeleted,
gamesAdded,
gamesDeleted,
gameUpdated,
resultUpdated,
TournamentAdded,
TournamentUpdated,
TournamentDeleted,
PlayerAdded,
PlayerUpdated,
PlayerDeleted,
TeamAdded,
TeamUpdated,
TeamDeleted,
GamesAdded,
GamesDeleted,
GameUpdated,
ResultUpdated,
TablesRenumbered
;
companion object {