diff --git a/TSH.exe b/TSH.exe index bde10700a..4bae7b215 100644 Binary files a/TSH.exe and b/TSH.exe differ diff --git a/layout/bracket_ultimate/index.js b/layout/bracket_ultimate/index.js index c72723754..12dd580a4 100644 --- a/layout/bracket_ultimate/index.js +++ b/layout/bracket_ultimate/index.js @@ -1335,7 +1335,7 @@ LoadEverything().then(() => { Object.entries(bracket).filter(([round]) => parseInt(round) < 0) ); - if (Object.keys(losersRounds).length % 2 == 0 && !allWinners) { + if (Object.keys(losersRounds).length % 2 == 0) { Object.values(bracket["-1"].sets).forEach((set, index) => { appearRounds.push([-1, index, 0]); appearRounds.push([-1, index, 1]); diff --git a/src/TSHBracket.py b/src/TSHBracket.py index 5961befe7..b742b122a 100644 --- a/src/TSHBracket.py +++ b/src/TSHBracket.py @@ -2,6 +2,7 @@ from .Helpers.TSHLocaleHelper import TSHLocaleHelper from loguru import logger + class BracketSet(): BYE = -1 PENDING = -2 @@ -20,32 +21,40 @@ def __init__(self, bracket: "Bracket", pos) -> None: # Bracket always has a power of 2 number of players # if there are less than that, we round up and add # 'bye's as the lower seeded players + + def next_power_of_2(x): return 1 if x == 0 else 2**math.ceil(math.log2(x)) # Seeding order logic + + def seeding(numPlayers): rounds = math.log(numPlayers)/math.log(2)-1 - pls = [1,2] + pls = [1, 2] for i in range(int(rounds)): pls = nextLayer(pls) return pls # Checks if a number is power of 2 + + def is_power_of_two(n): return (n != 0) and (n & (n-1) == 0) + def nextLayer(pls): out = [] length = len(pls)*2+1 - + for d in pls: out.append(d) out.append(length-d) return out + class Bracket(): - def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgressions=False, customSeeding=False) -> None: + def __init__(self, playerNumber, progressionsIn, seedMap=None, byeIds=[], winnersOnlyProgressions=False, customSeeding=False) -> None: self.originalPlayerNumber = playerNumber self.playerNumber = next_power_of_2(playerNumber) @@ -58,13 +67,16 @@ def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgre seeds = seedMap else: seeds = seeding(self.playerNumber) - + self.seedMap = seeds + # List for byes in the middle of a custom seed + self.byeIds = byeIds + self.winnersOnlyProgressions = winnersOnlyProgressions self.customSeeding = customSeeding - + if progressionsIn > 0 and -1 in self.seedMap: self.winnersOnlyProgressions = True @@ -82,34 +94,37 @@ def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgre _set.playerIds[0] = seeds[i] _set.playerIds[1] = seeds[i+1] self.rounds["1"].append(_set) - + # Create losers self.rounds["-1"] = [] self.rounds["-2"] = [] for i in range(int(self.playerNumber/2)): - self.rounds["-1"].append(BracketSet(self, [-1, int(len(self.rounds["-1"])/2)])) - self.rounds["-2"].append(BracketSet(self, [-1, int(len(self.rounds["-2"])/2)])) - + self.rounds["-1"].append(BracketSet(self, + [-1, int(len(self.rounds["-1"])/2)])) + self.rounds["-2"].append(BracketSet(self, + [-1, int(len(self.rounds["-2"])/2)])) + # Fill with -1 for round in ["-1", "-2"]: for _set in self.rounds[round]: _set.score = [-1, -1] _set.finished = True - + # Expand winners subBracket = [] i = self.playerNumber/2 while i > 1: i = math.floor(i/2) - round = [BracketSet(self, [2+len(subBracket), i]) for i in range(int(i))] + round = [BracketSet(self, [2+len(subBracket), i]) + for i in range(int(i))] subBracket.append(round) subBracket.append([BracketSet(self, [2+len(subBracket), 0])]) subBracket.append([BracketSet(self, [2+len(subBracket), 0])]) for r, round in enumerate(subBracket): self.rounds[str(2+r)] = round - + # Expand losers subBracket = [] i = self.playerNumber/2 @@ -117,7 +132,8 @@ def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgre while i > 1: i = math.floor(i/2) for j in range(2): - round = [BracketSet(self, [-1-len(subBracket), i]) for i in range(math.floor(i))] + round = [BracketSet(self, [-1-len(subBracket), i]) + for i in range(math.floor(i))] subBracket.append(round) for r, round in enumerate(subBracket): @@ -130,43 +146,53 @@ def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgre if roundNum > 0: for j, _set in enumerate(round): try: - _set.winNext = self.rounds[str(roundNum+1)][math.floor(j/2)] - targetIdW = j%2 - if int(k) < 0 and abs(int(k))%2 == 1: targetIdW = 1 + _set.winNext = self.rounds[str( + roundNum+1)][math.floor(j/2)] + targetIdW = j % 2 + if int(k) < 0 and abs(int(k)) % 2 == 1: + targetIdW = 1 _set.winNextSlot = targetIdW except Exception as e: logger.error(e) try: - if abs(roundNum)%4 == 0: - _set.loseNext = self.rounds[str(-int(2*(roundNum)))][(int(len(round)/2)+j)%len(round)] - elif abs(roundNum)%4 == 1: - _set.loseNext = self.rounds[str(-int(2*(roundNum)))][j] - elif abs(roundNum)%4 == 2: - _set.loseNext = self.rounds[str(-int(2*(roundNum)))][(-1-j)%len(round)] - elif abs(roundNum)%4 == 3: - _set.loseNext = self.rounds[str(-int(2*(roundNum)))][(int(len(round)/2)-1-j)%len(round)] - + shift = 0 + + if (abs(roundNum) + shift) % 4 == 0: + _set.loseNext = self.rounds[str(-int(2*(roundNum)))][( + int(len(round)/2)+j) % len(round)] + elif (abs(roundNum) + shift) % 4 == 1: + _set.loseNext = self.rounds[str( + -int(2*(roundNum)))][j] + elif (abs(roundNum) + shift) % 4 == 2: + _set.loseNext = self.rounds[str( + -int(2*(roundNum)))][(-1-j) % len(round)] + elif (abs(roundNum) + shift) % 4 == 3: + _set.loseNext = self.rounds[str(-int(2*(roundNum)))][( + int(len(round)/2)-1-j) % len(round)] + targetIdL = 0 - + if roundNum == 1: targetIdL = j % 2 - + _set.loseNextSlot = targetIdL except Exception as e: logger.error(e) else: for j, _set in enumerate(round): try: - if abs(roundNum)%2 == 0: - _set.winNext = self.rounds[str(roundNum-1)][math.floor(j/2)] + if abs(roundNum) % 2 == 0: + _set.winNext = self.rounds[str( + roundNum-1)][math.floor(j/2)] else: _set.winNext = self.rounds[str(roundNum-1)][j] - targetIdW = j%2 - if int(k) < 0 and abs(int(k))%2 == 1: targetIdW = 1 + targetIdW = j % 2 + if int(k) < 0 and abs(int(k)) % 2 == 1: + targetIdW = 1 _set.winNextSlot = targetIdW except Exception as e: logger.error(e) - + # Connect losers to winners for grand finals lastLosers = min([int(r) for r in self.rounds.keys()]) gfsRound = max([int(r) for r in self.rounds.keys()]) - 1 @@ -175,19 +201,23 @@ def __init__(self, playerNumber, progressionsIn, seedMap=None, winnersOnlyProgre # Connect grand finals to reset gfsResetRound = max([int(r) for r in self.rounds.keys()]) gfsRound = gfsResetRound - 1 - self.rounds[str(gfsRound)][0].winNext = self.rounds[str(gfsResetRound)][0] - self.rounds[str(gfsRound)][0].loseNext = self.rounds[str(gfsResetRound)][0] - + self.rounds[str(gfsRound)][0].winNext = self.rounds[str( + gfsResetRound)][0] + self.rounds[str(gfsRound)][0].loseNext = self.rounds[str( + gfsResetRound)][0] + def IsBye(self, playerId): - if playerId == -1 or playerId > self.originalPlayerNumber: return True + if playerId == -1 or playerId > self.originalPlayerNumber: + return True return False - + def UpdateBracket(self): for roundKey, round in sorted(self.rounds.items(), key=lambda x: (int(x[0]) < 0, abs(int(x[0])))): for j, _set in enumerate(round): - targetIdW = j%2 + targetIdW = j % 2 targetIdL = 0 - if int(roundKey) < 0 and abs(int(roundKey))%2 == 1: targetIdW = 1 + if int(roundKey) < 0 and abs(int(roundKey)) % 2 == 1: + targetIdW = 1 lastLosers = min([int(r) for r in self.rounds.keys()]) if roundKey == str(lastLosers): @@ -197,22 +227,34 @@ def UpdateBracket(self): if roundKey == str(gfsRound): targetIdW = 0 targetIdL = 1 - + # When we have progressions in, force first (hidden) sets to double DQs # If we have a non-power of 2 number of progressions, we do it for 2 rounds if self.progressionsIn > 0 and not self.winnersOnlyProgressions: if int(roundKey) == 1: _set.score = [-1, -1] _set.finished = True - - if int(roundKey) == 2 and not is_power_of_two(self.progressionsIn) and not self.customSeeding: + + if int(roundKey) == 2 and ( + (not is_power_of_two(self.progressionsIn) and not self.customSeeding) or + (self.customSeeding and not math.log2(self.playerNumber) % 2 == 0)): _set.score = [-1, -1] _set.finished = True if _set.winNext: + # One of the players is a forced loss + if _set.playerIds[0] in self.byeIds or _set.playerIds[1] in self.byeIds: + won = 0 + lost = 1 + if _set.playerIds[0] in self.byeIds: + won = 1 + lost = 0 + _set.winNext.playerIds[targetIdW] = _set.playerIds[won] + if _set.loseNext: + _set.loseNext.playerIds[targetIdL] = _set.playerIds[lost] # Both slots are bye OR slot 2 is bye, auto win for p1 - if (self.IsBye(_set.playerIds[0]) and self.IsBye(_set.playerIds[1])) or \ - (not self.IsBye(_set.playerIds[0]) and self.IsBye(_set.playerIds[1])): + elif (self.IsBye(_set.playerIds[0]) and self.IsBye(_set.playerIds[1])) or \ + (not self.IsBye(_set.playerIds[0]) and self.IsBye(_set.playerIds[1])): won = 0 lost = 1 _set.winNext.playerIds[targetIdW] = _set.playerIds[won] @@ -228,7 +270,10 @@ def UpdateBracket(self): # -1,-1 draw; advance higher seed elif _set.score[0] == -1 and _set.score[1] == -1: # Advance higher seed - won = 0 if _set.playerIds[0] < _set.playerIds[1] else 1 + found1 = self.seedMap.index(_set.playerIds[0]) + found2 = self.seedMap.index(_set.playerIds[1]) + + won = 0 if found1 < found2 else 1 lost = 0 if won == 1 else 1 _set.winNext.playerIds[targetIdW] = _set.playerIds[won] if _set.loseNext: @@ -264,7 +309,7 @@ def UpdateBracket(self): # _set.score[1] = 0 # Get round names - def GetRoundName(self, round: str, winnersCutout=[0,0], losersCutout=[0,0]): + def GetRoundName(self, round: str, winnersCutout=[0, 0], losersCutout=[0, 0]): roundNumber = int(round) gfsRound = max([int(r) for r in self.rounds.keys()]) - 1 @@ -288,10 +333,10 @@ def GetRoundName(self, round: str, winnersCutout=[0,0], losersCutout=[0,0]): return TSHLocaleHelper.matchNames.get("losers_semi_final") if roundNumber == lastLosers + 2: return TSHLocaleHelper.matchNames.get("losers_quarter_final") - + if roundNumber > 0: roundNumber -= winnersCutout[0] return TSHLocaleHelper.matchNames.get("winners_round").format(abs(roundNumber)) if roundNumber < 0: roundNumber += losersCutout[0] - return TSHLocaleHelper.matchNames.get("losers_round").format(abs(roundNumber)) \ No newline at end of file + return TSHLocaleHelper.matchNames.get("losers_round").format(abs(roundNumber)) diff --git a/src/TSHBracketView.py b/src/TSHBracketView.py index 20d3261df..872358cf2 100644 --- a/src/TSHBracketView.py +++ b/src/TSHBracketView.py @@ -8,17 +8,19 @@ import traceback from loguru import logger -# Checks if a number is power of 2 + def is_power_of_two(n): + ''' Checks if a number is power of 2 ''' return (n != 0) and (n & (n-1) == 0) + class BracketSetWidget(QWidget): def __init__(self, bracketSet: BracketSet = None, bracketView: "TSHBracketView" = None, *args) -> None: super().__init__(*args) self.setLayout(QVBoxLayout()) self.playerId: list(QLabel) = [] - self.name: list(QLineEdit) = [] + self.name: list(QLabel) = [] self.score: list(QSpinBox) = [] self.bracketSet = bracketSet @@ -27,24 +29,24 @@ def __init__(self, bracketSet: BracketSet = None, bracketView: "TSHBracketView" for i in [0, 1]: hbox = QWidget() hbox.setLayout(QHBoxLayout()) - hbox.layout().setContentsMargins(0,0,0,0) + hbox.layout().setContentsMargins(0, 0, 0, 0) hbox.layout().setSpacing(2) self.layout().addWidget(hbox) hbox.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) - idLabel = QLineEdit() - idLabel.setDisabled(True) + idLabel = QLabel() idLabel.setMinimumWidth(30) idLabel.setMaximumWidth(30) idLabel.setFont(QFont(idLabel.font().family(), 8)) idLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) + idLabel.setFrameShape(QFrame.Shape.StyledPanel) self.playerId.append(idLabel) hbox.layout().addWidget(idLabel) - name = QLineEdit() + name = QLabel() name.setMinimumWidth(120) name.setMaximumWidth(120) - name.setDisabled(True) + name.setFrameShape(QFrame.Shape.StyledPanel) self.name.append(name) hbox.layout().addWidget(name) name.sizePolicy().setRetainSizeWhenHidden(True) @@ -54,24 +56,33 @@ def __init__(self, bracketSet: BracketSet = None, bracketView: "TSHBracketView" self.score.append(score) hbox.layout().addWidget(score) score.setValue(-1) - score.valueChanged.connect(lambda newVal, i=i: self.SetScore(i, newVal)) + score.valueChanged.connect( + lambda newVal, i=i: self.SetScore(i, newVal)) self.finished = QCheckBox("Finished") self.layout().addWidget(self.finished) - self.finished.toggled.connect(lambda newVal: self.SetFinished(newVal)) - + self.finished.toggled.connect(lambda newVal: self.SetFinished(newVal)) + self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.sizePolicy().setRetainSizeWhenHidden(True) self.layout().setSpacing(2) - self.Update() - + if self.bracketSet is not None: + hasBye = \ + ((self.bracketSet.playerIds[0] == -1 and not self.bracketSet.playerIds[1] == -1) or + (self.bracketSet.playerIds[1] == -1 and not self.bracketSet.playerIds[0] == -1)) + + if self.bracketSet.pos[0] < 0 and hasBye: + self.hide() + elif self.bracketSet.pos[0] > 0 and self.bracketSet.pos[0] == 1 and hasBye: + self.hide() + def SetScore(self, id, score, updateDisplay=True): self.bracketSet.score[id] = score if updateDisplay: self.bracketSet.bracket.UpdateBracket() self.bracketView.Update() - + def SetFinished(self, finished, updateDisplay=True): self.bracketSet.finished = finished @@ -88,31 +99,41 @@ def Update(self): self.playerId[0].setText("") if self.playerId[1].text() == "-2": self.playerId[1].setText("") - + self.score[0].blockSignals(True) self.score[1].blockSignals(True) - self.score[0].setValue(min(self.bracketSet.score[0], self.score[0].maximum())) - self.score[1].setValue(min(self.bracketSet.score[1], self.score[1].maximum())) + self.score[0].setValue( + min(self.bracketSet.score[0], self.score[0].maximum())) + self.score[1].setValue( + min(self.bracketSet.score[1], self.score[1].maximum())) self.score[0].blockSignals(False) self.score[1].blockSignals(False) if self.bracketSet.score[0] > self.bracketSet.score[1]: - self.score[0].setStyleSheet("background-color: rgba(0, 255, 0, 50);") - self.score[1].setStyleSheet("background-color: rgba(0, 0, 0, 80);") + self.score[0].setStyleSheet( + "background-color: rgba(0, 255, 0, 50);") + self.score[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") elif self.bracketSet.score[0] < self.bracketSet.score[1]: - self.score[1].setStyleSheet("background-color: rgba(0, 255, 0, 50);") - self.score[0].setStyleSheet("background-color: rgba(0, 0, 0, 80);") + self.score[1].setStyleSheet( + "background-color: rgba(0, 255, 0, 50);") + self.score[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") else: - self.score[0].setStyleSheet("background-color: rgba(0, 0, 0, 80);") - self.score[1].setStyleSheet("background-color: rgba(0, 0, 0, 80);") - + self.score[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") + self.score[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") + try: if (self.bracketSet.playerIds[0]-1) < len(self.bracketView.playerList.slotWidgets) and self.bracketSet.playerIds[0] > 0: - team = StateManager.Get(f"bracket.players.slot.{self.bracketSet.playerIds[0]}", {}) + team = StateManager.Get( + f"bracket.players.slot.{self.bracketSet.playerIds[0]}", {}) if team.get("name"): teamName = team.get("name") else: - teamName = " / ".join([p.get("name", "") for p in team.get("player", {}).values()]) + teamName = " / ".join([p.get("name", "") + for p in team.get("player", {}).values()]) self.name[0].setText(teamName) else: self.name[0].setText("") @@ -121,11 +142,13 @@ def Update(self): try: if (self.bracketSet.playerIds[1]-1) < len(self.bracketView.playerList.slotWidgets) and self.bracketSet.playerIds[1] > 0: - team = StateManager.Get(f"bracket.players.slot.{self.bracketSet.playerIds[1]}", {}) + team = StateManager.Get( + f"bracket.players.slot.{self.bracketSet.playerIds[1]}", {}) if team.get("name"): teamName = team.get("name") else: - teamName = " / ".join([p.get("name", "") for p in team.get("player", {}).values()]) + teamName = " / ".join([p.get("name", "") + for p in team.get("player", {}).values()]) self.name[1].setText(teamName) else: self.name[1].setText("") @@ -136,38 +159,51 @@ def Update(self): self.finished.blockSignals(True) self.finished.setChecked(self.bracketSet.finished) self.finished.blockSignals(False) - + winnersCutout, losersCutout = self.bracketView.GetCutouts() hasBye = \ - ((self.bracketSet.playerIds[0] == -1 and not self.bracketSet.playerIds[1] == -1) or \ - (self.bracketSet.playerIds[1] == -1 and not self.bracketSet.playerIds[0] == -1)) + ((self.bracketSet.playerIds[0] == -1 and not self.bracketSet.playerIds[1] == -1) or + (self.bracketSet.playerIds[1] == -1 and not self.bracketSet.playerIds[0] == -1)) if self.bracketSet.pos[0] < 0 and hasBye: - self.hide() + if self.isVisible(): + self.hide() elif self.bracketSet.pos[0] > 0 and self.bracketSet.pos[0] == 1 and hasBye: - self.hide() + if self.isVisible(): + self.hide() else: - self.show() - + if not self.isVisible(): + self.show() + limitExportNumber, winnersOffset, losersOffset = self.bracketView.GetLimitedExportingBracketOffsets() if self.bracketSet.pos[0] > 0: - if self.bracketSet.pos[0] - winnersOffset <= 0: - self.name[0].setStyleSheet("background-color: rgba(0, 0, 0, 80);") - self.name[1].setStyleSheet("background-color: rgba(0, 0, 0, 80);") + if self.bracketSet.pos[0] - winnersOffset <= 0 or \ + self.bracketSet.pos[0] == winnersCutout[0]+1 and self.bracketView.progressionsIn > 0 and self.bracketSet.score[0] == -1 or self.bracketSet.score[1] == -1: + self.name[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") + self.name[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") else: - self.name[0].setStyleSheet("background-color: rgba(0, 0, 0, 0);") - self.name[1].setStyleSheet("background-color: rgba(0, 0, 0, 0);") + self.name[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 0);") + self.name[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 0);") elif self.bracketSet.pos[0] < 0: if self.bracketSet.pos[0] + losersOffset >= 0: - self.name[0].setStyleSheet("background-color: rgba(0, 0, 0, 80);") - self.name[1].setStyleSheet("background-color: rgba(0, 0, 0, 80);") + self.name[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") + self.name[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 80);") else: - self.name[0].setStyleSheet("background-color: rgba(0, 0, 0, 0);") - self.name[1].setStyleSheet("background-color: rgba(0, 0, 0, 0);") + self.name[0].setStyleSheet( + "background-color: rgba(0, 0, 0, 0);") + self.name[1].setStyleSheet( + "background-color: rgba(0, 0, 0, 0);") + class TSHBracketView(QGraphicsView): - def __init__(self, bracket: Bracket, playerList: TSHPlayerList = None, bracketWidget = None, *args): + def __init__(self, bracket: Bracket, playerList: TSHPlayerList = None, bracketWidget=None, *args): super().__init__(*args) self.bracketWidget = bracketWidget @@ -178,19 +214,19 @@ def __init__(self, bracket: Bracket, playerList: TSHPlayerList = None, bracketWi self._empty = True self._scene = QGraphicsScene(self) self.setScene(self._scene) - + self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - #self.setBackgroundBrush(QBrush(QColor(30, 30, 30))) + # self.setBackgroundBrush(QBrush(QColor(30, 30, 30))) self.setFrameShape(QFrame.NoFrame) self.setDragMode(QGraphicsView.ScrollHandDrag) self.SetBracket(bracket) self.bracketLines = [] - + def GetCutouts(self, forExport=False): winnersRounds = [r for r in self.bracket.rounds.keys() if int(r) > 0] losersRounds = [r for r in self.bracket.rounds.keys() if int(r) < 0] @@ -200,42 +236,58 @@ def GetCutouts(self, forExport=False): # Winners right side cutout if self.progressionsOut > 0: - progressionsWinners = math.pow(2, int(math.log2(self.progressionsOut/2))) - winnersCutout[1] = len(winnersRounds) - (int(math.log2(progressionsWinners)) + 1) - + progressionsWinners = math.pow( + 2, int(math.log2(self.progressionsOut/2))) + winnersCutout[1] = len(winnersRounds) - \ + (int(math.log2(progressionsWinners)) + 1) + # Winners left side cutout - if self.progressionsIn > 0 and not self.bracket.winnersOnlyProgressions: - if not is_power_of_two(self.progressionsIn) and not self.bracket.customSeeding: - winnersCutout[0] = 2 + if self.progressionsIn > 0: + if self.bracket.winnersOnlyProgressions: + exactMatch = (int(math.log2((self.progressionsIn-1)))) + 3 + winnersCutout[0] = len(winnersRounds) - exactMatch else: - winnersCutout[0] = 1 - + exactMatch = 1 + if not is_power_of_two(self.progressionsIn) and not self.bracket.customSeeding: + exactMatch += 1 + elif self.bracket.customSeeding and not math.log2(self.bracket.playerNumber) % 2 == 0: + exactMatch += 1 + winnersCutout[0] = exactMatch + # Losers right side cutout if self.progressionsOut > 0: - progressionsLosers = self.progressionsOut - math.pow(2, int(math.log2(self.progressionsOut/2))) - losersCutout[1] = len(losersRounds) - (math.log2(progressionsLosers) * 2 - 1) - - # Losers left side cutout - losersCutout[0] = 2 + progressionsLosers = self.progressionsOut - \ + math.pow(2, int(math.log2(self.progressionsOut/2))) + losersCutout[1] = len(losersRounds) - \ + (math.log2(progressionsLosers) * 2 - 1) - # Losers R1 skipping - # Losers R1 has bracket_size / 2 (half bracket is sent to losers from WR1) / 2 (2 players per set) sets - # If WR1 has as many sets or less, LR1 will be all [player vs bye] - # So this round is hidden - validWR1Sets = self.bracket.originalPlayerNumber - self.bracket.playerNumber/2 - - if not (self.bracketWidget.limitExport.isChecked() and self.bracketWidget.limitExportNumber.value() > 0): - if self.progressionsIn == 0 and validWR1Sets <= self.bracket.playerNumber/2/2: - losersCutout[0] += 1 + # Losers left side cutout + if self.progressionsIn <= 0 or self.bracket.winnersOnlyProgressions: + exactMatch = int(math.log2(self.bracket.playerNumber)) + \ + int(math.log2((self.bracket.originalPlayerNumber-1)/2)) + losersCutout[0] = len(losersRounds) - exactMatch + else: + exactMatch = int(math.log2(self.bracket.playerNumber)) + \ + round(math.log2(math.floor((self.bracket.progressionsIn - + int(math.log2(self.bracket.originalPlayerNumber-1)))))) - 2 + losersCutout[0] = len(losersRounds) - exactMatch + + # else: + # # Losers R1 skipping + # # Losers R1 has bracket_size / 2 (half bracket is sent to losers from WR1) / 2 (2 players per set) sets + # # If WR1 has as many sets or less, LR1 will be all [player vs bye] + # # So this round is hidden + # validWR1Sets = self.bracket.originalPlayerNumber - self.bracket.playerNumber/2 + + # if self.progressionsIn == 0 and validWR1Sets <= self.bracket.playerNumber/2/2: + # losersCutout[0] += 1 + # elif self.progressionsIn > 0: + # losersCutout[0] += 1 - if self.progressionsIn > 0 and not is_power_of_two(self.progressionsIn): - losersCutout[0] += 1 - if self.progressionsOut > 0 and not is_power_of_two(self.progressionsOut): losersCutout[1] += 1 - - return (winnersCutout, losersCutout) + return (winnersCutout, losersCutout) def SetBracket(self, bracket, progressionsIn=0, progressionsOut=0, winnersOnlyProgressions=False, customSeeding=False): self.bracket = bracket @@ -246,7 +298,7 @@ def SetBracket(self, bracket, progressionsIn=0, progressionsOut=0, winnersOnlyPr bracket.winnersOnlyProgressions = winnersOnlyProgressions else: bracket.winnersOnlyProgressions = True - + bracket.customSeeding = customSeeding self.bracketLines = [] @@ -281,21 +333,25 @@ def SetBracket(self, bracket, progressionsIn=0, progressionsOut=0, winnersOnlyPr for roundNum, round in self.bracket.rounds.items(): currentBracket = self.winnersBracket currentWidgets = self.winnersBracketWidgets - + if int(roundNum) < 0: currentBracket = self.losersBracket currentWidgets = self.losersBracketWidgets - + # Winners cutout if int(roundNum) > 0: - if int(roundNum) <= winnersCutout[0]: continue - if int(roundNum) >= winnersCutout[1]: continue - + if int(roundNum) <= winnersCutout[0]: + continue + if int(roundNum) >= winnersCutout[1]: + continue + # Losers cutout if int(roundNum) < 0: - if abs(int(roundNum)) <= losersCutout[0]: continue - if abs(int(roundNum)) >= losersCutout[1]: continue - + if abs(int(roundNum)) <= losersCutout[0]: + continue + if abs(int(roundNum)) >= losersCutout[1]: + continue + # Outer Round layout (column) layoutOuter = QWidget() currentBracket.layout().addWidget(layoutOuter) @@ -303,7 +359,8 @@ def SetBracket(self, bracket, progressionsIn=0, progressionsOut=0, winnersOnlyPr # Round name roundNameLabel = QLineEdit() - roundNameLabel.setPlaceholderText(self.bracket.GetRoundName(int(roundNum), winnersCutout, losersCutout)) + roundNameLabel.setPlaceholderText(self.bracket.GetRoundName( + int(roundNum), winnersCutout, losersCutout)) layoutOuter.layout().addWidget(roundNameLabel) self.roundNameLabels[roundNum] = roundNameLabel @@ -318,7 +375,7 @@ def SetBracket(self, bracket, progressionsIn=0, progressionsOut=0, winnersOnlyPr roundWidgets.append(wid) self.bracketWidgets.append(roundWidgets) currentWidgets.append(roundWidgets) - + QGuiApplication.processEvents() self.DrawLines() self.fitInView() @@ -337,25 +394,28 @@ def GetLimitedExportingBracketOffsets(self): winnersRounds = math.floor(limitExportNumber/8) + 3 try: - losersRounds = int(math.log2(limitExportNumber)) + int(math.log2((limitExportNumber-1)/2)) + 2 + losersRounds = int(math.log2(limitExportNumber)) + \ + int(math.log2((limitExportNumber-1)/2)) + 2 except: logger.error(traceback.format_exc()) losersRounds = 0 if self.bracketWidget.progressionsIn.value() > 0: StateManager.Set("bracket.bracket.progressionsIn", 0) - losersRounds += 2 - winnersRounds += 1 - - totalWinnersRounds = len([i for i in self.bracket.rounds.keys() if int(i) > 0]) - totalLosersRounds = len([i for i in self.bracket.rounds.keys() if int(i) < 0]) + # losersRounds += 2 + # winnersRounds += 1 + + totalWinnersRounds = len( + [i for i in self.bracket.rounds.keys() if int(i) > 0]) + totalLosersRounds = len( + [i for i in self.bracket.rounds.keys() if int(i) < 0]) if self.bracketWidget.limitExport.isChecked(): winnersOffset = (totalWinnersRounds-winnersRounds) losersOffset = (totalLosersRounds-losersRounds) return (limitExportNumber, winnersOffset, losersOffset) - + def Update(self): self.bracket.UpdateBracket() @@ -366,57 +426,73 @@ def Update(self): setWidget.Update() for w in setWidget.score: w.blockSignals(False) - - QGuiApplication.processEvents() + QGuiApplication.processEvents() self.DrawLines() - + StateManager.BlockSaving() data = {} - StateManager.Set("bracket.bracket.progressionsIn", self.bracket.progressionsIn) - StateManager.Set("bracket.bracket.progressionsOut", self.bracketWidget.progressionsOut.value()) + StateManager.Set("bracket.bracket.progressionsIn", + self.bracket.progressionsIn) + StateManager.Set("bracket.bracket.progressionsOut", + self.bracketWidget.progressionsOut.value()) limitExportNumber, winnersOffset, losersOffset = self.GetLimitedExportingBracketOffsets() winnersCutout, losersCutout = self.GetCutouts(forExport=True) - winnersOffset += winnersCutout[0] - losersOffset += losersCutout[0] + # winnersOffset += winnersCutout[0] + # losersOffset += losersCutout[0] - StateManager.Set("bracket.bracket.limitExportNumber", limitExportNumber) + StateManager.Set("bracket.bracket.limitExportNumber", + limitExportNumber) if limitExportNumber != -1 and limitExportNumber < self.bracket.playerNumber: StateManager.Set("bracket.bracket.winnersOnlyProgressions", False) else: - StateManager.Set("bracket.bracket.winnersOnlyProgressions", self.bracket.winnersOnlyProgressions) + StateManager.Set("bracket.bracket.winnersOnlyProgressions", + self.bracket.winnersOnlyProgressions) for roundKey, round in self.bracket.rounds.items(): # Winners cutout if int(roundKey) > 0: - if int(roundKey) <= winnersCutout[0]: continue - if int(roundKey) >= winnersCutout[1]: continue - + if int(roundKey) <= winnersCutout[0]: + continue + if int(roundKey) >= winnersCutout[1]: + continue + # Losers cutout if int(roundKey) < 0: - if abs(int(roundKey)) <= losersCutout[0]: continue - if abs(int(roundKey)) >= losersCutout[1]: continue - + if abs(int(roundKey)) <= losersCutout[0]: + continue + if abs(int(roundKey)) >= losersCutout[1]: + continue + + # Limited export number cutout + if int(roundKey) > 0: + if int(roundKey) - winnersOffset <= 0: + continue + if int(roundKey) < 0: + if int(roundKey) + losersOffset + 2 >= 0: + continue + # Get round name or placeholder name if self.roundNameLabels.get(roundKey): roundName = self.roundNameLabels.get(roundKey).text() if roundName == "": - roundName = self.roundNameLabels.get(roundKey).placeholderText() + roundName = self.roundNameLabels.get( + roundKey).placeholderText() else: roundName = "" - - # Limited export number cutout + + # Reassign round key if int(roundKey) > 0: - roundKey = str(int(roundKey) - winnersOffset) - if int(roundKey) <= 0: continue - if int(roundKey) < 0: - roundKey = str(int(roundKey) + losersOffset) - if int(roundKey) >= 0: continue + roundKey = str(int(roundKey) - + max(winnersOffset, winnersCutout[0])) + else: + roundKey = str(int(roundKey) + + max(losersOffset + 2, losersCutout[0])) data[roundKey] = { "name": roundName, @@ -432,12 +508,14 @@ def Update(self): # Reassign rounds based on export number if nextWin: if nextWin[0] > 0: - nextWin[0] -= winnersOffset + nextWin[0] -= max(winnersOffset, winnersCutout[0]) else: - nextWin[0] += losersOffset - 2 + nextWin[0] += max(losersOffset + 2, + losersCutout[0]) - 2 if nextLose: if nextLose[0] < 0: - nextLose[0] += losersOffset - 2 + nextLose[0] += max(losersOffset + 2, + losersCutout[0]) - 2 """if self.bracket.progressionsIn <= 0: nextLose[0] -= 1 @@ -446,13 +524,15 @@ def Update(self): # For grand finals into reset, nextLose is a positive round else: nextLose[0] -= winnersOffset - + p1name = "" if bracketSet.playerIds[0] > 0: try: - p1tree: dict = StateManager.Get(f"bracket.players.slot.{bracketSet.playerIds[0]}.player") - p1name = " / ".join([p.get("name") for p in p1tree.values()]) + p1tree: dict = StateManager.Get( + f"bracket.players.slot.{bracketSet.playerIds[0]}.player") + p1name = " / ".join([p.get("name") + for p in p1tree.values()]) except: pass @@ -460,14 +540,29 @@ def Update(self): if bracketSet.playerIds[1] > 0: try: - p2tree: dict = StateManager.Get(f"bracket.players.slot.{bracketSet.playerIds[1]}.player") - p2name = " / ".join([p.get("name") for p in p2tree.values()]) + p2tree: dict = StateManager.Get( + f"bracket.players.slot.{bracketSet.playerIds[1]}.player") + p2name = " / ".join([p.get("name") + for p in p2tree.values()]) except: pass + playerIds = [bracketSet.playerIds[0], bracketSet.playerIds[1]] + score = [bracketSet.score[0], bracketSet.score[1]] + + if bracketSet.score[0] == -1 or bracketSet.score[1] == -1: + if self.progressionsIn > 0 and int(roundKey) == 1 and bracketSet.pos[0] == winnersCutout[0]+1: + if bracketSet.score[0] == -1: + playerIds[0] = -1 + else: + playerIds[1] = -1 + p1name = "" + p2name = "" + score = [-1, -1] + data[roundKey]["sets"][j] = { - "playerId": bracketSet.playerIds, - "score": bracketSet.score, + "playerId": playerIds, + "score": score, "nextWin": nextWin, "winSlot": bracketSet.winNextSlot, "nextLose": nextLose, @@ -480,9 +575,8 @@ def Update(self): } StateManager.Set("bracket.bracket.rounds", data) - StateManager.ReleaseSaving() - + def DrawLines(self): for element in self.bracketLines: self._scene.removeItem(element) @@ -501,7 +595,8 @@ def DrawLines(self): if i < len(self.winnersBracketWidgets)-1: - nxtWidget = self.winnersBracketWidgets[i+1][math.floor(j/2)] + nxtWidget = self.winnersBracketWidgets[i + + 1][math.floor(j/2)] nxt = nxtWidget start = QPointF(setWidget.mapTo(self.bracketLayout, QPoint(0, 0)).x(), _set.mapTo(self.bracketLayout, QPoint(0, 0)).y()) + \ @@ -509,8 +604,10 @@ def DrawLines(self): end = QPointF(nxtWidget.mapTo(self.bracketLayout, QPoint(0, 0)).x(), nxt.mapTo(self.bracketLayout, QPoint(0, 0)).y()) + \ QPointF(0, _set.height()/2) - midpoint1 = QPointF(start.x()+(end.x()-start.x())/2, start.y()) - midpoint2 = QPointF(start.x()+(end.x()-start.x())/2, end.y()) + midpoint1 = QPointF( + start.x()+(end.x()-start.x())/2, start.y()) + midpoint2 = QPointF( + start.x()+(end.x()-start.x())/2, end.y()) path.addPolygon( QPolygonF([ @@ -527,7 +624,7 @@ def DrawLines(self): notch1 = end + QPointF(-10, +10) notch2 = end + QPointF(-10, -10) - + path.addPolygon( QPolygonF([ start, @@ -547,14 +644,14 @@ def DrawLines(self): end = QPointF(setWidget.mapTo(self.bracketLayout, QPoint(0, 0)).x(), _set.mapTo(self.bracketLayout, QPoint(0, 0)).y()) + \ QPointF(0, _set.height()/2) start = end - QPointF(50, 0) - + dashedPath.addPolygon( QPolygonF([ start, end ]) ) - + for i, round in enumerate(self.losersBracketWidgets): for j, setWidget in enumerate(round): try: @@ -565,7 +662,8 @@ def DrawLines(self): if i < len(self.losersBracketWidgets)-1: if len(self.losersBracketWidgets[i+1]) < len(self.losersBracketWidgets[i]): - nxtWidget = self.losersBracketWidgets[i+1][math.floor(j/2)] + nxtWidget = self.losersBracketWidgets[i + + 1][math.floor(j/2)] else: nxtWidget = self.losersBracketWidgets[i+1][j] nxt = nxtWidget @@ -575,8 +673,10 @@ def DrawLines(self): end = QPointF(nxtWidget.mapTo(self.bracketLayout, QPoint(0, 0)).x(), nxt.mapTo(self.bracketLayout, QPoint(0, 0)).y()) + \ QPointF(0, _set.height()/2) - midpoint1 = QPointF(start.x()+(end.x()-start.x())/2, start.y()) - midpoint2 = QPointF(start.x()+(end.x()-start.x())/2, end.y()) + midpoint1 = QPointF( + start.x()+(end.x()-start.x())/2, start.y()) + midpoint2 = QPointF( + start.x()+(end.x()-start.x())/2, end.y()) path.addPolygon( QPolygonF([ @@ -593,7 +693,7 @@ def DrawLines(self): notch1 = end + QPointF(-10, +10) notch2 = end + QPointF(-10, -10) - + path.addPolygon( QPolygonF([ start, @@ -613,7 +713,7 @@ def DrawLines(self): end = QPointF(setWidget.mapTo(self.bracketLayout, QPoint(0, 0)).x(), _set.mapTo(self.bracketLayout, QPoint(0, 0)).y()) + \ QPointF(0, _set.height()/2) start = end - QPointF(50, 0) - + dashedPath.addPolygon( QPolygonF([ start, @@ -622,7 +722,7 @@ def DrawLines(self): ) except: logger.error(traceback.format_exc()) - + pen = QPen(Qt.gray, 4, Qt.SolidLine) pen2 = QPen(Qt.black, 6, Qt.SolidLine) @@ -647,18 +747,18 @@ def fitInView(self): viewrect = self.viewport().rect() scenerect = self.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), - viewrect.height() / scenerect.height()) + viewrect.height() / scenerect.height()) self.scale(factor, factor) self._zoom = 0 def wheelEvent(self, event): if event.angleDelta().y() > 0: - factor = 1.25 + factor = 1.02 self._zoom += 1 else: - factor = 0.8 + factor = 0.98 self._zoom -= 1 - + if self._zoom > 0: self.scale(factor, factor) else: @@ -666,4 +766,4 @@ def wheelEvent(self, event): self._zoom = 0 def mousePressEvent(self, event): - super().mousePressEvent(event) \ No newline at end of file + super().mousePressEvent(event) diff --git a/src/TSHBracketWidget.py b/src/TSHBracketWidget.py index ff97dc713..b55fe7c1b 100644 --- a/src/TSHBracketWidget.py +++ b/src/TSHBracketWidget.py @@ -13,6 +13,7 @@ from .TSHPlayerList import TSHPlayerList from .TSHBracket import * import traceback +import threading from loguru import logger # Checks if a number is power of 2 @@ -35,6 +36,8 @@ def __init__(self, *args): StateManager.Set("bracket", {}) + self.loadLock = threading.RLock() + TSHTournamentDataProvider.instance.signals.tournament_phases_updated.connect( self.UpdatePhases) TSHTournamentDataProvider.instance.signals.tournament_phasegroup_updated.connect( @@ -219,7 +222,8 @@ def UpdatePhaseGroups(self): self.phaseGroupSelection.clear() if self.phaseSelection.currentData() != None: - logger.info(str(self.phaseSelection.currentData().get("groups", []))) + logger.info( + str(self.phaseSelection.currentData().get("groups", []))) for phaseGroup in self.phaseSelection.currentData().get("groups", []): self.phaseGroupSelection.addItem( phaseGroup.get("name"), phaseGroup) @@ -246,9 +250,15 @@ def PhaseGroupChanged(self): TSHTournamentDataProvider.instance.GetTournamentPhaseGroup( self.phaseGroupSelection.currentData().get("id")) - def RebuildBracket(self, playerNumber, seedMap=None, customSeeding=False): - self.bracket = Bracket(playerNumber, self.progressionsIn.value( - ), seedMap, self.winnersOnly.isChecked()) + def RebuildBracket(self, playerNumber, seedMap=None, byeIds=[], customSeeding=False): + self.bracket = Bracket( + playerNumber, + self.progressionsIn.value(), + seedMap, + byeIds, + self.winnersOnly.isChecked(), + customSeeding=customSeeding + ) self.bracketView.SetBracket( self.bracket, @@ -265,29 +275,40 @@ def RebuildBracket(self, playerNumber, seedMap=None, customSeeding=False): _set.finished = False def UpdatePhaseGroup(self, phaseGroupData): - StateManager.BlockSaving() - self.playerList.signals.DataChanged.disconnect() + with self.loadLock: + StateManager.BlockSaving() + self.playerList.signals.DataChanged.disconnect() try: logger.info("Phase Group Data: " + str(phaseGroupData)) if phaseGroupData.get("progressionsIn", {}) != None: + self.progressionsIn.blockSignals(True) self.progressionsIn.setValue( len(phaseGroupData.get("progressionsIn", {}))) + self.progressionsIn.blockSignals(False) else: + self.progressionsIn.blockSignals(True) self.progressionsIn.setValue(0) + self.progressionsIn.blockSignals(False) if phaseGroupData.get("progressionsOut", {}) != None: + self.progressionsOut.blockSignals(True) self.progressionsOut.setValue( len(phaseGroupData.get("progressionsOut", {}))) + self.progressionsIn.blockSignals(False) else: self.progressionsOut.setValue(0) if phaseGroupData.get("winnersOnlyProgressions", False) != None: + self.winnersOnly.blockSignals(True) self.winnersOnly.setChecked( phaseGroupData.get("winnersOnlyProgressions", False)) + self.winnersOnly.blockSignals(False) else: + self.winnersOnly.blockSignals(True) self.winnersOnly.setChecked(False) + self.winnersOnly.blockSignals(False) self.bracket.customSeeding = phaseGroupData.get( "customSeeding", False) @@ -295,7 +316,8 @@ def UpdatePhaseGroup(self, phaseGroupData): # Make sure progressions are exported QGuiApplication.processEvents() - self.playerList.LoadFromStandings(phaseGroupData.get("entrants")) + self.playerList.LoadFromStandings( + phaseGroupData.get("entrants")) # Wait for the player list to update QGuiApplication.processEvents() @@ -311,6 +333,7 @@ def UpdatePhaseGroup(self, phaseGroupData): self.RebuildBracket( len(phaseGroupData.get("entrants")), phaseGroupData.get("seedMap"), + phaseGroupData.get("byeIds", []), phaseGroupData.get("customSeeding", False) ) diff --git a/src/TournamentDataProvider/ChallongeDataProvider.py b/src/TournamentDataProvider/ChallongeDataProvider.py index 60fc3f357..acc0484ff 100644 --- a/src/TournamentDataProvider/ChallongeDataProvider.py +++ b/src/TournamentDataProvider/ChallongeDataProvider.py @@ -63,7 +63,7 @@ def __init__(self, url, threadpool, parent) -> None: i += 1 if i >= max_iter: raise e - #TODO: Find a way to open a warning box and unload tournament if failed + # TODO: Find a way to open a warning box and unload tournament if failed def GetSlug(self): # URL with language @@ -308,6 +308,8 @@ def GetTournamentPhaseGroup(self, id, progress_callback=None): if len(groups) > 0: finalData["progressionsIn"] = [ {}] * deep_get(groups[0], "tournament.participant_count_to_advance", 0) * len(groups) + + finalData["customSeeding"] = True else: if id != None: groupId = int(id.split("_")[-1]) @@ -448,7 +450,7 @@ def GetTournamentPhaseGroup(self, id, progress_callback=None): rounds[int(r)-1] = rounds[r] # If we had progressions in, we have to add a fake R1 to send half players to losers side - if len(finalData.get("progressionsIn", [])) > 0: + if len(finalData.get("progressionsIn", [])) > 0 and not finalData.get("winnersOnlyProgressions"): sortedRounds = list(rounds.keys()) sortedRounds.sort(key=lambda x: int(x), reverse=True) for r in sortedRounds: diff --git a/src/TournamentDataProvider/StartGGDataProvider.py b/src/TournamentDataProvider/StartGGDataProvider.py index f432cd1b4..5dc1ae4a5 100644 --- a/src/TournamentDataProvider/StartGGDataProvider.py +++ b/src/TournamentDataProvider/StartGGDataProvider.py @@ -14,7 +14,8 @@ from .TournamentDataProvider import TournamentDataProvider import json from ..Helpers.TSHLocaleHelper import TSHLocaleHelper -from ..TSHBracket import is_power_of_two +from ..TSHBracket import is_power_of_two, next_power_of_2 +import math from ..Workers import Worker import sys @@ -199,14 +200,39 @@ def GetTournamentPhaseGroup(self, id, progress_callback=None): ) oldData = json.loads(oldData.text) - seeds = deep_get(data, "data.phaseGroup.seeds.nodes", []) - seeds.sort(key=lambda s: s.get("seedNum")) + seeds: list = deep_get(data, "data.phaseGroup.seeds.nodes", []) + seeds.sort(key=lambda s: s.get("groupSeedNum")) + + # for s in seeds: + # s["seedNum"] = s.get("groupSeedNum") + + # StartGG hides empty seeds. Fix that + fixedSeeds = [] + + lastSeed = 0 + + byeIds = [] + + while len(seeds) > 0: + minSeed = min(seeds, key=lambda s: s.get("groupSeedNum")) + + while minSeed.get("groupSeedNum") > lastSeed+1: + fixedSeeds.append({}) + lastSeed += 1 + byeIds.append(lastSeed) + else: + fixedSeeds.append(minSeed) + seeds.remove(minSeed) + lastSeed = minSeed.get("groupSeedNum") + + seeds = fixedSeeds seedMap: list = deep_get(data, "data.phaseGroup.seedMap.1") if seedMap: seedMap = [s if s != "bye" else -1 for s in seedMap] finalData["seedMap"] = seedMap + finalData["byeIds"] = byeIds teams = [] @@ -252,8 +278,16 @@ def GetTournamentPhaseGroup(self, id, progress_callback=None): if not str(round) in finalSets: finalSets[str(round)] = [] + score = [s.get("entrant1Score"), s.get("entrant2Score")] + + if s.get("entrant1Score") == None and s.get("entrant2Score") == None and s.get("winnerId") != None and s.get("state", 0) == 3: + if s.get("winnerId") == s.get("entrant1Id"): + score = [1, 0] + else: + score = [0, 1] + finalSets[str(round)].append({ - "score": [s.get("entrant1Score"), s.get("entrant2Score")], + "score": score, "finished": s.get("state", 0) == 3 }) @@ -291,7 +325,8 @@ def GetTournamentPhaseGroup(self, id, progress_callback=None): len(finalData["progressionsIn"])) else 2 if deep_get(oldData, "entities.groups.hasCustomWinnerByes"): - shift = 1 + shift = 1 if math.log2( + next_power_of_2(len(teams))) % 2 == 0 else 2 for roundKey in originalKeys: round = int(roundKey) @@ -614,10 +649,8 @@ def ParseMatchDataNewApi(self, _set): player.get("id"), 0 ] - if playerData.get("id") and len(playerData.get("id")) > 0: - if playerData["id"][0] is not None: - playerData["seed"] = self.player_seeds.get( - playerData["id"][0]) + if playerData["id"][0] is not None: + playerData["seed"] = self.player_seeds[playerData["id"][0]] players[i].append(playerData) @@ -900,7 +933,6 @@ def GetStreamQueue(self, progress_callback=None): queueData = {} for setIndex, _set in enumerate(q.get("sets", [])): - phase_name = deep_get(_set, "phaseGroup.phase.name") if deep_get(_set, "phaseGroup.phase.groupCount") > 1: phase_name += " - " + TSHLocaleHelper.phaseNames.get( @@ -1457,7 +1489,7 @@ def GetEntrantsWorker(self, eventSlug, gameId, progress_callback): for j, entrant in enumerate(team.get("participants", [])): playerData = StartGGDataProvider.ProcessEntrantData( entrant) - if deep_get(team, "seeds", []) is not None and len(deep_get(team, "seeds", [])) > 0: + if deep_get(team, "seeds", []) != []: playerData["seed"] = deep_get(team, "seeds", [])[ 0].get("seedNum", 0) self.player_seeds[playerData["id"] diff --git a/src/TournamentDataProvider/StartGGTournamentPhaseGroupQuery.txt b/src/TournamentDataProvider/StartGGTournamentPhaseGroupQuery.txt index 053c5762c..0edff54c8 100644 --- a/src/TournamentDataProvider/StartGGTournamentPhaseGroupQuery.txt +++ b/src/TournamentDataProvider/StartGGTournamentPhaseGroupQuery.txt @@ -4,6 +4,7 @@ query TournamentPhaseGroupQuery($id: ID!, $videogameId: ID) { seeds(query: {page: 1, perPage: 500}) { nodes { seedNum + groupSeedNum progressionSource { originPhaseGroup { id @@ -18,22 +19,6 @@ query TournamentPhaseGroupQuery($id: ID!, $videogameId: ID) { gamerTag prefix name - sets(page: 1, perPage: 1, filters: { hideEmpty: true, videogameId: $videogameId, videogameIds: [$videogameId] }) { - nodes { - games { - selections { - entrant { - participants { - player { - id - } - } - } - selectionValue - } - } - } - } } user { id @@ -60,7 +45,9 @@ query TournamentPhaseGroupQuery($id: ID!, $videogameId: ID) { nodes { id round - identifier + entrant1Id + entrant2Id + winnerId entrant1Score entrant2Score state diff --git a/src/i18n/TSH_de.ts b/src/i18n/TSH_de.ts index 64371be4e..584d864b8 100644 --- a/src/i18n/TSH_de.ts +++ b/src/i18n/TSH_de.ts @@ -709,20 +709,20 @@ p, li { white-space: pre-wrap; } - + Number of slots Zahl der Slots - + Players per slot Spieler pro Slot - + Characters per player Charaktere pro Slot diff --git a/src/i18n/TSH_en.ts b/src/i18n/TSH_en.ts index 75b9b9544..578aca6ee 100644 --- a/src/i18n/TSH_en.ts +++ b/src/i18n/TSH_en.ts @@ -704,20 +704,20 @@ p, li { white-space: pre-wrap; } - + Number of slots - + Players per slot - + Characters per player diff --git a/src/i18n/TSH_es.ts b/src/i18n/TSH_es.ts index 314400bc5..d0812c693 100644 --- a/src/i18n/TSH_es.ts +++ b/src/i18n/TSH_es.ts @@ -714,20 +714,20 @@ p, li { white-space: pre-wrap; } - + Number of slots Número de grupos - + Players per slot Jugadores por grupo - + Characters per player Personajes por jugador diff --git a/src/i18n/TSH_fr.ts b/src/i18n/TSH_fr.ts index 6090bfd15..c1de7f2d9 100644 --- a/src/i18n/TSH_fr.ts +++ b/src/i18n/TSH_fr.ts @@ -1067,20 +1067,20 @@ p, li { white-space: pre-wrap; } - + Number of slots Nombre d'emplacements - + Players per slot Nombre de joueurs par emplacement - + Characters per player Nombre de personnages par joueur diff --git a/src/i18n/TSH_it.ts b/src/i18n/TSH_it.ts index a3c8a9df4..fcd031025 100644 --- a/src/i18n/TSH_it.ts +++ b/src/i18n/TSH_it.ts @@ -1013,20 +1013,20 @@ p, li { white-space: pre-wrap; } - + Number of slots - + Players per slot - + Characters per player Personaggi per giocatore diff --git a/src/i18n/TSH_ja.ts b/src/i18n/TSH_ja.ts index 8eae4997f..04922e453 100644 --- a/src/i18n/TSH_ja.ts +++ b/src/i18n/TSH_ja.ts @@ -1039,20 +1039,20 @@ p, li { white-space: pre-wrap; } - + Number of slots スロットの数 - + Players per slot 各スロットのプレイヤー数 - + Characters per player 各プレイヤーの使用キャラクター数 diff --git a/src/i18n/TSH_pt-BR.ts b/src/i18n/TSH_pt-BR.ts index bc87e414a..8ce85d6b8 100644 --- a/src/i18n/TSH_pt-BR.ts +++ b/src/i18n/TSH_pt-BR.ts @@ -1086,20 +1086,20 @@ p, li { white-space: pre-wrap; } - + Number of slots Número de grupos - + Players per slot Jogadores por grupo - + Characters per player Personagens por jogador diff --git a/src/i18n/TSH_zh-CN.ts b/src/i18n/TSH_zh-CN.ts index 4a40a39d6..be49fca93 100644 --- a/src/i18n/TSH_zh-CN.ts +++ b/src/i18n/TSH_zh-CN.ts @@ -1013,20 +1013,20 @@ p, li { white-space: pre-wrap; } - + Number of slots - + Players per slot - + Characters per player diff --git a/src/i18n/TSH_zh-TW.ts b/src/i18n/TSH_zh-TW.ts index b4f2129ca..3891a1231 100644 --- a/src/i18n/TSH_zh-TW.ts +++ b/src/i18n/TSH_zh-TW.ts @@ -1013,20 +1013,20 @@ p, li { white-space: pre-wrap; } - + Number of slots - + Players per slot - + Characters per player