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 ¶
- func AllocateColor(a, b *swisslib.PlayerState, roundNumber int, isAboveMedian bool, ...) (string, string)
- func CanReceiveColor(p *swisslib.PlayerState, c swisslib.Color) bool
- func ColourExchange(pairs [][2]*swisslib.PlayerState, forbidden map[[2]string]bool, isMaxi bool) [][2]*swisslib.PlayerState
- func ExchangeMatch(players []*swisslib.PlayerState, pairingDownward bool, ...) (pairs [][2]*swisslib.PlayerState, unpaired []*swisslib.PlayerState)
- func IsCompatible(a, b *swisslib.PlayerState, forbidden map[[2]string]bool) bool
- func SelectDownFloater(players []*swisslib.PlayerState, adjacent []*swisslib.PlayerState, ...) *swisslib.PlayerState
- func SelectUpFloater(players []*swisslib.PlayerState, adjacent []*swisslib.PlayerState, ...) *swisslib.PlayerState
- type FloatDirection
- type FloaterEntry
- type FloaterType
- type LimByeSelector
- type Options
- type Pairer
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:
- They have not already played each other.
- They are not in the forbidden pairs list.
- 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):
- Select to equalise due colours in the remaining group (Art. 3.2.2)
- If equal, lowest TPN when pairing downward (Art. 3.2.4)
- Must have compatible opponent in adjacent group (Art. 3.3)
- 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 ¶
ParseOptions converts a generic map[string]any into typed Options.
func (Options) WithDefaults ¶
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 NewFromMap ¶
NewFromMap creates a new Lim pairer from a generic options map.
func (*Pairer) Pair ¶
func (p *Pairer) Pair(_ context.Context, state *chesspairing.TournamentState) (*chesspairing.PairingResult, error)
Pair implements chesspairing.Pairer for the Lim Swiss system.