Skip to main content

Draws & Pairings

Generate tee-time pairings for competition rounds using various draw methods.

Draw types

TypeDescriptionUse Case
RANDOMRandom assignmentSocial events, casual comps
HANDICAP_ORDERGrouped by handicapClub competitions
SEEDEDManual seedingChampionships, knockouts
TEE_TIME_ORDERBased on existing bookingsPre-booked competitions

Generating draws

Basic draw

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'RANDOM',
});

With configuration

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'HANDICAP_ORDER',
groupSize: 4,
startTime: new Date('2025-12-15T07:00:00'),
intervalMinutes: 8,
});

Shotgun start

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'RANDOM',
groupSize: 4,
startingHoles: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
});

Draw input

interface GenerateDrawInput {
roundId: string;
drawType: 'RANDOM' | 'HANDICAP_ORDER' | 'SEEDED' | 'TEE_TIME_ORDER';
groupSize?: number; // Default: 4
startTime?: Date; // First tee time
intervalMinutes?: number; // Default: 8
startingHoles?: number[]; // For shotgun starts
}

Draw methods

Random

Entries shuffled randomly into groups.

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'RANDOM',
groupSize: 4,
startTime: new Date('2025-12-15T07:00:00'),
intervalMinutes: 8,
});

Result:

07:00 - Group 1: Player D, Player A, Player G, Player K
07:08 - Group 2: Player C, Player F, Player B, Player H
07:16 - Group 3: Player E, Player J, Player I, Player L

Handicap order

Entries sorted by handicap index, then grouped.

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'HANDICAP_ORDER',
groupSize: 4,
});

Options:

  • Low handicaps first (default)
  • High handicaps first (reverse)
  • Mixed (snake draft)

Result (low first):

07:00 - Group 1: +2.1, 3.4, 5.2, 6.8
07:08 - Group 2: 7.1, 8.3, 9.0, 10.2
07:16 - Group 3: 11.5, 12.3, 14.1, 15.8

Seeded

Manual seed order preserved.

// Pre-set seed order
await drawsService.setSeedOrder('round-123', [
'entry-1', // #1 seed
'entry-2', // #2 seed
'entry-3', // #3 seed
// ...
]);

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'SEEDED',
groupSize: 4,
});

Use cases:

  • Club championships (defending champion first)
  • Qualifying rounds (top qualifiers together)
  • Sponsored groups

Tee time order

Use existing tee sheet bookings as the draw.

await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'TEE_TIME_ORDER',
});

Behavior:

  1. Find all entries linked to tee time slots
  2. Order by slot time
  3. Create pairings matching existing groups

Pairing data

interface Pairing {
id: string;
roundId: string;
pairingNumber: number; // 1, 2, 3...
teeTime: Date;
startingHole: number; // 1-18 (for shotgun)
entries: CompetitionEntry[];
}

Start types

Configure on round creation:

Tee times

Sequential start from hole 1.

{
startType: 'TEE_TIMES',
// Draw generates sequential times
}

Shotgun

All groups start simultaneously on different holes.

{
startType: 'SHOTGUN',
shotgunTime: new Date('2025-12-15T08:00:00'),
}

Draw assigns starting holes:

08:00 - Group 1 → Hole 1
08:00 - Group 2 → Hole 2
08:00 - Group 3 → Hole 3
...
08:00 - Group 18 → Hole 18

Mixed

Combination of tee times and shotgun holes.

{
startType: 'MIXED',
startingHoles: [1, 10], // Two-tee start
}

Group sizes

SizeFormatUse Case
2TwosomesMatchplay, fast play
3ThreesomesOdd numbers, faster rounds
4FoursomesStandard club play

Handling odd numbers

When entries don't divide evenly:

// 14 entries with groupSize: 4
// Result: 3 groups of 4, 1 group of 2

Interval timing

Standard intervals:

Course TypeIntervalReasoning
Standard8 minutesNormal pace
Championship10 minutesMore setup time
Fast play7 minutesQuick turnaround
2-tee start8 minutesBoth tees

Manual pairings

Create specific pairings:

await drawsService.createPairing({
roundId: 'round-123',
pairingNumber: 1,
teeTime: new Date('2025-12-15T07:00:00'),
startingHole: 1,
entryIds: ['entry-a', 'entry-b', 'entry-c', 'entry-d'],
});

Swap players

await drawsService.swapEntries({
roundId: 'round-123',
entryId1: 'entry-a', // From pairing 1
entryId2: 'entry-e', // From pairing 3
});

Move player

await drawsService.moveEntry({
roundId: 'round-123',
entryId: 'entry-a',
toPairingNumber: 5,
});

Late entries

Add entries after draw generated:

// Option 1: Add to existing group with space
await drawsService.addToExistingPairing({
roundId: 'round-123',
entryId: 'late-entry',
pairingNumber: 12, // Has 3 players
});

// Option 2: Create new pairing at end
await drawsService.addNewPairing({
roundId: 'round-123',
entryIds: ['late-1', 'late-2'],
teeTime: new Date('2025-12-15T10:00:00'),
});

Draw output

Get draw for round

const draw = await drawsService.getDraw('round-123');

// Returns:
{
roundId: 'round-123',
startType: 'TEE_TIMES',
pairings: [
{
pairingNumber: 1,
teeTime: '2025-12-15T07:00:00',
startingHole: 1,
entries: [
{ id: 'entry-1', playerName: 'John Smith', handicap: 5.2 },
{ id: 'entry-2', playerName: 'Jane Doe', handicap: 12.4 },
// ...
],
},
// ...
],
}

Export draw

// CSV export
const csv = await drawsService.exportDraw('round-123', 'csv');

// PDF (if configured)
const pdf = await drawsService.exportDraw('round-123', 'pdf');

Clear and regenerate

// Clear existing draw
await drawsService.clearDraw('round-123');

// Regenerate with different method
await drawsService.generateDraw({
roundId: 'round-123',
drawType: 'HANDICAP_ORDER',
groupSize: 3,
});

Note: Clearing draw removes pairings but preserves entries.