Tentative next-up for bracket matches waiting on live courts; per-court score keeper QR codes
Matches whose opponent comes from a live match now show in the queue and under courts as 'X vs winner on Court 2 · ready ~time', which is what double elimination needed. Score keeper access is a QR per court on the desk plus a printable page; the copy-link button is gone. Release 0.4.1. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01MB7nCCAscYsb3zzkT6LHZi
This commit is contained in:
+18
-2
@@ -102,7 +102,7 @@ export class CourtEngine {
|
||||
const m = c.matchId ? this.t.match(c.matchId) : null;
|
||||
return { court: c.number, status: c.status, match: m ? this._matchView(m) : null };
|
||||
}),
|
||||
upNext: q.slice(0, 3).map(x => ({ ...this._matchView(x.match), court: x.court, etaMin: Math.round(x.eta / MIN) })),
|
||||
upNext: q.slice(0, 3).map(x => ({ ...this._matchView(x.match), court: x.court, etaMin: Math.round(x.eta / MIN), tentative: !!x.tentative, aFrom: x.aFrom ?? null, bFrom: x.bFrom ?? null })),
|
||||
avgMatchMin: Math.round(this.avgMatchMs() / MIN),
|
||||
};
|
||||
}
|
||||
@@ -121,6 +121,22 @@ export class CourtEngine {
|
||||
sims[0].freeAt = start + this.avgMatchMs();
|
||||
teamFree.set(m.teamA, sims[0].freeAt); teamFree.set(m.teamB, sims[0].freeAt);
|
||||
}
|
||||
// Bracket matches still waiting on a live match (one or both sides TBD) get a tentative slot too,
|
||||
// so late in a bracket the board still says "Net Gains vs winner on Court 2 · ready ~2:10".
|
||||
const decided = x => ['final', 'forfeit', 'bye', 'void'].includes(x.status);
|
||||
const liveCourt = x => this.courts.find(c => c.matchId === x.id)?.number ?? null;
|
||||
for (const m of this.t.matches) {
|
||||
if (m.status !== 'pending' || m.conditional || m.stage === 'pool' || (m.teamA && m.teamB)) continue;
|
||||
const feeders = this.t.matches.filter(x => x.feeds === m.id || x.loserFeeds === m.id);
|
||||
if (!feeders.length || !feeders.every(x => decided(x) || x.status === 'live') || !feeders.some(x => x.status === 'live')) continue;
|
||||
const side = (which) => { const f = feeders.find(x => (x.feeds === m.id && x.feedsSide === which) || (x.loserFeeds === m.id && x.loserFeedsSide === which)); return f && f.status === 'live' ? { court: liveCourt(f), loser: f.loserFeeds === m.id } : null; };
|
||||
const waitOn = feeders.filter(x => x.status === 'live').map(x => this._expectedFinish(this.courts.find(c => c.matchId === x.id)));
|
||||
sims.sort((a, b) => a.freeAt - b.freeAt);
|
||||
const ready = Math.max(sims[0].freeAt, ...waitOn, m.teamA ? teamFree.get(m.teamA) ?? 0 : 0, m.teamB ? teamFree.get(m.teamB) ?? 0 : 0);
|
||||
const start = ready + this.changeoverMs;
|
||||
out.push({ match: m, court: sims[0].number, eta: start - this.now(), tentative: true, aFrom: m.teamA ? null : side('A'), bFrom: m.teamB ? null : side('B') });
|
||||
sims[0].freeAt = start + this.avgMatchMs();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -173,7 +189,7 @@ export class CourtEngine {
|
||||
_freeCourt(c) { c.matchId = null; c.startedAt = null; c.freeAt = null; }
|
||||
|
||||
_refreshOnDeck() {
|
||||
const q = this.queue();
|
||||
const q = this.queue().filter(x => !x.tentative);
|
||||
const deck = q.slice(0, this.courts.filter(c => c.status === 'open').length);
|
||||
const deckIds = new Set(deck.map(x => x.match.id));
|
||||
for (const m of this.t.matches) if (m.status === 'on_deck' && !deckIds.has(m.id)) { m.status = 'pending'; m.court = null; }
|
||||
|
||||
Reference in New Issue
Block a user