Skip to main content

Scoring Engine Overview

The ScoringEngine is a stateful engine for point-by-point match scoring: a pure reducer over a typed timeline behind a stateful facade, with built-in undo/redo, event handlers, and multi-sport format support. Its rules are specified in the scoring engine spec.

When to Use ScoringEngine vs scoreGovernor​

Use CaseRecommended
Track a live match point-by-pointScoringEngine
Undo/redo scoring actionsScoringEngine
React to game/set/match completion eventsScoringEngine
Manage substitutions and lineupsScoringEngine
One-off score parsing or formattingscoreGovernor
Bulk score operations in tournament contextscoreGovernor

Key Capabilities​

  • Multi-level scoring — Points, games, sets, and segments can all be added through a unified timeline
  • Undo/redo — Full undo/redo stack across all input modes (points, games, sets, segments)
  • Event handlers — Callbacks for point, game completion, set completion, match completion, match tie, undo, redo, and reset
  • Multi-sport format support — matchUpFormat codes covering many sports
  • CODES-compliant state — Internal state is a standard CODES MatchUp object
  • Mixed-mode input — Combine point-level, game-level, and set-level input in the same match
  • competitionFormat integration — support for penalty types, timer profiles, substitution rules, and more
  • Persistence — Save and restore complete engine state including redo stack and lineup snapshots

Basic Usage​

import { scoreGovernor } from 'tods-competition-factory';
const { ScoringEngine } = scoreGovernor;

// Create engine with standard tennis format
const engine = new ScoringEngine({ matchUpFormat: 'SET3-S:6/TB7' });

// Add points — two conventions are supported:
// 0-based: winner: 0 (side 1) or 1 (side 2)
// 1-based: winningSide: 1 (side 1) or 2 (side 2)
engine.addPoint({ winner: 0 }); // 0-based: side 1 wins
engine.addPoint({ winningSide: 1 }); // 1-based: same thing
engine.addPoint({ winner: 0 });
engine.addPoint({ winner: 0 }); // Side 1 wins first game

// Query score
const scoreboard = engine.getScoreboard(); // '1-0'
const pointCount = engine.getPointCount(); // 4

// Undo last point
engine.undo();
engine.getScoreboard(); // '0-0 (40-0)'

// Redo the undone point
engine.redo();
engine.getScoreboard(); // '1-0'

// Check match completion
engine.isComplete(); // false
engine.getWinner(); // undefined

Architecture​

The score is a pure function of the configuration and the timeline: state = reduce(config, timeline).

┌──────────────────────────┐
│ ScoringEngine │ Stateful facade: the timeline, the redo stack,
│ (undo/redo, events, │ lineUps, events and the record's identity
│ format introspection) │
├──────────────────────────┤
│ reducer (step/reduce) │ One rule module per segment kind, service,
│ │ completion and the views
├──────────────────────────┤
│ CODES MatchUp record │ Written from the reduced state
└──────────────────────────┘

Every action is offered to the reducer, which refuses, ignores or records it; recorded actions go on the timeline in history.entries. Undo, redo and the corrections are timeline operations followed by a replay, so a saved record always replays to the same score. The direct functions on scoreGovernor (addPoint, getScore, …) are a separate, older surface: the engine does not score through them.

Constructor Options​

interface ScoringEngineOptions {
matchUpFormat?: string; // Format code (default: 'SET3-S:6/TB7')
matchUpId?: string; // Optional matchUp identifier
isDoubles?: boolean; // Doubles match (default: false)
competitionFormat?: competitionFormat; // Full competition format profile
pointMultipliers?: PointMultiplier[]; // Point value multipliers
eventHandlers?: ScoringEventHandlers; // Event callbacks
}
tip

If you provide a competitionFormat, the engine extracts matchUpFormat, pointMultipliers, and other rules automatically. You only need to pass matchUpFormat separately if you want to override the format from the competition profile.

Direct governor calls have their own ownership contracts: scoreGovernor.addPoint mutates the supplied matchUp. Use the engine facade when you need managed state and undo/redo.