Exercism - High Scores
This post shows you how to get High Scores exercise of Exercism.
Preparation
Before we click on our next exercise, let’s see what concepts of DART we need to consider

So we need to use the following concepts.
Lists
Lists are ordered collections of items. You can access elements by index, get the last element, and perform various operations on them.
void main() {
List<int> scores = [30, 50, 20, 70];
// Access last element
print(scores.last); // 70
// Access by index
print(scores[0]); // 30
// Get length
print(scores.length); // 4
}
Reduce Method
The reduce method combines all elements of a collection into a single value using a provided function. It’s useful for finding maximum or minimum values.
void main() {
List<int> numbers = [3, 1, 4, 1, 5, 9];
// Find maximum
int max = numbers.reduce((a, b) => a > b ? a : b);
print(max); // 9
// Find minimum
int min = numbers.reduce((a, b) => a < b ? a : b);
print(min); // 1
// Sum all elements
int sum = numbers.reduce((a, b) => a + b);
print(sum); // 23
}
Sort Method
The sort method sorts a list in place. You can provide a custom comparator function to control the sort order.
void main() {
List<int> scores = [30, 50, 20, 70];
// Sort ascending (default)
scores.sort();
print(scores); // [20, 30, 50, 70]
// Sort descending using comparator
scores.sort((a, b) => b.compareTo(a));
print(scores); // [70, 50, 30, 20]
// Alternative: using compareTo directly
List<int> scores2 = [30, 50, 20, 70];
scores2.sort((a, b) => b.compareTo(a));
print(scores2); // [70, 50, 30, 20]
}
Take Method
The take method returns the first n elements of a collection. It’s useful for getting the top items from a sorted list.
void main() {
List<int> scores = [70, 50, 30, 20, 10];
// Get top 3
List<int> topThree = scores.take(3).toList();
print(topThree); // [70, 50, 30]
// Works with any iterable
var topTwo = scores.take(2);
print(topTwo.toList()); // [70, 50]
}
Cascade Operator
The cascade operator (..) allows you to perform multiple operations on the same object in sequence. It’s useful for method chaining.
void main() {
List<int> scores = [30, 50, 20, 70];
// Create a copy and sort it
List<int> sorted = scores.toList()..sort();
print(scores); // [30, 50, 20, 70] (original unchanged)
print(sorted); // [20, 30, 50, 70] (sorted copy)
// Multiple operations
List<int> result = scores.toList()
..sort()
..reversed;
print(result); // [20, 30, 50, 70]
}
List Properties vs Methods
In Dart, some operations are properties (like last) while others are methods (like sort()). Properties don’t use parentheses, while methods do.
void main() {
List<int> scores = [30, 50, 20, 70];
// Property (no parentheses)
int lastScore = scores.last; // 70
// Method (with parentheses)
scores.sort(); // Sorts in place
// Getting a property vs calling a method
print(scores.length); // Property
print(scores.isEmpty); // Property
scores.add(80); // Method
}
Introduction
Manage a game player’s High Score list.
Your task is to build a high-score component of the classic Frogger game, one of the highest selling and most addictive games of all time, and a classic of the arcade era. Your task is to write methods that return the highest score from the list, the last added score and the three highest scores.
What is Frogger?
Frogger is a 1981 arcade game developed by Konami and originally published by Sega. The object of the game is to direct frogs to their homes one by one by crossing a busy road and navigating a river full of hazards. Frogger was one of the most popular games during the golden age of arcade video games.
— Wikipedia
How can we manage high scores?
To manage high scores, you need to:
- Get the latest score - Return the most recently added score (the last element in the list)
- Get the personal best - Return the highest score from all scores
- Get the top three - Return the three highest scores in descending order
For example, with scores [30, 50, 20, 70, 10]:
- Latest score: 10 (the last one added)
- Personal best: 70 (the highest score)
- Top three: [70, 50, 30] (the three highest scores)
⚠️ Old Solution (No Longer Works)
Previously, the solution used a getter property for personalTopThree and a helper method sortList(). Here’s what the old solution looked like:
class HighScores {
List<int> scores;
HighScores(this.scores);
int latest() => scores.last;
List<int> sortList() => scores.toList()..sort();
int personalBest() => sortList().last;
List<int> personalTopThree => sortList().reversed.take(3).toList();
}
Why This Solution Doesn’t Work Anymore
The old solution has several issues:
-
Getter vs Method:
personalTopThreewas defined as a getter property (without parentheses), but the exercise now requires it to be a method. This is a breaking change in the API design. -
Inefficient sorting: The solution sorts the entire list in ascending order, then reverses it to get descending order. This is less efficient than sorting directly in descending order.
-
Unnecessary helper method: The
sortList()method creates a copy and sorts it, but this pattern is repeated and can be simplified. -
Inefficient personal best: Using
sortList().lastsorts the entire list just to find the maximum value, which is inefficient. Usingreduce()is more efficient for finding a single maximum value.
The exercise now requires:
personalTopThree()to be a method (with parentheses) rather than a property- More efficient algorithms: using
reduce()for finding the maximum instead of sorting - Direct descending sort using a custom comparator instead of sorting and reversing
- Cleaner, more direct code without unnecessary helper methods
Solution
class HighScores {
List<int> scores;
HighScores(this.scores);
int latest() => scores.last;
int personalBest() => scores.reduce((a, b) => a > b ? a : b);
List<int> personalTopThree() {
final sorted = scores.toList()..sort((a, b) => b.compareTo(a));
return sorted.take(3).toList();
}
}
Let’s break down the solution:
-
int latest()- Returns the most recently added score:- Uses
scores.lastto get the last element in the list - This is the simplest and most efficient way to get the latest score
- Uses
-
int personalBest()- Returns the highest score:- Uses
reduce()with a comparison function(a, b) => a > b ? a : b - This efficiently finds the maximum value without sorting the entire list
- Much more efficient than sorting and taking the last element
- Uses
-
List<int> personalTopThree()- Returns the three highest scores:- Creates a copy of the scores list using
toList() - Uses the cascade operator
..to sort the copy in place (without affecting the original) - Sorts in descending order using
(a, b) => b.compareTo(a)- this compares b to a, so larger values come first - Uses
take(3)to get the first three elements (which are the top three after descending sort) - Converts to a list and returns
- Creates a copy of the scores list using
The solution is more efficient and follows modern Dart best practices by using reduce() for finding the maximum and direct descending sort for the top three scores.
You can watch this tutorial on YouTube. So don’t forget to like and subscribe. 😉
Watch on YouTube