Sprint Planner
Problem
Design SprintPlanner to create assigned tasks and time-bounded sprints, schedule each task into at most one sprint, enforce task workflow and sprint limits, and answer task views. Multiple threads share one planner instance.
Requirements
- Sprint creation.
createSprintcreates an unused sprint ID. A duplicate ID returnsfalsewithout changing the existing sprint. - Task creation.
createTaskcreates an unused task ID for the supplied assignee with initial statusTODO. A duplicate ID returnsfalsewithout changing the existing task. - Sprint membership.
addTaskschedules an existing unscheduled task in an existing sprint only while that sprint has fewer than 20 tasks. A task can belong to at most one sprint.removeTaskunschedules a member but preserves its task record and status. Missing objects, repeated addition, a full sprint, and missing or mismatched membership returnfalsewithout changing state. - Task workflow.
changeStatusapplies onlyTODOtoINPROGRESS,INPROGRESStoTODO, andINPROGRESStoDONEfor a task in the named sprint. Every other transition, missing object, or membership mismatch returnsfalsewithout changing status. - Work-in-progress limit. One assignee may have at most two
INPROGRESStasks in one sprint. Both changing a member toINPROGRESSand adding a preservedINPROGRESStask enforce this limit and returnfalsewithout mutation when it would be exceeded. - Assigned-task view.
getAssignedTasksreturns the current members for one assignee in the named sprint, ordered by their original task-creation positions. A missing sprint or no match produces an empty list. - Delayed-task view.
getDelayedTasksreturns the named sprint's currentTODOandINPROGRESSmembers in original task-creation order only whencurrentDayis greater than the sprint's end day. A missing sprint or a day on or before the end day produces an empty list. - Concurrent edits. Every public call is linearizable on the shared planner. Limit checks and accepted mutations form one atomic action, and queries observe one complete state, so neither cap can be exceeded by concurrent calls.
API
| Signature | Returns | Behavior |
|---|---|---|
SprintPlanner() | Not applicable | Creates an empty planner. |
createSprint(sprintId: string, startDay: integer, endDay: integer) | boolean | Creates a new sprint or returns false for a duplicate ID. |
createTask(taskId: string, taskType: string, assigneeId: string) | boolean | Creates a new assigned, unscheduled TODO task or returns false for a duplicate ID. |
addTask(sprintId: string, taskId: string) | boolean | Schedules an eligible task or returns false without mutation. |
removeTask(sprintId: string, taskId: string) | boolean | Unschedules a current member or returns false without mutation. |
changeStatus(sprintId: string, taskId: string, newStatus: string) | boolean | Applies one allowed transition or returns false without mutation. |
getAssignedTasks(sprintId: string, assigneeId: string) | string[] | Returns matching current members in task-creation order. |
getDelayedTasks(sprintId: string, currentDay: integer) | string[] | Returns incomplete current members after the sprint ends, in task-creation order. |
Examples
| Step | Operation | Result |
|---|---|---|
| 1 | createSprint("S1", 10, 14) | true |
| 2 | createTask("T1", "STORY", "Asha") | true |
| 3 | createTask("T2", "BUG", "Asha") | true |
| 4 | addTask("S1", "T1") | true |
| 5 | addTask("S1", "T2") | true |
| 6 | changeStatus("S1", "T1", "INPROGRESS") | true |
| 7 | getAssignedTasks("S1", "Asha") | ["T1", "T2"] |
| 8 | getDelayedTasks("S1", 14) | [] |
| 9 | getDelayedTasks("S1", 15) | ["T1", "T2"] |
| 10 | changeStatus("S1", "T1", "DONE") | true |
| 11 | getDelayedTasks("S1", 15) | ["T2"] |
Constraints
- IDs are nonempty, case-sensitive strings of at most 64 Unicode scalar values.
taskTypeisSTORY,FEATURE, orBUG;newStatusisTODO,INPROGRESS, orDONE.0 <= startDay <= endDay <= 1000000000000and0 <= currentDay <= 1000000000000.- One testcase contains at most 10,000 sprints, 100,000 tasks, and 200,000 method calls.
- A sprint contains at most 20 tasks, and one assignee has at most two
INPROGRESStasks in one sprint.
Notes
Calls made by one thread take effect in that thread's action order. Calls from different threads may take effect in any order that places each call at one point between its invocation and response. Methods may briefly wait for internal synchronization, but they do not wait for capacity or status changes, and no fairness, retry, cancellation, or wake-up behavior is required.