{"id":51319234,"url":"https://github.com/echecsjs/round-robin","last_synced_at":"2026-07-01T11:02:09.053Z","repository":{"id":346577091,"uuid":"1188286654","full_name":"echecsjs/round-robin","owner":"echecsjs","description":"Round-robin chess tournament pairings following FIDE Berger tables (C.05 Annex 1). Supports 3-16 players. Zero dependencies.","archived":false,"fork":false,"pushed_at":"2026-06-29T14:10:15.000Z","size":460,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-29T15:24:43.189Z","etag":null,"topics":["chess","fide","pairing","round-robin","typescript"],"latest_commit_sha":null,"homepage":"https://github.com/echecsjs/round-robin#readme","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/echecsjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-21T21:42:50.000Z","updated_at":"2026-06-29T14:11:40.000Z","dependencies_parsed_at":"2026-06-09T20:03:02.205Z","dependency_job_id":null,"html_url":"https://github.com/echecsjs/round-robin","commit_stats":null,"previous_names":["mormubis/round-robin","echecsjs/round-robin"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/echecsjs/round-robin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echecsjs%2Fround-robin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echecsjs%2Fround-robin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echecsjs%2Fround-robin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echecsjs%2Fround-robin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/echecsjs","download_url":"https://codeload.github.com/echecsjs/round-robin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echecsjs%2Fround-robin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35003464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chess","fide","pairing","round-robin","typescript"],"created_at":"2026-07-01T11:02:07.895Z","updated_at":"2026-07-01T11:02:09.042Z","avatar_url":"https://github.com/echecsjs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Round Robin\n\n[![npm](https://img.shields.io/npm/v/@echecs/round-robin)](https://www.npmjs.com/package/@echecs/round-robin)\n[![Coverage](https://codecov.io/gh/echecsjs/round-robin/branch/main/graph/badge.svg)](https://codecov.io/gh/echecsjs/round-robin)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Spec](https://img.shields.io/badge/Spec-FIDE-green.svg)](SPEC.md)\n\n**Round Robin** is a TypeScript library for round-robin (all-play-all) chess\ntournament pairings, following the official\n[FIDE Berger tables](https://handbook.fide.com/chapter/C05Annex1) (Handbook\nC.05, Annex 1). Supports 3 to 16 players. Zero runtime dependencies.\n\nPairings are generated from hardcoded FIDE tables — no algorithmic generation.\nThis guarantees bit-exact compliance with the published FIDE specification.\n\n## Installation\n\n```bash\nnpm install @echecs/round-robin\n```\n\n## Quick Start\n\n```typescript\nimport { pair } from '@echecs/round-robin';\nimport type { Player } from '@echecs/round-robin';\n\nconst players: Player[] = [\n  { id: 'alice' },\n  { id: 'bob' },\n  { id: 'carol' },\n  { id: 'dave' },\n];\n\n// Get pairings for round 1 (no previous games)\nconst round1 = pair(players, []);\nconsole.log(round1.pairings);\n// [{ white: 'alice', black: 'dave' }, { white: 'bob', black: 'carol' }]\n\n// After recording round-1 results, pair round 2\n// games[n] = round n+1; Game has no `round` field\nconst games = [\n  [\n    { white: 'alice', black: 'dave', result: 1 },\n    { white: 'bob', black: 'carol', result: 0.5 },\n  ],\n];\nconst round2 = pair(players, games); // next round = games.length + 1 = 2\n```\n\n## API\n\n### `pair(players, games)`\n\n```typescript\nfunction pair(players: Player[], games: Game[][]): PairingResult;\n```\n\nReturns pairings for the next round.\n\n- `players` — all registered players, ordered by seed (index 0 = seed 1)\n- `games` — completed games grouped by round: `games[0]` = round 1, `games[1]` =\n  round 2, … The round to pair is `games.length + 1`. The `games` parameter is\n  accepted for interface compatibility with `@echecs/swiss` but is ignored —\n  pairings are fully determined by seeding order and round index.\n\nThe `Game` type has no `round` field — round is encoded by array position.\n\nThrows `RangeError` if:\n\n- Fewer than 3 or more than 16 players\n- `games.length + 1` exceeds the total number of rounds\n\n```typescript\ninterface PairingResult {\n  byes: Bye[]; // players with no opponent this round\n  pairings: Pairing[]; // white/black assignments\n}\n\ninterface Pairing {\n  black: string;\n  white: string;\n}\n\ninterface Bye {\n  player: string;\n}\n```\n\n### Number of rounds\n\n| Players | Rounds |\n| ------- | ------ |\n| 3-4     | 3      |\n| 5-6     | 5      |\n| 7-8     | 7      |\n| 9-10    | 9      |\n| 11-12   | 11     |\n| 13-14   | 13     |\n| 15-16   | 15     |\n\nOdd player counts are padded to the next even number. The total number of rounds\nis always `effectiveSize - 1`.\n\n## Seeding\n\nSeeding is determined by array position — index 0 is seed 1, index 1 is seed 2,\netc. The caller controls seed order by arranging the `players` array before\ncalling the pairing function.\n\n```typescript\n// Seed by rating (highest first)\nconst seeded = players.sort((a, b) =\u003e (b.rating ?? 0) - (a.rating ?? 0));\nconst round1 = pair(seeded, []);\n```\n\n## Byes\n\nFor odd player counts, one player receives a bye each round. Per FIDE rules, the\nhighest-numbered seed is the bye seat — so the player paired against that seat\ngets the bye.\n\n```typescript\nconst players: Player[] = [{ id: 'alice' }, { id: 'bob' }, { id: 'carol' }];\n\nconst round1 = pair(players, []);\nconsole.log(round1.byes);\n// [{ player: 'alice' }]\nconsole.log(round1.pairings);\n// [{ white: 'bob', black: 'carol' }]\n```\n\n## Unified Pairing Interface\n\nThe `pair` function shares the same signature as Swiss pairing functions in\n`@echecs/swiss`:\n\n```typescript\ntype PairingSystem = (players: Player[], games: Game[][]) =\u003e PairingResult;\n```\n\nThis enables `@echecs/tournament` to consume any pairing system through a single\ninterface. The `games` parameter is accepted but ignored.\n\n```typescript\nimport { pair as dutch } from '@echecs/swiss';\nimport { pair as roundRobin } from '@echecs/round-robin';\nimport type { PairingResult, Player, Game } from '@echecs/round-robin';\n\ntype PairingSystem = (players: Player[], games: Game[][]) =\u003e PairingResult;\n\n// Both work as a PairingSystem\nconst system: PairingSystem = useSwiss ? dutch : roundRobin;\nconst pairings = system(players, games);\n```\n\n## Types\n\n```typescript\ninterface Player {\n  id: string;\n  rating?: number;\n}\n\ninterface Game {\n  black: string;\n  kind?: GameKind;\n  result: Result;\n  white: string;\n  // No `round` field — round is encoded by position in Game[][]\n}\n\ntype GameKind =\n  | 'forfeit-loss'\n  | 'forfeit-win'\n  | 'full-bye'\n  | 'half-bye'\n  | 'pairing-bye'\n  | 'zero-bye';\n\ntype Result = 0 | 0.5 | 1;\n```\n\n## FIDE References\n\n- [C.05 General Regulations for Competitions](https://handbook.fide.com/chapter/C05GeneralRegulations)\n- [C.05 Annex 1: Berger Tables](https://handbook.fide.com/chapter/C05Annex1)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fechecsjs%2Fround-robin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fechecsjs%2Fround-robin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fechecsjs%2Fround-robin/lists"}