export const TIME_CONTROLS = [ { id: "none", label: "no clock", base: 0, inc: 0 }, { id: "1+0", label: "1 + 0 bullet", base: 60, inc: 0 }, { id: "3+2", label: "3 + 2 blitz", base: 180, inc: 2 }, { id: "5+0", label: "5 + 0 blitz", base: 300, inc: 0 }, { id: "10+0", label: "10 + 0 rapid", base: 600, inc: 0 }, { id: "15+10", label: "15 + 10 rapid", base: 900, inc: 10 }, { id: "30+0", label: "30 + 0 classical", base: 1800, inc: 0 }, ]; export function timeControl(id, custom) { if (id === "custom" && custom) { return { id: "custom", label: "custom", base: custom.base, inc: custom.inc }; } return TIME_CONTROLS.find((t) => t.id === id) ?? TIME_CONTROLS[0]; } export class Clock { constructor(tc, onTick, onFlag) { this.tc = tc; this.onTick = onTick; this.onFlag = onFlag; this.turn = null; this.last = 0; this.flagged = null; this.tick = () => { if (!this.turn || this.flagged) return; const now = performance.now(); this.remaining[this.turn] -= now - this.last; this.last = now; if (this.remaining[this.turn] <= 0) { this.remaining[this.turn] = 0; this.flagged = this.turn; this.turn = null; this.stop(); this.onTick(this.remaining.w, this.remaining.b); this.onFlag(this.flagged); return; } this.onTick(this.remaining.w, this.remaining.b); }; this.remaining = { w: tc.base * 1000, b: tc.base * 1000 }; this.incMs = tc.inc * 1000; } get enabled() { return this.tc.base > 0; } start(side) { if (!this.enabled) return; this.turn = side; this.last = performance.now(); this.run(); } // The side that just moved gets the increment; the other side's clock starts running. press(mover) { if (!this.enabled || this.flagged) return; this.remaining[mover] += this.incMs; this.turn = mover === "w" ? "b" : "w"; this.last = performance.now(); this.onTick(this.remaining.w, this.remaining.b); this.run(); } pause() { this.stop(); this.turn = null; } stop() { if (this.timer) { clearInterval(this.timer); this.timer = undefined; } } run() { if (!this.timer) this.timer = setInterval(this.tick, 100); } } export function formatTime(ms) { if (ms < 0) ms = 0; if (ms < 10000) return (Math.floor(ms / 100) / 10).toFixed(1); const s = Math.ceil(ms / 1000); const m = Math.floor(s / 60); return m + ":" + String(s % 60).padStart(2, "0"); }