Skip to main content

drawMatic

DrawMatic is a probabilistic pairing engine for AD_HOC draws. It generates fair, balanced matchUp pairings round-by-round, with opponent avoidance, team-member avoidance, and optional rating-driven level-based play. For a deep dive into the algorithm, scoring analytics, and pressure scores, see the DrawMatic concept page.

When to Use DrawMatic

DrawMatic is designed for events where participants are paired fresh each round rather than following a bracket:

  • Social and recreational events — round-robin-style play without a fixed bracket
  • D3 college tennis — teams arrive and depart on different days; rosters change between rounds
  • Training sessions — coach wants to control skill-level matching
  • Level-based play — participants paired by rating with dynamic adjustments after each round
  • Flex-round formats — any scenario where the number of rounds isn't known in advance

Creating a DrawMatic Draw

DrawMatic operates on AD_HOC draw types. There are two creation paths:

Automated (DrawMatic generates pairings during draw creation)

const { drawDefinition } = engine.generateDrawDefinition({
drawType: 'AD_HOC',
automated: true,
roundsCount: 3,
drawMatic: {
dynamicRatings: true,
scaleName: 'WTN',
scaleAccessor: 'wtnRating',
},
eventId,
});

This generates a draw with 3 pre-paired rounds in one call. Useful when all participants and ratings are known up front.

Manual (empty rounds, pair later)

// 1. Generate an empty AD_HOC draw
const { drawDefinition } = engine.generateDrawDefinition({
drawType: 'AD_HOC',
automated: false,
eventId,
});

// 2. Add the draw to the tournament
engine.addDrawDefinition({ eventId, drawDefinition });

// 3. Generate pairings on demand
const result = engine.drawMatic({
drawId: drawDefinition.drawId,
roundsCount: 1,
dynamicRatings: true,
scaleName: 'WTN',
});

// 4. Add the generated matchUps to the draw
engine.addAdHocMatchUps({
drawId: drawDefinition.drawId,
matchUps: result.matchUps,
});

This is the typical workflow for interactive events where rounds are generated one at a time.

API Reference

engine.drawMatic(params)

Generates one or more rounds of pairings for an existing AD_HOC draw.

Parameters

ParameterTypeRequiredDefaultDescription
drawIdstringYesDraw to generate pairings for
roundsCountnumberYesNumber of rounds to generate (max: participants - 1)
participantIdsstring[]Noall entriesRestrict which participants appear in generated rounds
structureIdstringNoauto-detectedTarget structure (defaults to latest AD_HOC structure with matchUps)
matchUpIdsstring[]Noauto-generatedPre-assigned UUIDs for generated matchUps
eventTypeEventTypeUnionNofrom eventOverride event type (e.g., force SINGLES ratings in DOUBLES events)

Rating Configuration

ParameterTypeDefaultDescription
scaleNamestringRating system to use: 'WTN', 'UTR', 'ELO', or any custom scale
scaleAccessorstringProperty path to extract numeric value from scale objects (e.g., 'wtnRating')
dynamicRatingsbooleanfalseCalculate updated ratings from prior round results
refreshDynamicbooleanfalseRecalculate dynamic ratings from scratch instead of incrementally
adHocRatingsRecord<string, number>Seed ratings by participantId (overrides scale values)
updateParticipantRatingsbooleanfalsePersist modifiedScaleValues to participant records

Pairing Controls

ParameterTypeDefaultDescription
encounterValuenumber100Cost penalty for repeat matchUps (higher = stronger avoidance)
sameTeamValuenumber100Cost penalty for same-team pairings
saltednumber | boolean0.5Randomization factor for candidate selection (0 = deterministic)
minimizeDeltabooleanfalseForce minimum rating gap in pairings (good for first rounds)
restrictEntryStatusbooleanfalseOnly pair participants with STRUCTURE_SELECTED entry status
restrictRoundsCountbooleantrueEnforce maximum rounds limit
enableDoubleRobinbooleanfalseAllow rounds up to (participants - 1) * 2

