roundpairings
v1.0.1
Published
A TypeScript library for generating round-robin tournament pairings for 5-20 players
Maintainers
Readme
Round Robin Pairings
A TypeScript library for generating fair round-robin tournament pairings for 5–20 players using the Berger circle method.
Installation
npm install roundpairingsQuick Start
import { RoundRobin } from 'roundpairings';
const rr = new RoundRobin(['Alice', 'Bob', 'Charlie', 'David', 'Eve']);
// Print schedule
rr.getRounds().forEach(round => {
console.log(`Round ${round.roundNumber}:`);
round.pairings.forEach(p => {
console.log(` Player ${p.player1} vs Player ${p.player2}`);
});
});
// Submit results (after each round)
rr.submitRoundResult(1, ['1:0', '0:1', '1/2:1/2']);
// Display cross table
rr.displayCrossTable();Valid Results
| Result | Meaning |
| ----------- | ------------------------------ |
| 1:0 | White wins |
| 0:1 | Black wins |
| 1/2:1/2 | Draw |
| 0:0 | Both score 0 |
| Empty | Game not played (0:0) |
| 1F:0F | White wins by forfeit |
| 0F:1F | Black wins by forfeit |
| 0F:0F | Both forfeit (0:0) |
| Adjn | Adjourned (0:0) |
| 0:1/2 | White scores 0, Black scores ½ |
| 1/2:0 | White scores ½, Black scores 0 |
| 1U:0U | White wins (unrated) |
| 1/2U:1/2U | Draw (unrated) |
| 0U:1U | Black wins (unrated) |
API
new RoundRobin(players: string[])
Creates a tournament. players must have 5–20 entries.
getRounds(): Round[]
Returns all rounds. Each Round has roundNumber and pairings: Pairing[]. Each Pairing has player1 and player2 (1-based player numbers).
getRound(roundNumber: number): Round
Returns a specific round (1-based).
getRoundCount(): number
Returns total number of rounds.
getTournament(): Tournament
Returns the full tournament object ({ playerCount, rounds }).
getPlayerPairings(playerNumber: number): Pairing[]
Returns all pairings for a given player number.
getPlayerStats(playerNumber: number)
Returns { playerNumber, pairingCount, opponents[] }.
getPlayerNames(): string[]
Returns the array of player names.
getPlayerName(playerNumber: number): string
Returns the name of a player by number (1-based).
submitRoundResult(roundNumber: number, results: string[]): void
Submits results for a round. results must be one entry per pairing, using the valid result strings above.
getMatchResult(roundNumber: number, player1: number, player2: number): MatchResult | null
Returns the stored result for a specific match, or null if not submitted.
getPlayerScore(playerNumber: number): number
Returns the total score for a player across all submitted rounds.
isPlayoffNeeded(): boolean
Returns true if multiple players are tied for the highest score.
getPlayoffParticipants(): number[]
Returns the player numbers tied for the highest score.
getPlayoffPairings(): Pairing[]
Returns the head-to-head pairings for playoff participants.
submitPlayoffResult(results: string[]): void
Submits playoff results. Works the same as submitRoundResult but for the auto-generated playoff pairings.
getTotalScoreWithPlayoff(playerNumber: number): number
Returns a player's score including playoff round contributions.
displayCrossTable(options?): void
Prints the cross table to the console.
Options:
round?: number— show results up to this roundorderBy?: 'name' | 'score'— sort order (default:'name')
displayEveryCrossTable(orderBy?): void
Prints a cross table after every round, with game results listed below each table. Includes playoff games if present.
displayPlayoffResults(): void
Prints the playoff round matches and results.
displayFinalStandings(): void
Prints final standings including playoff scores and the winner.
Round Counts
| Players | Rounds | | ------- | ------ | | 5–6 | 5 | | 7–8 | 7 | | 9–10 | 9 | | 11–12 | 11 | | 13–14 | 13 | | 15–16 | 15 | | 17–18 | 17 | | 19–20 | 19 |
Odd player counts use the next even number internally (the extra slot acts as a bye).
Berger Table Reference
5–6 Players
1: 1-6 2-5 3-4
2: 6-4 5-3 1-2
3: 2-6 3-1 4-5
4: 6-5 1-4 2-3
5: 3-6 4-2 5-17-8 Players 1: 1-8 2-7 3-6 4-5 2: 8-5 6-4 7-3 1-2 3: 2-8 3-1 4-7 5-6 4: 8-6 7-5 1-4 2-3 5: 3-8 4-2 5-1 6-7 6: 8-7 1-6 2-5 3-4 7: 4-8 5-3 6-2 7-1
9-10 Players 1: 1-10 2-9 3-8 4-7 5-6 2: 10-6 7-5 8-4 9-3 1-2 3: 2-10 3-1 4-9 5-8 6-7 4: 10-7 8-6 9-5 1-4 2-3 5: 3-10 4-2 5-1 6-9 7-8 6: 10-8 9-7 1-6 2-5 3-4 7: 4-10 5-3 6-2 7-1 8-9 8: 10-9 1-8 2-7 3-6 4-5 9: 5-10 6-4 7-3 8-2 9-1
11-12 Players 1: 1-12 2-11 3-10 4-9 5-8 6-7 2: 12-7 8-6 9-5 10-4 11-3 1-2 3: 2-12 3-1 4-11 5-10 6-9 7-8 4: 12-8 9-7 10-6 11-5 1-4 2-3 5: 3-12 4-2 5-1 6-11 7-10 8-9 6: 12-9 10-8 11-7 1-6 2-5 3-4 7: 4-12 5-3 6-2 7-1 8-11 9-10 8: 12-10 11-9 1-8 2-7 3-6 4-5 9: 5-12 6-4 7-3 8-2 9-1 10-11 10: 12-11 1-10 2-9 3-8 4-7 5-6 11: 6-12 7-5 8-4 9-3 10-2 11-1
13-14 Players 1: 1-14 2-13 3-12 4-11 5-10 6-9 7-8 2: 14-8 9-7 10-6 11-5 12-4 13-3 1-2 3: 2-14 3-1 4-13 5-12 6-11 7-10 8-9 4: 14-9 10-8 11-7 12-6 13-5 1-4 2-3 5: 3-14 4-2 5-1 6-13 7-12 8-11 9-10 6: 14-10 11-9 12-8 13-7 1-6 2-5 3-4 7: 4-14 5-3 6-2 7-1 8-13 9-12 10-11 8: 14-11 12-10 13-9 1-8 2-7 3-6 4-5 9: 5-14 6-4 7-3 8-2 9-1 10-13 11-12 10: 14-12 13-11 1-10 2-9 3-8 4-7 5-6 11: 6-14 7-5 8-4 9-3 10-2 11-1 12-13 12: 14-13 1-12 2-11 3-10 4-9 5-8 6-7 13: 7-14 8-6 9-5 10-4 11-3 12-2 13-1
15-16 Players 1: 1-16 2-15 3-14 4-13 5-12 6-11 7-10 8-9 2: 16-9 10-8 11-7 12-6 13-5 14-4 15-3 1-2 3: 2-16 3-1 4-15 5-14 6-13 7-12 8-11 9-10 4: 16-10 11-9 12-8 13-7 14-6 15-5 1-4 2-3 5: 3-16 4-2 5-1 6-15 7-14 8-13 9-12 10-11 6: 16-11 12-10 13-9 14-8 15-7 1-6 2-5 3-4 7: 4-16 5-3 6-2 7-1 8-15 9-14 10-13 11-12 8: 16-12 13-11 14-10 15-9 1-8 2-7 3-6 4-5 9: 5-16 6-4 7-3 8-2 9-1 10-15 11-14 12-13 10: 16-13 14-12 15-11 1-10 2-9 3-8 4-7 5-6 11: 6-16 7-5 8-4 9-3 10-2 11-1 12-15 13-14 12: 16-14 15-13 1-12 2-11 3-10 4-9 5-8 6-7 13: 7-16 8-6 9-5 10-4 11-3 12-2 13-1 14-15 14: 16-15 1-14 2-13 3-12 4-11 5-10 6-9 7-8 15: 8-16 9-7 10-6 11-5 12-4 13-3 14-2 15-1
17-18 Players 1: 1-18 2-17 3-16 4-15 5-14 6-13 7-12 8-11 9-10 2: 18-10 11-9 12-8 13-7 14-6 15-5 16-4 17-3 1-2 3: 2-18 3-1 4-17 5-16 6-15 7-14 8-13 9-12 10-11 4: 18-11 12-10 13-9 14-8 15-7 16-6 17-5 1-4 2-3 5: 3-18 4-2 5-1 6-17 7-16 8-15 9-14 10-13 11-12 6: 18-12 13-11 14-10 15-9 16-8 17-7 1-6 2-5 3-4 7: 4-18 5-3 6-2 7-1 8-17 9-16 10-15 11-14 12-13 8: 18-13 14-12 15-11 16-10 17-9 1-8 2-7 3-6 4-5 9: 5-18 6-4 7-3 8-2 9-1 10-17 11-16 12-15 13-14 10: 18-14 15-13 16-12 17-11 1-10 2-9 3-8 4-7 5-6 11: 6-18 7-5 8-4 9-3 10-2 11-1 12-17 13-16 14-15 12: 18-15 16-14 17-13 1-12 2-11 3-10 4-9 5-8 6-7 13: 7-18 8-6 9-5 10-4 11-3 12-2 13-1 14-17 15-16 14: 18-16 17-15 1-14 2-13 3-12 4-11 5-10 6-9 7-8 15: 8-18 9-7 10-6 11-5 12-4 13-3 14-2 15-1 16-17 16: 18-17 1-16 2-15 3-14 4-13 5-12 6-11 7-10 8-9 17: 9-18 10-8 11-7 12-6 13-5 14-4 15-3 16-2 17-1
19-20 Players 1: 1-20 2-19 3-18 4-17 5-16 6-15 7-14 8-13 9-12 10-11 2: 20-11 12-10 13-9 14-8 15-7 16-6 17-5 18-4 19-3 1-2 3: 2-20 3-1 4-19 5-18 6-17 7-16 8-15 9-14 10-13 11-12 4: 20-12 13-11 14-10 15-9 16-8 17-7 18-6 19-5 1-4 2-3 5: 3-20 4-2 5-1 6-19 7-18 8-17 9-16 10-15 11-14 12-13 6: 20-13 14-12 15-11 16-10 17-9 18-8 19-7 1-6 2-5 3-4 7: 4-20 5-3 6-2 7-1 8-19 9-18 10-17 11-16 12-15 13-14 8: 20-14 15-13 16-12 17-11 18-10 19-9 1-8 2-7 3-6 4-5 9: 5-20 6-4 7-3 8-2 9-1 10-19 11-18 12-17 13-16 14-15 10: 20-15 16-14 17-13 18-12 19-11 1-10 2-9 3-8 4-7 5-6 11: 6-20 7-5 8-4 9-3 10-2 11-1 12-19 13-18 14-17 15-16 12: 20-16 17-15 18-14 19-13 1-12 2-11 3-10 4-9 5-8 6-7 13: 7-20 8-6 9-5 10-4 11-3 12-2 13-1 14-19 15-18 16-17 14: 20-17 18-16 19-15 1-14 2-13 3-12 4-11 5-10 6-9 7-8 15: 8-20 9-7 10-6 11-5 12-4 13-3 14-2 15-1 16-19 17-18 16: 20-18 19-17 1-16 2-15 3-14 4-13 5-12 6-11 7-10 8-9 17: 9-20 10-8 11-7 12-6 13-5 14-4 15-3 16-2 17-1 18-19 18: 20-19 1-18 2-17 3-16 4-15 5-14 6-13 7-12 8-11 9-10 19: 10-20 11-9 12-8 13-7 14-6 15-5 16-4 17-3 18-2 19-1
