import Toybox.Lang; // Teams const US = 0; const THEM = 1; // Court quadrants (your team = bottom half) enum { QUAD_BOTTOM_RIGHT, // US, deuce (right) QUAD_BOTTOM_LEFT, // US, ad (left) QUAD_UPPER_LEFT, // THEM, deuce (their right -> screen left) QUAD_UPPER_RIGHT // THEM, ad (their left -> screen right) } class PadelMatch { private var _rules as RulesConfig; private var _points as Array; // raw point count per team in the current game private var _games as Array; // games won in the current set private var _sets as Array; // sets won in the match private var _server as Number; // team serving the current game private var _inTiebreak as Boolean; private var _tbPoints as Array; private var _tbFirstServer as Number; // team that served the tiebreak's first point private var _matchOver as Boolean; private var _winner as Number; // US / THEM / -1 private var _history as Array; private const POINT_LABELS = ["0", "15", "30", "40"]; public function initialize(rules as RulesConfig) { _rules = rules; _points = [0, 0]; _games = [0, 0]; _sets = [0, 0]; _server = US; _inTiebreak = false; _tbPoints = [0, 0]; _tbFirstServer = US; _matchOver = false; _winner = -1; _history = []; } // ---- public API ---- public function pointTo(team as Number) as Void { if (_matchOver) { return; } _pushHistory(); if (_inTiebreak) { _tbPoints[team] += 1; _resolveTiebreak(team); } else { _points[team] += 1; _resolveGame(team); } } public function undo() as Void { var n = _history.size(); if (n == 0) { return; } var s = _history[n - 1]; _history = _history.slice(0, n - 1); _points = s["points"] as Array; _games = s["games"] as Array; _sets = s["sets"] as Array; _server = s["server"] as Number; _inTiebreak = s["inTiebreak"] as Boolean; _tbPoints = s["tbPoints"] as Array; _tbFirstServer = s["tbFirstServer"] as Number; _matchOver = s["matchOver"] as Boolean; _winner = s["winner"] as Number; } public function canSetServer() as Boolean { return _history.size() == 0 && !_matchOver; } public function toggleStartingServer() as Void { if (canSetServer()) { _server = 1 - _server; } } public function servingQuadrant() as Number { var team; var pointsPlayed; if (_inTiebreak) { pointsPlayed = _tbPoints[0] + _tbPoints[1]; team = _tiebreakServer(pointsPlayed); } else { pointsPlayed = _points[0] + _points[1]; team = _server; } var isDeuce = (pointsPlayed % 2) == 0; return _quadrantFor(team, isDeuce); } public function pointLabel(team as Number) as String { if (_inTiebreak) { return _tbPoints[team].toString(); } var a = _points[team]; var b = _points[1 - team]; if (!_rules.goldenPoint && a == 4 && b == 3) { return "AD"; } if (a >= 4) { return "40"; } // safety; game normally ends before display return POINT_LABELS[a]; } public function games(team as Number) as Number { return _games[team]; } public function sets(team as Number) as Number { return _sets[team]; } public function server() as Number { return _server; } public function isInTiebreak() as Boolean { return _inTiebreak; } public function isMatchOver() as Boolean { return _matchOver; } public function winner() as Number { return _winner; } public function tiebreakPoints(team as Number) as Number { return _tbPoints[team]; } // ---- internals ---- private function _resolveGame(team as Number) as Void { var other = 1 - team; var a = _points[team]; var b = _points[other]; if (_rules.goldenPoint) { if (a >= 4) { _winGame(team); } } else { if (a >= 4 && (a - b) >= 2) { _winGame(team); } else if (a >= 4 && b >= 4) { _points[team] = 3; _points[other] = 3; } // both past 40 -> deuce } } private function _winGame(team as Number) as Void { _games[team] += 1; _points = [0, 0]; _server = 1 - _server; _resolveSet(team); } private function _resolveSet(team as Number) as Void { var other = 1 - team; var a = _games[team]; var b = _games[other]; if (a >= _rules.gamesPerSet && (a - b) >= 2) { _winSet(team); } else if (_rules.tiebreakEnabled && a == _rules.gamesPerSet && b == _rules.gamesPerSet) { _inTiebreak = true; _tbPoints = [0, 0]; _tbFirstServer = _server; // team due to serve after the 12th game } } private function _resolveTiebreak(team as Number) as Void { var other = 1 - team; var a = _tbPoints[team]; var b = _tbPoints[other]; if (a >= _rules.tiebreakTarget && (a - b) >= 2) { _games[team] += 1; // e.g. 7-6 _winSet(team); } } private function _winSet(team as Number) as Void { _sets[team] += 1; _games = [0, 0]; if (_inTiebreak) { _inTiebreak = false; _server = 1 - _tbFirstServer; // tiebreak receiver serves first next set } _resolveMatch(team); } private function _resolveMatch(team as Number) as Void { if (_sets[team] >= _rules.setsToWin) { _matchOver = true; _winner = team; } } private function _tiebreakServer(pointsPlayed as Number) as Number { var offset = ((pointsPlayed + 1) / 2) % 2; // integer division return (offset == 0) ? _tbFirstServer : (1 - _tbFirstServer); } private function _quadrantFor(team as Number, isDeuce as Boolean) as Number { if (team == US) { return isDeuce ? QUAD_BOTTOM_RIGHT : QUAD_BOTTOM_LEFT; } return isDeuce ? QUAD_UPPER_LEFT : QUAD_UPPER_RIGHT; } private function _pushHistory() as Void { _history.add({ "points" => [_points[0], _points[1]], "games" => [_games[0], _games[1]], "sets" => [_sets[0], _sets[1]], "server" => _server, "inTiebreak" => _inTiebreak, "tbPoints" => [_tbPoints[0], _tbPoints[1]], "tbFirstServer" => _tbFirstServer, "matchOver" => _matchOver, "winner" => _winner }); } }