# @echecs/tournament 中文文档

规范地址：https://npmcn.com/package/%40echecs/tournament/

版本：3\.3\.0
npm 元数据更新时间：2026-05-27T20:04:58.992Z
中文译文更新时间：2026-11-13T04:56:49.746Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40echecs/tournament
原文对照：https://npmcn.com/package/%40echecs/tournament/?lang=original
项目主页：https://tournament.echecs.dev/
源码仓库：https://github.com/echecsjs/tournament

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：67.2 kB，7 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22
- 运行依赖：0 个
- 首次发布：2026-03-22T15:38:47.770Z
- 最新版本发布：2026-05-27T20:04:58.675Z
- 近 30 天下载量：3139（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

任何FIDE配对系统的高级国际象棋锦标赛指挥员 支持瑞士语,圆形robin,和加速格式. 零从属.

## 安装

```sh
npm install @echecs/tournament
```

也可以使用：`pnpm add @echecs/tournament`、`yarn add @echecs/tournament`、`bun add @echecs/tournament`

## README

# 比赛

[![npm](https://img.shields.io/npm/v/@echecs/tournament)](https://www.npmjs.com/package/@echecs/tournament) [![Coverage](https://codecov.io/gh/echecsjs/tournament/branch/main/graph/badge.svg)](https://codecov.io/gh/echecsjs/tournament) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://npmcn.com/package/%40echecs/tournament/LICENSE) [![Spec](https://img.shields.io/badge/Spec-FIDE-green.svg)](https://npmcn.com/package/%40echecs/tournament/SPEC.md)

**比赛** 是一个用于组织国际象棋锦标赛的 TypeScript 库 任何FIDE配对系统。 它提供一种状态 `Tournament` 管理类 整个生命周期——配对回合、记录结果、计算站位—— (单位:千美元) `bakuAcceleration()` c.04.7. 零运行时间 依赖性.

配对系统被作为函数参数注入. 自取自来 [`@echecs/swiss`](https://www.npmjs.com/package/@echecs/swiss), (中文(简体) ), [`@echecs/round-robin`](https://www.npmjs.com/package/@echecs/round-robin),或一个 自定义执行.

## 安装

```bash
npm install @echecs/tournament
```

## 快速启动

```typescript
import { Tournament } from '@echecs/tournament';
import { pair } from '@echecs/swiss/dutch';
import type { Game, GameKind, Player, Tiebreak } from '@echecs/tournament';

const players: Player[] = [
  { id: 'alice', rating: 2100 },
  { id: 'bob', rating: 1950 },
  { id: 'carol', rating: 1870 },
  { id: 'dave', rating: 1820 },
];

const tournament = new Tournament({
  pairingSystem: pair,
  players,
  rounds: 3,
});

// Round 1
const round1 = tournament.pairRound();
// round1.pairings = [{ black: 'carol', white: 'alice' }, ...]
// round1.byes    = [{ player: 'dave' }]

tournament.recordResult({ black: 'carol', result: 1, white: 'alice' });
tournament.recordResult({ black: 'dave', result: 0.5, white: 'bob' });

// Round 2
const round2 = tournament.pairRound();
// ...record results...

// Standings (no tiebreaks)
const table = tournament.standings();
// [{ player: 'alice', rank: 1, score: 2, tiebreaks: [] }, ...]
```

## API 密码

### `Tournament`

```typescript
class Tournament {
  constructor(options: TournamentOptions);

  clearResult(round: number, white: string, black: string): void;
  pairRound(): PairingResult;
  recordResult(game: Game): void;
  standings(tiebreaks?: Tiebreak[]): Standing[];
  updateResult(round: number, game: Game): void;

  get currentRound(): number;
  get games(): readonly (readonly Game[])[];
  get isComplete(): boolean;
  get players(): readonly Player[];
  get rounds(): number;
  get tiebreaks(): readonly string[];

  toJSON(): TournamentSnapshot;
  static fromJSON(
    snapshot: TournamentSnapshot,
    pairingSystem: PairingSystem,
    acceleration?: AccelerationMethod,
  ): Tournament;
}
```

#### `constructor(options)`

创建新的锦标赛.

```typescript
interface TournamentOptions {
  acceleration?: AccelerationMethod; // e.g. bakuAcceleration(players)
  pairingSystem: PairingSystem; // e.g. pair from @echecs/swiss/dutch
  players: Player[]; // all participants
  rounds: number; // total number of rounds
  tiebreaks?: string[]; // opaque IDs preserved through serialization
}
```

掷出 `RangeError` 如果少于2名或少于1轮.

#### `pairRound()`

使用注射配对系统生成下一轮的配对. 回返 (单位:千美元) `PairingResult` 与对接和再见.

掷出 `RangeError` 如果联赛结束,或者本轮比赛结束 未记录结果.

#### `clearResult(round, white, black)`

删除先前记录的由圆数和玩家识别的结果 双人 检查两个颜色,所以呼叫者可以通过 `white` 财务报告和审定财务报表 `black` 无论是哪种顺序.

```typescript
tournament.clearResult(1, 'alice', 'carol');
```

清空后,圆形变为不完整并可以重新记录配对 通过 `recordResult`。 。 。 .

掷出 `RangeError` 如果该回合无效或没有匹配结果.

#### `recordResult(game)`

记录本轮比赛的比赛结果.

```typescript
tournament.recordResult({
  black: 'carol',
  result: 1, // 1 = white wins, 0.5 = draw, 0 = black wins
  white: 'alice',
});
```

可选 `kind?: GameKind` 字段对游戏类型进行分类。 提供时, 结果必须与类型一致(见 [GameKind 验证](https://npmcn.com/package/%40echecs/tournament/#readme-gamekind-validation) 页:1.

```typescript
tournament.recordResult({
  black: 'carol',
  kind: 'forfeit-win',
  result: 1,
  white: 'alice',
});
```

掷出 `RangeError` 如果选手在本轮比赛中不匹配任何配对, 或如果 `kind` 财务报告和审定财务报表 `result` 不一致.

#### `updateResult(round, game)`

替换任意回合中的现有结果。 游戏由 `white`编号 :`black` 玩家配对(在两种命令中都选中). 存储游戏保留 它最初的颜色分配.

```typescript
// Change round 1 result from white-wins to draw
tournament.updateResult(1, {
  black: 'carol',
  result: 0.5,
  white: 'alice',
});

// Add a kind to an existing result
tournament.updateResult(1, {
  black: 'carol',
  kind: 'forfeit-win',
  result: 1,
  white: 'alice',
});
```

掷出 `RangeError` 如果回合无效,则没有匹配结果,或 `kind` 财务报告和审定财务报表 `result` 不一致.

#### `standings(tiebreaks?)`

返回玩家按分数排序,并按顺序应用可选的平分符. 每个 bringbreak 函数收到 `(playerId, games, players)` 然后返回一个数字.

```typescript
import { buchholz } from '@echecs/buchholz';
import { sonnebornBerger } from '@echecs/sonneborn-berger';

const table = tournament.standings([buchholz, sonnebornBerger]);
// [{ player: 'alice', rank: 1, score: 2.5, tiebreaks: [7.5, 6.25] }, ...]
```

断接功能符合 :

```typescript
type Tiebreak = (
  playerId: string,
  games: Game[][],
  players: Player[],
) => number;
```

#### `toJSON()` 编号 : `fromJSON()`

串行并恢复联赛状态. 配对系统功能必须是 在恢复时重新提供, 因为功能不能连续运行.

```typescript
const snapshot = tournament.toJSON();
const json = JSON.stringify(snapshot);

// Later...
const restored = Tournament.fromJSON(JSON.parse(json), pair);
const nextRound = restored.pairRound();
```

### `bakuAcceleration(players)`

```typescript
function bakuAcceleration(players: Player[]): AccelerationMethod;
```

返回 a `AccelerationMethod` 执行 [C.04.7 巴库加速](https://handbook.fide.com/chapter/C0407202602)。 。 。 .

将玩家分为两组(GA =上半部,GB = 休息部)并添加虚拟 在第一轮比赛中给GA球员的分数打分,导致更强大的球员 早点见面.

```typescript
import { Tournament, bakuAcceleration } from '@echecs/tournament';
import { pair } from '@echecs/swiss/dutch';

const tournament = new Tournament({
  acceleration: bakuAcceleration(players),
  pairingSystem: pair,
  players,
  rounds: 9,
});
```

虚拟点 :

-   **上半轮加速弹**: GA 玩家获得一分
-   **下半速发**: GA 玩家获得0.5分
-   **在加速回合后**: 0 点
-   **GB 播放器**: 总是0分

虚拟点只影响对等——它们从未被存储在游戏历史中 或反映于地位.

## 兼容对等系统

符合 `PairingSystem` 签名工作 :

```typescript
type PairingSystem = (players: Player[], games: Game[][]) => PairingResult;
```

| 软件包 | 子路径 | FIDE 规则 |
| --- | --- | --- |
| [`@echecs/swiss`](https://www.npmjs.com/package/@echecs/swiss) | `@echecs/swiss/dutch` | 页:1 |
|  | `@echecs/swiss/dubov` | 页:1 |
|  | `@echecs/swiss/burstein` | 第C.04.4.2条 |
|  | `@echecs/swiss/lim` | 页:1 |
|  | `@echecs/swiss/double` | 第C.04.5号决定 |
|  | `@echecs/swiss/team` | 第C.04.6号决定 |
| [`@echecs/round-robin`](https://www.npmjs.com/package/@echecs/round-robin) | `@echecs/round-robin` | 第05条 |

所有子路径导出 a `pair` 符合 `PairingSystem` 签名.

## 类型

```typescript
interface Player {
  id: string;
  rating?: number;
}

interface Game {
  black: string;
  kind?: GameKind; // optional: classifies unplayed rounds
  result: Result;
  white: string;
}

type GameKind =
  | 'forfeit-loss'
  | 'forfeit-win'
  | 'full-bye'
  | 'half-bye'
  | 'pairing-bye'
  | 'zero-bye';

type Result = 0 | 0.5 | 1;

interface Pairing {
  black: string;
  white: string;
}

interface Bye {
  player: string;
}

interface PairingResult {
  byes: Bye[];
  pairings: Pairing[];
}

interface Standing {
  player: string;
  rank: number;
  score: number;
  tiebreaks: number[];
}

type Tiebreak = (
  playerId: string,
  games: Game[][],
  players: Player[],
) => number;

type PairingSystem = (players: Player[], games: Game[][]) => PairingResult;

interface AccelerationMethod {
  virtualPoints: (player: Player, round: number, totalRounds: number) => number;
}

interface TournamentSnapshot {
  currentRound: number;
  games: Game[][];
  players: Player[];
  roundPairings: Record<string, PairingResult>;
  rounds: number;
  tiebreaks?: string[];
}
```

## GameKind 验证

何时 `kind` 以 `recordResult` 或者说 `updateResult`,则 `result` 必须 相匹配的。 匹配的。 投错 `RangeError`。 。 。 .

| `kind` | 需求 `result` | FIDE 参考文件 |
| --- | --- | --- |
| `forfeit-win` | `1` | 第16.2.2条 |
| `forfeit-loss` | `0` | 第16.2.4条 |
| `full-bye` | `1` | —— 说 |
| `half-bye` | `0.5` | 第16.2.5条 |
| `pairing-bye` | `1` | 第16.2.1条 |
| `zero-bye` | `0` | 第16.2.3条 |

何时 `kind` 删除,则接受任何结果.

## 参考文献

-   [C.07 《打猎和打铁条例》](https://handbook.fide.com/chapter/TieBreakRegulations032026)
-   [C.04.7 巴库加速](https://handbook.fide.com/chapter/C0407202602)

## 许可证

麻省理工学院

## 常见问题

### @echecs/tournament 是什么？

任何FIDE配对系统的高级国际象棋锦标赛指挥员 支持瑞士语,圆形robin,和加速格式\. 零从属\.

### 如何安装 @echecs/tournament？

在项目目录运行 npm install @echecs/tournament，或使用 pnpm add / yarn add / bun add。

### @echecs/tournament 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @echecs/tournament 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @echecs/tournament 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @echecs/tournament 可以商用吗？

@echecs/tournament 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @echecs/tournament 的下载量有多少？

根据 npm 官方下载统计，@echecs/tournament 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,139 次，日均约 105 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @echecs/tournament 还在维护吗？

最新版本 3\.3\.0 发布于 2026/05/28（5 个月前）；至今共发布 10 个版本，其中过去 12 个月发布了 10 个；首次发布于 2026/03/22。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

