chesspairing

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 13, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

README

chesspairing

Chess tournament pairing, scoring, and tiebreaking algorithms in pure Go.

Eight pairing systems, three scoring engines, twenty-five tiebreakers — zero external dependencies.

What it does

Chesspairing generates pairings, computes standings, and calculates tiebreakers for chess tournaments. It implements all six FIDE-approved Swiss pairing systems, plus Keizer and round-robin. Any pairing system can be combined with any scoring system — Swiss pairing with Keizer scoring, round-robin with football scoring, whatever the tournament needs.

Everything operates on in-memory data structures. No I/O, no database, no network calls. Build a TournamentState, pass it to an engine, get results back.

Pairing systems
System FIDE Regulation Description
Dutch C.04.3 Global Blossom matching with 21 quality criteria
Burstein C.04.4.2 Seeding rounds with opposition-index re-ranking
Dubov C.04.4.1 ARO-equalization with transposition matching
Lim C.04.4.3 Median-first processing with exchange matching
Double-Swiss C.04.5 Lexicographic bracket pairing
Team Swiss C.04.6 Team-level pairing with configurable colour preference
Keizer Top-down by Keizer score with repeat avoidance
Round-Robin C.05 FIDE Berger tables with multi-cycle support
Scoring systems

Standard (1–½–0), Keizer (iterative convergence), and Football (3–1–0), all with configurable point values for wins, draws, byes, forfeits, and absences.

Tiebreakers

Twenty-five implementations covering all FIDE-recognized methods: Buchholz (five variants), Sonneborn-Berger, Direct Encounter, Performance Rating, Progressive Score, Koya, ARO, and more. Self-registering registry — look up any tiebreaker by string ID.

Use as a Go library

go get github.com/gnutterts/chesspairing
pairer := dutch.New(dutch.Options{})
result, err := pairer.Pair(ctx, state)

scorer := standard.New(standard.Options{})
scores, err := scorer.Score(ctx, state)

tb, _ := tiebreaker.Get("buchholz-cut1")
values, err := tb.Compute(ctx, state, scores)

Three interfaces (Pairer, Scorer, TieBreaker) with a shared TournamentState input. Safe for concurrent use when each goroutine supplies its own state.

Use as a CLI tool

The chesspairing command reads FIDE Tournament Report Files (TRF16 and TRF-2026) and produces pairings, standings, and validation reports:

chesspairing pair tournament.trf
chesspairing standings tournament.trf
chesspairing validate tournament.trf

Output in five formats: plain list, wide tabular, board view, XML, and JSON. A legacy mode provides drop-in compatibility with bbpPairings and JaVaFo command-line conventions.

Documentation

Full documentation is available at gnutterts.github.io/chesspairing — including getting started guides, API reference, algorithm deep-dives with mathematical notation, and FIDE regulation mappings.

Testing

go test -race -count=1 ./...

1325 tests across 19 packages, including golden file comparisons against bbpPairings and JaVaFo reference output, plus fuzz testing for the TRF parser.

Acknowledgements

This project builds on the work of two chess pairing engines that came before it:

  • bbpPairings by Bierema Boyz Programming — a C++ implementation of the FIDE Dutch system using Blossom matching. The Dutch pairer in chesspairing follows the same architectural approach (global Blossom matching with completability pre-matching for bye determination), and bbpPairings' own test cases are included in the test suite for cross-validation.

  • JaVaFo by Roberto Ricca — a Java implementation that served as the FIDE reference pairer. Seven golden test scenarios from JaVaFo 2.2 are used to verify pairing correctness, and the CLI's legacy mode accepts JaVaFo command-line conventions.

The FIDE Handbook (handbook.fide.com) is the primary specification reference for all pairing and tiebreaking algorithms.

License

Licensed under the Apache License, Version 2.0. See LICENSE for the full text.

Disclaimer

This software is provided as-is, without warranty of any kind. Parts of this software were developed with the assistance of AI tools. While the code is tested against reference implementations and verified by over 1300 tests, errors may exist that testing has not uncovered. In a chess tournament context this means:

  • Pairings may violate FIDE regulations, requiring correction mid-tournament.
  • Scores may be calculated incorrectly, affecting standings and prizes.
  • Tiebreakers may produce wrong values, changing final rankings among equal-scored players.

If you use this software for rated or official events, verify the output independently. The author accepts no liability for errors in pairings, scores, or rankings.

