lim

package
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: 4 Imported by: 0

Documentation

Overview

Package lim implements the Lim Swiss pairing system (C.04.4.3).

The Lim system (approved 1987, amended through 1999) is a Swiss variant that processes scoregroups in median-first order and uses exchange-based matching within scoregroups. It has four floater types (A-D) with priority ordering and median-aware colour allocation.

Key differences from Dutch/Burstein/Dubov:

  • Scoregroups processed: highest -> above median, then lowest -> up to median, median last
  • Exchange-based matching (Art. 4), not Blossom or transposition matching
  • Four floater types (A-D) with priority ordering (Art. 3.9)
  • Compatibility: no 3 consecutive same colour, no 3+ colour imbalance (Art. 2.1)
  • Colour allocation with median-aware tiebreaking (Art. 5.4)
  • Optional "Maxi-tournament" 100-point rating constraint (Art. 3.2.3)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllocateColor

func AllocateColor(a, b *swisslib.PlayerState, roundNumber int, isAboveMedian bool, topSeedColor *swisslib.Color) (string, string)

AllocateColor decides which player gets White and which gets Black for a specific pairing, implementing Art. 5 with median-aware tiebreaking.

Parameters:

  • a, b: the two players in the pairing
  • roundNumber: 1-based round number (used to determine odd/even)
  • isAboveMedian: true if the scoregroup is at or above the median (affects Art. 5.4)
  • topSeedColor: override for round 1 top seed colour (nil = White default)

Returns (whiteID, blackID).

func CanReceiveColor

func CanReceiveColor(p *swisslib.PlayerState, c swisslib.Color) bool

CanReceiveColor returns true if the player can legally be assigned the given colour without violating Art. 2.1 (compatibility statement):

  • No player shall have the same colour in three successive rounds (Art. 5.1.1)
  • No player shall have three more of one colour than the other (Art. 5.1.2)

func ColourExchange

func ColourExchange(pairs [][2]*swisslib.PlayerState, forbidden map[[2]string]bool, isMaxi bool) [][2]*swisslib.PlayerState

ColourExchange performs the Art. 5.2 second scrutiny: after ExchangeMatch has established legal pairings, this pass swaps opponents between pairs to give each player, if possible, the alternating and equalising colour.

In Maxi-tournaments (Art. 5.7), an exchange of opponents is only allowed if the ratings of the exchanged players differ by 100 points or less.

func ExchangeMatch

func ExchangeMatch(players []*swisslib.PlayerState, pairingDownward bool, forbidden map[[2]string]bool) (pairs [][2]*swisslib.PlayerState, unpaired []*swisslib.PlayerState)

ExchangeMatch pairs players in a scoregroup using the Lim exchange algorithm (Art. 4). Players are split into top half (S1) and bottom half (S2), with initial proposed pairings S1[i] vs S2[i]. When a pairing is incompatible, the S2 player is exchanged per Art. 4.2.

Parameters:

  • players: sorted by TPN ascending within the scoregroup
  • pairingDownward: true when pairing above the median (scrutiny starts from highest-numbered in top half); false when pairing upward
  • forbidden: forbidden pairs map (nil if none)

Returns:

  • pairs: successfully matched pairs [top, bottom]
  • unpaired: players that could not be paired (must float)

func IsCompatible

func IsCompatible(a, b *swisslib.PlayerState, forbidden map[[2]string]bool) bool

IsCompatible returns true if two players can be legally paired per Art. 2.1. Two players are compatible if:

  1. They have not already played each other.
  2. They are not in the forbidden pairs list.
  3. There exists at least one legal colour assignment (a=W,b=B or a=B,b=W) that doesn't violate the consecutive or imbalance constraints for either player.

func SelectDownFloater

func SelectDownFloater(players []*swisslib.PlayerState, adjacent []*swisslib.PlayerState, forbidden map[[2]string]bool, floatedIDs map[string]bool, maxiTournament bool) *swisslib.PlayerState

SelectDownFloater selects the player to float down from a scoregroup per Art. 3.2-3.4.

Rules (Art. 3.2):

  1. Select to equalise due colours in the remaining group (Art. 3.2.2)
  2. If equal, lowest TPN when pairing downward (Art. 3.2.4)
  3. Must have compatible opponent in adjacent group (Art. 3.3)
  4. Minimise floater disadvantage type (Art. 3.9.2)

The floatedIDs set tracks players that have already been floated from a previous scoregroup; these are classified as "already floated" (Type A/B) per Art. 3.9.

Returns nil if no valid floater can be selected.

func SelectUpFloater

func SelectUpFloater(players []*swisslib.PlayerState, adjacent []*swisslib.PlayerState, forbidden map[[2]string]bool, floatedIDs map[string]bool, maxiTournament bool) *swisslib.PlayerState

SelectUpFloater selects the player to float up from a scoregroup per Art. 3.2, 3.4.

When pairing upwards, the highest numbered player (highest TPN) is chosen. The floatedIDs set tracks players already floated from a previous scoregroup.

Types

type FloatDirection

type FloatDirection int

FloatDirection indicates whether a player floated down or up.

const (
	FloatDown FloatDirection = iota
	FloatUp
)

type FloaterEntry

type FloaterEntry struct {
	Player      *swisslib.PlayerState
	Direction   FloatDirection
	SourceScore float64 // score of the scoregroup they floated from
}

FloaterEntry tracks a floater with metadata about where they came from.

func PairFloaters

func PairFloaters(floaters []FloaterEntry, targets []*swisslib.PlayerState, isUpperHalf bool, isMaxi bool, forbidden map[[2]string]bool) (pairs [][2]*swisslib.PlayerState, remainingFloaters []FloaterEntry, remainingTargets []*swisslib.PlayerState)

PairFloaters pairs incoming floaters with targets from the current scoregroup per Art. 3.6-3.8, before exchange matching.

Parameters:

  • floaters: players that floated into this scoregroup from other groups
  • targets: the native players of this scoregroup (the floater opponents)
  • isUpperHalf: true if this scoregroup is at or above the median (affects DF/UF priority)
  • isMaxi: true if maxi-tournament mode (100-point rating constraint on exchanges)
  • forbidden: forbidden pairs map

Returns:

  • pairs: floater-target pairs formed
  • remainingFloaters: floaters that could not be paired (will float further)
  • remainingTargets: targets not consumed by floater pairing (go into ExchangeMatch)

type FloaterType

type FloaterType int

FloaterType classifies a floater per Art. 3.9. Lower values indicate more disadvantage (worse).

const (
	FloaterTypeA FloaterType = iota // already floated + no compatible opponent in adjacent
	FloaterTypeB                    // already floated + has compatible opponent in adjacent
	FloaterTypeC                    // not floated + no compatible opponent in adjacent
	FloaterTypeD                    // not floated + has compatible opponent in adjacent
)

func ClassifyFloater

func ClassifyFloater(p *swisslib.PlayerState, alreadyFloated bool, adjacentPlayers []*swisslib.PlayerState, forbidden map[[2]string]bool) FloaterType

ClassifyFloater determines the floater type for a player per Art. 3.9.

Parameters:

  • p: the player being classified
  • alreadyFloated: true if the player was already floated into this scoregroup
  • adjacentPlayers: players in the adjacent scoregroup (the one p would float to)
  • forbidden: forbidden pairs map (nil if none)

func (FloaterType) String

func (ft FloaterType) String() string

String returns the floater type name.

type LimByeSelector

type LimByeSelector struct{}

LimByeSelector selects the bye player per Lim system rules (Art. 1.1): the player with the lowest rank (highest TPN) in the lowest scoregroup, who has not already received a PAB (Basic Rules Art. 3).

func (LimByeSelector) SelectBye

func (s LimByeSelector) SelectBye(players []*swisslib.PlayerState) *swisslib.PlayerState

SelectBye returns the player to receive the bye, or nil if all have already received one.

type Options

type Options struct {
	// TopSeedColor forces the top seed's color in round 1.
	// Values: "auto" (default), "white", "black".
	TopSeedColor *string `json:"topSeedColor,omitempty"`

	// ForbiddenPairs lists player ID pairs that must not be paired together.
	ForbiddenPairs [][]string `json:"forbiddenPairs,omitempty"`

	// MaxiTournament enables the 100-point rating constraint for exchanges
	// and floater selection (Art. 3.2.3, 3.8, 5.7).
	// Default: false.
	MaxiTournament *bool `json:"maxiTournament,omitempty"`
}

Options holds Lim-specific pairing configuration. All pointer fields use nil = use default.

func ParseOptions

func ParseOptions(m map[string]any) Options

ParseOptions converts a generic map[string]any into typed Options.

func (Options) WithDefaults

func (o Options) WithDefaults() Options

WithDefaults returns a copy of options with defaults applied for nil fields.

type Pairer

type Pairer struct {
	// contains filtered or unexported fields
}

Pairer implements the chesspairing.Pairer interface for the Lim Swiss system.

func New

func New(opts Options) *Pairer

New creates a new Lim pairer with the given options.

func NewFromMap

func NewFromMap(m map[string]any) *Pairer

NewFromMap creates a new Lim pairer from a generic options map.

func (*Pairer) Pair

Pair implements chesspairing.Pairer for the Lim Swiss system.

Jump to

Keyboard shortcuts

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