Algorithm Tuning

ParameterTypeDefaultDescription
maxIterationsnumber5000Maximum candidate solutions to evaluate
generateMatchUpsbooleantrueWhen false, returns only participantIdPairings without creating matchUp objects

Return Value

{
matchUps: MatchUp[]; // Generated matchUps ready for addAdHocMatchUps
roundResults: [{
modifiedScaleValues: Record<string, number>; // Updated ratings (if dynamicRatings)
participantIdPairings: string[][]; // The generated pairings
roundNumber: number;
matchUpsCount: number;
iterations: number; // Algorithm iterations used
candidatesCount: number; // Candidates evaluated
maxDelta: number; // Largest rating gap in selected pairings
maxDiff: number; // Largest value differential
}];
}

Round-by-Round Workflow

The typical interactive workflow:

// Round 1: generate pairings
const r1 = engine.drawMatic({
drawId,
roundsCount: 1,
dynamicRatings: true,
scaleName: 'WTN',
});

// Add matchUps to the draw
engine.addAdHocMatchUps({ drawId, matchUps: r1.matchUps });

// Persist dynamic ratings
for (const rr of r1.roundResults ?? []) {
if (rr.modifiedScaleValues) {
engine.addDynamicRatings({
modifiedScaleValues: rr.modifiedScaleValues,
replacePriorValues: true,
});
}
}

// ... score round 1 matchUps ...

// Round 2: ratings auto-update from completed matchUps
const r2 = engine.drawMatic({
drawId,
roundsCount: 1,
dynamicRatings: true,
scaleName: 'WTN',
});

engine.addAdHocMatchUps({ drawId, matchUps: r2.matchUps });

// Continue as needed...

Dynamic Ratings

When dynamicRatings: true, DrawMatic calculates updated ratings after each round:

  1. Completed matchUps from the previous round are processed
  2. An ELO-style calculation produces new ratings
  3. Ratings are stored as {scaleName}.DYNAMIC scale values (e.g., WTN.DYNAMIC)
  4. These feed into the next round's pairing algorithm

Use refreshDynamic: true to recalculate from scratch (ignoring previously persisted dynamic values). This is useful if matchUp results were corrected after ratings were generated.

Participant Management

Flexible Rosters

The participantIds parameter controls which participants appear in each round. This enables:

  • Late arrivals — add new participants in later rounds
  • Early departures — exclude participants who have left
  • Partial rounds — generate pairings for a subset of participants
// Round 1: full roster
engine.drawMatic({ drawId, roundsCount: 1, participantIds: allParticipants });

// Round 2: two players departed, one arrived
engine.drawMatic({ drawId, roundsCount: 1, participantIds: updatedRoster });

Odd Numbers

When the participant count is odd, one participant receives a bye each round. The algorithm distributes byes to minimize repeat byes across rounds.

MethodPurpose
generateDrawMaticRoundLow-level single-round generator (called internally by drawMatic)
addAdHocMatchUpsPersist generated matchUps to draw structure
deleteAdHocMatchUpsRemove matchUps from a structure
generateAdHocMatchUpsCreate empty matchUp shells for manual pairing
generateAdHocRoundsCreate empty rounds without DrawMatic pairing
shiftAdHocRoundsReorder rounds within a structure
swapAdHocRoundsSwap matchUps between rounds
adHocPositionSwapSwap participants within a matchUp
addDynamicRatingsPersist dynamic rating updates to participant records

Analytics

DrawMatic-generated events support two post-play analytics:

  • Pressure Scores (PS#) — per-participant quality-of-performance metric that accounts for opponent strength. See Pressure Scores.
  • Predictive Accuracy (Profile) — measures how well ratings predicted match outcomes, classifying each matchUp as COMPETITIVE, ROUTINE, or DECISIVE. See Predictive Accuracy.