Start learning free

LESSON 253 OF 573 · FUNCTIONS & CLASSES

Score Keeper Class in Kotlin: Total and Best

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

    KOTLIN · FUNCTIONS & CLASSES

    Score Keeper in Kotlin, explained

    Problem overview

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

    • add(points) records one turn.
    • total() returns the sum of all points added since the keeper was created or last reset.
    • best() returns the highest single add in that time, or 0 if nothing was added.
    • reset() starts over: both numbers go back to 0.

    After add(10), add(25) and add(5), the total is 40 and the best is 25.

    Approach

    You could store every turn in a list and compute the sum and the maximum on demand. That works, but every question would have to look at all the turns. Instead, keep just two numbers and update them as each turn arrives. Then total and best only report a stored value, and every method takes constant time.

    The two numbers are properties of the object: each ScoreKeeper has its own pair. Their names must differ from the method names total and best, so the lesson uses totalPoints and bestPoints.

    Step by step

    1. Declare the properties. Both are var, because add and reset change them, and both start at 0. Zero is a safe start for the best: before any add the answer must be 0, and every score is at least 0.
    2. add the points to the total. This happens on every call, whatever the points are.
    3. Update the best. If points is greater than bestPoints, store it. This is the "largest so far" idea applied one value at a time. An equal score leaves the best unchanged, which is the same number anyway.
    4. total and best just return the stored values.
    5. reset sets both properties back to 0, the values a new keeper starts with. The old best no longer counts: after a reset and add(20), the best is 20, even if it was 50 before.

    The solution in Kotlin

    class ScoreKeeper {
        var totalPoints: Int = 0
        var bestPoints: Int = 0
    
        fun add(points: Int) {
            totalPoints += points
            if (points > bestPoints) {
                bestPoints = points
            }
        }
    
        fun total(): Int {
            return totalPoints
        }
    
        fun best(): Int {
            return bestPoints
        }
    
        fun reset() {
            totalPoints = 0
            bestPoints = 0
        }
    }
    

    A property declared in the class body needs an initial value (here 0), and every new object gets its own copy. add and reset return nothing, so they have no return type; Kotlin treats that as Unit.

    Using the class

    fun main() {
        val s = ScoreKeeper()
        println("${s.total()} ${s.best()}")
        s.add(30)
        s.add(50)
        println("${s.total()} ${s.best()}")
        s.reset()
        println("${s.total()} ${s.best()}")
        s.add(20)
        println("${s.best()} ${s.total()}")
    }
    

    It prints:

    0 0
    80 50
    0 0
    20 20
    

    Why two numbers are enough

    The first idea many learners have is to store every turn in a list, because total and best sound like questions about a list. The list does work, but it has a price: it grows with each add, and each total() or best() call walks over all of it. With up to 300 operations that is harmless, but the habit is worth dropping. Ask what the answer needs to know about the past. The sum needs only the sum so far, and the maximum needs only the maximum so far. Everything else about the old turns can be forgotten the moment each turn is folded into the two numbers.

    That is also why reset is so short. There is no list to empty, only two numbers to put back to the values a new keeper starts with. After it, the object cannot be told apart from a fresh one.

    Each object has its own numbers

    Properties belong to the object, not to the class. Two keepers never share their totals:

    fun main() {
        val ann = ScoreKeeper()
        val bob = ScoreKeeper()
        ann.add(10)
        bob.add(7)
        bob.add(3)
        println("${ann.total()} ${ann.best()}")
        println("${bob.total()} ${bob.best()}")
    }
    

    It prints:

    10 10
    10 7
    

    Both totals are 10, but the best turns differ: 10 for Ann and 7 for Bob.

    Common mistakes

    • Forgetting to reset the best. Resetting only the total leaves the old best in place, so after a reset best() would still report the old best.
    • Starting the best at a huge negative number. It isn't needed here, and it would make best() return the wrong value before any add.
    • Recomputing from scratch. Don't keep a list of turns; two running numbers are enough.
    • Naming a property total. Kotlin would let a property and a function share a name, but the lesson's names keep the two apart and make the code easier to read.

    Edge cases to try

    • Nothing added yet. total() and best() must both return 0. Because the properties start at 0, this works without any special code.
    • A turn worth 0 points. add(0) changes neither number: the total grows by 0, and 0 is not greater than the best. The best stays 0 if it was 0.
    • Repeated equal scores. After add(40) twice, the total is 80 and the best is 40. The strict > doesn't matter here, because replacing 40 with 40 changes nothing.
    • Reset on a fresh keeper. Calling reset() before any add is harmless: it sets two zeros to zero.
    • Reset in the middle. Only turns added after the reset count, for both numbers.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free