fix bracket

shop
Razmig Sarkissian 8 months ago
parent 95c83163a2
commit 7aa0fb7591
  1. 4
      tournaments/models/match.py
  2. 72
      tournaments/models/round.py
  3. 38
      tournaments/models/tournament.py
  4. 33
      tournaments/templates/tournaments/tournament_bracket.html
  5. 153
      tournaments/views.py

@ -206,10 +206,14 @@ class Match(models.Model):
teams.append(team)
if previous_top_match:
names = [f"Gagnant {previous_top_match.computed_name()}"]
if previous_top_match.disabled:
names = ["Perdant tableau principal"]
team = self.default_live_team(names)
teams.append(team)
if previous_bottom_match:
names = [f"Gagnant {previous_bottom_match.computed_name()}"]
if previous_bottom_match.disabled:
names = ["Perdant tableau principal"]
team = self.default_live_team(names)
teams.append(team)
elif self.round and self.round.parent is None:

@ -23,10 +23,12 @@ class Round(models.Model):
# return f"{self.tournament.display_name()} - {self.name()}"
def name(self):
if self.parent:
return "Matchs de classement"
if self.parent and self.parent.parent is None:
return f"Classement {self.parent.name()}"
elif self.parent and self.parent.parent is not None:
return f"{self.parent.name()}"
elif self.group_stage_loser_bracket is True:
return "Matchs de classement de poule"
return "Classement de poule"
else:
if self.index == 0:
return "Finale"
@ -92,3 +94,67 @@ class Round(models.Model):
return False
return True
def prepare_match_group(self, next_round, parent_round, loser_final, double_butterfly_mode):
matches = self.match_set.filter(disabled=False).order_by('index')
if len(matches) == 0:
return None
if next_round:
next_round_matches = next_round.match_set.filter(disabled=False).order_by('index')
else:
next_round_matches = []
if len(matches) < len(next_round_matches):
all_matches = self.match_set.order_by('index')
filtered_matches = []
# Process matches in pairs
i = 0
while i < len(all_matches):
# Get the current match and its pair (if available)
current_match = all_matches[i]
pair_match = all_matches[i+1] if i+1 < len(all_matches) else None
# Only filter out the pair if both matches are disabled
if current_match.disabled and pair_match and pair_match.disabled:
# Skip one of the matches in the pair
filtered_matches.append(current_match)
pass
else:
# Keep the current match
if current_match.disabled == False:
filtered_matches.append(current_match)
# If there's a pair match, keep it too
if pair_match and pair_match.disabled == False:
filtered_matches.append(pair_match)
# Move to the next pair
i += 2
# Replace the matches list with our filtered list
matches = filtered_matches
if matches:
if len(matches) > 1 and double_butterfly_mode:
midpoint = int(len(matches) / 2)
first_half_matches = matches[:midpoint]
else:
first_half_matches = list(matches) # Convert QuerySet to a list
if self.index == 0 and loser_final:
loser_match = loser_final.match_set.first()
if loser_match:
first_half_matches.append(loser_match)
if first_half_matches:
name = self.name()
if parent_round and first_half_matches[0].name is not None:
name = first_half_matches[0].name
match_group = self.tournament.create_match_group(
name=name,
matches=first_half_matches,
round_id=self.id
)
return match_group
return None

@ -1328,6 +1328,44 @@ class Tournament(models.Model):
return ordered_matches
def get_butterfly_bracket_match_group(self, parent_round=None, double_butterfly_mode=False, display_loser_final=False):
loser_final = None
main_rounds_reversed = []
# Get main bracket rounds (excluding children/ranking matches)
main_rounds = self.round_set.filter(
parent=parent_round,
group_stage_loser_bracket=False
).order_by('-index')
count = main_rounds.count()
if display_loser_final and count > 1:
semi = main_rounds[count - 2]
loser_final = self.round_set.filter(
parent=semi,
group_stage_loser_bracket=False
).order_by('index').first()
# Create serializable match groups data
serializable_match_groups = []
# Add first half of each round (from last to semi-finals)
for round in main_rounds:
next_round = main_rounds.filter(index=round.index - 1).first()
match_group = round.prepare_match_group(next_round, parent_round, loser_final, double_butterfly_mode)
if match_group:
serializable_match_groups.append(match_group)
if double_butterfly_mode:
main_rounds_reversed = list(main_rounds)
main_rounds_reversed.reverse()
for round in main_rounds_reversed:
next_round = main_rounds.filter(index=round.index - 1).first()
match_group = round.prepare_match_group(next_round, parent_round, None, double_butterfly_mode)
if match_group:
serializable_match_groups.append(match_group)
return serializable_match_groups
class MatchGroup:
def __init__(self, name, matches, formatted_schedule, round_id=None):

