From 5821db29a06d2de62e8e9013935df6e57ab51cee Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 9 Oct 2026 17:56:05 +0200 Subject: [PATCH 01/27] refactor: run CI only on pull requests with specifics conditions --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76d1a63..1f59613 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,15 @@ name: CI on: - push: pull_request: + paths-ignore: + - '.idea/**' + - '.gitignore' + - 'README.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true jobs: test: From 97566d95f3383a69055115407337c780b792b155 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 9 Oct 2026 18:03:16 +0200 Subject: [PATCH 02/27] feat: activate PAIR category --- src/main/java/io/github/vbetsch/yams/CategoryEnum.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java index 3ac7db2..ce64a55 100644 --- a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java +++ b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java @@ -7,6 +7,7 @@ public enum CategoryEnum { FOURS, FIVES, SIXES, + PAIR, THREE_OF_A_KIND, FOUR_OF_A_KIND, // FULL_HOUSE, From 115a6ccec14e8370e30aab1e0f24f72a642b3f34 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 9 Oct 2026 18:03:44 +0200 Subject: [PATCH 03/27] refactor: split categories with chapters --- src/main/java/io/github/vbetsch/yams/CategoryEnum.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java index ce64a55..fe7e074 100644 --- a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java +++ b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java @@ -1,13 +1,17 @@ package io.github.vbetsch.yams; public enum CategoryEnum { + // --- TOP PART --- ACES, TWOS, THREES, FOURS, FIVES, SIXES, + // --- BONUS PART (kata) --- PAIR, +// TWO_PAIRS, + // --- BOTTOM PART --- THREE_OF_A_KIND, FOUR_OF_A_KIND, // FULL_HOUSE, From b06342ebbc778f7ff3194908f628174489e53b81 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 9 Oct 2026 19:34:54 +0200 Subject: [PATCH 04/27] feat: create occurrencesByValue hashmap for handlePairScore --- pom.xml | 6 ++++++ src/main/java/io/github/vbetsch/yams/Yams.java | 16 ++++++++++++++++ .../java/io/github/vbetsch/yams/YamsTest.java | 12 ++++++++++++ 3 files changed, 34 insertions(+) diff --git a/pom.xml b/pom.xml index c54c7ce..9082ba0 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,12 @@ 5.11.0 test + + org.jetbrains + annotations + RELEASE + compile + diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 765f539..54dfef5 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -1,6 +1,8 @@ package io.github.vbetsch.yams; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.IntStream; public class Yams { @@ -46,6 +48,19 @@ private boolean containsDuplicatesNth(List roll, int duplicatesNumber) return reducedRoll.count() == (Yams.DICES_COUNT - duplicatesNumber + 1); } + private int handlePairScore(List roll) throws IllegalArgumentException { + if (!this.containsDuplicatesNth(roll, 2)) { + throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); + } + Map occurrencesByValue = new HashMap<>(); + for (int i = 0; i < roll.size(); i++) { + int diceValue = roll.get(i); + occurrencesByValue.merge(diceValue, 1, Integer::sum); + } + IO.println(occurrencesByValue); + return 4; + } + private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { if (!this.containsDuplicatesNth(roll, 3)) { throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.THREE_OF_A_KIND); @@ -73,6 +88,7 @@ public int computeScore(List roll, CategoryEnum category) throws Invali case CategoryEnum.FOURS -> this.handleTopPartScores(roll, 4); case CategoryEnum.FIVES -> this.handleTopPartScores(roll, 5); case CategoryEnum.SIXES -> this.handleTopPartScores(roll, 6); + case CategoryEnum.PAIR -> this.handlePairScore(roll); case CategoryEnum.THREE_OF_A_KIND -> this.handleThreeOfAKindScore(roll); case CategoryEnum.FOUR_OF_A_KIND -> this.handleFourOfAKindScore(roll); default -> 1000; diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 9683c49..06f523b 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -152,6 +152,18 @@ void sixes_return18Points_whenGivenRollWithThreeDicesSixes() { assertEquals(18, result); } + @Test + void pair_return4Points_whenGivenRollWithOnlyOnePair() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(2, 2, 3, 4, 5), CategoryEnum.PAIR); + + // Assert + assertEquals(4, result); + } + @Test void threeOfAKind_return3Points_whenGivenThreeDicesOnes() { // Arrange From 1f77b6134d93b0272519c48aed5b8901f052fea1 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 9 Oct 2026 20:00:33 +0200 Subject: [PATCH 05/27] feat: create method getOccurrencesByValue and return sum of pairs --- .../java/io/github/vbetsch/yams/Yams.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 54dfef5..2e3ebf8 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -48,17 +48,28 @@ private boolean containsDuplicatesNth(List roll, int duplicatesNumber) return reducedRoll.count() == (Yams.DICES_COUNT - duplicatesNumber + 1); } - private int handlePairScore(List roll) throws IllegalArgumentException { - if (!this.containsDuplicatesNth(roll, 2)) { - throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); - } + private Map getOccurrencesByValue(List roll) { Map occurrencesByValue = new HashMap<>(); for (int i = 0; i < roll.size(); i++) { int diceValue = roll.get(i); occurrencesByValue.merge(diceValue, 1, Integer::sum); } IO.println(occurrencesByValue); - return 4; + return occurrencesByValue; + } + + private int handlePairScore(List roll) throws IllegalArgumentException { + if (!this.containsDuplicatesNth(roll, 2)) { + throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); + } + Map occurrencesByValue = this.getOccurrencesByValue(roll); + return occurrencesByValue + .entrySet() + .stream() + .filter(occurrenceByValue -> occurrenceByValue.getValue() == 2) + .map(Map.Entry::getKey) + .max(Integer::compare) + .orElse(0) * 2; } private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { From cde45ebeaef6140b048feb03637ff521b7aad15b Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:19:21 +0200 Subject: [PATCH 06/27] refactor: use the right exception to throw in tests --- .../java/io/github/vbetsch/yams/YamsTest.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 06f523b..a64cbb2 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -152,6 +152,15 @@ void sixes_return18Points_whenGivenRollWithThreeDicesSixes() { assertEquals(18, result); } +// @Test +// void pair_throwIllegalArgumentException_whenGivenNotPair() { +// // Arrange +// Yams yams = new Yams(); +// +// // Act +// int result = yams.computeScore(List.of(6, 6, 6, 2, 3), CategoryEnum.SIXES); +// } + @Test void pair_return4Points_whenGivenRollWithOnlyOnePair() { // Arrange @@ -245,7 +254,7 @@ void throwIllegalArgumentException_whenGivenLessThanFiveDices() { // Act & Assert assertThrows( - InvalidRollSizeError.class, + IllegalArgumentException.class, () -> yams.computeScore(List.of(1, 2, 3, 4), CategoryEnum.CHANCE), "Roll must contain exactly 5 dices" ); @@ -258,7 +267,7 @@ void throwIllegalArgumentException_whenGivenMoreThanFiveDices() { // Act & Assert assertThrows( - InvalidRollSizeError.class, + IllegalArgumentException.class, () -> yams.computeScore(List.of(1, 2, 3, 4, 5, 6), CategoryEnum.CHANCE), "Roll must contain exactly 5 dices" ); @@ -271,7 +280,7 @@ void throwIllegalArgumentException_whenGivenNoDice() { // Act & Assert assertThrows( - InvalidRollSizeError.class, + IllegalArgumentException.class, () -> yams.computeScore(List.of(), CategoryEnum.CHANCE), "Roll must contain exactly 5 dices" ); From 1ed9d6869b3bce31ff1216691d39bd0882921ea0 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:22:36 +0200 Subject: [PATCH 07/27] style: add chapters --- src/test/java/io/github/vbetsch/yams/YamsTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index a64cbb2..5a38659 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -8,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; class YamsTest { + // --- CHANCE --- @Test void chance_return15Points_whenGivenLargeStraight() { // Arrange @@ -32,6 +33,7 @@ void chance_return16Points_whenGivenSmallStraight() { assertEquals(16, result); } + // --- YAMS --- @Test void yams_return50Points_whenGivenFiveDicesSix() { // Arrange @@ -80,6 +82,7 @@ void yams_return0Points_whenGivenRollWithoutDuplicates() { assertEquals(0, result); } + // --- ACES --- @Test void aces_return3Points_whenGivenRollWithThreeDicesAces() { // Arrange @@ -92,6 +95,7 @@ void aces_return3Points_whenGivenRollWithThreeDicesAces() { assertEquals(3, result); } + // --- TOP PARTS --- @Test void twos_return6Points_whenGivenRollWithThreeDicesTwos() { // Arrange @@ -173,6 +177,7 @@ void pair_return4Points_whenGivenRollWithOnlyOnePair() { assertEquals(4, result); } + // --- THREE OF A KIND --- @Test void threeOfAKind_return3Points_whenGivenThreeDicesOnes() { // Arrange @@ -210,6 +215,7 @@ void threeOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { ); } + // --- FOUR OF A KIND --- @Test void fourOfAKind_return7Points_whenGivenFourDicesOnes() { // Arrange @@ -247,6 +253,7 @@ void fourOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { ); } + // --- CHECKS --- @Test void throwIllegalArgumentException_whenGivenLessThanFiveDices() { // Arrange From d9a2dc70b0b61974ba23dfa1175ab442c5a89569 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:23:46 +0200 Subject: [PATCH 08/27] test: add pair_throwIllegalArgumentException_whenGivenNotPair --- .../java/io/github/vbetsch/yams/YamsTest.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 5a38659..3d19833 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -156,14 +156,19 @@ void sixes_return18Points_whenGivenRollWithThreeDicesSixes() { assertEquals(18, result); } -// @Test -// void pair_throwIllegalArgumentException_whenGivenNotPair() { -// // Arrange -// Yams yams = new Yams(); -// -// // Act -// int result = yams.computeScore(List.of(6, 6, 6, 2, 3), CategoryEnum.SIXES); -// } + // --- PAIRS --- + @Test + void pair_throwIllegalArgumentException_whenGivenNotPair() { + // Arrange + Yams yams = new Yams(); + + // Act & Assert + assertThrows( + IllegalArgumentException.class, + () -> yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.PAIR), + "We cannot compute score with category PAIR for this roll" + ); + } @Test void pair_return4Points_whenGivenRollWithOnlyOnePair() { From 291fe25ebfb79e5e78a76664bfcb0db3fdf9b571 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:37:05 +0200 Subject: [PATCH 09/27] test: pair_return4Points_whenGivenRollWithOnlyOnePairOfThree --- .../java/io/github/vbetsch/yams/YamsTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 3d19833..b4a5cb1 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -171,7 +171,7 @@ void pair_throwIllegalArgumentException_whenGivenNotPair() { } @Test - void pair_return4Points_whenGivenRollWithOnlyOnePair() { + void pair_return4Points_whenGivenRollWithOnlyOnePairOfTwo() { // Arrange Yams yams = new Yams(); @@ -182,6 +182,19 @@ void pair_return4Points_whenGivenRollWithOnlyOnePair() { assertEquals(4, result); } + @Test + void pair_return4Points_whenGivenRollWithOnlyOnePairOfThree() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(3, 3, 4, 5, 1), CategoryEnum.PAIR); + + // Assert + assertEquals(6, result); + } + + // --- THREE OF A KIND --- @Test void threeOfAKind_return3Points_whenGivenThreeDicesOnes() { From 841754453df0021b3087f176ff36a19fcba62228 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:38:51 +0200 Subject: [PATCH 10/27] refactor: remove points numbers in tests names --- .../java/io/github/vbetsch/yams/YamsTest.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index b4a5cb1..38978cb 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -10,7 +10,7 @@ class YamsTest { // --- CHANCE --- @Test - void chance_return15Points_whenGivenLargeStraight() { + void chance_returnPoints_whenGivenLargeStraight() { // Arrange Yams yams = new Yams(); @@ -22,7 +22,7 @@ void chance_return15Points_whenGivenLargeStraight() { } @Test - void chance_return16Points_whenGivenSmallStraight() { + void chance_returnPoints_whenGivenSmallStraight() { // Arrange Yams yams = new Yams(); @@ -35,7 +35,7 @@ void chance_return16Points_whenGivenSmallStraight() { // --- YAMS --- @Test - void yams_return50Points_whenGivenFiveDicesSix() { + void yams_returnPoints_whenGivenFiveDicesSix() { // Arrange Yams yams = new Yams(); @@ -47,7 +47,7 @@ void yams_return50Points_whenGivenFiveDicesSix() { } @Test - void yams_return50Points_whenGivenFiveDicesThree() { + void yams_returnPoints_whenGivenFiveDicesThree() { // Arrange Yams yams = new Yams(); @@ -59,7 +59,7 @@ void yams_return50Points_whenGivenFiveDicesThree() { } @Test - void yams_return0Points_whenGivenRollWithDuplicates() { + void yams_returnPoints_whenGivenRollWithDuplicates() { // Arrange Yams yams = new Yams(); @@ -71,7 +71,7 @@ void yams_return0Points_whenGivenRollWithDuplicates() { } @Test - void yams_return0Points_whenGivenRollWithoutDuplicates() { + void yams_returnPoints_whenGivenRollWithoutDuplicates() { // Arrange Yams yams = new Yams(); @@ -84,7 +84,7 @@ void yams_return0Points_whenGivenRollWithoutDuplicates() { // --- ACES --- @Test - void aces_return3Points_whenGivenRollWithThreeDicesAces() { + void aces_returnPoints_whenGivenRollWithThreeDicesAces() { // Arrange Yams yams = new Yams(); @@ -97,7 +97,7 @@ void aces_return3Points_whenGivenRollWithThreeDicesAces() { // --- TOP PARTS --- @Test - void twos_return6Points_whenGivenRollWithThreeDicesTwos() { + void twos_returnPoints_whenGivenRollWithThreeDicesTwos() { // Arrange Yams yams = new Yams(); @@ -109,7 +109,7 @@ void twos_return6Points_whenGivenRollWithThreeDicesTwos() { } @Test - void three_return9Points_whenGivenRollWithThreeDicesThrees() { + void three_returnPoints_whenGivenRollWithThreeDicesThrees() { // Arrange Yams yams = new Yams(); @@ -121,7 +121,7 @@ void three_return9Points_whenGivenRollWithThreeDicesThrees() { } @Test - void four_return12Points_whenGivenRollWithThreeDicesFours() { + void four_returnPoints_whenGivenRollWithThreeDicesFours() { // Arrange Yams yams = new Yams(); @@ -133,7 +133,7 @@ void four_return12Points_whenGivenRollWithThreeDicesFours() { } @Test - void five_return15Points_whenGivenRollWithThreeDicesFives() { + void five_returnPoints_whenGivenRollWithThreeDicesFives() { // Arrange Yams yams = new Yams(); @@ -145,7 +145,7 @@ void five_return15Points_whenGivenRollWithThreeDicesFives() { } @Test - void sixes_return18Points_whenGivenRollWithThreeDicesSixes() { + void sixes_returnPoints_whenGivenRollWithThreeDicesSixes() { // Arrange Yams yams = new Yams(); @@ -171,7 +171,7 @@ void pair_throwIllegalArgumentException_whenGivenNotPair() { } @Test - void pair_return4Points_whenGivenRollWithOnlyOnePairOfTwo() { + void pair_returnPoints_whenGivenRollWithOnlyOnePairOfTwo() { // Arrange Yams yams = new Yams(); @@ -183,7 +183,7 @@ void pair_return4Points_whenGivenRollWithOnlyOnePairOfTwo() { } @Test - void pair_return4Points_whenGivenRollWithOnlyOnePairOfThree() { + void pair_returnPoints_whenGivenRollWithOnlyOnePairOfThree() { // Arrange Yams yams = new Yams(); @@ -197,7 +197,7 @@ void pair_return4Points_whenGivenRollWithOnlyOnePairOfThree() { // --- THREE OF A KIND --- @Test - void threeOfAKind_return3Points_whenGivenThreeDicesOnes() { + void threeOfAKind_returnPoints_whenGivenThreeDicesOnes() { // Arrange Yams yams = new Yams(); @@ -209,7 +209,7 @@ void threeOfAKind_return3Points_whenGivenThreeDicesOnes() { } @Test - void threeOfAKind_return10Points_whenGivenThreeDicesTwos() { + void threeOfAKind_returnPoints_whenGivenThreeDicesTwos() { // Arrange Yams yams = new Yams(); @@ -235,7 +235,7 @@ void threeOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { // --- FOUR OF A KIND --- @Test - void fourOfAKind_return7Points_whenGivenFourDicesOnes() { + void fourOfAKind_returnPoints_whenGivenFourDicesOnes() { // Arrange Yams yams = new Yams(); @@ -247,7 +247,7 @@ void fourOfAKind_return7Points_whenGivenFourDicesOnes() { } @Test - void fourOfAKind_return11Points_whenGivenFourDicesTwos() { + void fourOfAKind_returnPoints_whenGivenFourDicesTwos() { // Arrange Yams yams = new Yams(); From 5149fa050d32ae6c4d29f342bffbb5136445548b Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:46:09 +0200 Subject: [PATCH 11/27] style: format Yams class --- .../java/io/github/vbetsch/yams/Yams.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 2e3ebf8..41d4045 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -8,6 +8,25 @@ public class Yams { static final int DICES_COUNT = 5; + // Utils + private Map getOccurrencesByValue(List roll) { + Map occurrencesByValue = new HashMap<>(); + for (int i = 0; i < roll.size(); i++) { + int diceValue = roll.get(i); + occurrencesByValue.merge(diceValue, 1, Integer::sum); + } + IO.println(occurrencesByValue); + return occurrencesByValue; + } + + private boolean containsDuplicatesNth(List roll, int duplicatesNumber) { + IntStream reducedRoll = roll + .stream() + .mapToInt(Integer::intValue) + .distinct(); + return reducedRoll.count() == (Yams.DICES_COUNT - duplicatesNumber + 1); + } + private int calculateSumOfDices(List roll) { return roll .stream() @@ -15,6 +34,7 @@ private int calculateSumOfDices(List roll) { .sum(); } + // Handlers private int handleChanceScore(List roll) { return this.calculateSumOfDices(roll); } @@ -40,24 +60,6 @@ private int handleTopPartScores(List roll, int target) { .sum(); } - private boolean containsDuplicatesNth(List roll, int duplicatesNumber) { - IntStream reducedRoll = roll - .stream() - .mapToInt(Integer::intValue) - .distinct(); - return reducedRoll.count() == (Yams.DICES_COUNT - duplicatesNumber + 1); - } - - private Map getOccurrencesByValue(List roll) { - Map occurrencesByValue = new HashMap<>(); - for (int i = 0; i < roll.size(); i++) { - int diceValue = roll.get(i); - occurrencesByValue.merge(diceValue, 1, Integer::sum); - } - IO.println(occurrencesByValue); - return occurrencesByValue; - } - private int handlePairScore(List roll) throws IllegalArgumentException { if (!this.containsDuplicatesNth(roll, 2)) { throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); @@ -86,8 +88,9 @@ private int handleFourOfAKindScore(List roll) throws IllegalArgumentExc return this.calculateSumOfDices(roll); } + // Public method public int computeScore(List roll, CategoryEnum category) throws InvalidRollSizeError { - if(roll.size() != Yams.DICES_COUNT) { + if (roll.size() != Yams.DICES_COUNT) { throw new InvalidRollSizeError(roll.size()); } return switch (category) { From 44ff3fa6029553186ac25f5e58f1fb8eb5aee92f Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:04:20 +0200 Subject: [PATCH 12/27] feat: migrate containsDuplicatesNth to containsAtLeastDuplicatesNth using occurrencesByValue --- .../java/io/github/vbetsch/yams/Yams.java | 19 ++++++++++--------- .../java/io/github/vbetsch/yams/YamsTest.java | 12 ++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 41d4045..012842c 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -19,12 +19,11 @@ private Map getOccurrencesByValue(List roll) { return occurrencesByValue; } - private boolean containsDuplicatesNth(List roll, int duplicatesNumber) { - IntStream reducedRoll = roll + private boolean containsAtLeastDuplicatesNth(Map occurrencesByValue, int duplicatesNumber) { + return occurrencesByValue + .entrySet() .stream() - .mapToInt(Integer::intValue) - .distinct(); - return reducedRoll.count() == (Yams.DICES_COUNT - duplicatesNumber + 1); + .anyMatch(occurrenceByValue -> occurrenceByValue.getValue() >= duplicatesNumber); } private int calculateSumOfDices(List roll) { @@ -61,10 +60,10 @@ private int handleTopPartScores(List roll, int target) { } private int handlePairScore(List roll) throws IllegalArgumentException { - if (!this.containsDuplicatesNth(roll, 2)) { + Map occurrencesByValue = this.getOccurrencesByValue(roll); + if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 2)) { throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); } - Map occurrencesByValue = this.getOccurrencesByValue(roll); return occurrencesByValue .entrySet() .stream() @@ -75,14 +74,16 @@ private int handlePairScore(List roll) throws IllegalArgumentException } private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { - if (!this.containsDuplicatesNth(roll, 3)) { + Map occurrencesByValue = this.getOccurrencesByValue(roll); + if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 3)) { throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.THREE_OF_A_KIND); } return this.calculateSumOfDices(roll); } private int handleFourOfAKindScore(List roll) throws IllegalArgumentException { - if (!this.containsDuplicatesNth(roll, 4)) { + Map occurrencesByValue = this.getOccurrencesByValue(roll); + if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 4)) { throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.FOUR_OF_A_KIND); } return this.calculateSumOfDices(roll); diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 38978cb..6e263dc 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -194,6 +194,18 @@ void pair_returnPoints_whenGivenRollWithOnlyOnePairOfThree() { assertEquals(6, result); } + @Test + void pair_returnPoints_whenGivenRollWithTwoPairs() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(3, 3, 4, 4, 1), CategoryEnum.PAIR); + + // Assert + assertEquals(8, result); + } + // --- THREE OF A KIND --- @Test From 287d5ab13b1d52c20f6be7b254fd567f3a49e6d3 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:08:20 +0200 Subject: [PATCH 13/27] test: if we have more than expected --- .../java/io/github/vbetsch/yams/YamsTest.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 6e263dc..20ac9a6 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -206,7 +206,6 @@ void pair_returnPoints_whenGivenRollWithTwoPairs() { assertEquals(8, result); } - // --- THREE OF A KIND --- @Test void threeOfAKind_returnPoints_whenGivenThreeDicesOnes() { @@ -232,6 +231,18 @@ void threeOfAKind_returnPoints_whenGivenThreeDicesTwos() { assertEquals(10, result); } + @Test + void threeOfAKind_returnPoints_whenGivenMoreThanThreeDicesTwos() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(2, 2, 2, 2, 3), CategoryEnum.THREE_OF_A_KIND); + + // Assert + assertEquals(11, result); + } + @Test void threeOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { // Arrange @@ -270,6 +281,18 @@ void fourOfAKind_returnPoints_whenGivenFourDicesTwos() { assertEquals(11, result); } + @Test + void fourOfAKind_returnPoints_whenGivenMoreThanFourDicesTwos() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(2, 2, 2, 2, 2), CategoryEnum.FOUR_OF_A_KIND); + + // Assert + assertEquals(10, result); + } + @Test void fourOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { // Arrange From 9999ad51f5c73c27d92e053c3b9ad46e7f03aec0 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:10:19 +0200 Subject: [PATCH 14/27] fix: filter in pair handler --- src/main/java/io/github/vbetsch/yams/Yams.java | 2 +- src/test/java/io/github/vbetsch/yams/YamsTest.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 012842c..3f48db5 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -67,7 +67,7 @@ private int handlePairScore(List roll) throws IllegalArgumentException return occurrencesByValue .entrySet() .stream() - .filter(occurrenceByValue -> occurrenceByValue.getValue() == 2) + .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2) .map(Map.Entry::getKey) .max(Integer::compare) .orElse(0) * 2; diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 20ac9a6..685fd7a 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -194,6 +194,18 @@ void pair_returnPoints_whenGivenRollWithOnlyOnePairOfThree() { assertEquals(6, result); } + @Test + void pair_returnPoints_whenGivenRollWithMoreThanTwoDices() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(3, 3, 3, 5, 1), CategoryEnum.PAIR); + + // Assert + assertEquals(6, result); + } + @Test void pair_returnPoints_whenGivenRollWithTwoPairs() { // Arrange From 3af76084bce74c4492212878428287da4759cdad Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:13:04 +0200 Subject: [PATCH 15/27] docs: update checklist --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0af2dba..4467b2c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The following categories exists: - [x] Ones, Twos, Threes, Fours, Fives, Sixes: The player scores the sum of the dice that reads one, two, three, four, five or six, respectively. For example, 1, 1, 2, 4, 4 placed on “fours” gives 8 points. -- [ ] Pair: The player scores the sum of the two highest matching dice. For example, 3, 3, 3, 4, 4 placed on “pair” +- [x] Pair: The player scores the sum of the two highest matching dice. For example, 3, 3, 3, 4, 4 placed on “pair” gives 8. - [ ] Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, the player scores 0. For example, 1, 1, 2, 3, 3 placed on “two pairs” gives 8. From 6ee2138bd73210835423573c1f172366bc11b062 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:17:25 +0200 Subject: [PATCH 16/27] refactor: rename zero points tests --- src/test/java/io/github/vbetsch/yams/YamsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 685fd7a..feaae5e 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -59,7 +59,7 @@ void yams_returnPoints_whenGivenFiveDicesThree() { } @Test - void yams_returnPoints_whenGivenRollWithDuplicates() { + void yams_returnZeroPoints_whenGivenRollWithDuplicates() { // Arrange Yams yams = new Yams(); @@ -71,7 +71,7 @@ void yams_returnPoints_whenGivenRollWithDuplicates() { } @Test - void yams_returnPoints_whenGivenRollWithoutDuplicates() { + void yams_returnZeroPoints_whenGivenRollWithoutDuplicates() { // Arrange Yams yams = new Yams(); From 25e288991bec72aaa08e8335bf90b7a83cdff1a5 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:20:30 +0200 Subject: [PATCH 17/27] fix: return zero points if duplicates check failed --- ...CategoryNotAuthorizedForThisRollError.java | 7 ---- .../java/io/github/vbetsch/yams/Yams.java | 6 +-- .../java/io/github/vbetsch/yams/YamsTest.java | 39 +++++++++---------- 3 files changed, 21 insertions(+), 31 deletions(-) delete mode 100644 src/main/java/io/github/vbetsch/yams/CategoryNotAuthorizedForThisRollError.java diff --git a/src/main/java/io/github/vbetsch/yams/CategoryNotAuthorizedForThisRollError.java b/src/main/java/io/github/vbetsch/yams/CategoryNotAuthorizedForThisRollError.java deleted file mode 100644 index 6b01ff4..0000000 --- a/src/main/java/io/github/vbetsch/yams/CategoryNotAuthorizedForThisRollError.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.vbetsch.yams; - -public class CategoryNotAuthorizedForThisRollError extends IllegalArgumentException { - public CategoryNotAuthorizedForThisRollError(CategoryEnum category) { - super("We cannot compute score with category " + category + " for this roll"); - } -} diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 3f48db5..c89c344 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -62,7 +62,7 @@ private int handleTopPartScores(List roll, int target) { private int handlePairScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 2)) { - throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.PAIR); + return 0; } return occurrencesByValue .entrySet() @@ -76,7 +76,7 @@ private int handlePairScore(List roll) throws IllegalArgumentException private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 3)) { - throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.THREE_OF_A_KIND); + return 0; } return this.calculateSumOfDices(roll); } @@ -84,7 +84,7 @@ private int handleThreeOfAKindScore(List roll) throws IllegalArgumentEx private int handleFourOfAKindScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 4)) { - throw new CategoryNotAuthorizedForThisRollError(CategoryEnum.FOUR_OF_A_KIND); + return 0; } return this.calculateSumOfDices(roll); } diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index feaae5e..0fb02a0 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -158,16 +158,15 @@ void sixes_returnPoints_whenGivenRollWithThreeDicesSixes() { // --- PAIRS --- @Test - void pair_throwIllegalArgumentException_whenGivenNotPair() { + void pair_returnZeroPoints_whenGivenNotPair() { // Arrange Yams yams = new Yams(); - // Act & Assert - assertThrows( - IllegalArgumentException.class, - () -> yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.PAIR), - "We cannot compute score with category PAIR for this roll" - ); + // Act + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND); + + // Assert + assertEquals(0, result); } @Test @@ -256,16 +255,15 @@ void threeOfAKind_returnPoints_whenGivenMoreThanThreeDicesTwos() { } @Test - void threeOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { + void threeOfAKind_returnZeroPoints_whenGivenLargeStraight() { // Arrange Yams yams = new Yams(); - // Act & Assert - assertThrows( - IllegalArgumentException.class, - () -> yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.THREE_OF_A_KIND), - "We cannot compute score with category ThreeOfAKind for this roll" - ); + // Act + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND); + + // Assert + assertEquals(0, result); } // --- FOUR OF A KIND --- @@ -306,16 +304,15 @@ void fourOfAKind_returnPoints_whenGivenMoreThanFourDicesTwos() { } @Test - void fourOfAKind_throwIllegalArgumentException_whenGivenLargeStraight() { + void fourOfAKind_returnZeroPoints_whenGivenLargeStraight() { // Arrange Yams yams = new Yams(); - // Act & Assert - assertThrows( - IllegalArgumentException.class, - () -> yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND), - "We cannot compute score with category FourOfAKind for this roll" - ); + // Act + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND); + + // Assert + assertEquals(0, result); } // --- CHECKS --- From eb46f5cac5fc2c15c7e393be7e98f1b4b94be8a3 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:24:39 +0200 Subject: [PATCH 18/27] fix: categories in tests --- src/test/java/io/github/vbetsch/yams/YamsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 0fb02a0..3d864df 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -163,7 +163,7 @@ void pair_returnZeroPoints_whenGivenNotPair() { Yams yams = new Yams(); // Act - int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND); + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.PAIR); // Assert assertEquals(0, result); @@ -260,7 +260,7 @@ void threeOfAKind_returnZeroPoints_whenGivenLargeStraight() { Yams yams = new Yams(); // Act - int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.FOUR_OF_A_KIND); + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.THREE_OF_A_KIND); // Assert assertEquals(0, result); From bd8dbffb1195d6b196e046a63997d19795527e96 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:25:53 +0200 Subject: [PATCH 19/27] feat: handle two pairs --- .../java/io/github/vbetsch/yams/CategoryEnum.java | 2 +- src/main/java/io/github/vbetsch/yams/Yams.java | 1 + src/test/java/io/github/vbetsch/yams/YamsTest.java | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java index fe7e074..0738fcc 100644 --- a/src/main/java/io/github/vbetsch/yams/CategoryEnum.java +++ b/src/main/java/io/github/vbetsch/yams/CategoryEnum.java @@ -10,7 +10,7 @@ public enum CategoryEnum { SIXES, // --- BONUS PART (kata) --- PAIR, -// TWO_PAIRS, + TWO_PAIRS, // --- BOTTOM PART --- THREE_OF_A_KIND, FOUR_OF_A_KIND, diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index c89c344..dc20017 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -104,6 +104,7 @@ public int computeScore(List roll, CategoryEnum category) throws Invali case CategoryEnum.FIVES -> this.handleTopPartScores(roll, 5); case CategoryEnum.SIXES -> this.handleTopPartScores(roll, 6); case CategoryEnum.PAIR -> this.handlePairScore(roll); + case CategoryEnum.TWO_PAIRS -> this.handlePairScore(roll); case CategoryEnum.THREE_OF_A_KIND -> this.handleThreeOfAKindScore(roll); case CategoryEnum.FOUR_OF_A_KIND -> this.handleFourOfAKindScore(roll); default -> 1000; diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 3d864df..7bb7e2a 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -217,6 +217,19 @@ void pair_returnPoints_whenGivenRollWithTwoPairs() { assertEquals(8, result); } + // --- TWO PAIRS --- + @Test + void twopairs_returnZeroPoints_whenGivenNotPair() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(1, 2, 3, 4, 5), CategoryEnum.TWO_PAIRS); + + // Assert + assertEquals(0, result); + } + // --- THREE OF A KIND --- @Test void threeOfAKind_returnPoints_whenGivenThreeDicesOnes() { From 6e6c1e176a966c5175e32c42980d5be157fe0c5c Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:37:07 +0200 Subject: [PATCH 20/27] feat: create containsAtLeastXDuplicatesOnYDifferentDices --- .../java/io/github/vbetsch/yams/Yams.java | 25 +++++++++++++++++- .../java/io/github/vbetsch/yams/YamsTest.java | 26 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index dc20017..9f2ad04 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; import java.util.stream.IntStream; +import java.util.stream.Stream; public class Yams { static final int DICES_COUNT = 5; @@ -26,6 +27,14 @@ private boolean containsAtLeastDuplicatesNth(Map occurrencesBy .anyMatch(occurrenceByValue -> occurrenceByValue.getValue() >= duplicatesNumber); } + private boolean containsAtLeastXDuplicatesOnYDifferentDices(Map occurrencesByValue, int duplicatesNumber, int differentDices) { + Stream> matchingOccurrences = occurrencesByValue + .entrySet() + .stream() + .filter(occurrenceByValue -> occurrenceByValue.getValue() >= duplicatesNumber); + return matchingOccurrences.count() == differentDices; + } + private int calculateSumOfDices(List roll) { return roll .stream() @@ -73,6 +82,20 @@ private int handlePairScore(List roll) throws IllegalArgumentException .orElse(0) * 2; } + private int handleTwoPairsScore(List roll) throws IllegalArgumentException { + Map occurrencesByValue = this.getOccurrencesByValue(roll); + if (!this.containsAtLeastXDuplicatesOnYDifferentDices(occurrencesByValue, 2, 2)) { + return 0; + } + return occurrencesByValue + .entrySet() + .stream() + .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2) + .map(Map.Entry::getKey) + .max(Integer::compare) + .orElse(0) * 2; + } + private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 3)) { @@ -104,7 +127,7 @@ public int computeScore(List roll, CategoryEnum category) throws Invali case CategoryEnum.FIVES -> this.handleTopPartScores(roll, 5); case CategoryEnum.SIXES -> this.handleTopPartScores(roll, 6); case CategoryEnum.PAIR -> this.handlePairScore(roll); - case CategoryEnum.TWO_PAIRS -> this.handlePairScore(roll); + case CategoryEnum.TWO_PAIRS -> this.handleTwoPairsScore(roll); case CategoryEnum.THREE_OF_A_KIND -> this.handleThreeOfAKindScore(roll); case CategoryEnum.FOUR_OF_A_KIND -> this.handleFourOfAKindScore(roll); default -> 1000; diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 7bb7e2a..5dac3cc 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -219,7 +219,7 @@ void pair_returnPoints_whenGivenRollWithTwoPairs() { // --- TWO PAIRS --- @Test - void twopairs_returnZeroPoints_whenGivenNotPair() { + void two_pairs_returnZeroPoints_whenGivenNotPair() { // Arrange Yams yams = new Yams(); @@ -230,6 +230,30 @@ void twopairs_returnZeroPoints_whenGivenNotPair() { assertEquals(0, result); } + @Test + void two_pairs_returnZeroPoints_whenGivenRollWithOnlyOnePair() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(2, 2, 3, 4, 5), CategoryEnum.TWO_PAIRS); + + // Assert + assertEquals(0, result); + } + + @Test + void two_pairs_returnPoints_whenGivenRollWithTwoPairs() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(3, 3, 4, 4, 1), CategoryEnum.TWO_PAIRS); + + // Assert + assertEquals(14, result); + } + // --- THREE OF A KIND --- @Test void threeOfAKind_returnPoints_whenGivenThreeDicesOnes() { From 8fb00da405492d892c6f88b62db954671b5264ed Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:41:33 +0200 Subject: [PATCH 21/27] refactor: merge contains duplicates methods --- .../java/io/github/vbetsch/yams/Yams.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 9f2ad04..8072efe 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -20,19 +20,12 @@ private Map getOccurrencesByValue(List roll) { return occurrencesByValue; } - private boolean containsAtLeastDuplicatesNth(Map occurrencesByValue, int duplicatesNumber) { - return occurrencesByValue - .entrySet() - .stream() - .anyMatch(occurrenceByValue -> occurrenceByValue.getValue() >= duplicatesNumber); - } - - private boolean containsAtLeastXDuplicatesOnYDifferentDices(Map occurrencesByValue, int duplicatesNumber, int differentDices) { + private boolean containsAtLeastXDuplicatesOnAtLeastYDifferentDices(Map occurrencesByValue, int duplicatesNumber, int differentDices) { Stream> matchingOccurrences = occurrencesByValue .entrySet() .stream() .filter(occurrenceByValue -> occurrenceByValue.getValue() >= duplicatesNumber); - return matchingOccurrences.count() == differentDices; + return matchingOccurrences.count() >= differentDices; } private int calculateSumOfDices(List roll) { @@ -70,7 +63,7 @@ private int handleTopPartScores(List roll, int target) { private int handlePairScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); - if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 2)) { + if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 2, 1)) { return 0; } return occurrencesByValue @@ -84,7 +77,7 @@ private int handlePairScore(List roll) throws IllegalArgumentException private int handleTwoPairsScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); - if (!this.containsAtLeastXDuplicatesOnYDifferentDices(occurrencesByValue, 2, 2)) { + if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 2, 2)) { return 0; } return occurrencesByValue @@ -98,7 +91,7 @@ private int handleTwoPairsScore(List roll) throws IllegalArgumentExcept private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); - if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 3)) { + if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 3, 1)) { return 0; } return this.calculateSumOfDices(roll); @@ -106,7 +99,7 @@ private int handleThreeOfAKindScore(List roll) throws IllegalArgumentEx private int handleFourOfAKindScore(List roll) throws IllegalArgumentException { Map occurrencesByValue = this.getOccurrencesByValue(roll); - if (!this.containsAtLeastDuplicatesNth(occurrencesByValue, 4)) { + if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 4, 1)) { return 0; } return this.calculateSumOfDices(roll); From 6a675ea372cf84f301c7905dadab16ddc504666b Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:54:08 +0200 Subject: [PATCH 22/27] fix: compute score for two pairs --- src/main/java/io/github/vbetsch/yams/Yams.java | 6 +++--- src/test/java/io/github/vbetsch/yams/YamsTest.java | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 8072efe..dbb0cd0 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -84,9 +84,9 @@ private int handleTwoPairsScore(List roll) throws IllegalArgumentExcept .entrySet() .stream() .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2) - .map(Map.Entry::getKey) - .max(Integer::compare) - .orElse(0) * 2; + .map(occurrenceByValue -> occurrenceByValue.getKey() * 2) + .mapToInt(Integer::intValue) + .sum(); } private int handleThreeOfAKindScore(List roll) throws IllegalArgumentException { diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index 5dac3cc..b0c9eca 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -254,6 +254,18 @@ void two_pairs_returnPoints_whenGivenRollWithTwoPairs() { assertEquals(14, result); } + @Test + void two_pairs_returnPoints_whenGivenRollWithFull() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(3, 3, 4, 4, 4), CategoryEnum.TWO_PAIRS); + + // Assert + assertEquals(14, result); + } + // --- THREE OF A KIND --- @Test void threeOfAKind_returnPoints_whenGivenThreeDicesOnes() { From 4f9b50904d9a48f4e9f405c9870cbbec04151a56 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:56:28 +0200 Subject: [PATCH 23/27] test: two_pairs_returnPoints_whenGivenRollWithTwoPairsOfFourAndFive --- src/test/java/io/github/vbetsch/yams/YamsTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/github/vbetsch/yams/YamsTest.java b/src/test/java/io/github/vbetsch/yams/YamsTest.java index b0c9eca..44a175d 100644 --- a/src/test/java/io/github/vbetsch/yams/YamsTest.java +++ b/src/test/java/io/github/vbetsch/yams/YamsTest.java @@ -243,7 +243,7 @@ void two_pairs_returnZeroPoints_whenGivenRollWithOnlyOnePair() { } @Test - void two_pairs_returnPoints_whenGivenRollWithTwoPairs() { + void two_pairs_returnPoints_whenGivenRollWithTwoPairsOfThreeAndFour() { // Arrange Yams yams = new Yams(); @@ -254,6 +254,18 @@ void two_pairs_returnPoints_whenGivenRollWithTwoPairs() { assertEquals(14, result); } + @Test + void two_pairs_returnPoints_whenGivenRollWithTwoPairsOfFourAndFive() { + // Arrange + Yams yams = new Yams(); + + // Act + int result = yams.computeScore(List.of(4, 4, 5, 5, 1), CategoryEnum.TWO_PAIRS); + + // Assert + assertEquals(18, result); + } + @Test void two_pairs_returnPoints_whenGivenRollWithFull() { // Arrange From a0575903ebb2f1c19e8bbd1ce7b9c6edd7ba0e12 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:56:45 +0200 Subject: [PATCH 24/27] docs: update checklist --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4467b2c..a2449b6 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The following categories exists: five or six, respectively. For example, 1, 1, 2, 4, 4 placed on “fours” gives 8 points. - [x] Pair: The player scores the sum of the two highest matching dice. For example, 3, 3, 3, 4, 4 placed on “pair” gives 8. -- [ ] Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, +- [x] Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, the player scores 0. For example, 1, 1, 2, 3, 3 placed on “two pairs” gives 8. - [x] Three of a kind: If there are three dice with the same number, the player scores the sum of these dice. Otherwise, the player scores 0. For example, 3, 3, 3, 4, 5 places on “three of a kind” gives 9. From a2a117629c831bf641e4e5dc3a3388178f621ef3 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:04:32 +0200 Subject: [PATCH 25/27] refactor: create getAllPairsOccurrences --- src/main/java/io/github/vbetsch/yams/Yams.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index dbb0cd0..5d2bbe1 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -35,6 +35,13 @@ private int calculateSumOfDices(List roll) { .sum(); } + private Stream> getAllPairsOccurrences(Map occurrencesByValue) { + return occurrencesByValue + .entrySet() + .stream() + .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2); + } + // Handlers private int handleChanceScore(List roll) { return this.calculateSumOfDices(roll); @@ -66,10 +73,7 @@ private int handlePairScore(List roll) throws IllegalArgumentException if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 2, 1)) { return 0; } - return occurrencesByValue - .entrySet() - .stream() - .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2) + return this.getAllPairsOccurrences(occurrencesByValue) .map(Map.Entry::getKey) .max(Integer::compare) .orElse(0) * 2; @@ -80,10 +84,7 @@ private int handleTwoPairsScore(List roll) throws IllegalArgumentExcept if (!this.containsAtLeastXDuplicatesOnAtLeastYDifferentDices(occurrencesByValue, 2, 2)) { return 0; } - return occurrencesByValue - .entrySet() - .stream() - .filter(occurrenceByValue -> occurrenceByValue.getValue() >= 2) + return this.getAllPairsOccurrences(occurrencesByValue) .map(occurrenceByValue -> occurrenceByValue.getKey() * 2) .mapToInt(Integer::intValue) .sum(); From 952dc1852fe384fbb58ed7451650a09a40c28395 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:07:09 +0200 Subject: [PATCH 26/27] refactor: rename i to index --- src/main/java/io/github/vbetsch/yams/Yams.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/vbetsch/yams/Yams.java b/src/main/java/io/github/vbetsch/yams/Yams.java index 5d2bbe1..e1e904f 100644 --- a/src/main/java/io/github/vbetsch/yams/Yams.java +++ b/src/main/java/io/github/vbetsch/yams/Yams.java @@ -12,8 +12,8 @@ public class Yams { // Utils private Map getOccurrencesByValue(List roll) { Map occurrencesByValue = new HashMap<>(); - for (int i = 0; i < roll.size(); i++) { - int diceValue = roll.get(i); + for (int index = 0; index < roll.size(); index++) { + int diceValue = roll.get(index); occurrencesByValue.merge(diceValue, 1, Integer::sum); } IO.println(occurrencesByValue); From 5a9f4a69ad9b4f9196bf13673afe970f78b576f3 Mon Sep 17 00:00:00 2001 From: vbetsch <71458556+vbetsch@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:12:50 +0200 Subject: [PATCH 27/27] revert: annotations config --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 9082ba0..c54c7ce 100644 --- a/pom.xml +++ b/pom.xml @@ -21,12 +21,6 @@ 5.11.0 test - - org.jetbrains - annotations - RELEASE - compile -