Start learning free

LESSON 253 OF 573 · FUNCTIONS & CLASSES

Score Keeper in TypeScript: A Class with State and reset()

Practice O(1) Read the full explanation

A game shows each player two numbers: their total, all the points of their turns added up, and their best single turn. Write a class ScoreKeeper that keeps both numbers up to date as the points come in, and can start over.

Implement the class ScoreKeeper:

  • ScoreKeeper() creates a keeper with no points yet.
  • add(points) records the points of one turn.
  • total() returns the sum of all the points added since the keeper was created or last reset.
  • best() returns the highest points of a single add in that time, or 0 if there was no add yet.
  • reset() starts over: afterwards total() and best() both return 0 until the next add.

The input is a list of operations, applied in order to one new ScoreKeeper. The output lists what the total and best calls return, in order. The starter code spells these names the way your language does (in Go and Rust, ScoreKeeper is a struct with methods). Give the fields names that differ from the methods' names: in several languages a field named total would clash with the method total().

 

Example 1:

Input:
    add(10)
    add(25)
    add(5)
    total()
    best()
Output: 40 25
Explanation: 10 + 25 + 5 = 40. The best single turn was the 25.

Example 2:

Input:
    best()
    total()
    add(0)
    best()
    total()
Output: 0 0 0 0
Explanation: Before any add, both numbers are 0. A turn worth 0 points changes neither.

Example 3:

Input:
    add(30)
    add(50)
    total()
    best()
    reset()
    total()
    best()
    add(20)
    best()
    total()
Output: 80 50 0 0 20 20
Explanation: After reset() the keeper starts over. The 50 from before no longer counts,
so after add(20) the best is 20, not 50.

 

Constraints:

  • 0 <= points <= 1000
  • At most 300 operations on one ScoreKeeper.

Note:

Every method should run in O(1) time: add updates the two numbers as each turn comes in, so total and best never need to look back at old turns.

STEP 1 OF 7
    Ctrl + Enter to check

    TYPESCRIPT · FUNCTIONS & CLASSES

    Score Keeper in TypeScript, explained

    Problem overview

    ScoreKeeper follows one player's game. add(points) records one turn, total() returns the sum of all turns, best() returns the highest single turn (0 before any turn), and reset() starts over.

    After add(10), add(25) and add(5), the total is 40 and the best turn is 25. Points are never negative, which is why 0 is a safe starting value for the best.

    Approach

    The tempting design stores every turn in a list and works out the total and the best when asked. That needs memory for every turn and a pass over them for each question. It is simpler to keep just two numbers and update them as each turn arrives. Then every method runs in constant time: add adds to the total and compares with the best, and the other methods only report the fields.

    Step by step

    1. Two fields with starting values. totalPoints and bestPoints both start at 0. Because the fields are initialized where they are declared, the class needs no constructor.
    2. Names that differ from the methods. A field called total would clash with the method total(), so the fields are totalPoints and bestPoints.
    3. add. Add the points to the total with +=. Then, if the points beat the best so far, replace the best. This is the "largest so far" idea applied one value at a time.
    4. total and best. Each returns its field.
    5. reset. Set both fields back to 0, the values a new keeper starts with.

    The solution in TypeScript

    class ScoreKeeper {
        totalPoints: number = 0;
        bestPoints: number = 0;
    
        add(points: number): void {
            this.totalPoints += points;
            if (points > this.bestPoints) {
                this.bestPoints = points;
            }
        }
    
        total(): number {
            return this.totalPoints;
        }
    
        best(): number {
            return this.bestPoints;
        }
    
        reset(): void {
            this.totalPoints = 0;
            this.bestPoints = 0;
        }
    }
    
    • totalPoints: number = 0; declares the field and gives it an initial value. Each new object gets its own copy.
    • void as a return type means the method returns nothing useful: add and reset change the object instead.
    • Strict >. An equal score leaves the best unchanged, which is the same number anyway.

    Using the class

    const k = new ScoreKeeper();
    k.add(10);
    k.add(25);
    k.add(5);
    console.log(k.total(), k.best());
    k.reset();
    console.log(k.total(), k.best());
    k.add(20);
    console.log(k.total(), k.best());
    const other = new ScoreKeeper();
    other.add(7);
    console.log(k.total(), other.total());
    const e = new ScoreKeeper();
    e.add(0);
    console.log(e.best(), e.total());
    
    40 25
    0 0
    20 20
    20 7
    0 0
    

    After reset() the earlier 25 no longer counts, so after add(20) the best is 20. The two keepers are independent: other has its own total. A turn worth 0 changes nothing.

    Tracing the state

    Because the class keeps only two numbers, you can follow its whole life by watching them. Starting from a new keeper, with the fields shown as total and best:

    Calltotalbest
    add(30)3030
    add(50)8050
    add(20)10050
    reset()00
    add(20)2020

    The 20 that comes after the reset becomes the best, even though the best was 50 before it: the old 50 is gone. The total always grows by the points of the turn, while the best changes only when a turn beats it. Two equal turns, such as add(7) twice on a new keeper, give a total of 14 and a best of 7.

    Why not store the turns

    A list of turns would answer the same questions, but best() would have to scan the whole list every time, and the list would grow with every turn. Keeping a running summary is a common pattern: when a question can be answered from a few numbers that are easy to update, keep those numbers and drop the history. The limit of 300 operations in the lesson is small, but the habit matters for larger programs.

    Another way: set the fields in a constructor

    Field initializers are not the only choice. You can declare the fields without values and set them in a constructor, which behaves the same:

    class ScoreKeeper {
        totalPoints: number;
        bestPoints: number;
        constructor() { this.totalPoints = 0; this.bestPoints = 0; }
        add(points: number): void {
            this.totalPoints += points;
            if (points > this.bestPoints) { this.bestPoints = points; }
        }
        total(): number { return this.totalPoints; }
        best(): number { return this.bestPoints; }
    }
    const k = new ScoreKeeper();
    k.add(3);
    k.add(9);
    k.add(4);
    console.log(k.total(), k.best());
    

    This prints 16 9. The initializer form is shorter when every field starts with a fixed value, and the lesson uses it because there is nothing else for a constructor to do. Note that reset() repeats the same two zeros: the starting values and the reset values must always agree.

    Edge cases and common mistakes

    • Forgetting to reset the best. Resetting only the total would leave an old best behind. Both fields must go back to 0.
    • Replacing the best on every add. Without the if, best() would return the latest turn, not the highest.
    • Calling best() before any add. It returns 0 because the field starts at 0.
    • Forgetting this.. Inside a method, totalPoints += points does not refer to the field; always write this.totalPoints.

    Key points

    • Keep a running summary instead of the full history when a few numbers answer every question.
    • A field initializer gives each new object its own starting value, so no constructor is needed.
    • Name fields differently from methods: totalPoints next to total().
    • The best so far changes only when a bigger value arrives, and a reset must restore every field.
    • All four methods run in constant time.
    Keep going with TypeScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free