@ -20,6 +20,7 @@
data-disabled="{{ match.disabled|lower }}"
data-match-group-name="{{ match_group.name }}"
data-match-format="{{ match.format }}"
data-match-title="{{ match.title }}"
data-round-id="{{ match_group.round_id }}"
class="match-template">
{% include 'tournaments/bracket_match_cell.html' %}
@ -89,7 +90,7 @@ function renderBracket() {
let nameSpan = document.createElement('div');
nameSpan.className = 'round-name';
nameSpan.textContent = matchGroupName;
if (roundIndex == finalRoundIndex) {
if (roundIndex == finalRoundIndex || roundIndex == finalRoundIndex - 1 && displayLoserFinal ||roundIndex == finalRoundIndex + 1 && displayLoserFinal) {
} else {
nameSpan = document.createElement('a');
nameSpan.className = 'round-name btn small-button';
@ -124,6 +125,7 @@ function renderBracket() {
matchPositions[roundIndex] = [];
matchDisabled[roundIndex] = []; // Initialize array for this round
roundMatches.forEach((matchTemplate, matchIndex) => {
const matchTitle = matchTemplate.dataset.matchTitle;
const matchDiv = document.createElement('div');
matchDiv.className = 'butterfly-match';
@ -146,7 +148,7 @@ function renderBracket() {
if (roundCount > 1) {
const nextMatchesCount = rounds[roundIndex + 1].length;
if (currentMatchesCount == nextMatchesCount) {
if (currentMatchesCount == nextMatchesCount && roundCount > 2) {
nextMatchDistance = 0;
}
} else {
@ -186,12 +188,19 @@ function renderBracket() {
const parentPos2 = matchPositions[roundIndex - 1][parentIndex2];
top = (parentPos1 + parentPos2) / 2;
nextMatchDistance = 0;
if (displayLoserFinal == true) {
if (matchIndex == 1) {
top = matchPositions[roundIndex][0] + baseDistance + 80;
isIncomingLineIsDisabled = true;
}
}
}
} else if (roundIndex < finalRoundIndex) {
const previousMatchesCount = rounds[roundIndex - 1].length;
const nextMatchesCount = rounds[roundIndex + 1].length;
if (currentMatchesCount == nextMatchesCount) {
if (currentMatchesCount == nextMatchesCount && displayLoserFinal == false) {
nextMatchDistance = 0;
} else if (matchPositions.length > roundIndex - 1) {
nextMatchDistance = (matchPositions[roundIndex - 1][1] - matchPositions[roundIndex - 1][0]);
@ -273,12 +282,28 @@ function renderBracket() {
matchesContainer.appendChild(titleDiv);
}
if (roundIndex == finalRoundIndex && matchIndex === 1 && displayLoserFinal == true && doubleButterflyMode == false) {
let nameSpan = document.createElement('div');
nameSpan.className = 'round-name';
nameSpan.textContent = matchTitle;
const formatSpan = document.createElement('div');
formatSpan.className = 'round-format';
formatSpan.textContent = matchFormat;
const titleDiv = document.createElement('div');
titleDiv.className = 'round-title';
titleDiv.appendChild(nameSpan);
titleDiv.appendChild(formatSpan);
titleDiv.style.top = `${top - 80}px`; // Adjust the 60px offset as needed
titleDiv.style.position = 'absolute';
matchesContainer.appendChild(titleDiv);
}
matchDiv.innerHTML = `
<div class="incoming-line ${isIncomingLineIsDisabled ? 'disabled' : ''}"></div>
<div class="match-content ${isDisabled ? 'disabled' : ''}">${matchTemplate.innerHTML}</div>
`;
if (roundIndex == finalRoundIndex - 1 && displayLoserFinal == true) {
if (roundIndex == finalRoundIndex - 1 && displayLoserFinal == true && doubleButterflyMode == true) {
const matchDiv2 = document.createElement('div');
matchDiv2.className = 'butterfly-match';
matchDiv2.classList.add('inward');

@ -960,7 +960,7 @@ def tournament_bracket(request, tournament_id):
View to display tournament bracket structure.
"""
tournament = get_object_or_404(Tournament, pk=tournament_id)
context = get_bracket(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=False)
context = get_butterfly_bracket_view_context(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=True)
return render(request, 'tournaments/tournament_bracket.html', context)
def round_bracket(request, tournament_id, round_id):
@ -969,158 +969,15 @@ def round_bracket(request, tournament_id, round_id):
"""
tournament = get_object_or_404(Tournament, pk=tournament_id)
round = get_object_or_404(Round, pk=round_id)
context = get_bracket(tournament, round, double_butterfly_mode=False, display_loser_final=False)
context = get_butterfly_bracket_view_context(tournament, round, double_butterfly_mode=False, display_loser_final=False)
return render(request, 'tournaments/tournament_bracket.html', context)
def get_bracket(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=False):
loser_final = None
main_rounds_reversed = []
def get_butterfly_bracket_view_context(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=False):
if parent_round:
double_butterfly_mode = False
display_loser_final = False
# Get main bracket rounds (excluding children/ranking matches)
main_rounds = tournament.round_set.filter(
parent=parent_round,
group_stage_loser_bracket=False
).order_by('-index')
if double_butterfly_mode:
main_rounds_reversed = tournament.round_set.filter(
parent=parent_round,
group_stage_loser_bracket=False
).order_by('index')
if display_loser_final:
if len(main_rounds_reversed) >= 1:
semi = main_rounds_reversed[1]
loser_round = tournament.round_set.filter(
parent=semi,
group_stage_loser_bracket=False
).order_by('index')
if len(loser_round) >= 1:
loser_final = loser_round[0]
# Create serializable match groups data
serializable_match_groups = []
# Add first half of each round (from last to semi-finals)
for round in main_rounds:
matches = round.match_set.filter(disabled=False).order_by('index')
next_round = main_rounds.filter(index=round.index - 1).first()
if next_round:
next_round_matches = next_round.match_set.filter(disabled=False).order_by('index')
else:
next_round_matches = []
if len(matches) < len(next_round_matches):
all_matches = round.match_set.order_by('index')
filtered_matches = []
# Process matches in pairs
i = 0
while i < len(all_matches):
# Get the current match and its pair (if available)
current_match = all_matches[i]
pair_match = all_matches[i+1] if i+1 < len(all_matches) else None
# Only filter out the pair if both matches are disabled
if current_match.disabled and pair_match and pair_match.disabled:
# Skip one of the matches in the pair
filtered_matches.append(current_match)
pass
else:
# Keep the current match
if current_match.disabled == False:
filtered_matches.append(current_match)
# If there's a pair match, keep it too
if pair_match and pair_match.disabled == False:
filtered_matches.append(pair_match)
# Move to the next pair
i += 2
# Replace the matches list with our filtered list
matches = filtered_matches
if matches:
if len(matches) > 1 and double_butterfly_mode:
midpoint = int(len(matches) / 2)
first_half_matches = matches[:midpoint]
else:
first_half_matches = list(matches) # Convert QuerySet to a list
if loser_final:
loser_matches = loser_final.match_set.all()
if len(loser_matches) >= 1:
first_half_matches.append(loser_matches[0])
display_loser_final = True
if first_half_matches:
name = round.name()
if parent_round:
name = first_half_matches[0].computed_name()
match_group = tournament.create_match_group(
name=name,
matches=first_half_matches,
round_id=round.id
)
serializable_match_groups.append(match_group)
if double_butterfly_mode:
for round in main_rounds_reversed:
matches = round.match_set.filter(disabled=False).order_by('index')
next_round = main_rounds_reversed.filter(index=round.index - 1).first()
if next_round:
next_round_matches = next_round.match_set.filter(disabled=False).order_by('index')
else:
next_round_matches = []
if len(matches) < len(next_round_matches):
all_matches = round.match_set.order_by('index')
filtered_matches = []
# Process matches in pairs
i = 0
while i < len(all_matches):
# Get the current match and its pair (if available)
current_match = all_matches[i]
pair_match = all_matches[i+1] if i+1 < len(all_matches) else None
# Only filter out the pair if both matches are disabled
if current_match.disabled and pair_match and pair_match.disabled:
# Skip one of the matches in the pair
filtered_matches.append(current_match)
pass
else:
# Keep the current match
if current_match.disabled == False:
filtered_matches.append(current_match)
# If there's a pair match, keep it too
if pair_match and pair_match.disabled == False:
filtered_matches.append(pair_match)
# Move to the next pair
i += 2
# Replace the matches list with our filtered list
matches = filtered_matches
if matches:
if len(matches) > 1:
midpoint = int(len(matches) / 2)
first_half_matches = matches[midpoint:]
name = round.name()
if parent_round:
name = first_half_matches[0].computed_name()
match_group = tournament.create_match_group(
name=name,
matches=first_half_matches,
round_id=round.id
)
serializable_match_groups.append(match_group)
serializable_match_groups = tournament.get_butterfly_bracket_match_group(parent_round, double_butterfly_mode, display_loser_final)
context = {
'tournament': tournament,

Loading…
Cancel
Save