{ "version": 3, "sources": ["../../../../server/tournaments/generator-round-robin.ts"], "sourcesContent": ["interface Match {\r\n\tstate: string;\r\n\tscore?: number[];\r\n\tresult?: string;\r\n}\r\n\r\nimport {Utils} from '../../lib/utils';\r\nimport type {TournamentPlayer} from './index';\r\n\r\nexport class RoundRobin {\r\n\treadonly name: string;\r\n\treadonly isDrawingSupported: boolean;\r\n\treadonly isDoubles: boolean;\r\n\tisBracketFrozen: boolean;\r\n\tplayers: TournamentPlayer[];\r\n\tmatches: (Match | null)[][];\r\n\ttotalPendingMatches: number;\r\n\tperPlayerPendingMatches: number;\r\n\tmatchesPerPlayer?: number;\r\n\tconstructor(isDoubles: string) {\r\n\t\tthis.name = \"Round Robin\";\r\n\t\tthis.isDrawingSupported = true;\r\n\t\tthis.isDoubles = !!isDoubles;\r\n\t\tthis.isBracketFrozen = false;\r\n\t\tthis.players = [];\r\n\r\n\t\tthis.matches = [];\r\n\t\tthis.totalPendingMatches = -1;\r\n\t\tthis.perPlayerPendingMatches = -1;\r\n\r\n\t\tif (isDoubles) this.name = \"Double \" + this.name;\r\n\t}\r\n\r\n\tgetPendingBracketData(players: TournamentPlayer[]) {\r\n\t\treturn {\r\n\t\t\ttype: 'table',\r\n\t\t\ttableHeaders: {\r\n\t\t\t\tcols: players.slice(0),\r\n\t\t\t\trows: players.slice(0),\r\n\t\t\t},\r\n\t\t\ttableContents: players.map(\r\n\t\t\t\t(p1, row) => players.map((p2, col) => {\r\n\t\t\t\t\tif (!this.isDoubles && col >= row) return null;\r\n\t\t\t\t\tif (p1 === p2) return null;\r\n\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tstate: 'unavailable',\r\n\t\t\t\t\t};\r\n\t\t\t\t})\r\n\t\t\t),\r\n\t\t\tscores: players.map(player => 0),\r\n\t\t};\r\n\t}\r\n\tgetBracketData() {\r\n\t\tconst players = this.players;\r\n\t\treturn {\r\n\t\t\ttype: 'table',\r\n\t\t\ttableHeaders: {\r\n\t\t\t\tcols: players.slice(0),\r\n\t\t\t\trows: players.slice(0),\r\n\t\t\t},\r\n\t\t\ttableContents: players.map(\r\n\t\t\t\t(p1, row) => players.map((p2, col) => {\r\n\t\t\t\t\tif (!this.isDoubles && col >= row) return null;\r\n\t\t\t\t\tif (p1 === p2) return null;\r\n\t\t\t\t\tconst match = this.matches[row][col];\r\n\t\t\t\t\tif (!match) return null;\r\n\r\n\t\t\t\t\tconst cell: any = {\r\n\t\t\t\t\t\tstate: match.state,\r\n\t\t\t\t\t};\r\n\t\t\t\t\tif (match.state === 'finished' && match.score) {\r\n\t\t\t\t\t\tcell.result = match.result;\r\n\t\t\t\t\t\tcell.score = match.score.slice(0);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn cell;\r\n\t\t\t\t})\r\n\t\t\t),\r\n\t\t\tscores: players.map(player => player.score),\r\n\t\t};\r\n\t}\r\n\tfreezeBracket(players: TournamentPlayer[]) {\r\n\t\tthis.players = players;\r\n\t\tthis.isBracketFrozen = true;\r\n\r\n\t\tthis.matches = players.map(\r\n\t\t\t(p1, row) => players.map((p2, col) => {\r\n\t\t\t\tif (!this.isDoubles && col >= row) return null;\r\n\t\t\t\tif (p1 === p2) return null;\r\n\r\n\t\t\t\treturn {state: 'available'};\r\n\t\t\t})\r\n\t\t);\r\n\t\tthis.matchesPerPlayer = players.length - 1;\r\n\t\t// total matches = total players * matches per player / players per match\r\n\t\t// alternatively: the (playercount)th triangular number\r\n\t\tthis.totalPendingMatches = players.length * this.matchesPerPlayer / 2;\r\n\t\tif (this.isDoubles) {\r\n\t\t\tthis.totalPendingMatches *= 2;\r\n\t\t\tthis.matchesPerPlayer *= 2;\r\n\t\t}\r\n\t}\r\n\r\n\tdisqualifyUser(user: TournamentPlayer) {\r\n\t\tif (!this.isBracketFrozen) return 'BracketNotFrozen';\r\n\r\n\t\tconst playerIndex = this.players.indexOf(user);\r\n\r\n\t\tfor (const [col, match] of this.matches[playerIndex].entries()) {\r\n\t\t\tif (!match || match.state !== 'available') continue;\r\n\t\t\tconst p2 = this.players[col];\r\n\t\t\tmatch.state = 'finished';\r\n\t\t\tmatch.result = 'loss';\r\n\t\t\tmatch.score = [0, 1];\r\n\t\t\tp2.score += 1;\r\n\t\t\tp2.games += 1;\r\n\t\t\tthis.totalPendingMatches--;\r\n\t\t}\r\n\r\n\t\tfor (const [row, challenges] of this.matches.entries()) {\r\n\t\t\tconst match = challenges[playerIndex];\r\n\t\t\tif (!match || match.state !== 'available') continue;\r\n\t\t\tconst p1 = this.players[row];\r\n\t\t\tmatch.state = 'finished';\r\n\t\t\tmatch.result = 'win';\r\n\t\t\tmatch.score = [1, 0];\r\n\t\t\tp1.score += 1;\r\n\t\t\tp1.games += 1;\r\n\t\t\tthis.totalPendingMatches--;\r\n\t\t}\r\n\r\n\t\tuser.unlinkUser();\r\n\t}\r\n\r\n\tgetAvailableMatches() {\r\n\t\tif (!this.isBracketFrozen) return 'BracketNotFrozen';\r\n\r\n\t\tconst matches: [TournamentPlayer, TournamentPlayer][] = [];\r\n\t\tfor (const [row, challenges] of this.matches.entries()) {\r\n\t\t\tconst p1 = this.players[row];\r\n\t\t\tfor (const [col, match] of challenges.entries()) {\r\n\t\t\t\tconst p2 = this.players[col];\r\n\t\t\t\tif (!match) continue;\r\n\t\t\t\tif (match.state === 'available' && !p1.isBusy && !p2.isBusy) {\r\n\t\t\t\t\tmatches.push([p1, p2]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn matches;\r\n\t}\r\n\tsetMatchResult([p1, p2]: [TournamentPlayer, TournamentPlayer], result: string, score: number[]) {\r\n\t\tif (!this.isBracketFrozen) return 'BracketNotFrozen';\r\n\r\n\t\tif (!['win', 'loss', 'draw'].includes(result)) return 'InvalidMatchResult';\r\n\r\n\t\tconst row = this.players.indexOf(p1);\r\n\t\tconst col = this.players.indexOf(p2);\r\n\t\tif (row < 0 || col < 0) return 'UserNotAdded';\r\n\r\n\t\tconst match = this.matches[row][col];\r\n\t\tif (!match || match.state !== 'available') return 'InvalidMatch';\r\n\r\n\t\tmatch.state = 'finished';\r\n\t\tmatch.result = result;\r\n\t\tmatch.score = score.slice(0);\r\n\t\tthis.totalPendingMatches--;\r\n\t}\r\n\r\n\tisTournamentEnded() {\r\n\t\treturn this.isBracketFrozen && this.totalPendingMatches === 0;\r\n\t}\r\n\r\n\tgetResults() {\r\n\t\tif (!this.isTournamentEnded()) return 'TournamentNotEnded';\r\n\r\n\t\tconst sortedScores = Utils.sortBy([...this.players], p => -p.score);\r\n\r\n\t\tconst results: TournamentPlayer[][] = [];\r\n\t\tlet currentScore = sortedScores[0].score;\r\n\t\tlet currentRank: TournamentPlayer[] = [];\r\n\t\tresults.push(currentRank);\r\n\t\tfor (const player of sortedScores) {\r\n\t\t\tif (player.score < currentScore) {\r\n\t\t\t\tcurrentScore = player.score;\r\n\t\t\t\tcurrentRank = [];\r\n\t\t\t\tresults.push(currentRank);\r\n\t\t\t}\r\n\t\t\tcurrentRank.push(player);\r\n\t\t}\r\n\t\treturn results;\r\n\t}\r\n}\r\n"], "mappings": "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", "names": [] }