Documentation

Overview

Package chesspairing provides chess tournament pairing, scoring, and tiebreaking engines in pure Go. It implements FIDE-approved Swiss pairing systems (Dutch C.04.3, Burstein C.04.4.2, Dubov C.04.4.1, Lim C.04.4.3, Double-Swiss C.04.5, and Team Swiss C.04.6), Keizer pairing, and round-robin pairing, along with standard, Keizer, and football scoring systems and 25 tiebreaker algorithms.

Engines operate on in-memory data structures (TournamentState, PlayerEntry, RoundData) and have no I/O, database, or network dependencies. They are safe for concurrent use when each goroutine supplies its own TournamentState.

Context: all engine interface methods accept context.Context as their first parameter for API compatibility with service layers. However, since all computation is CPU-bound and in-memory (no I/O, no network), the context is not currently checked for cancellation. Callers should still pass a context for forward compatibility.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BoolPtr

func BoolPtr(v bool) *bool

BoolPtr returns a pointer to v.

func DefaultTiebreakers

func DefaultTiebreakers(system PairingSystem) []string

DefaultTiebreakers returns the FIDE-recommended tiebreaker order for the given pairing system.

func Float64Ptr

func Float64Ptr(v float64) *float64

Float64Ptr returns a pointer to v. Used by options packages to set pointer-nil-pattern fields.

func GetBool

func GetBool(m map[string]any, key string) (bool, bool)

GetBool extracts a bool from a map. Returns (false, false) if the key is missing or has an incompatible type.

func GetFloat64

func GetFloat64(m map[string]any, key string) (float64, bool)

GetFloat64 extracts a float64 from a map, handling float64, int, and int64 value types. Returns (0, false) if the key is missing or has an incompatible type.

func GetInt

func GetInt(m map[string]any, key string) (int, bool)

GetInt extracts an int from a map, handling int, int64, and float64 value types. Returns (0, false) if the key is missing or has an incompatible type.

func GetString

func GetString(m map[string]any, key string) (string, bool)

GetString extracts a string from a map. Returns ("", false) if the key is missing or has an incompatible type.

func IntPtr

func IntPtr(v int) *int

IntPtr returns a pointer to v.

func StringPtr

func StringPtr(v string) *string

StringPtr returns a pointer to v.

Types

type ByeEntry

type ByeEntry struct {
	PlayerID string
	Type     ByeType
}

ByeEntry records a bye assignment with its type.

type ByeType

type ByeType int

ByeType classifies how a bye is scored.

const (
	ByePAB            ByeType = iota // Pairing-Allocated Bye (full point, TRF "F")
	ByeHalf                          // Half-point bye (TRF "H")
	ByeZero                          // Zero-point bye (TRF "Z")
	ByeAbsent                        // Absent/unpaired, unexcused (TRF "U")
	ByeExcused                       // Excused absence (notified in advance)
	ByeClubCommitment                // Club commitment (absent for interclub team duty)
)

func (ByeType) IsValid

func (bt ByeType) IsValid() bool

IsValid returns true if the bye type is a recognized value.

func (ByeType) String

func (bt ByeType) String() string

String returns the human-readable name of the bye type.

type GameData

type GameData struct {
	WhiteID   string
	BlackID   string
	Result    GameResult
	IsForfeit bool
}

GameData is a single game result for engine consumption.

type GamePairing

type GamePairing struct {
	Board   int
	WhiteID string
	BlackID string
}

GamePairing is a single pairing assignment for a round.

type GameResult

type GameResult string

GameResult represents the outcome of a chess game.

const (
	ResultWhiteWins        GameResult = "1-0"
	ResultBlackWins        GameResult = "0-1"
	ResultDraw             GameResult = "0.5-0.5"
	ResultPending          GameResult = "*"
	ResultForfeitWhiteWins GameResult = "1-0f"
	ResultForfeitBlackWins GameResult = "0-1f"
	ResultDoubleForfeit    GameResult = "0-0f"
)

func (GameResult) IsDoubleForfeit

func (gr GameResult) IsDoubleForfeit() bool

IsDoubleForfeit returns true if both players forfeited. Double-forfeit games are excluded from both pairing and scoring — the game never happened.

func (GameResult) IsForfeit

func (gr GameResult) IsForfeit() bool

IsForfeit returns true if the result is a forfeit (single or double). Forfeit games are excluded from pairing history — players can be re-paired within the same period.

