Teams handing in progress
This commit is contained in:
@@ -88,7 +88,7 @@ fun Tournament<*>.getSortedPairables(round: Int): List<Json.Object> {
|
||||
Criterion.DC -> StandingsHandler.nullMap
|
||||
}
|
||||
}
|
||||
val pairables = pairables.values.filter { it.final }.map { it.toMutableJson() }
|
||||
val pairables = pairables.values.filter { it.final }.map { it.toDetailedJson() }
|
||||
pairables.forEach { player ->
|
||||
for (crit in criteria) {
|
||||
player[crit.first] = (crit.second[player.getID()] ?: 0.0).toInt()
|
||||
|
@@ -14,8 +14,8 @@ object PlayerHandler: PairgothApiHandler {
|
||||
override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? {
|
||||
val tournament = getTournament(request)
|
||||
return when (val pid = getSubSelector(request)?.toIntOrNull()) {
|
||||
null -> tournament.pairables.values.map { it.toJson() }.toJsonArray()
|
||||
else -> tournament.pairables[pid]?.toJson() ?: badRequest("no player with id #${pid}")
|
||||
null -> tournament.players.values.map { it.toJson() }.toJsonArray()
|
||||
else -> tournament.players[pid]?.toJson() ?: badRequest("no player with id #${pid}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,8 +14,8 @@ object TeamHandler: PairgothApiHandler {
|
||||
val tournament = getTournament(request)
|
||||
if (tournament !is TeamTournament) badRequest("tournament is not a team tournament")
|
||||
return when (val pid = getSubSelector(request)?.toIntOrNull()) {
|
||||
null -> tournament.teams.values.map { it.toJson() }.toJsonArray()
|
||||
else -> tournament.teams[pid]?.toJson() ?: badRequest("no team with id #${pid}")
|
||||
null -> tournament.teams.values.map { it.toDetailedJson() }.toJsonArray()
|
||||
else -> tournament.teams[pid]?.toDetailedJson() ?: badRequest("no team with id #${pid}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,12 +26,14 @@ object TournamentHandler: PairgothApiHandler {
|
||||
else ->
|
||||
when {
|
||||
ApiServlet.isJson(accept) -> {
|
||||
getStore(request).getTournament(id)?.let {
|
||||
getStore(request).getTournament(id)?.let { tour ->
|
||||
if (accept == "application/pairgoth") {
|
||||
it.toFullJson()
|
||||
tour.toFullJson()
|
||||
} else {
|
||||
it.toJson().also { json ->
|
||||
(json as Json.MutableObject)["stats"] = it.stats()
|
||||
tour.toJson().also { json ->
|
||||
// additional attributes for the webapp
|
||||
json["stats"] = tour.stats()
|
||||
json["teamSize"] = tour.type.playersNumber
|
||||
}
|
||||
}
|
||||
} ?: badRequest("no tournament with id #${id}")
|
||||
|
@@ -8,13 +8,14 @@ import java.util.*
|
||||
|
||||
// Pairable
|
||||
|
||||
sealed class Pairable(val id: ID, val name: String, open val rating: Int, open val rank: Int, val final: Boolean, val mmsCorrection: Int = 0) {
|
||||
sealed class Pairable(val id: ID, val name: String, val rating: Int, val rank: Int, val final: Boolean, val mmsCorrection: Int = 0) {
|
||||
companion object {
|
||||
const val MIN_RANK: Int = -30 // 30k
|
||||
const val MAX_RANK: Int = 8 // 9D
|
||||
}
|
||||
abstract fun toJson(): Json.Object
|
||||
fun toJson(): Json.Object = toMutableJson()
|
||||
abstract fun toMutableJson(): Json.MutableObject
|
||||
open fun toDetailedJson() = toMutableJson()
|
||||
abstract val club: String?
|
||||
abstract val country: String?
|
||||
open fun fullName(separator: String = " "): String {
|
||||
@@ -28,9 +29,6 @@ sealed class Pairable(val id: ID, val name: String, open val rating: Int, open v
|
||||
}
|
||||
|
||||
object ByePlayer: Pairable(0, "bye", 0, Int.MIN_VALUE, true) {
|
||||
override fun toJson(): Json.Object {
|
||||
throw Error("bye player should never be serialized")
|
||||
}
|
||||
override fun toMutableJson(): Json.MutableObject {
|
||||
throw Error("bye player should never be serialized")
|
||||
}
|
||||
@@ -95,7 +93,6 @@ class Player(
|
||||
}
|
||||
}
|
||||
|
||||
override fun toJson(): Json.Object = toMutableJson()
|
||||
override fun fullName(separator: String): String {
|
||||
return name + separator + firstname
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import java.time.LocalDate
|
||||
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
||||
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
|
||||
import org.jeudego.pairgoth.pairing.solver.SwissSolver
|
||||
import org.jeudego.pairgoth.store.Store
|
||||
import org.jeudego.pairgoth.store.nextPlayerId
|
||||
import org.jeudego.pairgoth.store.nextTournamentId
|
||||
import kotlin.math.max
|
||||
@@ -172,39 +171,53 @@ class TeamTournament(
|
||||
gobanSize: Int = 19,
|
||||
komi: Double = 7.5
|
||||
): Tournament<TeamTournament.Team>(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) {
|
||||
companion object {}
|
||||
companion object {
|
||||
private val epsilon = 0.0001
|
||||
}
|
||||
override val players = mutableMapOf<ID, Player>()
|
||||
val teams: MutableMap<ID, Team> = _pairables
|
||||
|
||||
inner class Team(id: ID, name: String, final: Boolean): Pairable(id, name, 0, 0, final) {
|
||||
private fun List<Int>.average(provider: (Player)->Int) = (sumOf {id -> provider(players[id]!!)} - epsilon / players.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) {
|
||||
val playerIds = mutableSetOf<ID>()
|
||||
val teamPlayers: Set<Player> get() = playerIds.mapNotNull { players[id] }.toSet()
|
||||
override val rating: Int get() = if (teamPlayers.isEmpty()) super.rating else (teamPlayers.sumOf { player -> player.rating.toDouble() } / players.size).roundToInt()
|
||||
override val rank: Int get() = if (teamPlayers.isEmpty()) super.rank else (teamPlayers.sumOf { player -> player.rank.toDouble() } / players.size).roundToInt()
|
||||
override val club: String? get() = teamPlayers.map { club }.distinct().let { if (it.size == 1) it[0] else null }
|
||||
override val country: String? get() = teamPlayers.map { country }.distinct().let { if (it.size == 1) it[0] else null }
|
||||
val teamPlayers: Set<Player> get() = playerIds.mapNotNull { players[it] }.toSet()
|
||||
override val club: String? get() = teamPlayers.map { it.club }.distinct().let { if (it.size == 1) it[0] else null }
|
||||
override val country: String? get() = teamPlayers.map { it.country }.distinct().let { if (it.size == 1) it[0] else null }
|
||||
override fun toMutableJson() = Json.MutableObject(
|
||||
"id" to id,
|
||||
"name" to name,
|
||||
"players" to playerIds.toList().toJsonArray()
|
||||
)
|
||||
override fun toJson(): Json.Object = toMutableJson()
|
||||
|
||||
override fun toDetailedJson() = toMutableJson().also { json ->
|
||||
json["rank"] = rank
|
||||
country?.also { json["country"] = it }
|
||||
club?.also { json["club"] = it }
|
||||
}
|
||||
val teamOfIndividuals: Boolean get() = type.individual
|
||||
}
|
||||
|
||||
fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null) = Team(
|
||||
id = json.getInt("id") ?: default?.id ?: nextPlayerId,
|
||||
name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
|
||||
final = json.getBoolean("final") ?: default?.final ?: badRequest("missing final")
|
||||
).apply {
|
||||
json.getArray("players")?.let { arr ->
|
||||
arr.mapTo(playerIds) {
|
||||
if (it != null && it is Number) it.toInt().also { id -> players.containsKey(id) }
|
||||
fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null): Team {
|
||||
val teamPlayersIds = json.getArray("players")?.let { arr ->
|
||||
arr.map {
|
||||
if (it != null && it is Number) it.toInt().also { id ->
|
||||
if (!players.containsKey(id)) badRequest("invalid player id: ${id}")
|
||||
}
|
||||
else badRequest("invalid players array")
|
||||
}
|
||||
} ?: badRequest("missing players")
|
||||
return Team(
|
||||
id = json.getInt("id") ?: default?.id ?: nextPlayerId,
|
||||
name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
|
||||
rating = json.getInt("rating") ?: default?.rating ?: teamPlayersIds.average(Player::rating),
|
||||
rank = json.getInt("rank") ?: default?.rank ?: teamPlayersIds.average(Player::rank),
|
||||
final = teamPlayersIds.all { players[it]!!.final },
|
||||
mmsCorrection = json.getInt("mmsCorrection") ?: default?.mmsCorrection ?: 0
|
||||
).also {
|
||||
it.playerIds.addAll(teamPlayersIds)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Serialization
|
||||
@@ -250,10 +263,16 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n
|
||||
rounds = json.getInt("rounds") ?: default?.rounds ?: badRequest("missing rounds"),
|
||||
pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing")
|
||||
)
|
||||
(json["players"] as Json.Array?)?.forEach { obj ->
|
||||
json.getArray("players")?.forEach { obj ->
|
||||
val pairable = obj as Json.Object
|
||||
tournament.players[pairable.getID("id")!!] = Player.fromJson(pairable)
|
||||
}
|
||||
if (tournament is TeamTournament) {
|
||||
json.getArray("teams")?.forEach { obj ->
|
||||
val team = obj as Json.Object
|
||||
tournament.teams[team.getID("id")!!] = tournament.teamFromJson(team)
|
||||
}
|
||||
}
|
||||
(json["games"] as Json.Array?)?.forEachIndexed { i, arr ->
|
||||
val round = i + 1
|
||||
val tournamentGames = tournament.games(round)
|
||||
@@ -286,7 +305,7 @@ fun Tournament<*>.toJson() = Json.MutableObject(
|
||||
)
|
||||
|
||||
fun Tournament<*>.toFullJson(): Json.Object {
|
||||
val json = Json.MutableObject(toJson())
|
||||
val json = toJson()
|
||||
json["players"] = Json.Array(players.values.map { it.toJson() })
|
||||
if (this is TeamTournament) {
|
||||
json["teams"] = Json.Array(teams.values.map { it.toJson() })
|
||||
|
@@ -2,11 +2,13 @@ package org.jeudego.pairgoth.test
|
||||
|
||||
import com.republicate.kson.Json
|
||||
import com.republicate.kson.toJsonObject
|
||||
import com.republicate.kson.toMutableJsonObject
|
||||
import org.jeudego.pairgoth.model.ID
|
||||
import org.junit.jupiter.api.MethodOrderer.MethodName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.api.TestMethodOrder
|
||||
import java.io.Serializable
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
@@ -143,7 +145,13 @@ class BasicTests: TestBase() {
|
||||
// filter out "id", and also "komi", "rules" and "gobanSize" which were provided by default
|
||||
// also filter out "pairing", which is filled by all default values
|
||||
val cmp = Json.Object(*resp.entries.filter { it.key !in listOf("id", "komi", "rules", "gobanSize", "pairing") }.map { Pair(it.key, it.value) }.toTypedArray())
|
||||
val expected = aTournament.entries.filter { it.key != "pairing" }.map { Pair(it.key, it.value) }.toMap().toJsonObject()
|
||||
val expected = aTournament.entries.filter { it.key != "pairing" }.map { Pair(it.key, it.value) }.toMap().toMutableJsonObject().also { map ->
|
||||
map["stats"] = Json.Array(
|
||||
Json.Object("participants" to 0, "paired" to 0, "games" to 0, "ready" to 0),
|
||||
Json.Object("participants" to 0, "paired" to 0, "games" to 0, "ready" to 0)
|
||||
)
|
||||
map["teamSize"] = 1
|
||||
}
|
||||
assertEquals(expected.toString(), cmp.toString(), "tournament differs")
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user