From 19009e63a85ec401b0871e4a3420099d3882d122 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Mon, 28 Apr 2025 19:41:26 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=F0=9F=9A=80=202=EB=8B=A8=EA=B3=84=20-?= =?UTF-8?q?=20=EC=82=AC=EB=8B=A4=EB=A6=AC(=EC=83=9D=EC=84=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/ladder/domain/ladder/Line.java | 11 ++++++----- src/main/java/nextstep/ladder/domain/name/Names.java | 1 - src/main/java/nextstep/ladder/view/ResultView.java | 7 +++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index 3613a8f7cf..cf906630a5 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; public class Line { List line = new ArrayList<>(); @@ -33,9 +32,11 @@ public int size() { @Override public String toString() { - return line.stream() - .map(b -> b ? "|-----" : "| ") - .collect(Collectors.joining()) - + "|"; + StringBuilder sb = new StringBuilder(); + for (boolean b : line) { + sb.append(b ? "|-----" : "| "); + } + sb.append("|"); + return sb.toString(); } } diff --git a/src/main/java/nextstep/ladder/domain/name/Names.java b/src/main/java/nextstep/ladder/domain/name/Names.java index c608f41978..c3a10916df 100644 --- a/src/main/java/nextstep/ladder/domain/name/Names.java +++ b/src/main/java/nextstep/ladder/domain/name/Names.java @@ -7,7 +7,6 @@ public class Names { private final String DELIM = ","; private List nameList; - public Names(String names) { if (names == null || names.isBlank()) { throw new IllegalArgumentException("이름 문자열은 빈공백일 수 없습니다."); diff --git a/src/main/java/nextstep/ladder/view/ResultView.java b/src/main/java/nextstep/ladder/view/ResultView.java index 68ab5869d7..40e1dda52a 100644 --- a/src/main/java/nextstep/ladder/view/ResultView.java +++ b/src/main/java/nextstep/ladder/view/ResultView.java @@ -18,9 +18,8 @@ public static void result(Names names, Ladder ladder) { System.out.println(""); - ladder.values() - .stream() - .map(line -> " " + line.toString()); - + for(Line line: ladder.values()) { + System.out.println(" " + line.toString()); + } } } From aa3d29e4319a6245e254b7c2e6a66dea4982ded2 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Mon, 28 Apr 2025 20:03:56 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=EC=8A=A4=ED=8A=B8=EB=A6=BC?= =?UTF-8?q?=ED=99=9C=EC=9A=A9,=20=EC=95=88=EC=93=B0=EB=8A=94=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/ladder/domain/ladder/Line.java | 11 +++++------ src/main/java/nextstep/ladder/domain/name/Names.java | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index cf906630a5..3613a8f7cf 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; public class Line { List line = new ArrayList<>(); @@ -32,11 +33,9 @@ public int size() { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - for (boolean b : line) { - sb.append(b ? "|-----" : "| "); - } - sb.append("|"); - return sb.toString(); + return line.stream() + .map(b -> b ? "|-----" : "| ") + .collect(Collectors.joining()) + + "|"; } } diff --git a/src/main/java/nextstep/ladder/domain/name/Names.java b/src/main/java/nextstep/ladder/domain/name/Names.java index c3a10916df..c608f41978 100644 --- a/src/main/java/nextstep/ladder/domain/name/Names.java +++ b/src/main/java/nextstep/ladder/domain/name/Names.java @@ -7,6 +7,7 @@ public class Names { private final String DELIM = ","; private List nameList; + public Names(String names) { if (names == null || names.isBlank()) { throw new IllegalArgumentException("이름 문자열은 빈공백일 수 없습니다."); From aea49e171e45644f314f911b058fc3ba3939e7b9 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Wed, 30 Apr 2025 11:17:15 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:PR=EB=B0=98=EC=98=81,=20README?= =?UTF-8?q?=EC=97=90=20TODO=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++++ .../nextstep/ladder/domain/ladder/Line.java | 7 +++++- .../nextstep/ladder/domain/name/Name.java | 2 +- .../nextstep/ladder/domain/name/Names.java | 13 +++++++--- .../nextstep/ladder/domain/name/NameTest.java | 4 ++-- .../ladder/domain/name/NamesTest.java | 24 +++++++++++++++++++ 6 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 src/test/java/nextstep/ladder/domain/name/NamesTest.java diff --git a/README.md b/README.md index a45073411c..9e0652a01c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ ## 2단계 - 사다리 생성 ### TODO +- [ ] 사다리 실행 결과를 출력해야 한다. +- [ ] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다. + + +- [x] PR 반영 - [x] 사다리 게임에 참여하는 사람에 이름을 최대5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다. - [x] 사람 이름은 쉼표(,)를 기준으로 구분한다. - [x] 사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다. @@ -11,6 +16,7 @@ ### 프로그래밍 요구사항 - 자바 8의 스트림과 람다를 적용해 프로그래밍한다. - 규칙 6: 모든 엔티티를 작게 유지한다. +- **규칙 7: 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.** ## 진행 방법 diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index 3613a8f7cf..a005eadd6b 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -6,7 +6,12 @@ import java.util.stream.Collectors; public class Line { - List line = new ArrayList<>(); + private List line = new ArrayList<>(); + + + public Line(List values) { + this.line = values; + } public Line(int countOfPerson) { boolean lastBoolean = false; diff --git a/src/main/java/nextstep/ladder/domain/name/Name.java b/src/main/java/nextstep/ladder/domain/name/Name.java index 0ab10ab1ce..cdc6777180 100644 --- a/src/main/java/nextstep/ladder/domain/name/Name.java +++ b/src/main/java/nextstep/ladder/domain/name/Name.java @@ -7,7 +7,7 @@ public Name(String name) { if (null == name || name.isBlank() || name.length() > 5) { throw new IllegalArgumentException("이름의 형식이 올바르지 않습니다. name=" + name); } - this.name = name; + this.name = name.trim(); } @Override diff --git a/src/main/java/nextstep/ladder/domain/name/Names.java b/src/main/java/nextstep/ladder/domain/name/Names.java index c608f41978..6748799e86 100644 --- a/src/main/java/nextstep/ladder/domain/name/Names.java +++ b/src/main/java/nextstep/ladder/domain/name/Names.java @@ -5,15 +5,22 @@ import java.util.stream.Collectors; public class Names { - private final String DELIM = ","; + private static final String DELIM = ","; private List nameList; public Names(String names) { - if (names == null || names.isBlank()) { + this(parseNameString(names)); + } + + public Names(List nameList) { + if (nameList == null || nameList.isEmpty()) { throw new IllegalArgumentException("이름 문자열은 빈공백일 수 없습니다."); } + this.nameList = nameList; + } - nameList = Arrays.stream(names.split(DELIM)) + private static List parseNameString(String names) { + return Arrays.stream(names.split(DELIM)) .map(Name::new) .collect(Collectors.toList()); } diff --git a/src/test/java/nextstep/ladder/domain/name/NameTest.java b/src/test/java/nextstep/ladder/domain/name/NameTest.java index 70d15f6fe3..e8424a7f06 100644 --- a/src/test/java/nextstep/ladder/domain/name/NameTest.java +++ b/src/test/java/nextstep/ladder/domain/name/NameTest.java @@ -1,11 +1,11 @@ package nextstep.ladder.domain.name; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; class NameTest { @ParameterizedTest diff --git a/src/test/java/nextstep/ladder/domain/name/NamesTest.java b/src/test/java/nextstep/ladder/domain/name/NamesTest.java new file mode 100644 index 0000000000..51880ea38e --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/name/NamesTest.java @@ -0,0 +1,24 @@ +package nextstep.ladder.domain.name; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class NamesTest { + + @Test + public void 공백문자열은_입력될수없다() { + assertThatIllegalArgumentException().isThrownBy(() -> { + new Names(""); + }); + } + + @Test + public void 빈리스트는_입력될수없다() { + assertThatIllegalArgumentException().isThrownBy(() -> { + new Names(new ArrayList<>()); + }); + } +} \ No newline at end of file From c339f081bccab3562d1fa0537aa09e574beb5168 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Wed, 30 Apr 2025 18:15:43 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/CombinationGenerator.java | 41 ------------ .../domain/generator/LadderGenerator.java | 5 +- .../domain/generator/LineGenerator.java | 41 ++++++++++++ .../nextstep/ladder/domain/ladder/Line.java | 39 +++-------- .../java/nextstep/ladder/view/ResultView.java | 20 ++++-- .../ladder/CombinationsGeneratorTest.java | 22 ------- .../nextstep/ladder/LadderGeneratorTest.java | 20 ++++-- .../domain/generator/LineGeneratorTest.java | 66 +++++++++++++++++++ .../ladder/domain/ladder/LineTest.java | 30 +++++++++ 9 files changed, 178 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/nextstep/ladder/domain/generator/CombinationGenerator.java create mode 100644 src/main/java/nextstep/ladder/domain/generator/LineGenerator.java delete mode 100644 src/test/java/nextstep/ladder/CombinationsGeneratorTest.java create mode 100644 src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java create mode 100644 src/test/java/nextstep/ladder/domain/ladder/LineTest.java diff --git a/src/main/java/nextstep/ladder/domain/generator/CombinationGenerator.java b/src/main/java/nextstep/ladder/domain/generator/CombinationGenerator.java deleted file mode 100644 index aa7140a4a7..0000000000 --- a/src/main/java/nextstep/ladder/domain/generator/CombinationGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -package nextstep.ladder.domain.generator; - -import java.util.*; - -public class CombinationGenerator { - public static void main(String[] args) { - int countOfPerson = 3; - List> result = new ArrayList<>(); - generateCombinations(countOfPerson, new ArrayList<>(), result); - - for (List combination : result) { - if(hasConsecutiveTrues(combination)) { - System.out.println(combination); - } - } - } - - public static void generateCombinations(int n, List current, List> result) { - if (current.size() == n) { - result.add(new ArrayList<>(current)); - return; - } - - current.add(true); - generateCombinations(n, current, result); - current.remove(current.size() - 1); - - current.add(false); - generateCombinations(n, current, result); - current.remove(current.size() - 1); - } - - private static boolean hasConsecutiveTrues(List combination) { - for (int i = 0; i < combination.size() - 1; i++) { - if (combination.get(i) && combination.get(i + 1)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java b/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java index a57e3164b2..b464343ad5 100644 --- a/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java +++ b/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java @@ -5,10 +5,11 @@ import nextstep.ladder.domain.ladder.Line; public class LadderGenerator { - public static Ladder generateLadder(int countOfPerson, Height height) { + public static Ladder generateLadder(int countOfPeople + , Height height) { Ladder ladder = new Ladder(); for (int i = 0; i < height.value(); i++) { - Line line = new Line(countOfPerson); + Line line = new Line(countOfPeople); ladder.add(line); } diff --git a/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java b/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java new file mode 100644 index 0000000000..ca5ec41e0c --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java @@ -0,0 +1,41 @@ +package nextstep.ladder.domain.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class LineGenerator { + public static List generateLine(int countOfPerson) { + boolean lastBoolean = false; + List line = new ArrayList<>(); + for (int i = 0; i < countOfPerson - 1; i++) { + boolean currBoolean = randomBoolean(); + if(isConsecutiveLine(currBoolean, lastBoolean)) { + currBoolean = false; + } + line.add(currBoolean); + lastBoolean = currBoolean; + } + return line; + } + + public static void assertValidLine(List values) { + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException("사다리에는 빈값이 올 수 없습니다. values=" + values); + } + + for(int i = 0; i < values.size() -1; i++) { + if(isConsecutiveLine(values.get(i), values.get(i + 1))) { + throw new IllegalArgumentException("연속된 사다리 계단은 나올 수 없습니다."); + } + } + } + + private static boolean isConsecutiveLine(boolean curr, boolean last) { + return curr && last; + } + + private static boolean randomBoolean() { + return ThreadLocalRandom.current().nextBoolean(); + } +} diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index a005eadd6b..51297939c4 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -1,46 +1,27 @@ package nextstep.ladder.domain.ladder; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; + +import static nextstep.ladder.domain.generator.LineGenerator.assertValidLine; +import static nextstep.ladder.domain.generator.LineGenerator.generateLine; public class Line { - private List line = new ArrayList<>(); + private List line; + public Line(int countOfPeople) { + this(generateLine(countOfPeople)); + } public Line(List values) { + assertValidLine(values); this.line = values; } - public Line(int countOfPerson) { - boolean lastBoolean = false; - for (int i = 0; i < countOfPerson - 1; i++) { - boolean currBoolean = randomBoolean(); - if(isConsecutiveLine(currBoolean, lastBoolean)) { - currBoolean = false; - } - line.add(currBoolean); - lastBoolean = currBoolean; - } - } - private boolean isConsecutiveLine(boolean curr, boolean last) { - return curr && last; - } - - private boolean randomBoolean() { - return ThreadLocalRandom.current().nextBoolean(); - } - public int size() { return line.size(); } - @Override - public String toString() { - return line.stream() - .map(b -> b ? "|-----" : "| ") - .collect(Collectors.joining()) - + "|"; + public List values() { + return line; } } diff --git a/src/main/java/nextstep/ladder/view/ResultView.java b/src/main/java/nextstep/ladder/view/ResultView.java index 40e1dda52a..bd9aa7617a 100644 --- a/src/main/java/nextstep/ladder/view/ResultView.java +++ b/src/main/java/nextstep/ladder/view/ResultView.java @@ -5,6 +5,8 @@ import nextstep.ladder.domain.name.Name; import nextstep.ladder.domain.name.Names; +import java.util.stream.Collectors; + public class ResultView { public static void result(Names names, Ladder ladder) { System.out.println("\n실행결과\n"); @@ -12,14 +14,20 @@ public static void result(Names names, Ladder ladder) { System.out.printf("%-5s ", name.toString()); } - names.values() - .stream() - .map(name -> System.out.printf("%-5s ", name)); - - System.out.println(""); - for(Line line: ladder.values()) { System.out.println(" " + line.toString()); } + + ladder.values() + .stream() + .map(line -> " " + viewLine(line)); + + } + + private static String viewLine(Line line) { + return line.values().stream() + .map(b -> b ? "|-----" : "| ") + .collect(Collectors.joining()) + + "|"; } } diff --git a/src/test/java/nextstep/ladder/CombinationsGeneratorTest.java b/src/test/java/nextstep/ladder/CombinationsGeneratorTest.java deleted file mode 100644 index 49f5d550ce..0000000000 --- a/src/test/java/nextstep/ladder/CombinationsGeneratorTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package nextstep.ladder; - -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; - -import static nextstep.ladder.domain.generator.CombinationGenerator.generateCombinations; -import static org.assertj.core.api.Assertions.assertThat; - -public class CombinationsGeneratorTest { - - @Test - public void 연속된TRUE를_제외한_모든조합을_생성한다() { - int n = 3; // 원하는 길이 입력 - List> result = new ArrayList<>(); - generateCombinations(n, new ArrayList<>(), result); - - assertThat(result).hasSize(5); - } - -} diff --git a/src/test/java/nextstep/ladder/LadderGeneratorTest.java b/src/test/java/nextstep/ladder/LadderGeneratorTest.java index d1864cb792..ecaff70c2f 100644 --- a/src/test/java/nextstep/ladder/LadderGeneratorTest.java +++ b/src/test/java/nextstep/ladder/LadderGeneratorTest.java @@ -1,27 +1,35 @@ package nextstep.ladder; +import nextstep.ladder.domain.generator.LadderGenerator; +import nextstep.ladder.domain.generator.LineGenerator; import nextstep.ladder.domain.ladder.Height; import nextstep.ladder.domain.ladder.Ladder; -import nextstep.ladder.domain.generator.LadderGenerator; import nextstep.ladder.domain.ladder.Line; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; public class LadderGeneratorTest { @Test public void 입력된갯수만큼_사다리를_생성한다() { - int countOfPerson = 4; + int countOfPeople = 4; Height height = new Height(5); - LadderGenerator ladderGenerator = new LadderGenerator(); - - Ladder ladder = ladderGenerator.generateLadder(countOfPerson, height); + Ladder ladder = LadderGenerator.generateLadder(countOfPeople, height); for(Line line : ladder.values()) { System.out.println(line); - assertThat(line.size()).isEqualTo(countOfPerson - 1); + assertThat(line.size()).isEqualTo(countOfPeople - 1); } assertThat(ladder.values()).hasSize(5); } + + @Test + public void 사람수를_입력하면_사람수보다_하나작은_사다리가_만들어진다() { + int countOfPeople = 10; + List line = LineGenerator.generateLine(countOfPeople); + assertThat(line.size()).isEqualTo(countOfPeople - 1); + } } diff --git a/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java b/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java new file mode 100644 index 0000000000..9fe8dc06e3 --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java @@ -0,0 +1,66 @@ +package nextstep.ladder.domain.generator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +import java.util.List; +import java.util.stream.Stream; + +import static nextstep.ladder.domain.generator.LineGenerator.assertValidLine; +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +class LineGeneratorTest { + @Test + public void 사람수를_입력하면_사람수보다_하나작은_계단이_만들어진다() { + int countOfPeople = 10; + + List line = LineGenerator.generateLine(countOfPeople); + + assertThat(line.size()).isEqualTo(countOfPeople - 1); + } + + @ParameterizedTest + @MethodSource("invalidLines") + public void 연속된_계단은_생성될수없다(List invalidLine) { + assertThatIllegalArgumentException().isThrownBy(() -> { + assertValidLine(invalidLine); + }); + } + static Stream> invalidLines() { + return Stream.of( + List.of(true, true), + List.of(true, true, true), + List.of(false, true, true), + List.of(true, true, false) + ); + } + + @ParameterizedTest + @NullAndEmptySource + public void 계단은_null이거나_빈값일수없다(List invalidLine) { + assertThatIllegalArgumentException().isThrownBy(() -> { + assertValidLine(invalidLine); + }); + } + + @ParameterizedTest + @MethodSource("validLines") + public void 연속되지_않은_계단은_생성할수있다(List line) { + assertDoesNotThrow(() -> { + assertValidLine(line); + }); + } + static Stream> validLines() { + return Stream.of( + List.of(false, false), + List.of(true, false), + List.of(false, true), + List.of(true, false, false), + List.of(false, true, false), + List.of(false, false, true) + ); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/ladder/LineTest.java b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java new file mode 100644 index 0000000000..ca12d9d060 --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java @@ -0,0 +1,30 @@ +package nextstep.ladder.domain.ladder; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class LineTest { + @Test + public void 연속된_계단은_생성될수없다() { + List line = new ArrayList<>(); + line.add(true); + line.add(true); + + assertThatIllegalArgumentException().isThrownBy(() -> { + new Line(line); + }); + } + + @Test + public void 사람수를_입력하면_사람수보다_하나작은_사다리가_만들어진다() { + int countOfPeople = 10; + Line line = new Line(countOfPeople); + + assertThat(line.size()).isEqualTo(countOfPeople - 1); + } +} \ No newline at end of file From 9fc762fb33306bd4db7456e3bfdc3a5031e2a6f5 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Wed, 30 Apr 2025 21:38:16 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:3=EB=8B=A8=EA=B3=84=20=EC=82=AC?= =?UTF-8?q?=EB=8B=A4=EB=A6=AC(=EA=B2=8C=EC=9E=84=20=EC=8B=A4=ED=96=89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +- src/main/java/nextstep/ladder/LadderGame.java | 34 ++++++++++++- .../domain/common/AbstractValueList.java | 34 +++++++++++++ .../domain/generator/LadderGenerator.java | 5 +- .../nextstep/ladder/domain/ladder/Ladder.java | 22 ++++++--- .../nextstep/ladder/domain/ladder/Line.java | 24 +++++++++ .../nextstep/ladder/domain/name/Name.java | 15 ++++++ .../nextstep/ladder/domain/name/Names.java | 32 +++--------- .../domain/resolver/LadderResolver.java | 33 +++++++++++++ .../nextstep/ladder/domain/reward/Reward.java | 36 ++++++++++++++ .../ladder/domain/reward/Rewards.java | 17 +++++++ .../ladder/domain/util/StringParserUtil.java | 20 ++++++++ .../java/nextstep/ladder/view/InputView.java | 12 +++++ .../java/nextstep/ladder/view/ResultView.java | 23 ++++++--- .../nextstep/ladder/LadderGeneratorTest.java | 3 +- .../ladder/domain/ladder/LineTest.java | 36 ++++++++++++++ .../ladder/domain/name/NamesTest.java | 19 +++++-- .../domain/resolver/LadderResolverTest.java | 49 +++++++++++++++++++ .../ladder/domain/reward/RewardTest.java | 16 ++++++ .../ladder/domain/reward/RewardsTest.java | 26 ++++++++++ 20 files changed, 410 insertions(+), 51 deletions(-) create mode 100644 src/main/java/nextstep/ladder/domain/common/AbstractValueList.java create mode 100644 src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java create mode 100644 src/main/java/nextstep/ladder/domain/reward/Reward.java create mode 100644 src/main/java/nextstep/ladder/domain/reward/Rewards.java create mode 100644 src/main/java/nextstep/ladder/domain/util/StringParserUtil.java create mode 100644 src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java create mode 100644 src/test/java/nextstep/ladder/domain/reward/RewardTest.java create mode 100644 src/test/java/nextstep/ladder/domain/reward/RewardsTest.java diff --git a/README.md b/README.md index 9e0652a01c..725889424d 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,8 @@ ## 2단계 - 사다리 생성 ### TODO -- [ ] 사다리 실행 결과를 출력해야 한다. -- [ ] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다. - +- [x] 사다리 실행 결과를 출력해야 한다. +- [x] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다. - [x] PR 반영 - [x] 사다리 게임에 참여하는 사람에 이름을 최대5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다. diff --git a/src/main/java/nextstep/ladder/LadderGame.java b/src/main/java/nextstep/ladder/LadderGame.java index ed89926e64..512659a30e 100644 --- a/src/main/java/nextstep/ladder/LadderGame.java +++ b/src/main/java/nextstep/ladder/LadderGame.java @@ -3,18 +3,50 @@ import nextstep.ladder.domain.ladder.Height; import nextstep.ladder.domain.ladder.Ladder; import nextstep.ladder.domain.generator.LadderGenerator; +import nextstep.ladder.domain.name.Name; import nextstep.ladder.domain.name.Names; +import nextstep.ladder.domain.resolver.LadderResolver; +import nextstep.ladder.domain.reward.Reward; +import nextstep.ladder.domain.reward.Rewards; import nextstep.ladder.view.InputView; import nextstep.ladder.view.ResultView; +import java.util.ArrayList; +import java.util.List; + public class LadderGame { public static void main(String[] args) { Names names = new Names(InputView.getNames()); Height height = new Height(InputView.getHeight()); + Rewards rewards = new Rewards(InputView.getRewards()); Ladder ladder = LadderGenerator.generateLadder(names.count(), height); - ResultView.result(names, ladder); + ResultView.ladderResult(names, ladder); + + LadderResolver resolver = new LadderResolver(ladder); + while(true) { + String playerName = InputView.getPlayerName(); + + if (playerName.equalsIgnoreCase("quit")) { + break; + } + + if (playerName.equalsIgnoreCase("all")) { + List rewardList = resolver.all(); + ResultView.rewardResult(names, rewards, rewardList); + continue; + } + + Name name = new Name(playerName); + int rewardIdx = resolver.resultOf(names.positionOf(name)); + try { + Reward reward = rewards.get(rewardIdx); + System.out.println(reward); + } catch(IndexOutOfBoundsException e) { + System.out.println("이름이 명단에 없습니다."); + } + } } } diff --git a/src/main/java/nextstep/ladder/domain/common/AbstractValueList.java b/src/main/java/nextstep/ladder/domain/common/AbstractValueList.java new file mode 100644 index 0000000000..924dba3e98 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/common/AbstractValueList.java @@ -0,0 +1,34 @@ +package nextstep.ladder.domain.common; + +import java.util.List; + +public abstract class AbstractValueList { + protected final List values; + + protected AbstractValueList(List values) { + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException("리스트는 비어 있을 수 없습니다."); + } + this.values = List.copyOf(values); + } + + public List values() { + return values; + } + + public int count() { + return values.size(); + } + + public T get(int index) { + return values.get(index); + } + + public int positionOf(Object value) { + if (value == null) { + throw new IllegalArgumentException("찾는 값은 null일 수 없습니다."); + } + + return values.indexOf(value); + } +} diff --git a/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java b/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java index b464343ad5..e0298fd002 100644 --- a/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java +++ b/src/main/java/nextstep/ladder/domain/generator/LadderGenerator.java @@ -5,9 +5,8 @@ import nextstep.ladder.domain.ladder.Line; public class LadderGenerator { - public static Ladder generateLadder(int countOfPeople - , Height height) { - Ladder ladder = new Ladder(); + public static Ladder generateLadder(int countOfPeople, Height height) { + Ladder ladder = new Ladder(countOfPeople); for (int i = 0; i < height.value(); i++) { Line line = new Line(countOfPeople); ladder.add(line); diff --git a/src/main/java/nextstep/ladder/domain/ladder/Ladder.java b/src/main/java/nextstep/ladder/domain/ladder/Ladder.java index 08f02e4472..9f38396364 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Ladder.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Ladder.java @@ -4,17 +4,23 @@ import java.util.List; public class Ladder { - List lineList; + private final List lineList; + private final int countOfPeople; - public Ladder() { + public Ladder(int countOfPeople) { + this.countOfPeople = countOfPeople; this.lineList = new ArrayList<>(); } - public List values() { - return lineList; - } + public List values() { + return lineList; + } + + public void add(Line line) { + lineList.add(line); + } - public void add(Line line) { - lineList.add(line); - } + public int countOfPeople() { + return countOfPeople; + } } diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index 51297939c4..b4bccd8197 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -24,4 +24,28 @@ public int size() { public List values() { return line; } + + public boolean canMoveLeft(int index) { + try { + if (line.get(index - 1)) { return true; } + } catch(IndexOutOfBoundsException e) { + return false; + } + return false; + } + + public boolean canMoveRight(int index) { + try { + if (line.get(index)) { return true; } + } catch(IndexOutOfBoundsException e) { + return false; + } + return false; + } + + public int move(int index) { + if (canMoveLeft(index)) { return index - 1; } + if (canMoveRight(index)) { return index + 1; } + return index; + } } diff --git a/src/main/java/nextstep/ladder/domain/name/Name.java b/src/main/java/nextstep/ladder/domain/name/Name.java index cdc6777180..300bb7dcf6 100644 --- a/src/main/java/nextstep/ladder/domain/name/Name.java +++ b/src/main/java/nextstep/ladder/domain/name/Name.java @@ -1,5 +1,7 @@ package nextstep.ladder.domain.name; +import java.util.Objects; + public class Name { private String name; @@ -14,4 +16,17 @@ public Name(String name) { public String toString() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Name name1 = (Name) o; + return Objects.equals(name, name1.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } diff --git a/src/main/java/nextstep/ladder/domain/name/Names.java b/src/main/java/nextstep/ladder/domain/name/Names.java index 6748799e86..97edaf23d7 100644 --- a/src/main/java/nextstep/ladder/domain/name/Names.java +++ b/src/main/java/nextstep/ladder/domain/name/Names.java @@ -1,35 +1,17 @@ package nextstep.ladder.domain.name; -import java.util.Arrays; +import nextstep.ladder.domain.common.AbstractValueList; + import java.util.List; -import java.util.stream.Collectors; -public class Names { - private static final String DELIM = ","; - private List nameList; +import static nextstep.ladder.domain.util.StringParserUtil.parseInputString; - public Names(String names) { - this(parseNameString(names)); +public class Names extends AbstractValueList { + public Names(String input) { + this(parseInputString(input, Name::new)); } public Names(List nameList) { - if (nameList == null || nameList.isEmpty()) { - throw new IllegalArgumentException("이름 문자열은 빈공백일 수 없습니다."); - } - this.nameList = nameList; - } - - private static List parseNameString(String names) { - return Arrays.stream(names.split(DELIM)) - .map(Name::new) - .collect(Collectors.toList()); - } - - public List values() { - return nameList; - } - - public int count() { - return nameList.size(); + super(nameList); } } diff --git a/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java b/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java new file mode 100644 index 0000000000..edcb0ff733 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java @@ -0,0 +1,33 @@ +package nextstep.ladder.domain.resolver; + +import nextstep.ladder.domain.ladder.Ladder; +import nextstep.ladder.domain.ladder.Line; + +import java.util.ArrayList; +import java.util.List; + +public class LadderResolver { + + private Ladder ladder; + + public LadderResolver(Ladder ladder) { + this.ladder = ladder; + } + + public int resultOf(int position) { + int result = position; + for(Line line: ladder.values()) { + result = line.move(result); + } + + return result; + } + + public List all() { + List results = new ArrayList<>(); + for(int i = 0; i < ladder.countOfPeople(); i++) { + results.add(resultOf(i)); + } + return results; + } +} diff --git a/src/main/java/nextstep/ladder/domain/reward/Reward.java b/src/main/java/nextstep/ladder/domain/reward/Reward.java new file mode 100644 index 0000000000..c83f22b6ec --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/reward/Reward.java @@ -0,0 +1,36 @@ +package nextstep.ladder.domain.reward; + +import java.util.Objects; + +public class Reward { + private String reward; + + public Reward(String reward) { + if (reward == null || reward.isBlank()) { + throw new IllegalArgumentException("보상은 null이거나 빈값일 수 없습니다. reward=" + reward); + } + this.reward = reward; + } + + public String value() { + return reward; + } + + @Override + public String toString() { + return reward; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Reward reward = (Reward) o; + return Objects.equals(this.reward, reward.reward); + } + + @Override + public int hashCode() { + return Objects.hash(reward); + } +} diff --git a/src/main/java/nextstep/ladder/domain/reward/Rewards.java b/src/main/java/nextstep/ladder/domain/reward/Rewards.java new file mode 100644 index 0000000000..4d87618e2d --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/reward/Rewards.java @@ -0,0 +1,17 @@ +package nextstep.ladder.domain.reward; + +import nextstep.ladder.domain.common.AbstractValueList; + +import java.util.List; + +import static nextstep.ladder.domain.util.StringParserUtil.parseInputString; + +public class Rewards extends AbstractValueList { + public Rewards(String input) { + this(parseInputString(input, Reward::new)); + } + + public Rewards(List rewardList) { + super(rewardList); + } +} diff --git a/src/main/java/nextstep/ladder/domain/util/StringParserUtil.java b/src/main/java/nextstep/ladder/domain/util/StringParserUtil.java new file mode 100644 index 0000000000..f2d5c2f667 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/util/StringParserUtil.java @@ -0,0 +1,20 @@ +package nextstep.ladder.domain.util; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class StringParserUtil { + private static final String DELIM = ","; + + public static List parseInputString(String input, Function mapper) { + if (input == null || input.isBlank()) { + throw new IllegalArgumentException("입력 문자열은 비어 있을 수 없습니다."); + } + + return Arrays.stream(input.split(DELIM)) + .map(mapper) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/nextstep/ladder/view/InputView.java b/src/main/java/nextstep/ladder/view/InputView.java index d1378c6ed3..31e17e9f1e 100644 --- a/src/main/java/nextstep/ladder/view/InputView.java +++ b/src/main/java/nextstep/ladder/view/InputView.java @@ -15,4 +15,16 @@ public static Integer getHeight() { Scanner scanner = new Scanner(System.in); return scanner.nextInt(); } + + public static String getRewards() { + System.out.println("\n실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + Scanner scanner = new Scanner(System.in); + return scanner.nextLine(); + } + + public static String getPlayerName() { + System.out.println("\n결과를 보고 싶은 사람은?(종료=quit)"); + Scanner scanner = new Scanner(System.in); + return scanner.nextLine(); + } } diff --git a/src/main/java/nextstep/ladder/view/ResultView.java b/src/main/java/nextstep/ladder/view/ResultView.java index bd9aa7617a..83bf6ef5c6 100644 --- a/src/main/java/nextstep/ladder/view/ResultView.java +++ b/src/main/java/nextstep/ladder/view/ResultView.java @@ -4,12 +4,14 @@ import nextstep.ladder.domain.ladder.Line; import nextstep.ladder.domain.name.Name; import nextstep.ladder.domain.name.Names; +import nextstep.ladder.domain.reward.Rewards; +import java.util.List; import java.util.stream.Collectors; public class ResultView { - public static void result(Names names, Ladder ladder) { - System.out.println("\n실행결과\n"); + public static void ladderResult(Names names, Ladder ladder) { + System.out.println("\n사다리 결과\n"); for(Name name: names.values()) { System.out.printf("%-5s ", name.toString()); } @@ -18,16 +20,23 @@ public static void result(Names names, Ladder ladder) { System.out.println(" " + line.toString()); } - ladder.values() - .stream() - .map(line -> " " + viewLine(line)); - + for(Line line: ladder.values()) { + System.out.println(" " + viewLine(line)); + } } - private static String viewLine(Line line) { + public static String viewLine(Line line) { return line.values().stream() .map(b -> b ? "|-----" : "| ") .collect(Collectors.joining()) + "|"; } + + public static void rewardResult(Names names, Rewards rewards, List rewardList) { + System.out.println("\n실행 결과"); + + for(Name name: names.values()) { + System.out.println(name + " : " + rewards.get(rewardList.get(names.positionOf(name)))); + } + } } diff --git a/src/test/java/nextstep/ladder/LadderGeneratorTest.java b/src/test/java/nextstep/ladder/LadderGeneratorTest.java index ecaff70c2f..f54737bef2 100644 --- a/src/test/java/nextstep/ladder/LadderGeneratorTest.java +++ b/src/test/java/nextstep/ladder/LadderGeneratorTest.java @@ -5,6 +5,7 @@ import nextstep.ladder.domain.ladder.Height; import nextstep.ladder.domain.ladder.Ladder; import nextstep.ladder.domain.ladder.Line; +import nextstep.ladder.view.ResultView; import org.junit.jupiter.api.Test; import java.util.List; @@ -19,7 +20,7 @@ public class LadderGeneratorTest { Ladder ladder = LadderGenerator.generateLadder(countOfPeople, height); for(Line line : ladder.values()) { - System.out.println(line); + System.out.println(ResultView.viewLine(line)); assertThat(line.size()).isEqualTo(countOfPeople - 1); } diff --git a/src/test/java/nextstep/ladder/domain/ladder/LineTest.java b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java index ca12d9d060..440215f88b 100644 --- a/src/test/java/nextstep/ladder/domain/ladder/LineTest.java +++ b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java @@ -27,4 +27,40 @@ class LineTest { assertThat(line.size()).isEqualTo(countOfPeople - 1); } + + @Test + public void 사다리_왼쪽으로_이동불가() { + Line line = new Line(List.of(false, false)); + assertThat(line.canMoveLeft(1)).isFalse(); + } + + @Test + public void 사다리_왼쪽으로_이동가능() { + Line line = new Line(List.of(true, false)); + assertThat(line.canMoveLeft(1)).isTrue(); + } + + @Test + public void 사다리_왼쪽끝일경우_왼쪽으로_이동불가() { + Line line = new Line(List.of(true, false)); + assertThat(line.canMoveLeft(0)).isFalse(); + } + + @Test + public void 사다리_오른쪽으로_이동가능() { + Line line = new Line(List.of(true, false)); + assertThat(line.canMoveRight(0)).isTrue(); + } + + @Test + public void 사다리_오른쪽으로_이동불가() { + Line line = new Line(List.of(false, false)); + assertThat(line.canMoveRight(0)).isFalse(); + } + + @Test + public void 사다리_오른쪽끝일경우_오른쪽으로_이동불가() { + Line line = new Line(List.of(false, false)); + assertThat(line.canMoveRight(1)).isFalse(); + } } \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/name/NamesTest.java b/src/test/java/nextstep/ladder/domain/name/NamesTest.java index 51880ea38e..c9216db67b 100644 --- a/src/test/java/nextstep/ladder/domain/name/NamesTest.java +++ b/src/test/java/nextstep/ladder/domain/name/NamesTest.java @@ -1,17 +1,22 @@ package nextstep.ladder.domain.name; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; import java.util.ArrayList; +import java.util.List; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; class NamesTest { - @Test - public void 공백문자열은_입력될수없다() { + @ParameterizedTest + @NullAndEmptySource + public void 공백문자열은_입력될수없다(String input) { assertThatIllegalArgumentException().isThrownBy(() -> { - new Names(""); + new Names(input); }); } @@ -21,4 +26,12 @@ class NamesTest { new Names(new ArrayList<>()); }); } + + @Test + public void 이름을통해_position값을_구할수있다() { + String input = "aaa, bbb, ccc"; + Names names = new Names(input); + + assertThat(names.positionOf(new Name("bbb"))).isEqualTo(1); + } } \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java b/src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java new file mode 100644 index 0000000000..dca29479a6 --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java @@ -0,0 +1,49 @@ +package nextstep.ladder.domain.resolver; + +import nextstep.ladder.domain.generator.LadderGenerator; +import nextstep.ladder.domain.ladder.Height; +import nextstep.ladder.domain.ladder.Ladder; +import nextstep.ladder.domain.name.Names; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LadderResolverTest { + + @Test + public void 단건으로_사람들의_정보가_입력되면_중복없는_결과를_리턴한다() { + Names names = new Names("aaa, bbb, ccc"); + Height height = new Height(5); + Ladder ladder = LadderGenerator.generateLadder(names.count(), height); + LadderResolver resolver = new LadderResolver(ladder); + + Set setList = new HashSet(); + for(int i = 0; i < names.count(); i++) { + int result = resolver.resultOf(i); + setList.add(result); + } + + assertThat(setList).hasSize(3); + } + + @Test + public void 전체_사람들의_정보가_입력되면_중복없는_결과를_리턴한다() { + Names names = new Names("aaa, bbb, ccc"); + Height height = new Height(5); + Ladder ladder = LadderGenerator.generateLadder(names.count(), height); + LadderResolver resolver = new LadderResolver(ladder); + + List results = resolver.all(); + + Set setList = new HashSet(); + for(Integer result: results) { + setList.add(result); + } + + assertThat(setList).hasSize(3); + } +} diff --git a/src/test/java/nextstep/ladder/domain/reward/RewardTest.java b/src/test/java/nextstep/ladder/domain/reward/RewardTest.java new file mode 100644 index 0000000000..415305fba1 --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/reward/RewardTest.java @@ -0,0 +1,16 @@ +package nextstep.ladder.domain.reward; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +public class RewardTest { + @ParameterizedTest + @NullAndEmptySource + public void 보상값은_null이거나_빈공백일경우_에러(String value) { + assertThatIllegalArgumentException().isThrownBy(() -> + new Reward(value) + ); + } +} diff --git a/src/test/java/nextstep/ladder/domain/reward/RewardsTest.java b/src/test/java/nextstep/ladder/domain/reward/RewardsTest.java new file mode 100644 index 0000000000..331ebd0273 --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/reward/RewardsTest.java @@ -0,0 +1,26 @@ +package nextstep.ladder.domain.reward; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +import java.util.ArrayList; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +public class RewardsTest { + @ParameterizedTest + @NullAndEmptySource + public void 공백문자열은_입력될수없다(String input) { + assertThatIllegalArgumentException().isThrownBy(() -> { + new Rewards(input); + }); + } + + @Test + public void 빈리스트는_입력될수없다() { + assertThatIllegalArgumentException().isThrownBy(() -> { + new Rewards(new ArrayList<>()); + }); + } +} From d06a3c7db920d90bc208c7f6db5696aacf9817b3 Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Mon, 5 May 2025 01:36:30 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:PR=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 +++++++++ src/main/java/nextstep/ladder/LadderGame.java | 15 +++--- .../domain/generator/LineGenerator.java | 29 ++++++----- .../ladder/domain/generator/Point.java | 23 +++++++++ .../ladder/domain/ladder/Direction.java | 24 ++++++++++ .../nextstep/ladder/domain/ladder/Index.java | 43 +++++++++++++++++ .../nextstep/ladder/domain/ladder/Ladder.java | 16 ++++++- .../nextstep/ladder/domain/ladder/Line.java | 48 +++++++++++-------- .../domain/resolver/LadderResolver.java | 33 ------------- .../java/nextstep/ladder/view/ResultView.java | 7 ++- .../nextstep/ladder/LadderGeneratorTest.java | 2 +- .../domain/generator/LineGeneratorTest.java | 23 +++------ .../LadderTest.java} | 25 ++++------ .../ladder/domain/ladder/LineTest.java | 30 +++++++----- 14 files changed, 219 insertions(+), 121 deletions(-) create mode 100644 src/main/java/nextstep/ladder/domain/generator/Point.java create mode 100644 src/main/java/nextstep/ladder/domain/ladder/Direction.java create mode 100644 src/main/java/nextstep/ladder/domain/ladder/Index.java delete mode 100644 src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java rename src/test/java/nextstep/ladder/domain/{resolver/LadderResolverTest.java => ladder/LadderTest.java} (63%) diff --git a/README.md b/README.md index 725889424d..45b607c25d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,27 @@ # 사다리 게임 + +## 3단계 - 사다리(게임 실행) +### TODO +- [x] PR 반영 + - [x] Line 객체에 가변 인자를 받은 생성자를 추가 + - [x] LineGenerator가 generateLine에서 Line 객체를 리턴 + - [x] LineGeneratorTest의 너무 많은 가변인자 테스트 정리->보다 적은수로 경우의 수를 커버 + - [x] Ladder.java에 game Play에 대한 책임 부여 검토 + - [x] Line.java에 LEFT, RIGHT, PASS와 같은 상태값을 enum으로 구현 + - [x] Line의 index 원시값 포장 + - [x] LineGenerator에 현재값,이전값을 가지는 Point 객체 도입 검토 + +- [x] 사다리 실행 결과를 출력해야 한다. +- [x] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다. + +### 프로그래밍 요구사항 +- 자바 8의 스트림과 람다를 적용해 프로그래밍한다. +- 규칙 6: 모든 엔티티를 작게 유지한다. +- **규칙 7: 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.** + + + ## 2단계 - 사다리 생성 ### TODO - [x] 사다리 실행 결과를 출력해야 한다. diff --git a/src/main/java/nextstep/ladder/LadderGame.java b/src/main/java/nextstep/ladder/LadderGame.java index 512659a30e..456eab0e74 100644 --- a/src/main/java/nextstep/ladder/LadderGame.java +++ b/src/main/java/nextstep/ladder/LadderGame.java @@ -1,18 +1,18 @@ package nextstep.ladder; import nextstep.ladder.domain.ladder.Height; +import nextstep.ladder.domain.ladder.Index; import nextstep.ladder.domain.ladder.Ladder; import nextstep.ladder.domain.generator.LadderGenerator; import nextstep.ladder.domain.name.Name; import nextstep.ladder.domain.name.Names; -import nextstep.ladder.domain.resolver.LadderResolver; import nextstep.ladder.domain.reward.Reward; import nextstep.ladder.domain.reward.Rewards; import nextstep.ladder.view.InputView; import nextstep.ladder.view.ResultView; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public class LadderGame { @@ -23,9 +23,8 @@ public static void main(String[] args) { Ladder ladder = LadderGenerator.generateLadder(names.count(), height); - ResultView.ladderResult(names, ladder); + ResultView.ladderResult(names, ladder, rewards); - LadderResolver resolver = new LadderResolver(ladder); while(true) { String playerName = InputView.getPlayerName(); @@ -34,15 +33,17 @@ public static void main(String[] args) { } if (playerName.equalsIgnoreCase("all")) { - List rewardList = resolver.all(); + List rewardList = ladder.all().stream() + .map(Index::value) + .collect(Collectors.toList()); ResultView.rewardResult(names, rewards, rewardList); continue; } Name name = new Name(playerName); - int rewardIdx = resolver.resultOf(names.positionOf(name)); + Index rewardIdx = ladder.resultOf(names.positionOf(name)); try { - Reward reward = rewards.get(rewardIdx); + Reward reward = rewards.get(rewardIdx.value()); System.out.println(reward); } catch(IndexOutOfBoundsException e) { System.out.println("이름이 명단에 없습니다."); diff --git a/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java b/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java index ca5ec41e0c..9a1f4fceeb 100644 --- a/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java +++ b/src/main/java/nextstep/ladder/domain/generator/LineGenerator.java @@ -1,22 +1,28 @@ package nextstep.ladder.domain.generator; +import nextstep.ladder.domain.ladder.Line; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; public class LineGenerator { - public static List generateLine(int countOfPerson) { - boolean lastBoolean = false; + public static Line generateLine(int countOfPerson) { List line = new ArrayList<>(); + Point point = new Point(false, false); + for (int i = 0; i < countOfPerson - 1; i++) { - boolean currBoolean = randomBoolean(); - if(isConsecutiveLine(currBoolean, lastBoolean)) { - currBoolean = false; + boolean nextBoolean = randomBoolean(); + point = new Point(point.next(), nextBoolean); + + if (point.isConsecutive()) { + nextBoolean = false; + point = new Point(point.current(), false); } - line.add(currBoolean); - lastBoolean = currBoolean; + + line.add(nextBoolean); } - return line; + return new Line(line); } public static void assertValidLine(List values) { @@ -25,16 +31,13 @@ public static void assertValidLine(List values) { } for(int i = 0; i < values.size() -1; i++) { - if(isConsecutiveLine(values.get(i), values.get(i + 1))) { + Point point = new Point(values.get(i), values.get(i + 1)); + if(point.isConsecutive()) { throw new IllegalArgumentException("연속된 사다리 계단은 나올 수 없습니다."); } } } - private static boolean isConsecutiveLine(boolean curr, boolean last) { - return curr && last; - } - private static boolean randomBoolean() { return ThreadLocalRandom.current().nextBoolean(); } diff --git a/src/main/java/nextstep/ladder/domain/generator/Point.java b/src/main/java/nextstep/ladder/domain/generator/Point.java new file mode 100644 index 0000000000..5da6c33f8d --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/generator/Point.java @@ -0,0 +1,23 @@ +package nextstep.ladder.domain.generator; + +public class Point { + private final boolean current; + private final boolean next; + + public Point(boolean current, boolean next) { + this.current = current; + this.next = next; + } + + public boolean isConsecutive() { + return current && next; + } + + public boolean current() { + return current; + } + + public boolean next() { + return next; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/ladder/domain/ladder/Direction.java b/src/main/java/nextstep/ladder/domain/ladder/Direction.java new file mode 100644 index 0000000000..62d60c26d7 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/ladder/Direction.java @@ -0,0 +1,24 @@ +package nextstep.ladder.domain.ladder; + +public enum Direction { + LEFT { + @Override + public Index move(Index index) { + return index.decrement(); + } + }, + RIGHT { + @Override + public Index move(Index index) { + return index.increment(); + } + }, + PASS { + @Override + public Index move(Index index) { + return index; + } + }; + + public abstract Index move(Index index); +} \ No newline at end of file diff --git a/src/main/java/nextstep/ladder/domain/ladder/Index.java b/src/main/java/nextstep/ladder/domain/ladder/Index.java new file mode 100644 index 0000000000..40f838e5a9 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/ladder/Index.java @@ -0,0 +1,43 @@ +package nextstep.ladder.domain.ladder; + +public class Index { + private final int value; + private final int max; + + public Index(int value, int max) { + validate(value, max); + this.value = value; + this.max = max; + } + + private void validate(int value, int max) { + if (value < 0 || value >= max) { + throw new IllegalArgumentException("인덱스는 0 이상 " + (max - 1) + " 이하여야 합니다."); + } + } + + public int value() { + return value; + } + + public Index increment() { + return new Index(value + 1, max); + } + + public Index decrement() { + return new Index(value - 1, max); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Index index = (Index) o; + return value == index.value && max == index.max; + } + + @Override + public int hashCode() { + return value; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/ladder/domain/ladder/Ladder.java b/src/main/java/nextstep/ladder/domain/ladder/Ladder.java index 9f38396364..d4b1a7cb1c 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Ladder.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Ladder.java @@ -20,7 +20,19 @@ public void add(Line line) { lineList.add(line); } - public int countOfPeople() { - return countOfPeople; + public Index resultOf(int position) { + Index index = new Index(position, countOfPeople); + for(Line line: values()) { + index = line.movePerson(index); + } + return index; + } + + public List all() { + List results = new ArrayList<>(); + for(int i = 0; i < countOfPeople; i++) { + results.add(resultOf(i)); + } + return results; } } diff --git a/src/main/java/nextstep/ladder/domain/ladder/Line.java b/src/main/java/nextstep/ladder/domain/ladder/Line.java index b4bccd8197..3b42056b2c 100644 --- a/src/main/java/nextstep/ladder/domain/ladder/Line.java +++ b/src/main/java/nextstep/ladder/domain/ladder/Line.java @@ -6,15 +6,23 @@ import static nextstep.ladder.domain.generator.LineGenerator.generateLine; public class Line { - private List line; + private final List line; public Line(int countOfPeople) { this(generateLine(countOfPeople)); } + public Line(Line other) { + this(List.copyOf(other.line)); + } + + public Line(Boolean... values) { + this(List.of(values)); + } + public Line(List values) { assertValidLine(values); - this.line = values; + this.line = List.copyOf(values); } public int size() { @@ -22,30 +30,30 @@ public int size() { } public List values() { - return line; + return List.copyOf(line); } - public boolean canMoveLeft(int index) { - try { - if (line.get(index - 1)) { return true; } - } catch(IndexOutOfBoundsException e) { - return false; + public Index movePerson(Index index) { + Direction direction = determineDirection(index); + return direction.move(index); + } + private Direction determineDirection(Index index) { + if (isMovableToLeft(index)) { + return Direction.LEFT; + } + if (isMovableToRight(index)) { + return Direction.RIGHT; } - return false; + return Direction.PASS; } - public boolean canMoveRight(int index) { - try { - if (line.get(index)) { return true; } - } catch(IndexOutOfBoundsException e) { - return false; - } - return false; + public boolean isMovableToLeft(Index index) { + int targetIndex = index.value() - 1; + return targetIndex >= 0 && line.get(targetIndex); } - public int move(int index) { - if (canMoveLeft(index)) { return index - 1; } - if (canMoveRight(index)) { return index + 1; } - return index; + public boolean isMovableToRight(Index index) { + int targetIndex = index.value(); + return targetIndex < line.size() && line.get(targetIndex); } } diff --git a/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java b/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java deleted file mode 100644 index edcb0ff733..0000000000 --- a/src/main/java/nextstep/ladder/domain/resolver/LadderResolver.java +++ /dev/null @@ -1,33 +0,0 @@ -package nextstep.ladder.domain.resolver; - -import nextstep.ladder.domain.ladder.Ladder; -import nextstep.ladder.domain.ladder.Line; - -import java.util.ArrayList; -import java.util.List; - -public class LadderResolver { - - private Ladder ladder; - - public LadderResolver(Ladder ladder) { - this.ladder = ladder; - } - - public int resultOf(int position) { - int result = position; - for(Line line: ladder.values()) { - result = line.move(result); - } - - return result; - } - - public List all() { - List results = new ArrayList<>(); - for(int i = 0; i < ladder.countOfPeople(); i++) { - results.add(resultOf(i)); - } - return results; - } -} diff --git a/src/main/java/nextstep/ladder/view/ResultView.java b/src/main/java/nextstep/ladder/view/ResultView.java index 83bf6ef5c6..481bad1358 100644 --- a/src/main/java/nextstep/ladder/view/ResultView.java +++ b/src/main/java/nextstep/ladder/view/ResultView.java @@ -4,13 +4,14 @@ import nextstep.ladder.domain.ladder.Line; import nextstep.ladder.domain.name.Name; import nextstep.ladder.domain.name.Names; +import nextstep.ladder.domain.reward.Reward; import nextstep.ladder.domain.reward.Rewards; import java.util.List; import java.util.stream.Collectors; public class ResultView { - public static void ladderResult(Names names, Ladder ladder) { + public static void ladderResult(Names names, Ladder ladder, Rewards rewards) { System.out.println("\n사다리 결과\n"); for(Name name: names.values()) { System.out.printf("%-5s ", name.toString()); @@ -23,6 +24,10 @@ public static void ladderResult(Names names, Ladder ladder) { for(Line line: ladder.values()) { System.out.println(" " + viewLine(line)); } + + for(Reward reward: rewards.values()) { + System.out.printf("%-5s ", reward.toString()); + } } public static String viewLine(Line line) { diff --git a/src/test/java/nextstep/ladder/LadderGeneratorTest.java b/src/test/java/nextstep/ladder/LadderGeneratorTest.java index f54737bef2..28a3b3a2d8 100644 --- a/src/test/java/nextstep/ladder/LadderGeneratorTest.java +++ b/src/test/java/nextstep/ladder/LadderGeneratorTest.java @@ -30,7 +30,7 @@ public class LadderGeneratorTest { @Test public void 사람수를_입력하면_사람수보다_하나작은_사다리가_만들어진다() { int countOfPeople = 10; - List line = LineGenerator.generateLine(countOfPeople); + Line line = LineGenerator.generateLine(countOfPeople); assertThat(line.size()).isEqualTo(countOfPeople - 1); } } diff --git a/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java b/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java index 9fe8dc06e3..2a89973190 100644 --- a/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java +++ b/src/test/java/nextstep/ladder/domain/generator/LineGeneratorTest.java @@ -1,5 +1,6 @@ package nextstep.ladder.domain.generator; +import nextstep.ladder.domain.ladder.Line; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -17,26 +18,17 @@ class LineGeneratorTest { public void 사람수를_입력하면_사람수보다_하나작은_계단이_만들어진다() { int countOfPeople = 10; - List line = LineGenerator.generateLine(countOfPeople); + Line line = LineGenerator.generateLine(countOfPeople); assertThat(line.size()).isEqualTo(countOfPeople - 1); } - @ParameterizedTest - @MethodSource("invalidLines") - public void 연속된_계단은_생성될수없다(List invalidLine) { + @Test + public void 연속된_계단은_생성될수없다() { assertThatIllegalArgumentException().isThrownBy(() -> { - assertValidLine(invalidLine); + assertValidLine(List.of(true, true)); }); } - static Stream> invalidLines() { - return Stream.of( - List.of(true, true), - List.of(true, true, true), - List.of(false, true, true), - List.of(true, true, false) - ); - } @ParameterizedTest @NullAndEmptySource @@ -57,10 +49,7 @@ static Stream> validLines() { return Stream.of( List.of(false, false), List.of(true, false), - List.of(false, true), - List.of(true, false, false), - List.of(false, true, false), - List.of(false, false, true) + List.of(false, true) ); } } \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java b/src/test/java/nextstep/ladder/domain/ladder/LadderTest.java similarity index 63% rename from src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java rename to src/test/java/nextstep/ladder/domain/ladder/LadderTest.java index dca29479a6..70f7afa270 100644 --- a/src/test/java/nextstep/ladder/domain/resolver/LadderResolverTest.java +++ b/src/test/java/nextstep/ladder/domain/ladder/LadderTest.java @@ -1,8 +1,6 @@ -package nextstep.ladder.domain.resolver; +package nextstep.ladder.domain.ladder; import nextstep.ladder.domain.generator.LadderGenerator; -import nextstep.ladder.domain.ladder.Height; -import nextstep.ladder.domain.ladder.Ladder; import nextstep.ladder.domain.name.Names; import org.junit.jupiter.api.Test; @@ -12,19 +10,17 @@ import static org.assertj.core.api.Assertions.assertThat; -public class LadderResolverTest { - +class LadderTest { @Test public void 단건으로_사람들의_정보가_입력되면_중복없는_결과를_리턴한다() { Names names = new Names("aaa, bbb, ccc"); Height height = new Height(5); Ladder ladder = LadderGenerator.generateLadder(names.count(), height); - LadderResolver resolver = new LadderResolver(ladder); - Set setList = new HashSet(); + Set setList = new HashSet<>(); for(int i = 0; i < names.count(); i++) { - int result = resolver.resultOf(i); - setList.add(result); + Index result = ladder.resultOf(i); + setList.add(result.value()); } assertThat(setList).hasSize(3); @@ -35,15 +31,14 @@ public class LadderResolverTest { Names names = new Names("aaa, bbb, ccc"); Height height = new Height(5); Ladder ladder = LadderGenerator.generateLadder(names.count(), height); - LadderResolver resolver = new LadderResolver(ladder); - List results = resolver.all(); + List results = ladder.all(); - Set setList = new HashSet(); - for(Integer result: results) { - setList.add(result); + Set setList = new HashSet<>(); + for(Index result: results) { + setList.add(result.value()); } assertThat(setList).hasSize(3); } -} +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/ladder/LineTest.java b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java index 440215f88b..094472be5d 100644 --- a/src/test/java/nextstep/ladder/domain/ladder/LineTest.java +++ b/src/test/java/nextstep/ladder/domain/ladder/LineTest.java @@ -30,37 +30,43 @@ class LineTest { @Test public void 사다리_왼쪽으로_이동불가() { - Line line = new Line(List.of(false, false)); - assertThat(line.canMoveLeft(1)).isFalse(); + Line line = new Line(false, false); + Index index = new Index(1, 2); + assertThat(line.isMovableToLeft(index)).isFalse(); } @Test public void 사다리_왼쪽으로_이동가능() { - Line line = new Line(List.of(true, false)); - assertThat(line.canMoveLeft(1)).isTrue(); + Line line = new Line(true, false); + Index index = new Index(1, 2); + assertThat(line.isMovableToLeft(index)).isTrue(); } @Test public void 사다리_왼쪽끝일경우_왼쪽으로_이동불가() { - Line line = new Line(List.of(true, false)); - assertThat(line.canMoveLeft(0)).isFalse(); + Line line = new Line(true, false); + Index index = new Index(0, 2); + assertThat(line.isMovableToLeft(index)).isFalse(); } @Test public void 사다리_오른쪽으로_이동가능() { - Line line = new Line(List.of(true, false)); - assertThat(line.canMoveRight(0)).isTrue(); + Line line = new Line(true, false); + Index index = new Index(0, 2); + assertThat(line.isMovableToRight(index)).isTrue(); } @Test public void 사다리_오른쪽으로_이동불가() { - Line line = new Line(List.of(false, false)); - assertThat(line.canMoveRight(0)).isFalse(); + Line line = new Line(false, false); + Index index = new Index(0, 2); + assertThat(line.isMovableToRight(index)).isFalse(); } @Test public void 사다리_오른쪽끝일경우_오른쪽으로_이동불가() { - Line line = new Line(List.of(false, false)); - assertThat(line.canMoveRight(1)).isFalse(); + Line line = new Line(false, false); + Index index = new Index(1, 2); + assertThat(line.isMovableToRight(index)).isFalse(); } } \ No newline at end of file From 9d3c205968703755992d898c9e304a6e39f21fcb Mon Sep 17 00:00:00 2001 From: "victor.shin" Date: Mon, 5 May 2025 20:40:25 +0900 Subject: [PATCH 7/7] =?UTF-8?q?chore:=EA=B2=8C=EC=9E=84=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EA=B0=9C=EC=84=A0.=20=EC=95=88=EC=93=B0=EB=8A=94?= =?UTF-8?q?=20import=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/ladder/view/ResultView.java | 5 +---- src/test/java/nextstep/ladder/LadderGeneratorTest.java | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/nextstep/ladder/view/ResultView.java b/src/main/java/nextstep/ladder/view/ResultView.java index 481bad1358..c6c86c9f61 100644 --- a/src/main/java/nextstep/ladder/view/ResultView.java +++ b/src/main/java/nextstep/ladder/view/ResultView.java @@ -16,10 +16,7 @@ public static void ladderResult(Names names, Ladder ladder, Rewards rewards) { for(Name name: names.values()) { System.out.printf("%-5s ", name.toString()); } - - for(Line line: ladder.values()) { - System.out.println(" " + line.toString()); - } + System.out.println(""); for(Line line: ladder.values()) { System.out.println(" " + viewLine(line)); diff --git a/src/test/java/nextstep/ladder/LadderGeneratorTest.java b/src/test/java/nextstep/ladder/LadderGeneratorTest.java index 28a3b3a2d8..e785875922 100644 --- a/src/test/java/nextstep/ladder/LadderGeneratorTest.java +++ b/src/test/java/nextstep/ladder/LadderGeneratorTest.java @@ -8,8 +8,6 @@ import nextstep.ladder.view.ResultView; import org.junit.jupiter.api.Test; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; public class LadderGeneratorTest { @@ -25,6 +23,7 @@ public class LadderGeneratorTest { } assertThat(ladder.values()).hasSize(5); + } @Test