func (GameResult) IsRecordable

func (gr GameResult) IsRecordable() bool

IsRecordable returns true if the game result is a valid result that can be recorded by a user. ResultPending ("*") is valid but not recordable — it is the initial state set by the system when a game is created.

func (GameResult) IsValid

func (gr GameResult) IsValid() bool

IsValid returns true if the game result is a recognized value.

type NamedValue

type NamedValue struct {
	ID    string  `json:"id"`
	Name  string  `json:"name"`
	Value float64 `json:"value"`
}

NamedValue pairs a tiebreaker identifier with its computed value.

type Pairer

type Pairer interface {
	Pair(ctx context.Context, state *TournamentState) (*PairingResult, error)
}

Pairer generates pairings for a round given tournament state.

type PairingConfig

type PairingConfig struct {
	System  PairingSystem
	Options map[string]any
}

PairingConfig holds per-period pairing settings.

type PairingResult

type PairingResult struct {
	Pairings []GamePairing
	Byes     []ByeEntry
	Notes    []string
}

PairingResult is returned by a Pairer.

type PairingSystem

type PairingSystem string

PairingSystem identifies which pairing algorithm to use.

const (
	PairingDutch       PairingSystem = "dutch"
	PairingBurstein    PairingSystem = "burstein"
	PairingDubov       PairingSystem = "dubov"
	PairingLim         PairingSystem = "lim"
	PairingDoubleSwiss PairingSystem = "doubleswiss"
	PairingTeam        PairingSystem = "team"
	PairingKeizer      PairingSystem = "keizer"
	PairingRoundRobin  PairingSystem = "roundrobin"
)

func (PairingSystem) IsValid

func (p PairingSystem) IsValid() bool

IsValid returns true if the pairing system is a recognized value.

type PlayerEntry

type PlayerEntry struct {
	ID          string
	DisplayName string
	Rating      int
	Active      bool
	Federation  string // FIDE federation code (e.g. "NED", "USA", "IND"). Empty if unknown.
	FideID      string // FIDE player ID number. Empty if unknown.
	Title       string // FIDE title code (GM, IM, FM, WGM, WIM, WFM, CM, WCM). Empty if untitled.
	Sex         string // "m" or "w". Empty if unknown.
	BirthDate   string // Birth date as YYYY/MM/DD. Empty if unknown.
	JoinedRound int    // Round number the player joined. 0 or 1 means original player (joined from the start).
}

PlayerEntry represents a player for engine purposes.

type PlayerScore

type PlayerScore struct {
	PlayerID string
	Score    float64
	Rank     int
}

PlayerScore holds a player's calculated score from the scoring engine.

type ResultContext

type ResultContext struct {
	OpponentRank        int
	OpponentValueNumber int
	PlayerRank          int
	PlayerValueNumber   int
	IsBye               bool
	IsAbsent            bool
	IsForfeit           bool
}

ResultContext provides additional information needed by scoring systems when calculating points for a specific game result.

type RoundData

type RoundData struct {
	Number int
	Games  []GameData
	Byes   []ByeEntry
}

RoundData contains all games for a completed round.

type Scorer

type Scorer interface {
	Score(ctx context.Context, state *TournamentState) ([]PlayerScore, error)
	PointsForResult(result GameResult, rctx ResultContext) float64
}

Scorer calculates standings from game results.

type ScoringConfig

type ScoringConfig struct {
	System      ScoringSystem
	Tiebreakers []string
	Options     map[string]any
}

ScoringConfig holds tournament-wide scoring settings.

type ScoringSystem

type ScoringSystem string

ScoringSystem identifies which scoring algorithm to use.

const (
	ScoringStandard ScoringSystem = "standard"
	ScoringKeizer   ScoringSystem = "keizer"
	ScoringFootball ScoringSystem = "football"
)

func (ScoringSystem) IsValid

func (s ScoringSystem) IsValid() bool

IsValid returns true if the scoring system is a recognized value.

type Standing

type Standing struct {
	Rank        int          `json:"rank"`
	PlayerID    string       `json:"playerId"`
	DisplayName string       `json:"displayName"`
	Score       float64      `json:"score"`
	TieBreakers []NamedValue `json:"tieBreakers"`
	GamesPlayed int          `json:"gamesPlayed"`
	Wins        int          `json:"wins"`
	Draws       int          `json:"draws"`
	Losses      int          `json:"losses"`
}

