Problemseasonal competition standings

Session: Sign in to solve

Solution.txt

Seasonal Competition Standings

Problem

A competition operator records results throughout one season and may later receive score corrections. Design SeasonStandings to keep registered teams, current match results, rankings, and team histories consistent under fixed scoring and tie-break rules. Calls are sequential on one instance.

Requirements

  • Fixed rules. Construction fixes the win, draw, and loss awards and selects either score-difference or wins as the tie-break policy.
  • Registered teams. A valid team ID is registered once before use. Registration order is permanent and is the final ranking tie-break.
  • Single contribution. A match ID keeps one ordered home-and-away pairing and contributes exactly once to both teams' current aggregates.
  • Safe corrections. Repeating the same pairing and scores returns unchanged. New scores for the stored pairing return corrected, atomically replace both old contributions, and keep the match's history position.
  • Configured aggregates. Current results determine all counters, scores, and configured points exactly. For each team, played = wins + draws + losses and scoreDifference = scoreFor - scoreAgainst. Across the season, total played is twice the match count and total score for equals total score against; every aggregate except score difference is nonnegative.
  • Deterministic ranking. The selected policy and registration fallback produce one strict order with global one-based ranks.
  • Detached pages. Queries do not change state, and each standings page is stable while season state is unchanged. Changing a returned collection or record where the language permits it cannot change stored state or another snapshot.
  • Ordered history. A team's history shows its current perspective on each match in first-submission order. A correction replaces the existing entry without moving it.
  • Atomic failures. Every rejected call reports the specified error code and changes no state, registration position, or first-submission position.

API

integer is a signed 64-bit integer. Identifiers are case-sensitive ASCII strings matching [A-Za-z0-9][A-Za-z0-9_-]{0,31}. No public argument may be null.

SignatureReturnsBehavior
SeasonStandings(winPoints: integer, drawPoints: integer, lossPoints: integer, tieBreakPolicy: string)Not applicableCreates an empty season. Each point value must be from 0 through 100. The policy must be exactly score-difference or wins.
registerTeam(teamId: string)voidRegisters a new team at the next permanent registration position.
recordMatch(matchId: string, homeTeamId: string, awayTeamId: string, homeScore: integer, awayScore: integer)stringCreates or updates a match and returns created, corrected, or unchanged. Scores must be from 0 through 1,000,000.
getStandings(offset: integer, limit: integer)Standing[]Returns at most limit records from zero-based offset. Offset must be from 0 through 10,000 and limit from 1 through 100. An offset at or beyond the team count returns an empty array.
getTeamHistory(teamId: string)MatchHistoryEntry[]Returns the registered team's current history, or an empty array when it has no matches.

Standing has fields in this order:

FieldTypeMeaning
rankintegerOne-based position in the complete current ordering.
teamIdstringRegistered team ID.
playedintegerNumber of current contributing matches.
winsintegerCurrent wins.
drawsintegerCurrent draws.
lossesintegerCurrent losses.
scoreForintegerSum of this team's current scores.
scoreAgainstintegerSum of opponents' current scores.
scoreDifferenceintegerscoreFor - scoreAgainst.
pointsintegerSum of configured awards for current outcomes.

MatchHistoryEntry has fields in this order:

FieldTypeMeaning
matchIdstringMatch ID.
opponentTeamIdstringThe other team.
venuestringhome or away from this team's perspective.
scoreForintegerThis team's corrected current score.
scoreAgainstintegerThe opponent's corrected current score.
outcomestringwin, draw, or loss.
pointsAwardedintegerThis match's current contribution to this team's points.

For a new match ID, the ordered pair must contain two distinct registered teams. The match receives the next first-submission position and contributes once to both teams. For an existing match ID, the supplied ordered pair must exactly match the stored pair. A correction first removes both old contributions, then applies both new contributions as one atomic change.

A greater score awards winPoints to that team and lossPoints to the other. Equal scores award drawPoints to both teams. The three configured awards need not be ordered or distinct.

Standings comparisons are descending except for registration order:

PolicyComparison keys in order
score-differencepoints, score difference, score for, registration order ascending
winspoints, wins, score difference, score for, registration order ascending

A semantic failure raises or throws the runtime's standings error with one observable code. Message text is not observable.

CallChecks in precedence order
ConstructorwinPoints, drawPoints, and lossPoints ranges, then policy. Any failure is INVALID_ARGUMENT.
registerTeamID syntax gives INVALID_ARGUMENT; an existing ID gives DUPLICATE_TEAM; a full 10,000-team season gives LIMIT_EXCEEDED.
recordMatchmatchId, homeTeamId, and awayTeamId syntax; homeScore and awayScore ranges; equal team IDs; missing home team; missing away team; changed ordered pair for an existing match; new match beyond 100,000. The corresponding codes are INVALID_ARGUMENT, INVALID_ARGUMENT, TEAM_NOT_FOUND, TEAM_NOT_FOUND, MATCH_TEAMS_MISMATCH, and LIMIT_EXCEEDED.
getStandingsInvalid offset, then invalid limit, each gives INVALID_ARGUMENT.
getTeamHistoryInvalid ID syntax gives INVALID_ARGUMENT; an unregistered valid ID gives TEAM_NOT_FOUND.

Equal team IDs give INVALID_ARGUMENT even when the ID is unregistered. A correction remains allowed when the match limit is full.

Examples

With SeasonStandings(3, 1, 0, "score-difference"), register ALPHA, BETA, and GAMMA in that order.

StepOperationResult
1recordMatch("m1", "ALPHA", "BETA", 2, 1)created
2Repeat step 1unchanged
3recordMatch("m2", "GAMMA", "ALPHA", 2, 0)created
4getStandings(0, 3)GAMMA rank 1 with 3 points and difference 2; ALPHA rank 2 with 3 points and difference -1; BETA rank 3 with 0 points and difference -1.
5recordMatch("m1", "ALPHA", "BETA", 3, 3)corrected
6getStandings(0, 3)GAMMA rank 1 with 3 points; BETA rank 2 with 1 point and difference 0; ALPHA rank 3 with 1 point and difference -2.
7getStandings(1, 1)One BETA snapshot whose global rank is 2.
8getTeamHistory("ALPHA")m1 first as a home draw, then m2 as an away loss.

For equal points, policy wins compares wins before score difference. Policy score-difference compares score difference directly after points.

Constraints

  • At most 10,000 teams and 100,000 distinct matches exist in one season.
  • At most 200,000 public method calls occur after construction.
  • Point values are from 0 through 100, and match scores are from 0 through 1,000,000.
  • Each identifier contains 1 through 32 characters under the declared ASCII grammar.
  • Aggregate scores, score differences, and points require signed 64-bit arithmetic.
  • One standings call returns at most 100 records. One history call may return every current match involving the team.

Notes

Calls are sequential in total action order. Implementations need no synchronization, waiting, or blocking. Python exposes StandingsError.code; Java and C++ expose StandingsException through getCode() and code() respectively. Python returns lists, Java returns List values, and C++ returns std::vector values. Returned field names and serialized values match the language-neutral fields above.

PRIVATE WORKSPACE

Checking your session…

The statement is public. The editor, editorial, submissions, and saved work are private.