Table numbers exclusion is functional

This commit is contained in:
Claude Brisson
2024-07-27 16:34:35 +02:00
parent 6e97c91b2f
commit 471b316dce
4 changed files with 44 additions and 2 deletions

View File

@@ -3,6 +3,7 @@ package org.jeudego.pairgoth.api
import com.republicate.kson.Json
import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.api.TournamentHandler.dispatchEvent
import org.jeudego.pairgoth.model.Game
import org.jeudego.pairgoth.model.getID
import org.jeudego.pairgoth.model.toID
@@ -38,6 +39,7 @@ object PairingHandler: PairgothApiHandler {
if (round > tournament.lastRound() + 1) badRequest("invalid round: previous round has not been played")
val payload = getArrayPayload(request)
if (payload.isEmpty()) badRequest("nobody to pair")
// CB TODO - change convention to empty array for all players
val allPlayers = payload.size == 1 && payload[0] == "all"
//if (!allPlayers && tournament.pairing.type == PairingType.SWISS) badRequest("Swiss pairing requires all pairable players")
val playing = (tournament.games(round).values).flatMap {
@@ -57,6 +59,10 @@ object PairingHandler: PairgothApiHandler {
} ?: badRequest("invalid pairable id: #$id")
}
val games = tournament.pair(round, pairables)
// always renumber table to take table exclusion into account
tournament.renumberTables(round)
val ret = games.map { it.toJson() }.toJsonArray()
tournament.dispatchEvent(GamesAdded, request, Json.Object("round" to round, "games" to ret))
return ret
@@ -122,6 +128,14 @@ object PairingHandler: PairgothApiHandler {
return Json.Object("success" to true)
} else {
// without id, it's a table renumbering
if (payload.containsKey("excludeTables")) {
val tablesExclusion = payload.getString("excludeTables") ?: badRequest("missing 'excludeTables'")
TournamentHandler.validateTablesExclusion(tablesExclusion)
while (tournament.tablesExclusion.size < round) tournament.tablesExclusion.add("")
tournament.tablesExclusion[round - 1] = tablesExclusion
tournament.dispatchEvent(TournamentUpdated, request, tournament.toJson())
}
val sortedPairables = tournament.getSortedPairables(round)
val sortedMap = sortedPairables.associateBy {
it.getID()!!

View File

@@ -91,7 +91,7 @@ object TournamentHandler: PairgothApiHandler {
return Json.Object("success" to true)
}
private fun validateTablesExclusion(exclusion: String) {
internal fun validateTablesExclusion(exclusion: String) {
if (!tablesExclusionValidator.matches(exclusion)) badRequest("invalid tables exclusion pattern")
}

View File

@@ -6,10 +6,12 @@ import com.republicate.kson.toJsonArray
//import kotlinx.datetime.LocalDate
import java.time.LocalDate
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.api.ApiHandler.Companion.logger
import org.jeudego.pairgoth.store.nextPlayerId
import org.jeudego.pairgoth.store.nextTournamentId
import kotlin.math.max
import java.util.*
import java.util.regex.Pattern
import kotlin.math.roundToInt
sealed class Tournament <P: Pairable>(
@@ -127,9 +129,12 @@ sealed class Tournament <P: Pairable>(
fun renumberTables(round: Int, pivot: Game? = null, orderBY: (Game) -> Int = ::defaultGameOrderBy): Boolean {
var changed = false
var nextTable = 1
val excluded = excludedTables(round)
games(round).values.filter{ game -> pivot?.let { pivot.id != game.id } ?: true }.sortedBy(orderBY).forEach { game ->
while (excluded.contains(nextTable)) ++nextTable
if (pivot != null && nextTable == pivot.table) {
++nextTable
while (excluded.contains(nextTable)) ++nextTable
}
if (game.table != 0) {
changed = changed || game.table != nextTable
@@ -150,6 +155,22 @@ sealed class Tournament <P: Pairable>(
"ready" to (games.getOrNull(index)?.values?.count { it.result != Game.Result.UNKNOWN } ?: 0)
)
}.toJsonArray()
fun excludedTables(round: Int): Set<Int> {
if (round > tablesExclusion.size) return emptySet()
val excluded = mutableSetOf<Int>()
val parser = Regex("(\\d+)(?:-(\\d+))?")
parser.findAll(tablesExclusion[round - 1]).forEach { match ->
val left = match.groupValues[1].toInt()
val right = match.groupValues[2].let { if (it.isEmpty()) left else it.toInt() }
var t = left
do {
excluded.add(t)
++t
} while (t <= right)
}
return excluded
}
}
// standard tournament of individuals

View File

@@ -38,7 +38,14 @@ function unpair(games) {
}
function renumberTables() {
api.putJson(`tour/${tour_id}/pair/${activeRound}`, {})
let payload = {}
let tablesExclusionControl = $('#exclude-tables');
let value = tablesExclusionControl[0].value;
let origValue = tablesExclusionControl.data('orig');
if (value !== origValue) {
payload['excludeTables'] = value;
}
api.putJson(`tour/${tour_id}/pair/${activeRound}`, payload)
.then(rst => {
if (rst !== 'error') {
document.location.reload();