Standing is the final ranked output combining score and tiebreakers.

type TieBreakValue

type TieBreakValue struct {
	PlayerID string
	Value    float64
}

TieBreakValue is a single tiebreak computation for one player.

type TieBreaker

type TieBreaker interface {
	ID() string
	Name() string
	Compute(ctx context.Context, state *TournamentState, scores []PlayerScore) ([]TieBreakValue, error)
}

TieBreaker computes a single tiebreak value for each player.

type TournamentInfo

type TournamentInfo struct {
	Name          string
	City          string
	Federation    string // Organizing federation code
	StartDate     string // YYYY/MM/DD
	EndDate       string // YYYY/MM/DD
	ChiefArbiter  string
	DeputyArbiter string
	TimeControl   string   // Allotted time description
	RoundDates    []string // YYYY/MM/DD per round
}

TournamentInfo holds tournament metadata for display and TRF round-trip fidelity. Engines ignore this struct; it is populated from TRF header lines and written back when serializing to TRF.

type TournamentState

type TournamentState struct {
	Players       []PlayerEntry
	Rounds        []RoundData
	CurrentRound  int
	PairingConfig PairingConfig
	ScoringConfig ScoringConfig
	Info          TournamentInfo // Tournament metadata. Zero value if not set.
}

TournamentState is the read-only snapshot of a tournament passed to engines. The caller constructs this from their data source before calling any engine method. Engines never perform I/O directly.

func (*TournamentState) Validate

func (s *TournamentState) Validate() error

Validate checks structural invariants of the tournament state. Returns an error describing the first problem found, or nil if valid.

Directories

Path Synopsis
algorithm
blossom
Package blossom implements Edmonds' maximum weight matching algorithm for general graphs.
Package blossom implements Edmonds' maximum weight matching algorithm for general graphs.
varma
Package varma implements the Varma Tables pre-processing number assignment scheme for round-robin chess tournaments (FIDE C.05 Annex 2).
Package varma implements the Varma Tables pre-processing number assignment scheme for round-robin chess tournaments (FIDE C.05 Annex 2).
cmd
chesspairing command
cmd/chesspairing/check.go
cmd/chesspairing/check.go
pairing
burstein
Package burstein implements the Burstein Swiss pairing system (C.04.4.2).
Package burstein implements the Burstein Swiss pairing system (C.04.4.2).
doubleswiss
Package doubleswiss implements the FIDE Double-Swiss pairing system (C.04.5).
Package doubleswiss implements the FIDE Double-Swiss pairing system (C.04.5).
dubov
pairing/dubov/dubov.go
pairing/dubov/dubov.go
dutch
Package dutch implements the FIDE Dutch Swiss pairing system (C.04.3).
Package dutch implements the FIDE Dutch Swiss pairing system (C.04.3).
keizer
Package keizer implements Keizer-style pairing for chess tournaments.
Package keizer implements Keizer-style pairing for chess tournaments.
lexswiss
Package lexswiss provides shared data structures and algorithms for lexicographic Swiss pairing systems.
Package lexswiss provides shared data structures and algorithms for lexicographic Swiss pairing systems.
lim
Package lim implements the Lim Swiss pairing system (C.04.4.3).
Package lim implements the Lim Swiss pairing system (C.04.4.3).
roundrobin
Package roundrobin implements round-robin pairing for chess tournaments.
Package roundrobin implements round-robin pairing for chess tournaments.
swisslib
Package swisslib provides shared data structures and algorithms for Swiss pairing engines.
Package swisslib provides shared data structures and algorithms for Swiss pairing engines.
team
Package team implements the FIDE Swiss Team Pairing System (C.04.6).
Package team implements the FIDE Swiss Team Pairing System (C.04.6).
scoring
football
Package football implements football-style scoring (3-1-0) for chess tournaments.
Package football implements football-style scoring (3-1-0) for chess tournaments.
keizer
Package keizer implements Keizer point scoring for chess tournaments.
Package keizer implements Keizer point scoring for chess tournaments.
standard
Package standard implements standard chess scoring (1-½-0).
Package standard implements standard chess scoring (1-½-0).
Package tiebreaker implements chess tournament tiebreakers.
Package tiebreaker implements chess tournament tiebreakers.
Package trf implements reading and writing of TRF16 (FIDE Tournament Report File) documents.
Package trf implements reading and writing of TRF16 (FIDE Tournament Report File) documents.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL