Skip to content

Commit 71fb813

Browse files
committed
Refactor helpers
1 parent d29f27c commit 71fb813

File tree

3 files changed

+112
-106
lines changed

3 files changed

+112
-106
lines changed

src/helpers.ts

Lines changed: 59 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,11 @@ export function splitBy<T>(array: T[], key: keyof T): T[][] {
1313
return Object.values(obj);
1414
}
1515

16-
interface Ranking {
17-
[prop: string]: number,
18-
rank: number,
19-
id: number,
20-
played: number,
21-
wins: number,
22-
draws: number,
23-
losses: number,
24-
forfeits: number,
25-
scoreFor: number,
26-
scoreAgainst: number,
27-
scoreDifference: number,
28-
points: number,
29-
}
30-
31-
interface Header {
32-
value: string,
33-
tooltip: string,
16+
export function isMajorRound(roundNumber: number) {
17+
return roundNumber === 1 || roundNumber % 2 === 0;
3418
}
3519

36-
type Headers = { [name in keyof Ranking]: Header };
37-
38-
const headers: Headers = {
20+
const headers: RankingHeaders = {
3921
'rank': {
4022
value: '#',
4123
tooltip: 'Rank',
@@ -82,78 +64,78 @@ const headers: Headers = {
8264
},
8365
}
8466

85-
export function isMajorRound(roundNumber: number) {
86-
return roundNumber === 1 || roundNumber % 2 === 0;
87-
}
88-
89-
export function rankingHeader(name: keyof Ranking): Header {
67+
export function rankingHeader(name: keyof RankingItem): Header {
9068
return headers[name];
9169
}
9270

93-
export function getRanking(matches: Match[], pointsFormula?: (ranking: Ranking) => number): Ranking[] {
94-
const teams: { [id: number]: Ranking } = {};
95-
96-
function processTeam(current: ParticipantResult | null, other: ParticipantResult | null) {
97-
if (!current || current.id === null) return;
71+
export function getRanking(matches: Match[], formula?: RankingFormula): Ranking {
72+
formula = formula || (
73+
(item: RankingItem) => 3 * item.wins + 1 * item.draws + 0 * item.losses
74+
);
9875

99-
const state = teams[current.id] || {
100-
rank: 0,
101-
id: 0,
102-
played: 0,
103-
wins: 0,
104-
draws: 0,
105-
losses: 0,
106-
forfeits: 0,
107-
scoreFor: 0,
108-
scoreAgainst: 0,
109-
scoreDifference: 0,
110-
points: 0,
111-
};
76+
const rankingMap: RankingMap = {};
11277

113-
state.id = current.id;
114-
state.played++;
78+
for (const match of matches) {
79+
processTeam(rankingMap, formula, match.opponent1, match.opponent2);
80+
processTeam(rankingMap, formula, match.opponent2, match.opponent1);
81+
}
11582

116-
if (current.result === 'win')
117-
state.wins++;
83+
return createRanking(rankingMap);
84+
}
11885

119-
if (current.result === 'draw')
120-
state.draws++;
86+
function createRanking(rankingMap: RankingMap) {
87+
const ranking = Object.values(rankingMap).sort((a, b) => b.points - a.points);
88+
89+
const rank = {
90+
value: 0,
91+
lastPoints: -1,
92+
};
12193

122-
if (current.result === 'loss')
123-
state.losses++;
94+
for (const item of ranking) {
95+
item.rank = rank.lastPoints !== item.points ? ++rank.value : rank.value;
96+
rank.lastPoints = item.points;
97+
}
12498

125-
if (current.forfeit)
126-
state.forfeits++;
99+
return ranking;
100+
}
127101

128-
state.scoreFor += current.score || 0;
129-
state.scoreAgainst += other && other.score || 0;
130-
state.scoreDifference = state.scoreFor - state.scoreAgainst;
102+
function processTeam(rankingMap: RankingMap, formula: RankingFormula, current: ParticipantResult | null, other: ParticipantResult | null) {
103+
if (!current || current.id === null) return;
104+
105+
const state = rankingMap[current.id] || {
106+
rank: 0,
107+
id: 0,
108+
played: 0,
109+
wins: 0,
110+
draws: 0,
111+
losses: 0,
112+
forfeits: 0,
113+
scoreFor: 0,
114+
scoreAgainst: 0,
115+
scoreDifference: 0,
116+
points: 0,
117+
};
131118

132-
const formula = pointsFormula || (
133-
(ranking: Ranking) => 3 * ranking.wins + 1 * ranking.draws + 0 * ranking.losses
134-
);
119+
state.id = current.id;
120+
state.played++;
135121

136-
state.points = formula(state);
122+
if (current.result === 'win')
123+
state.wins++;
137124

138-
teams[current.id] = state;
139-
}
125+
if (current.result === 'draw')
126+
state.draws++;
140127

141-
for (const match of matches) {
142-
processTeam(match.opponent1, match.opponent2);
143-
processTeam(match.opponent2, match.opponent1);
144-
}
128+
if (current.result === 'loss')
129+
state.losses++;
145130

146-
const rankings = Object.values(teams).sort((a, b) => b.points - a.points);
131+
if (current.forfeit)
132+
state.forfeits++;
147133

148-
let rank = {
149-
value: 0,
150-
lastPoints: -1,
151-
};
134+
state.scoreFor += current.score || 0;
135+
state.scoreAgainst += other && other.score || 0;
136+
state.scoreDifference = state.scoreFor - state.scoreAgainst;
152137

153-
for (const ranking of rankings) {
154-
ranking.rank = rank.lastPoints !== ranking.points ? ++rank.value : rank.value;
155-
rank.lastPoints = ranking.points;
156-
}
138+
state.points = formula(state);
157139

158-
return rankings;
140+
rankingMap[current.id] = state;
159141
}

src/main.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,6 @@ import './style.scss';
22
import { Participant, Match, MatchResults, ParticipantResult, ViewerData } from "brackets-model";
33
import { splitBy, getRanking, rankingHeader, isMajorRound } from "./helpers";
44

5-
type ConnectionType = 'square' | 'straight' | false;
6-
type Placement = 'none' | 'before' | 'after';
7-
type FinalType = 'consolation_final' | 'grand_final';
8-
type MatchHint = ((i: number) => string) | undefined;
9-
10-
interface Connection {
11-
connectPrevious?: ConnectionType,
12-
connectNext?: ConnectionType,
13-
}
14-
15-
interface Config {
16-
/**
17-
* Where the position of a participant is placed relative to its name.
18-
* - If `before`, the position is prepended before the team name. "#1 Team"
19-
* - If `after`, the position is appended after the team name, in parentheses. "Team (#1)"
20-
*/
21-
participantOriginPlacement: Placement,
22-
23-
/**
24-
* Whether to show the origin of a slot (wherever possible).
25-
*/
26-
showSlotsOrigin: boolean,
27-
28-
/**
29-
* Whether to show the origin of a slot (in the lower bracket of an elimination stage).
30-
*/
31-
showLowerBracketSlotsOrigin: boolean,
32-
}
33-
345
class BracketsViewer {
356

367
readonly teamRefsDOM: { [key: number]: HTMLElement[] } = {};

src/types.d.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
type ConnectionType = 'square' | 'straight' | false;
2+
type Placement = 'none' | 'before' | 'after';
3+
type FinalType = 'consolation_final' | 'grand_final';
4+
type MatchHint = ((i: number) => string) | undefined;
5+
6+
interface Connection {
7+
connectPrevious?: ConnectionType,
8+
connectNext?: ConnectionType,
9+
}
10+
11+
interface Config {
12+
/**
13+
* Where the position of a participant is placed relative to its name.
14+
* - If `before`, the position is prepended before the team name. "#1 Team"
15+
* - If `after`, the position is appended after the team name, in parentheses. "Team (#1)"
16+
*/
17+
participantOriginPlacement: Placement,
18+
19+
/**
20+
* Whether to show the origin of a slot (wherever possible).
21+
*/
22+
showSlotsOrigin: boolean,
23+
24+
/**
25+
* Whether to show the origin of a slot (in the lower bracket of an elimination stage).
26+
*/
27+
showLowerBracketSlotsOrigin: boolean,
28+
}
29+
30+
interface RankingItem {
31+
[prop: string]: number,
32+
rank: number,
33+
id: number,
34+
played: number,
35+
wins: number,
36+
draws: number,
37+
losses: number,
38+
forfeits: number,
39+
scoreFor: number,
40+
scoreAgainst: number,
41+
scoreDifference: number,
42+
points: number,
43+
}
44+
45+
interface Header {
46+
value: string,
47+
tooltip: string,
48+
}
49+
50+
type RankingFormula = (ranking: RankingItem) => number;
51+
type RankingHeaders = { [name in keyof RankingItem]: Header };
52+
type RankingMap = { [id: number]: RankingItem };
53+
type Ranking = RankingItem[];

0 commit comments

Comments
 (0)