From f2354a0295f70689185bce23a53624761af9254f Mon Sep 17 00:00:00 2001 From: mperor Date: Mon, 24 Feb 2025 13:33:01 +0100 Subject: [PATCH] Add new task "player ranking system" --- README.md | 1 + .../interview/tasks/ranking/Player.java | 13 ++ .../interview/tasks/ranking/Ranking.java | 68 ++++++++++ .../ranking/PlayerRankingSystemTest.java | 120 ++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 src/main/java/pl/mperor/interview/tasks/ranking/Player.java create mode 100644 src/main/java/pl/mperor/interview/tasks/ranking/Ranking.java create mode 100644 src/test/java/pl/mperor/interview/tasks/ranking/PlayerRankingSystemTest.java diff --git a/README.md b/README.md index ba1d385..2a81122 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ are not the only possible solutions to these cases. * [Number Challenges 🔢](src/test/java/pl/mperor/interview/tasks/challenge/NumberChallengeTest.java) 7. [Quiz Questions ❔](src/test/java/pl/mperor/interview/tasks/QuizQuestionsTest.java) 8. [Wolf 🐺 & Sheep 🐑](src/test/java/pl/mperor/interview/tasks/exception/WolfFullAndSheepWholeTest.java) +9. [Player Ranking System 🏆](src/test/java/pl/mperor/interview/tasks/ranking/PlayerRankingSystemTest.java) ## Sources 🔗 diff --git a/src/main/java/pl/mperor/interview/tasks/ranking/Player.java b/src/main/java/pl/mperor/interview/tasks/ranking/Player.java new file mode 100644 index 0000000..ee28db0 --- /dev/null +++ b/src/main/java/pl/mperor/interview/tasks/ranking/Player.java @@ -0,0 +1,13 @@ +package pl.mperor.interview.tasks.ranking; + +import java.util.Comparator; + +public record Player(String name, int score) implements Comparable { + + @Override + public int compareTo(Player other) { + return Comparator.comparingInt(Player::score).reversed() + .thenComparing(Player::name) + .compare(this, other); + } +} diff --git a/src/main/java/pl/mperor/interview/tasks/ranking/Ranking.java b/src/main/java/pl/mperor/interview/tasks/ranking/Ranking.java new file mode 100644 index 0000000..91897f3 --- /dev/null +++ b/src/main/java/pl/mperor/interview/tasks/ranking/Ranking.java @@ -0,0 +1,68 @@ +package pl.mperor.interview.tasks.ranking; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.TreeSet; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +class Ranking { + + private final TreeSet items; + + private Ranking(Comparator comparator, T... varargs) { + this.items = new TreeSet<>(comparator); + items.addAll(Arrays.asList(varargs)); + } + + public void add(T item) { + items.add(item); + } + + public void replace(Predicate filter, T item) { + deleteIf(filter); + add(item); + } + + public void deleteIf(Predicate filter) { + items.removeIf(filter); + } + + public T getLeader() { + return items.first(); + } + + public List list() { + return items.stream().toList(); + } + + public static > Ranking of(T... varargs) { + return new Ranking<>(Comparable::compareTo, varargs); + } + + public static Ranking of(Comparator comparator, T... varargs) { + return new Ranking<>(comparator, varargs); + } + + public String format(BiFunction formatter) { + return format(formatter, Function.identity()); + } + + public String format(BiFunction formatter, Function positionUniqueValueMapper) { + int counter = 0; + StringBuilder builder = new StringBuilder(); + T previous = null; + for (T item : items) { + if (previous == null || !positionUniqueValueMapper.apply(item).equals(positionUniqueValueMapper.apply(previous))) { + counter++; + } + String formatted = formatter.apply(counter, item); + builder.append(formatted); + previous = item; + } + return builder.toString(); + } + +} diff --git a/src/test/java/pl/mperor/interview/tasks/ranking/PlayerRankingSystemTest.java b/src/test/java/pl/mperor/interview/tasks/ranking/PlayerRankingSystemTest.java new file mode 100644 index 0000000..7e85917 --- /dev/null +++ b/src/test/java/pl/mperor/interview/tasks/ranking/PlayerRankingSystemTest.java @@ -0,0 +1,120 @@ +package pl.mperor.interview.tasks.ranking; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Objects; + +/** + * Task: Player Ranking System 🏆 + * + *

Description: + * Your task is to develop a ranking system for players in a game using Java. + * The application should allow adding players, updating their scores, and displaying the ranking + * in a sorted manner based on their scores. + * + *

Requirements: + * - Implement a `Player` class with attributes: `name` (String) and `score` (int). + * - Create a ranking system that maintains a collection of players and sorts them dynamically. + * - Implement methods for: + * - Adding a new player to the ranking. + * - Updating the score of an existing player. + * - Displaying the current ranking in descending order of scores. + * + *

Conditions: + * - The ranking should always be sorted from the highest to the lowest score. + * - If a player's score is updated, their position in the ranking should be adjusted accordingly. + * - Player names should be unique. + * + *

Example: + * + *

Given the following players: + *

+ * Player("Alice", 1200)
+ * Player("Bob", 1500)
+ * Player("Charlie", 1300)
+ * Player("Zeus", 1300)
+ * 
+ *

+ * The ranking should be displayed as: + *

+ * 1. Bob - 1500 pts
+ * 2. Charlie - 1300 pts
+ * 2. Zeus - 1300 pts
+ * 3. Alice - 1200 pts
+ * 
+ *

+ * If Alice's score is increased by 400 points, the updated ranking should be: + *

+ * 1. Alice - 1600 pts
+ * 2. Bob - 1500 pts
+ * 3. Charlie - 1300 pts
+ * 3. Zeus - 1300 pts
+ * 
+ * + *

Additional Points: + * - Use a suitable data structure (e.g., `TreeSet`, `PriorityQueue`, or `List`). + * - Consider optimizing performance for frequent updates. + * - Implement test cases to verify correct ranking behavior. + * + *

Expected Points: + * - Code Quality: Is the code well-structured and easy to understand? + * - Correctness: Does the ranking update correctly after score changes? + * - Performance: Is the chosen data structure efficient for ranking operations? + */ +public class PlayerRankingSystemTest { + + private Ranking ranking; + + private Player bob; + private Player charlie; + private Player zeus; + private Player alice; + + @BeforeEach + void setUp() { + bob = new Player("Bob", 1500); + charlie = new Player("Charlie", 1300); + zeus = new Player("Zeus", 1300); + alice = new Player("Alice", 1200); + ranking = Ranking.of( + alice, + bob, + charlie, + zeus + ); + } + + @Test + public void shouldReturnLeaderFromPlayerRanking() { + Assertions.assertEquals(bob, ranking.getLeader()); + } + + @Test + public void shouldDisplayRankingWithPlayers() { + var formatted = ranking.format((position, player) -> + "%d. %s - %d pts%n".formatted(position, player.name(), player.score()), Player::score); + System.out.println(formatted); + Assertions.assertLinesMatch(""" + 1. Bob - 1500 pts + 2. Charlie - 1300 pts + 2. Zeus - 1300 pts + 3. Alice - 1200 pts + """.lines(), formatted.lines()); + } + + @Test + public void shouldAllowIncreasePlayerScore() { + alice = new Player(alice.name(), alice.score() + 400); + ranking.replace(player -> alice.name().equals(player.name()), alice); + Assertions.assertTrue(Objects.deepEquals(List.of( + alice, + bob, + charlie, + zeus + ), ranking.list())); + } + +}