Reorder teams for 5-teams pools

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2023-03-25 07:54:53 +01:00
parent 3cd40ee192
commit 942c96dbfa
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
4 changed files with 244 additions and 182 deletions

View File

@ -1,6 +1,6 @@
# Copyright (C) 2023 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later
from collections import OrderedDict
from random import randint
from asgiref.sync import sync_to_async
@ -436,6 +436,37 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
{'type': 'draw.box_visibility', 'visible': True})
else:
# Pool is ended
if pool.size == 5:
# Maybe reorder teams if the same problem is presented twice
problems = OrderedDict()
async for td in pool.team_draws:
problems.setdefault(td.accepted, [])
problems[td.accepted].append(td)
p_index = 0
for pb, tds in problems.items():
if len(tds) == 2:
tds[0].passage_index = p_index
tds[1].passage_index = p_index + 1
p_index += 2
await sync_to_async(tds[0].save)()
await sync_to_async(tds[1].save)()
for pb, tds in problems.items():
if len(tds) == 1:
tds[0].passage_index = p_index
p_index += 1
await sync_to_async(tds[0].save)()
print(p_index)
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", {
'type': 'draw.reorder_pool',
'round': r.number,
'pool': pool.get_letter_display(),
'teams': [td.participation.team.trigram
async for td in pool.team_draws.prefetch_related('participation__team')],
'problems': [td.accepted async for td in pool.team_draws],
})
msg += f"<br><br>Le tirage de la poule {pool.get_letter_display()}{r.number} est terminé. " \
f"Le tableau récapitulatif est en bas."
self.tournament.draw.last_message = msg
@ -451,7 +482,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
else:
# Round is ended
# TODO: For the final tournament, add some adjustments
# TODO: Make some adjustments for 5-teams-pools
if r.number == 1:
# Next round
r2 = await self.tournament.draw.round_set.filter(number=2).aget()
@ -583,3 +613,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async def draw_reject_problem(self, content):
await self.send_json({'type': 'reject_problem', 'round': content['round'],
'team': content['team'], 'rejected': content['rejected']})
async def draw_reorder_pool(self, content):
await self.send_json({'type': 'reorder_poule', 'round': content['round'],
'poule': content['pool'], 'teams': content['teams'],
'problems': content['problems']})

View File

@ -238,7 +238,7 @@ document.addEventListener('DOMContentLoaded', () => {
tablesRoundDiv = document.createElement('div')
tablesRoundDiv.id = `tables-${tournament.id}-round-${round}`
tablesRoundDiv.classList.add('card-body')
tablesRoundDiv.classList.add('card-body', 'd-flex', 'flex-wrap')
card.append(tablesRoundDiv)
}
@ -246,148 +246,153 @@ document.addEventListener('DOMContentLoaded', () => {
if (poule.teams.length === 0)
continue
let pouleTable = document.getElementById(`table-${tournament.id}-${round}-${poule.letter}`)
if (pouleTable === null) {
// Create table
let card = document.createElement('div')
card.classList.add('card', 'my-3')
tablesRoundDiv.append(card)
updatePouleTable(round, poule)
}
}
}
let cardHeader = document.createElement('div')
cardHeader.classList.add('card-header')
cardHeader.innerHTML = `<h2>Poule ${poule.letter}</h2>`
card.append(cardHeader)
function updatePouleTable(round, poule) {
let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`)
let pouleTable = document.getElementById(`table-${tournament.id}-${round}-${poule.letter}`)
if (pouleTable === null) {
// Create table
let card = document.createElement('div')
card.classList.add('card', 'w-100', 'my-3', `order-${poule.letter.charCodeAt(0) - 64}`)
tablesRoundDiv.append(card)
let cardBody = document.createElement('div')
cardBody.classList.add('card-body')
card.append(cardBody)
let cardHeader = document.createElement('div')
cardHeader.classList.add('card-header')
cardHeader.innerHTML = `<h2>Poule ${poule.letter}${round}</h2>`
card.append(cardHeader)
pouleTable = document.createElement('table')
pouleTable.id = `table-${tournament.id}-${round}-${poule.letter}`
pouleTable.classList.add('table', 'table-stripped')
cardBody.append(pouleTable)
let cardBody = document.createElement('div')
cardBody.classList.add('card-body')
card.append(cardBody)
let thead = document.createElement('thead')
pouleTable.append(thead)
pouleTable = document.createElement('table')
pouleTable.id = `table-${tournament.id}-${round}-${poule.letter}`
pouleTable.classList.add('table', 'table-stripped')
cardBody.append(pouleTable)
let phaseTr = document.createElement('tr')
thead.append(phaseTr)
let thead = document.createElement('thead')
pouleTable.append(thead)
let teamTh = document.createElement('th')
teamTh.classList.add('text-center')
teamTh.rowSpan = poule.teams.length === 5 ? 3 : 2
teamTh.textContent = "Équipe"
phaseTr.append(teamTh)
let phaseTr = document.createElement('tr')
thead.append(phaseTr)
for (let i = 1; i <= (poule.teams.length === 4 ? 4 : 3); ++i) {
let phaseTh = document.createElement('th')
phaseTh.classList.add('text-center')
if (poule.teams.length === 5 && i < 3)
phaseTh.colSpan = 2
phaseTh.textContent = `Phase ${i}`
phaseTr.append(phaseTh)
let teamTh = document.createElement('th')
teamTh.classList.add('text-center')
teamTh.rowSpan = poule.teams.length === 5 ? 3 : 2
teamTh.textContent = "Équipe"
phaseTr.append(teamTh)
for (let i = 1; i <= (poule.teams.length === 4 ? 4 : 3); ++i) {
let phaseTh = document.createElement('th')
phaseTh.classList.add('text-center')
if (poule.teams.length === 5 && i < 3)
phaseTh.colSpan = 2
phaseTh.textContent = `Phase ${i}`
phaseTr.append(phaseTh)
}
if (poule.teams.length === 5) {
let roomTr = document.createElement('tr')
thead.append(roomTr)
for (let i = 0; i < 5; ++i) {
let roomTh = document.createElement('th')
roomTh.classList.add('text-center')
roomTh.textContent = `Salle ${1 + (i % 2)}`
roomTr.append(roomTh)
}
}
let problemTr = document.createElement('tr')
thead.append(problemTr)
for (let team of poule.teams) {
let problemTh = document.createElement('th')
problemTh.classList.add('text-center')
problemTh.innerHTML = `Pb. <span id="table-${tournament.id}-round-${round}-problem-${team}">?</span>`
problemTr.append(problemTh)
}
let tbody = document.createElement('tbody')
pouleTable.append(tbody)
for (let i = 0; i < poule.teams.length; ++i) {
let team = poule.teams[i]
let teamTr = document.createElement('tr')
tbody.append(teamTr)
let teamTd = document.createElement('td')
teamTd.classList.add('text-center')
teamTd.innerText = team
teamTr.append(teamTd)
let defenderTd = document.createElement('td')
defenderTd.classList.add('text-center')
defenderTd.innerText = 'Déf'
let opponentTd = document.createElement('td')
opponentTd.classList.add('text-center')
opponentTd.innerText = 'Opp'
let reporterTd = document.createElement('td')
reporterTd.classList.add('text-center')
reporterTd.innerText = 'Rap'
let emptyTd = document.createElement('td')
let emptyTd2 = document.createElement('td')
if (poule.teams.length === 3) {
switch (i) {
case 0:
teamTr.append(defenderTd, reporterTd, opponentTd)
break
case 1:
teamTr.append(opponentTd, defenderTd, reporterTd)
break
case 2:
teamTr.append(reporterTd, opponentTd, defenderTd)
break
}
if (poule.teams.length === 5) {
let roomTr = document.createElement('tr')
thead.append(roomTr)
for (let i = 0; i < 5; ++i) {
let roomTh = document.createElement('th')
roomTh.classList.add('text-center')
roomTh.textContent = `Salle ${1 + (i % 2)}`
roomTr.append(roomTh)
}
}
else if (poule.teams.length === 4) {
switch (i) {
case 0:
teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
break
case 1:
teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
break
case 2:
teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
break
case 3:
teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
break
}
let problemTr = document.createElement('tr')
thead.append(problemTr)
for (let team of poule.teams) {
let problemTh = document.createElement('th')
problemTh.classList.add('text-center')
problemTh.innerHTML = `Pb. <span id="table-${tournament.id}-round-${round}-problem-${team}">?</span>`
problemTr.append(problemTh)
}
let tbody = document.createElement('tbody')
pouleTable.append(tbody)
for (let i = 0; i < poule.teams.length; ++i) {
let team = poule.teams[i]
let teamTr = document.createElement('tr')
tbody.append(teamTr)
let teamTd = document.createElement('td')
teamTd.classList.add('text-center')
teamTd.innerText = team
teamTr.append(teamTd)
let defenderTd = document.createElement('td')
defenderTd.classList.add('text-center')
defenderTd.innerText = 'Déf'
let opponentTd = document.createElement('td')
opponentTd.classList.add('text-center')
opponentTd.innerText = 'Opp'
let reporterTd = document.createElement('td')
reporterTd.classList.add('text-center')
reporterTd.innerText = 'Rap'
let emptyTd = document.createElement('td')
let emptyTd2 = document.createElement('td')
if (poule.teams.length === 3) {
switch (i) {
case 0:
teamTr.append(defenderTd, reporterTd, opponentTd)
break
case 1:
teamTr.append(opponentTd, defenderTd, reporterTd)
break
case 2:
teamTr.append(reporterTd, opponentTd, defenderTd)
break
}
}
else if (poule.teams.length === 4) {
switch (i) {
case 0:
teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
break
case 1:
teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
break
case 2:
teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
break
case 3:
teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
break
}
}
else if (poule.teams.length === 5) {
switch (i) {
case 0:
teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd2)
break
case 1:
teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd2, opponentTd)
break
case 2:
teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reporterTd)
break
case 3:
teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd2)
break
case 4:
teamTr.append(emptyTd, reporterTd, emptyTd2, opponentTd, defenderTd)
break
}
}
}
else if (poule.teams.length === 5) {
switch (i) {
case 0:
teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd2)
break
case 1:
teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd2, opponentTd)
break
case 2:
teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reporterTd)
break
case 3:
teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd2)
break
case 4:
teamTr.append(emptyTd, reporterTd, emptyTd2, opponentTd, defenderTd)
break
}
}
}
@ -442,6 +447,20 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
function reorderPoule(round, poule, teams, problems) {
let table = document.getElementById(`table-${tournament.id}-${round}-${poule}`)
table.parentElement.parentElement.remove()
updatePouleTable(round, {'letter': poule, 'teams': teams})
for (let i = 0; i < teams.length; ++i) {
let team = teams[i]
let problem = problems[i]
setProblemAccepted(round, team, problem)
}
}
socket.addEventListener('message', e => {
const data = JSON.parse(e.data)
console.log(data)
@ -486,6 +505,9 @@ document.addEventListener('DOMContentLoaded', () => {
case 'reject_problem':
setProblemRejected(data.round, data.team, data.rejected)
break
case 'reorder_poule':
reorderPoule(data.round, data.poule, data.teams, data.problems)
break
}
})

View File

@ -160,10 +160,10 @@
{{ round }}
</h2>
</div>
<div id="tables-{{ tournament.id }}-round-{{ round.number }}" class="card-body">
<div id="tables-{{ tournament.id }}-round-{{ round.number }}" class="card-body d-flex flex-wrap">
{% for pool in round.pool_set.all %}
{% if pool.teamdraw_set.count %}
<div class="card my-3">
<div class="card w-100 my-3 order-{{ pool.letter }}">
<div class="card-header">
<h3>
{% trans "pool"|capfirst %} {{ pool }}

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-24 12:29+0100\n"
"POT-Creation-Date: 2023-03-25 07:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -25,53 +25,54 @@ msgstr "API"
msgid "Draw"
msgstr "Tirage au sort"
#: draw/consumers.py:20
#: draw/consumers.py:21
msgid "You are not an organizer."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
#: draw/consumers.py:81
#: draw/consumers.py:91
msgid "Invalid format"
msgstr "Format invalide"
#: draw/consumers.py:85
#: draw/consumers.py:95
#, python-brace-format
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
msgstr ""
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
#: draw/consumers.py:105
#: draw/consumers.py:121
msgid "Draw started!"
msgstr "Le tirage a commencé !"
#: draw/consumers.py:115
#: draw/consumers.py:131
#, python-brace-format
msgid "The draw for the tournament {tournament} will start."
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
#: draw/consumers.py:121
#: draw/consumers.py:142
#, python-brace-format
msgid "The draw for the tournament {tournament} is aborted."
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
#: draw/consumers.py:141 draw/consumers.py:144
#: draw/consumers.py:176 draw/consumers.py:179
msgid "You've already launched the dice."
msgstr "Vous avez déjà lancé le dé."
#: draw/consumers.py:147
#: draw/consumers.py:182
msgid "It is not your turn."
msgstr "Ce n'est pas votre tour."
#: draw/consumers.py:149
#: draw/consumers.py:184 draw/consumers.py:353 draw/consumers.py:392
#: draw/consumers.py:510
msgid "This is not the time for this."
msgstr "Ce n'est pas le moment pour cela."
#: draw/consumers.py:182 draw/consumers.py:279
#: draw/consumers.py:217 draw/consumers.py:316
#, python-brace-format
msgid "Dices from teams {teams} are identical. Please relaunch your dices."
msgstr ""
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
#: draw/consumers.py:216
#: draw/consumers.py:251
msgid "Two pools are identical. Please relaunch your dices."
msgstr "Deux poules sont identiques. Merci de relancer vos dés."
@ -88,98 +89,98 @@ msgstr "tour actuel"
msgid "last message"
msgstr "dernier message"
#: draw/models.py:102 draw/models.py:110
#: draw/models.py:104 draw/models.py:112
msgid "draw"
msgstr "tirage au sort"
#: draw/models.py:103
#: draw/models.py:105
msgid "draws"
msgstr "tirages au sort"
#: draw/models.py:115
#: draw/models.py:117
msgid "Round 1"
msgstr "Tour 1"
#: draw/models.py:116
#: draw/models.py:118
msgid "Round 2"
msgstr "Tour 2"
#: draw/models.py:118
#: draw/models.py:120
msgid "number"
msgstr "numéro"
#: draw/models.py:127
#: draw/models.py:129
msgid "current pool"
msgstr "poule actuelle"
#: draw/models.py:138 draw/models.py:199 participation/models.py:355
#: draw/models.py:144 draw/models.py:215 participation/models.py:355
msgid "round"
msgstr "tour"
#: draw/models.py:139
#: draw/models.py:145
msgid "rounds"
msgstr "tours"
#: draw/models.py:154
#: draw/models.py:160
msgid "letter"
msgstr "lettre"
#: draw/models.py:158
#: draw/models.py:164
#: participation/templates/participation/tournament_detail.html:15
msgid "size"
msgstr "taille"
#: draw/models.py:167
#: draw/models.py:173
msgid "current team"
msgstr "équipe actuelle"
#: draw/models.py:185 draw/models.py:207
#: draw/models.py:201 draw/models.py:223
#: draw/templates/draw/tournament_content.html:70
#: draw/templates/draw/tournament_content.html:151 participation/models.py:407
#: draw/templates/draw/tournament_content.html:169 participation/models.py:407
#: participation/models.py:415
msgid "pool"
msgstr "poule"
#: draw/models.py:186 participation/models.py:408
#: draw/models.py:202 participation/models.py:408
msgid "pools"
msgstr "poules"
#: draw/models.py:193 participation/models.py:342 participation/models.py:539
#: draw/models.py:209 participation/models.py:342 participation/models.py:539
#: participation/models.py:569 participation/models.py:607
msgid "participation"
msgstr "participation"
#: draw/models.py:214
#: draw/models.py:230
msgid "passage index"
msgstr "numéro de passage"
#: draw/models.py:221
#: draw/models.py:237
msgid "choose index"
msgstr "numéro de choix"
#: draw/models.py:226 draw/models.py:242 participation/models.py:422
#: draw/models.py:242 draw/models.py:258 participation/models.py:422
#: participation/models.py:576
#, python-brace-format
msgid "Problem #{problem}"
msgstr "Problème n°{problem}"
#: draw/models.py:230 draw/models.py:246
#: draw/models.py:246 draw/models.py:262
msgid "accepted problem"
msgstr "problème accepté"
#: draw/models.py:237
#: draw/models.py:253
msgid "last dice"
msgstr "dernier dé"
#: draw/models.py:251
#: draw/models.py:267
msgid "rejected problems"
msgstr "problèmes rejetés"
#: draw/models.py:258
#: draw/models.py:275
msgid "team draw"
msgstr "tirage d'équipe"
#: draw/models.py:259
#: draw/models.py:276
msgid "team draws"
msgstr "tirages d'équipe"
@ -203,28 +204,32 @@ msgstr "Derniers jets de dés"
msgid "Abort"
msgstr "Annuler"
#: draw/templates/draw/tournament_content.html:118
#: draw/templates/draw/tournament_content.html:119
msgid "Launch dice"
msgstr "Lancer le dé"
#: draw/templates/draw/tournament_content.html:125
#: draw/templates/draw/tournament_content.html:132
msgid "Draw a problem"
msgstr "Tirer un problème"
#: draw/templates/draw/tournament_content.html:142
msgid "Accept"
msgstr "Accepter"
#: draw/templates/draw/tournament_content.html:128
#: draw/templates/draw/tournament_content.html:145
msgid "Decline"
msgstr "Refuser"
#: draw/templates/draw/tournament_content.html:158 participation/models.py:125
#: draw/templates/draw/tournament_content.html:176 participation/models.py:125
#: participation/models.py:310 registration/models.py:127
msgid "team"
msgstr "équipe"
#: draw/templates/draw/tournament_content.html:168
#: draw/templates/draw/tournament_content.html:169
#: draw/templates/draw/tournament_content.html:170
#: draw/templates/draw/tournament_content.html:171
#: draw/templates/draw/tournament_content.html:172
#: draw/templates/draw/tournament_content.html:186
#: draw/templates/draw/tournament_content.html:187
#: draw/templates/draw/tournament_content.html:188
#: draw/templates/draw/tournament_content.html:189
#: draw/templates/draw/tournament_content.html:190
msgid "Room"
msgstr "Salle"