From b6d502c06064ab038a0498d36dcd3dbf1f900973 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Wed, 11 Jun 2025 19:55:58 +0900 Subject: [PATCH 01/15] =?UTF-8?q?refactor:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=20=ED=94=8C=EB=A0=88=EC=9D=B4=EC=96=B4=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Width.java | 24 ------ src/main/java/domain/dto/RequestLadder.java | 37 --------- .../java/domain/dto/RequestLadderGame.java | 47 ++++++++++++ .../java/domain/{ => ladder}/Direction.java | 0 src/main/java/domain/{ => ladder}/Height.java | 2 +- src/main/java/domain/{ => ladder}/Line.java | 0 src/main/java/domain/{ => ladder}/Point.java | 0 src/main/java/domain/player/Name.java | 25 ++++++ src/main/java/domain/player/Player.java | 14 ++++ src/main/java/domain/player/Players.java | 57 ++++++++++++++ src/test/java/domain/WidthTest.java | 22 ------ .../domain/dto/RequestLadderGameTest.java | 36 +++++++++ .../java/domain/dto/RequestLadderTest.java | 76 ------------------- .../java/domain/{ => ladder}/HeightTest.java | 6 +- .../java/domain/{ => ladder}/LineTest.java | 0 .../java/domain/{ => ladder}/PointTest.java | 0 src/test/java/domain/player/NameTest.java | 32 ++++++++ src/test/java/domain/player/PlayersTest.java | 42 ++++++++++ 18 files changed, 257 insertions(+), 163 deletions(-) delete mode 100644 src/main/java/domain/Width.java delete mode 100644 src/main/java/domain/dto/RequestLadder.java create mode 100644 src/main/java/domain/dto/RequestLadderGame.java rename src/main/java/domain/{ => ladder}/Direction.java (100%) rename src/main/java/domain/{ => ladder}/Height.java (96%) rename src/main/java/domain/{ => ladder}/Line.java (100%) rename src/main/java/domain/{ => ladder}/Point.java (100%) create mode 100644 src/main/java/domain/player/Name.java create mode 100644 src/main/java/domain/player/Player.java create mode 100644 src/main/java/domain/player/Players.java delete mode 100644 src/test/java/domain/WidthTest.java create mode 100644 src/test/java/domain/dto/RequestLadderGameTest.java delete mode 100644 src/test/java/domain/dto/RequestLadderTest.java rename src/test/java/domain/{ => ladder}/HeightTest.java (84%) rename src/test/java/domain/{ => ladder}/LineTest.java (100%) rename src/test/java/domain/{ => ladder}/PointTest.java (100%) create mode 100644 src/test/java/domain/player/NameTest.java create mode 100644 src/test/java/domain/player/PlayersTest.java diff --git a/src/main/java/domain/Width.java b/src/main/java/domain/Width.java deleted file mode 100644 index 86b2a348..00000000 --- a/src/main/java/domain/Width.java +++ /dev/null @@ -1,24 +0,0 @@ -package domain; - -public record Width( - int value -) { - - static final int MIN_LADDER_WIDTH_SIZE = 2; - static final int MAX_LADDER_WIDTH_SIZE = 24; - - public Width { - validateWidthSize(value); - } - - public static Width from(final int value) { - return new Width(value); - } - - private void validateWidthSize(final int value) { - if (value < MIN_LADDER_WIDTH_SIZE || MAX_LADDER_WIDTH_SIZE < value) { - throw new IllegalArgumentException( - "사다리의 넓이는 %s 이상 %s 이하여야 합니다.".formatted(MIN_LADDER_WIDTH_SIZE, MAX_LADDER_WIDTH_SIZE)); - } - } -} diff --git a/src/main/java/domain/dto/RequestLadder.java b/src/main/java/domain/dto/RequestLadder.java deleted file mode 100644 index e054051d..00000000 --- a/src/main/java/domain/dto/RequestLadder.java +++ /dev/null @@ -1,37 +0,0 @@ -package domain.dto; - -import domain.Height; -import domain.Width; - -public record RequestLadder( - String width, - String height -) { - - public RequestLadder { - validateEmpty(width, height); - } - - private void validateEmpty(final String width, final String height) { - if (width == null || width.isBlank() || height == null || height.isBlank()) { - throw new IllegalArgumentException("사다리의 넓이와 높이를 입력해야 합니다."); - } - } - - public Width toWidth() { - try { - return new Width(Integer.parseInt(width.strip())); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("사다리의 넓이는 숫자여야 합니다."); - } - } - - public Height toHeight() { - try { - return new Height(Integer.parseInt(height.strip())); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("사다리의 높이는 숫자여야 합니다."); - } - } - -} diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java new file mode 100644 index 00000000..8510d777 --- /dev/null +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -0,0 +1,47 @@ +package domain.dto; + +import domain.ladder.Height; +import domain.player.Players; +import java.util.List; +import java.util.stream.Stream; + +public record RequestLadderGame( + String playerNames, + String height +) { + + static final String NAME_DELIMITER = ","; + + public RequestLadderGame { + validateEmptyPlayerNames(playerNames); + validateEmptyHeight(height); + } + + private void validateEmptyPlayerNames(final String playerNames) { + if (playerNames == null || playerNames.isBlank()) { + throw new IllegalArgumentException("플레이어들의 이름을 입력해야 합니다."); + } + } + + private void validateEmptyHeight(final String height) { + if (height == null || height.isBlank()) { + throw new IllegalArgumentException("사다리의 높이를 입력해야 합니다."); + } + } + + public Players toPlayers() { + List names = Stream.of(playerNames.split(NAME_DELIMITER)) + .map(String::strip) + .toList(); + return Players.from(names); + } + + public Height toHeight() { + try { + return new Height(Integer.parseInt(height.strip())); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("사다리의 높이는 숫자여야 합니다."); + } + } + +} diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/ladder/Direction.java similarity index 100% rename from src/main/java/domain/Direction.java rename to src/main/java/domain/ladder/Direction.java diff --git a/src/main/java/domain/Height.java b/src/main/java/domain/ladder/Height.java similarity index 96% rename from src/main/java/domain/Height.java rename to src/main/java/domain/ladder/Height.java index 28f9d5a0..9d7a0167 100644 --- a/src/main/java/domain/Height.java +++ b/src/main/java/domain/ladder/Height.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; public record Height( int value diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/ladder/Line.java similarity index 100% rename from src/main/java/domain/Line.java rename to src/main/java/domain/ladder/Line.java diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/ladder/Point.java similarity index 100% rename from src/main/java/domain/Point.java rename to src/main/java/domain/ladder/Point.java diff --git a/src/main/java/domain/player/Name.java b/src/main/java/domain/player/Name.java new file mode 100644 index 00000000..7d0e3493 --- /dev/null +++ b/src/main/java/domain/player/Name.java @@ -0,0 +1,25 @@ +package domain.player; + +public record Name( + String value +) { + + static final int MAX_NAME_LENGTH = 5; + + public Name { + validateEmptyName(value); + validateNameLength(value); + } + + private void validateEmptyName(String value) { + if (value == null || value.isBlank()) { + throw new IllegalArgumentException("플레이어의 이름을 입력해야 합니다."); + } + } + + private void validateNameLength(String value) { + if (MAX_NAME_LENGTH < value.length()) { + throw new IllegalArgumentException("플레이어의 이름이 %d를 초과합니다.".formatted(MAX_NAME_LENGTH)); + } + } +} diff --git a/src/main/java/domain/player/Player.java b/src/main/java/domain/player/Player.java new file mode 100644 index 00000000..84e737a2 --- /dev/null +++ b/src/main/java/domain/player/Player.java @@ -0,0 +1,14 @@ +package domain.player; + +public class Player { + + private final Name name; + + public Player(final Name name) { + this.name = name; + } + + public Name getName() { + return name; + } +} diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java new file mode 100644 index 00000000..7fc71480 --- /dev/null +++ b/src/main/java/domain/player/Players.java @@ -0,0 +1,57 @@ +package domain.player; + +import static java.util.stream.Collectors.toSet; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class Players { + static final int MIN_PLAYER_SIZE = 2; + static final int MAX_PLAYER_SIZE = 24; + private final List players; + + private Players(final List players) { + validatePlayerSize(players); + validateDuplicateName(players); + this.players = players; + } + + public static Players from(final List names) { + return new Players( + names.stream() + .map(Name::new) + .map(Player::new) + .toList() + ); + } + + private void validatePlayerSize(final List players) { + int size = players.size(); + if (size < MIN_PLAYER_SIZE || MAX_PLAYER_SIZE < size) { + throw new IllegalArgumentException( + "플레이어 수는 %s 이상 %s 이하여야 합니다.".formatted(MIN_PLAYER_SIZE, MAX_PLAYER_SIZE)); + } + } + + private void validateDuplicateName(final List players) { + Set distinctNames = uniqueNamesFrom(players); + validateNameCountEqualsDistinctCount(players.size(), distinctNames.size()); + } + + private Set uniqueNamesFrom(final List players) { + return players.stream() + .map(player -> player.getName().value()) + .collect(toSet()); + } + + private void validateNameCountEqualsDistinctCount(final int total, final int distinct) { + if (total != distinct) { + throw new IllegalArgumentException("플레이어의 이름은 중복될 수 없습니다."); + } + } + + public List values() { + return Collections.unmodifiableList(players); + } +} diff --git a/src/test/java/domain/WidthTest.java b/src/test/java/domain/WidthTest.java deleted file mode 100644 index 43449786..00000000 --- a/src/test/java/domain/WidthTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package domain; - -import static domain.Width.MAX_LADDER_WIDTH_SIZE; -import static domain.Width.MIN_LADDER_WIDTH_SIZE; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class WidthTest { - - @ParameterizedTest - @ValueSource(ints = {1, 25}) - @DisplayName("사다리 넓이가 최소 기준을 준수하지 않았을 시 예외가 발생한다.") - void shouldThrowException_whenInvalidWidth(int width) { - // given & when & then - assertThatThrownBy(() -> Width.from(width)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 넓이는 %s 이상 %s 이하여야 합니다.".formatted(MIN_LADDER_WIDTH_SIZE, MAX_LADDER_WIDTH_SIZE)); - } -} diff --git a/src/test/java/domain/dto/RequestLadderGameTest.java b/src/test/java/domain/dto/RequestLadderGameTest.java new file mode 100644 index 00000000..61040552 --- /dev/null +++ b/src/test/java/domain/dto/RequestLadderGameTest.java @@ -0,0 +1,36 @@ +package domain.dto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import domain.Height; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +class RequestLadderTest { + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("사다리의 높이를 입력하지 않았을 경우 예외가 발생한다.") + void shouldThrowException_whenEmptyHeight(String height) { + // given & when & then + assertThatThrownBy(() -> new RequestLadder(height)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("사다리의 넓이와 높이를 입력해야 합니다."); + } + + @Test + @DisplayName("유효한 넓이와 높이를 입력하면 올바르게 객체가 생성된다.") + void shouldReturnCorrectWidthAndHeight() { + // given + RequestLadder requestLadder = new RequestLadder("7"); + + // when + Height height = requestLadder.toHeight(); + + // then + assertThat(height.value()).isEqualTo(7); + } +} diff --git a/src/test/java/domain/dto/RequestLadderTest.java b/src/test/java/domain/dto/RequestLadderTest.java deleted file mode 100644 index 0dfb3b7c..00000000 --- a/src/test/java/domain/dto/RequestLadderTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package domain.dto; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import domain.Height; -import domain.Width; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.junit.jupiter.params.provider.ValueSource; - -class RequestLadderTest { - - @ParameterizedTest - @NullAndEmptySource - @DisplayName("사다리의 넓이를 입력하지 않았을 경우 예외가 발생한다.") - void shouldThrowException_whenEmptyWidth(String width) { - // given & when & then - assertThatThrownBy(() -> new RequestLadder(width, "3")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 넓이와 높이를 입력해야 합니다."); - } - - @ParameterizedTest - @NullAndEmptySource - @DisplayName("사다리의 높이를 입력하지 않았을 경우 예외가 발생한다.") - void shouldThrowException_whenEmptyHeight(String height) { - // given & when & then - assertThatThrownBy(() -> new RequestLadder("3", height)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 넓이와 높이를 입력해야 합니다."); - } - - @ParameterizedTest - @ValueSource(strings = {"aa", "3ab"}) - @DisplayName("사다리의 넓이가 숫자가 아닌 경우 예외가 발생한다.") - void shouldThrowException_whenNoNumericalWidth(String width) { - // given - RequestLadder requestLadder = new RequestLadder(width, "3"); - - // when & then - assertThatThrownBy(requestLadder::toWidth) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 넓이는 숫자여야 합니다."); - } - - @ParameterizedTest - @ValueSource(strings = {"bb", "3cd"}) - @DisplayName("사다리의 높이가 숫자가 아닌 경우 예외가 발생한다.") - void shouldThrowException_whenNoNumericalHeight(String height) { - // given - RequestLadder requestLadder = new RequestLadder("3", height); - - // when & then - assertThatThrownBy(requestLadder::toHeight) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 높이는 숫자여야 합니다."); - } - - @Test - @DisplayName("유효한 넓이와 높이를 입력하면 올바르게 객체가 생성된다.") - void shouldReturnCorrectWidthAndHeight() { - // given - RequestLadder requestLadder = new RequestLadder("5", "7"); - - // when - Width width = requestLadder.toWidth(); - Height height = requestLadder.toHeight(); - - // then - assertThat(width.value()).isEqualTo(5); - assertThat(height.value()).isEqualTo(7); - } -} diff --git a/src/test/java/domain/HeightTest.java b/src/test/java/domain/ladder/HeightTest.java similarity index 84% rename from src/test/java/domain/HeightTest.java rename to src/test/java/domain/ladder/HeightTest.java index 902ceae4..661f3ce2 100644 --- a/src/test/java/domain/HeightTest.java +++ b/src/test/java/domain/ladder/HeightTest.java @@ -1,7 +1,7 @@ -package domain; +package domain.ladder; -import static domain.Height.MAX_LADDER_HEIGHT_SIZE; -import static domain.Height.MIN_LADDER_HEIGHT_SIZE; +import static domain.ladder.Height.MAX_LADDER_HEIGHT_SIZE; +import static domain.ladder.Height.MIN_LADDER_HEIGHT_SIZE; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/ladder/LineTest.java similarity index 100% rename from src/test/java/domain/LineTest.java rename to src/test/java/domain/ladder/LineTest.java diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/ladder/PointTest.java similarity index 100% rename from src/test/java/domain/PointTest.java rename to src/test/java/domain/ladder/PointTest.java diff --git a/src/test/java/domain/player/NameTest.java b/src/test/java/domain/player/NameTest.java new file mode 100644 index 00000000..460a76ce --- /dev/null +++ b/src/test/java/domain/player/NameTest.java @@ -0,0 +1,32 @@ +package domain.player; + +import static domain.player.Name.MAX_NAME_LENGTH; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +class NameTest { + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("이름이 빈 값이거나 공백일 경우 예외가 발생한다.") + void shouldThrowException_whenEmptyOrBlank(String value) { + // given & when & then + assertThatThrownBy(() -> new Name(value)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어의 이름을 입력해야 합니다."); + } + + @ParameterizedTest + @ValueSource(strings = {"jiyuni", "spiderman", "player2"}) + @DisplayName("이름의 최대 길이를 초과하였을 경우 예외가 발생한다.") + void shouldThrowException_whenOverMaxLength(String value) { + // given & when & then + assertThatThrownBy(() -> new Name(value)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어의 이름이 %d를 초과합니다.".formatted(MAX_NAME_LENGTH)); + } +} diff --git a/src/test/java/domain/player/PlayersTest.java b/src/test/java/domain/player/PlayersTest.java new file mode 100644 index 00000000..d899e12f --- /dev/null +++ b/src/test/java/domain/player/PlayersTest.java @@ -0,0 +1,42 @@ +package domain.player; + +import static domain.player.Players.MAX_PLAYER_SIZE; +import static domain.player.Players.MIN_PLAYER_SIZE; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import java.util.stream.IntStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PlayersTest { + + @ParameterizedTest + @ValueSource(ints = {1, 25}) + @DisplayName("플레이어의 수가 기준을 준수하지 않았을 시 예외가 발생한다.") + void shouldThrowException_whenInvalidPlayerSize(int size) { + // given + List names = IntStream.range(0, size) + .mapToObj(i -> "dd" + i) + .toList(); + + // when & then + assertThatThrownBy(() -> Players.from(names)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어 수는 %s 이상 %s 이하여야 합니다.".formatted(MIN_PLAYER_SIZE, MAX_PLAYER_SIZE)); + } + + @Test + @DisplayName("플레이어의 이름이 중복되었을 경우 예외가 발생한다.") + void shouldThrowException_whenDuplicatePlayerNames() { + // given + List duplicateNames = List.of("dd", "pobi", "dd"); + + // when & then + assertThatThrownBy(() -> Players.from(duplicateNames)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어의 이름은 중복될 수 없습니다."); + } +} From fe94e06955aa68adbeb2a348334823f0b65b36ab Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Wed, 11 Jun 2025 20:01:03 +0900 Subject: [PATCH 02/15] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/dto/ResponseLadderResult.java | 6 ++--- src/main/java/domain/dto/ResponseLine.java | 4 +-- src/main/java/domain/ladder/Direction.java | 2 +- src/main/java/domain/ladder/Ladder.java | 8 +++--- .../java/domain/ladder/LadderFactory.java | 19 +++++++------ src/main/java/domain/ladder/Line.java | 2 +- src/main/java/domain/ladder/Point.java | 2 +- src/main/java/domain/player/Players.java | 1 + src/main/java/strategy/LineGenerator.java | 2 +- .../java/strategy/RandomLineGenerator.java | 4 +-- .../domain/dto/RequestLadderGameTest.java | 27 ++++++++++++++----- .../java/domain/ladder/LadderFactoryTest.java | 17 ++++++------ src/test/java/domain/ladder/LadderTest.java | 8 +++--- src/test/java/domain/ladder/LineTest.java | 2 +- src/test/java/domain/ladder/PointTest.java | 2 +- .../java/strategy/FixedLineGenerator.java | 4 +-- 16 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/main/java/domain/dto/ResponseLadderResult.java b/src/main/java/domain/dto/ResponseLadderResult.java index 02a76253..fdcc7cc5 100644 --- a/src/main/java/domain/dto/ResponseLadderResult.java +++ b/src/main/java/domain/dto/ResponseLadderResult.java @@ -1,7 +1,7 @@ package domain.dto; -import domain.Width; import domain.ladder.Ladder; +import domain.player.Players; import java.util.List; import java.util.stream.IntStream; @@ -11,8 +11,8 @@ public record ResponseLadderResult( private static final String LADDER_RESULT_ARROW = " -> "; - public static ResponseLadderResult of(final Ladder ladder, final Width width) { - List result = IntStream.range(0, width.value()) + public static ResponseLadderResult of(final Ladder ladder, final Players players) { + List result = IntStream.range(0, players.values().size()) .mapToObj(start -> start + LADDER_RESULT_ARROW + ladder.move(start)) .toList(); return new ResponseLadderResult(result); diff --git a/src/main/java/domain/dto/ResponseLine.java b/src/main/java/domain/dto/ResponseLine.java index da04e413..7cfde70d 100644 --- a/src/main/java/domain/dto/ResponseLine.java +++ b/src/main/java/domain/dto/ResponseLine.java @@ -1,7 +1,7 @@ package domain.dto; -import domain.Line; -import domain.Point; +import domain.ladder.Line; +import domain.ladder.Point; import java.util.List; public record ResponseLine( diff --git a/src/main/java/domain/ladder/Direction.java b/src/main/java/domain/ladder/Direction.java index 198689b5..3311b311 100644 --- a/src/main/java/domain/ladder/Direction.java +++ b/src/main/java/domain/ladder/Direction.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; public enum Direction { LEFT(-1), diff --git a/src/main/java/domain/ladder/Ladder.java b/src/main/java/domain/ladder/Ladder.java index 61176358..69828929 100644 --- a/src/main/java/domain/ladder/Ladder.java +++ b/src/main/java/domain/ladder/Ladder.java @@ -1,8 +1,6 @@ package domain.ladder; -import domain.Direction; -import domain.Line; -import domain.Width; +import domain.player.Players; import java.util.Collections; import java.util.List; import java.util.stream.IntStream; @@ -19,8 +17,8 @@ public static Ladder from(final List lines) { return new Ladder(lines); } - public boolean isFullyConnected(final Width width) { - return IntStream.range(0, width.value() - 1) + public boolean isFullyConnected(final Players players) { + return IntStream.range(0, players.values().size() - 1) .allMatch(this::isConnectedBetween); } diff --git a/src/main/java/domain/ladder/LadderFactory.java b/src/main/java/domain/ladder/LadderFactory.java index c8eb0875..27030bcd 100644 --- a/src/main/java/domain/ladder/LadderFactory.java +++ b/src/main/java/domain/ladder/LadderFactory.java @@ -1,8 +1,6 @@ package domain.ladder; -import domain.Height; -import domain.Line; -import domain.Width; +import domain.player.Players; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -13,22 +11,23 @@ public class LadderFactory { private static final int MAX_ATTEMPTS = 50; - public Ladder draw(final Width width, final Height height, final LineGenerator generator) { - return findDrawableLadder(width, height, generator) + public Ladder draw(final Players players, final Height height, final LineGenerator generator) { + return findDrawableLadder(players, height, generator) .orElseThrow(() -> new IllegalArgumentException("유효한 사다리를 생성할 수 없습니다.")); } - private Optional findDrawableLadder(final Width width, final Height height, final LineGenerator generator) { + private Optional findDrawableLadder(final Players players, final Height height, + final LineGenerator generator) { return IntStream.range(0, MAX_ATTEMPTS) - .mapToObj(attempt -> drawLadder(width, height, generator)) - .filter(ladder -> ladder.isFullyConnected(width)) + .mapToObj(attempt -> drawLadder(players, height, generator)) + .filter(ladder -> ladder.isFullyConnected(players)) .findFirst(); } - private Ladder drawLadder(final Width width, final Height height, final LineGenerator lineGenerator) { + private Ladder drawLadder(final Players players, final Height height, final LineGenerator lineGenerator) { List lines = new ArrayList<>(); for (int i = 0; i < height.value(); i++) { - lines.add(lineGenerator.generate(width.value())); + lines.add(lineGenerator.generate(players.values().size())); } return Ladder.from(lines); } diff --git a/src/main/java/domain/ladder/Line.java b/src/main/java/domain/ladder/Line.java index 52427b52..53f3aa8e 100644 --- a/src/main/java/domain/ladder/Line.java +++ b/src/main/java/domain/ladder/Line.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; import java.util.List; diff --git a/src/main/java/domain/ladder/Point.java b/src/main/java/domain/ladder/Point.java index c2b244f5..8c99c759 100644 --- a/src/main/java/domain/ladder/Point.java +++ b/src/main/java/domain/ladder/Point.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; public record Point( boolean right diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java index 7fc71480..849b3239 100644 --- a/src/main/java/domain/player/Players.java +++ b/src/main/java/domain/player/Players.java @@ -7,6 +7,7 @@ import java.util.Set; public class Players { + static final int MIN_PLAYER_SIZE = 2; static final int MAX_PLAYER_SIZE = 24; private final List players; diff --git a/src/main/java/strategy/LineGenerator.java b/src/main/java/strategy/LineGenerator.java index 5c8d314e..42b15702 100644 --- a/src/main/java/strategy/LineGenerator.java +++ b/src/main/java/strategy/LineGenerator.java @@ -1,6 +1,6 @@ package strategy; -import domain.Line; +import domain.ladder.Line; public interface LineGenerator { Line generate(int width); diff --git a/src/main/java/strategy/RandomLineGenerator.java b/src/main/java/strategy/RandomLineGenerator.java index e4833820..f5b31f75 100644 --- a/src/main/java/strategy/RandomLineGenerator.java +++ b/src/main/java/strategy/RandomLineGenerator.java @@ -1,7 +1,7 @@ package strategy; -import domain.Line; -import domain.Point; +import domain.ladder.Line; +import domain.ladder.Point; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/domain/dto/RequestLadderGameTest.java b/src/test/java/domain/dto/RequestLadderGameTest.java index 61040552..929cf8f2 100644 --- a/src/test/java/domain/dto/RequestLadderGameTest.java +++ b/src/test/java/domain/dto/RequestLadderGameTest.java @@ -3,34 +3,47 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import domain.Height; +import domain.ladder.Height; +import domain.player.Players; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; -class RequestLadderTest { +class RequestLadderGameTest { + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("플레이어들의 이름을 입력하지 않았을 경우 예외가 발생한다.") + void shouldThrowException_whenEmptyPlayerNames(String playerNames) { + // given & when & then + assertThatThrownBy(() -> new RequestLadderGame(playerNames, "5")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어들의 이름을 입력해야 합니다."); + } @ParameterizedTest @NullAndEmptySource @DisplayName("사다리의 높이를 입력하지 않았을 경우 예외가 발생한다.") void shouldThrowException_whenEmptyHeight(String height) { // given & when & then - assertThatThrownBy(() -> new RequestLadder(height)) + assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", height)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 넓이와 높이를 입력해야 합니다."); + .hasMessage("사다리의 높이를 입력해야 합니다."); } @Test - @DisplayName("유효한 넓이와 높이를 입력하면 올바르게 객체가 생성된다.") + @DisplayName("유효한 플레이어의 이름과 높이를 입력하면 올바르게 객체가 생성된다.") void shouldReturnCorrectWidthAndHeight() { // given - RequestLadder requestLadder = new RequestLadder("7"); + RequestLadderGame requestLadderGame = new RequestLadderGame("neo,brown,brie,tommy", "7"); // when - Height height = requestLadder.toHeight(); + Players players = requestLadderGame.toPlayers(); + Height height = requestLadderGame.toHeight(); // then + assertThat(players.values().size()).isEqualTo(4); assertThat(height.value()).isEqualTo(7); } } diff --git a/src/test/java/domain/ladder/LadderFactoryTest.java b/src/test/java/domain/ladder/LadderFactoryTest.java index cc342279..499490f4 100644 --- a/src/test/java/domain/ladder/LadderFactoryTest.java +++ b/src/test/java/domain/ladder/LadderFactoryTest.java @@ -3,8 +3,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import domain.Height; -import domain.Width; +import domain.player.Name; +import domain.player.Player; +import domain.player.Players; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -27,11 +28,11 @@ void shouldReturnLadder_whenValid() { LadderFactory factory = new LadderFactory(); // when - Ladder ladder = factory.draw(Width.from(4), Height.from(4), fixedGenerator); +// Ladder ladder = factory.draw(, Height.from(4), fixedGenerator); // then - assertThat(ladder).isNotNull(); - assertThat(ladder.isFullyConnected(Width.from(4))).isTrue(); +// assertThat(ladder).isNotNull(); +// assertThat(ladder.isFullyConnected(Players.from(4))).isTrue(); } @Test @@ -46,8 +47,8 @@ void shouldThrowException_whenInvalidLadder() { LadderFactory factory = new LadderFactory(); // when & then - assertThatThrownBy(() -> factory.draw(Width.from(4), Height.from(4), fixedGenerator)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("유효한 사다리를 생성할 수 없습니다."); +// assertThatThrownBy(() -> factory.draw(Players.from(4), Height.from(4), fixedGenerator)) +// .isInstanceOf(IllegalArgumentException.class) +// .hasMessage("유효한 사다리를 생성할 수 없습니다."); } } diff --git a/src/test/java/domain/ladder/LadderTest.java b/src/test/java/domain/ladder/LadderTest.java index 9af5de48..53b5b146 100644 --- a/src/test/java/domain/ladder/LadderTest.java +++ b/src/test/java/domain/ladder/LadderTest.java @@ -3,9 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import domain.Line; -import domain.Point; -import domain.Width; +import domain.player.Players; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -50,7 +48,7 @@ void shouldCheckIsFullyConnected() { Ladder ladder = Ladder.from(lines); // when & then - assertThat(ladder.isFullyConnected(Width.from(3))).isTrue(); +// assertThat(ladder.isFullyConnected(Players.from(3))).isTrue(); } @Test @@ -65,7 +63,7 @@ void shouldCheckIsNotFullyConnected() { Ladder ladder = Ladder.from(lines); // when & then - assertThat(ladder.isFullyConnected(Width.from(3))).isFalse(); +// assertThat(ladder.isFullyConnected(Players.from(3))).isFalse(); } @Test diff --git a/src/test/java/domain/ladder/LineTest.java b/src/test/java/domain/ladder/LineTest.java index aaa00aa9..a13b6a20 100644 --- a/src/test/java/domain/ladder/LineTest.java +++ b/src/test/java/domain/ladder/LineTest.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/domain/ladder/PointTest.java b/src/test/java/domain/ladder/PointTest.java index 5f22da7c..8bbf6197 100644 --- a/src/test/java/domain/ladder/PointTest.java +++ b/src/test/java/domain/ladder/PointTest.java @@ -1,4 +1,4 @@ -package domain; +package domain.ladder; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/strategy/FixedLineGenerator.java b/src/test/java/strategy/FixedLineGenerator.java index 75e702de..cf8ef62e 100644 --- a/src/test/java/strategy/FixedLineGenerator.java +++ b/src/test/java/strategy/FixedLineGenerator.java @@ -1,7 +1,7 @@ package strategy; -import domain.Line; -import domain.Point; +import domain.ladder.Line; +import domain.ladder.Point; import java.util.ArrayList; import java.util.List; From 0c22e46e6c49aa7666c0515d07b4dc3a727f862d Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Wed, 11 Jun 2025 20:01:18 +0900 Subject: [PATCH 03/15] =?UTF-8?q?docs:=20step=204=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7ea051c7..70fc053e 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,31 @@ ## 요구사항 -- 사다리의 높이와 넓이를 입력받아 생성한다. - - 넓이와 높이는 2 이상 24 이하 여야한다. -- 사다리의 시작 지점과 도착 지점을 출력한다. +- 참여할 사람 이름 (쉼표 기준) + - 이름은 최대 5자까지 가능하다. +- 실행 결과 ex) 꽝, 5000, 꽝, 3000 +- 최대 사다리 높이 + - 높이는 2 이상 24 이하 여야한다. +- 결과를 볼 사람의 이름 + - 참여할 사람을 입력할 시 결과만 출력 + ```text + 결과를 보고 싶은 사람은? + neo + + 실행 결과 + 꽝 + ``` + - `all`을 입력할 시 전체 출력 후 종료 + ```text + 결과를 보고 싶은 사람은? + all + + 실행 결과 + neo : 꽝 + brown : 3000 + brie : 꽝 + tommy : 5000 + ``` ## 구현 기능 From 087c8a10d64be3f4be71624556ffed15fccca459 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Wed, 11 Jun 2025 20:06:45 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/player/Players.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java index 849b3239..413b223e 100644 --- a/src/main/java/domain/player/Players.java +++ b/src/main/java/domain/player/Players.java @@ -10,6 +10,7 @@ public class Players { static final int MIN_PLAYER_SIZE = 2; static final int MAX_PLAYER_SIZE = 24; + private final List players; private Players(final List players) { From d76f7f316a06f9a735c59b63fca0e49013ad96b9 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Wed, 11 Jun 2025 20:56:18 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor:=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 27 ++++++++--------- .../java/domain/dto/RequestLadderGame.java | 27 +++++++++++++++-- .../java/domain/runningResult/Result.java | 16 ++++++++++ .../java/domain/runningResult/Results.java | 29 +++++++++++++++++++ src/main/java/view/InputView.java | 11 +++++-- .../domain/dto/RequestLadderGameTest.java | 23 +++++++++++---- 6 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 src/main/java/domain/runningResult/Result.java create mode 100644 src/main/java/domain/runningResult/Results.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 2b480778..69fde5cd 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,12 +1,12 @@ package controller; -import domain.Height; -import domain.Width; -import domain.dto.RequestLadder; +import domain.dto.RequestLadderGame; import domain.dto.ResponseLadder; import domain.dto.ResponseLadderResult; +import domain.ladder.Height; import domain.ladder.Ladder; import domain.ladder.LadderFactory; +import domain.player.Players; import strategy.LineGenerator; import strategy.PointGenerator; import strategy.RandomLineGenerator; @@ -17,21 +17,22 @@ public class LadderController { public void play() { - RequestLadder requestLadder = inputLadderSettings(); - Width width = requestLadder.toWidth(); - Height height = requestLadder.toHeight(); + RequestLadderGame requestLadderGame = inputLadderSettings(); + Players players = requestLadderGame.toPlayers(); + Height height = requestLadderGame.toHeight(); LineGenerator lineGenerator = createLineGenerator(); LadderFactory factory = new LadderFactory(); - Ladder ladder = factory.draw(width, height, lineGenerator); + Ladder ladder = factory.draw(players, height, lineGenerator); - drawLadder(ladder, width); + drawLadder(ladder, players); } - private RequestLadder inputLadderSettings() { - String width = InputView.inputLadderWidth(); + private RequestLadderGame inputLadderSettings() { + String playerNames = InputView.inputPlayerNames(); + String runningResult = InputView.inputRunningResult(); String height = InputView.inputLadderHeight(); - return new RequestLadder(width, height); + return new RequestLadderGame(playerNames, runningResult, height); } private LineGenerator createLineGenerator() { @@ -39,13 +40,13 @@ private LineGenerator createLineGenerator() { return new RandomLineGenerator(pointGenerator); } - private void drawLadder(final Ladder ladder, final Width width) { + private void drawLadder(final Ladder ladder, final Players players) { OutputView.printLadderResultTitle(); ResponseLadder responseLadder = ResponseLadder.from(ladder); OutputView.drawLadder(responseLadder); - ResponseLadderResult responseResult = ResponseLadderResult.of(ladder, width); + ResponseLadderResult responseResult = ResponseLadderResult.of(ladder, players); OutputView.printLadderResult(responseResult); } } diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java index 8510d777..fa338f43 100644 --- a/src/main/java/domain/dto/RequestLadderGame.java +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -2,18 +2,21 @@ import domain.ladder.Height; import domain.player.Players; +import domain.runningResult.Results; import java.util.List; import java.util.stream.Stream; public record RequestLadderGame( String playerNames, + String runningResults, String height ) { - static final String NAME_DELIMITER = ","; + static final String INPUT_DELIMITER = ","; public RequestLadderGame { validateEmptyPlayerNames(playerNames); + validateEmptyResults(runningResults); validateEmptyHeight(height); } @@ -23,6 +26,12 @@ private void validateEmptyPlayerNames(final String playerNames) { } } + private void validateEmptyResults(final String results) { + if (results == null || results.isBlank()) { + throw new IllegalArgumentException("실행 결과를 입력해야 합니다."); + } + } + private void validateEmptyHeight(final String height) { if (height == null || height.isBlank()) { throw new IllegalArgumentException("사다리의 높이를 입력해야 합니다."); @@ -30,7 +39,7 @@ private void validateEmptyHeight(final String height) { } public Players toPlayers() { - List names = Stream.of(playerNames.split(NAME_DELIMITER)) + List names = Stream.of(playerNames.split(INPUT_DELIMITER)) .map(String::strip) .toList(); return Players.from(names); @@ -44,4 +53,18 @@ public Height toHeight() { } } + public Results toResults(final int playerCount) { + List results = Stream.of(runningResults.split(INPUT_DELIMITER)) + .map(String::strip) + .toList(); + + validatePlayerCountEqualsResultsCount(playerCount, results); + return Results.from(results); + } + + private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List results) { + if (playerCount != results.size()) { + throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다."); + } + } } diff --git a/src/main/java/domain/runningResult/Result.java b/src/main/java/domain/runningResult/Result.java new file mode 100644 index 00000000..a267bcac --- /dev/null +++ b/src/main/java/domain/runningResult/Result.java @@ -0,0 +1,16 @@ +package domain.runningResult; + +public record Result( + String value +) { + + public Result { + validateEmptyResult(value); + } + + private void validateEmptyResult(final String value) { + if (value == null || value.isBlank()) { + throw new IllegalArgumentException("실행 결과를 입력해야 합니다."); + } + } +} diff --git a/src/main/java/domain/runningResult/Results.java b/src/main/java/domain/runningResult/Results.java new file mode 100644 index 00000000..44f740a3 --- /dev/null +++ b/src/main/java/domain/runningResult/Results.java @@ -0,0 +1,29 @@ +package domain.runningResult; + +import java.util.Collections; +import java.util.List; + +public class Results { + + private final List values; + + private Results(final List values) { + this.values = values; + } + + public static Results from(final List results) { + return new Results( + results.stream() + .map(Result::new) + .toList() + ); + } + + public Result get(final int index) { + return values.get(index); + } + + public List asList() { + return Collections.unmodifiableList(values); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 79e8bb23..311f9570 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -9,14 +9,19 @@ public final class InputView { private InputView() { } - public static String inputLadderWidth() { - System.out.println("사다리의 넓이는 몇 인가요?"); + public static String inputPlayerNames() { + System.out.println("참여할 플레이어의 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + return sc.nextLine(); + } + + public static String inputRunningResult() { + System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); return sc.nextLine(); } public static String inputLadderHeight() { System.out.println(); - System.out.println("사다리의 높이는 몇 인가요?"); + System.out.println("사다리의 최대 높이는 몇 인가요?"); return sc.nextLine(); } } diff --git a/src/test/java/domain/dto/RequestLadderGameTest.java b/src/test/java/domain/dto/RequestLadderGameTest.java index 929cf8f2..a7791025 100644 --- a/src/test/java/domain/dto/RequestLadderGameTest.java +++ b/src/test/java/domain/dto/RequestLadderGameTest.java @@ -5,6 +5,7 @@ import domain.ladder.Height; import domain.player.Players; +import domain.runningResult.Results; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -17,33 +18,45 @@ class RequestLadderGameTest { @DisplayName("플레이어들의 이름을 입력하지 않았을 경우 예외가 발생한다.") void shouldThrowException_whenEmptyPlayerNames(String playerNames) { // given & when & then - assertThatThrownBy(() -> new RequestLadderGame(playerNames, "5")) + assertThatThrownBy(() -> new RequestLadderGame(playerNames, "꽝,5000,꽝,2000", "5")) .isInstanceOf(IllegalArgumentException.class) .hasMessage("플레이어들의 이름을 입력해야 합니다."); } + @ParameterizedTest + @NullAndEmptySource + @DisplayName("실행 결과를 입력하지 않았을 경우 예외가 발생한다.") + void shouldThrowException_whenEmptyRunningResults(String runningResults) { + // given & when & then + assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", runningResults, "5")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행 결과를 입력해야 합니다."); + } + @ParameterizedTest @NullAndEmptySource @DisplayName("사다리의 높이를 입력하지 않았을 경우 예외가 발생한다.") void shouldThrowException_whenEmptyHeight(String height) { // given & when & then - assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", height)) + assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", "꽝,5000,꽝,2000", height)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("사다리의 높이를 입력해야 합니다."); } @Test - @DisplayName("유효한 플레이어의 이름과 높이를 입력하면 올바르게 객체가 생성된다.") - void shouldReturnCorrectWidthAndHeight() { + @DisplayName("유효한 사다리 게임의 입력 값인 경우 객체가 생성된다.") + void shouldReturn_whenValidLadderGameValue() { // given - RequestLadderGame requestLadderGame = new RequestLadderGame("neo,brown,brie,tommy", "7"); + RequestLadderGame requestLadderGame = new RequestLadderGame("neo,brown,brie,tommy", "꽝,5000,꽝,2000", "7"); // when Players players = requestLadderGame.toPlayers(); + Results results = requestLadderGame.toResults(players.values().size()); Height height = requestLadderGame.toHeight(); // then assertThat(players.values().size()).isEqualTo(4); + assertThat(results.asList().size()).isEqualTo(4); assertThat(height.value()).isEqualTo(7); } } From 7368b284bdae8d58db48a8c042a0415b6571990c Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Thu, 12 Jun 2025 02:37:30 +0900 Subject: [PATCH 06/15] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 입력받은 플레이어의 결과와 전체 결과를 볼 수 있게 수정하였습니다. - 전체 결과를 출력하기 전까지 확인하고 싶은 플레이어의 결과를 계속 확인할 수 있게 하였습니다. --- .../java/controller/LadderController.java | 71 ++++++++++++++----- .../java/domain/dto/RequestLadderGame.java | 12 ++-- .../java/domain/dto/ResponseLadderResult.java | 20 ------ .../domain/ladder/result/LadderResult.java | 7 ++ .../ladder/result/LadderResultBoard.java | 45 ++++++++++++ src/main/java/domain/player/Player.java | 14 +--- src/main/java/domain/player/Players.java | 2 +- .../java/domain/runningResult/Results.java | 4 -- src/main/java/view/InputView.java | 7 ++ src/main/java/view/OutputView.java | 44 ++++++++++-- .../java/domain/ladder/LadderFactoryTest.java | 6 -- src/test/java/domain/ladder/LadderTest.java | 1 - 12 files changed, 162 insertions(+), 71 deletions(-) delete mode 100644 src/main/java/domain/dto/ResponseLadderResult.java create mode 100644 src/main/java/domain/ladder/result/LadderResult.java create mode 100644 src/main/java/domain/ladder/result/LadderResultBoard.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 69fde5cd..02fbf89e 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -2,11 +2,14 @@ import domain.dto.RequestLadderGame; import domain.dto.ResponseLadder; -import domain.dto.ResponseLadderResult; import domain.ladder.Height; import domain.ladder.Ladder; import domain.ladder.LadderFactory; +import domain.ladder.result.LadderResultBoard; import domain.player.Players; +import domain.runningResult.Results; +import java.util.function.Function; +import java.util.function.Supplier; import strategy.LineGenerator; import strategy.PointGenerator; import strategy.RandomLineGenerator; @@ -16,23 +19,33 @@ public class LadderController { + private static final String FINISH_KEYWORD = "all"; + private static final String NOT_FOUND_PLAYER_RETRY_MESSAGE = "존재하지 않는 플레이어입니다. 다시 입력해주세요."; + public void play() { - RequestLadderGame requestLadderGame = inputLadderSettings(); - Players players = requestLadderGame.toPlayers(); - Height height = requestLadderGame.toHeight(); + RequestLadderGame request = inputLadderSettings(); + Players players = request.toPlayers(); + Height height = request.toHeight(); + Results results = request.toResults(players.values().size()); - LineGenerator lineGenerator = createLineGenerator(); - LadderFactory factory = new LadderFactory(); - Ladder ladder = factory.draw(players, height, lineGenerator); + Ladder ladder = drawLadder(players, height); + LadderResultBoard resultBoard = LadderResultBoard.of(players, ladder, results); - drawLadder(ladder, players); + showGameScreen(players, ladder, results); + showPlayerResult(resultBoard); } private RequestLadderGame inputLadderSettings() { - String playerNames = InputView.inputPlayerNames(); - String runningResult = InputView.inputRunningResult(); + String names = InputView.inputPlayerNames(); + String results = InputView.inputRunningResult(); String height = InputView.inputLadderHeight(); - return new RequestLadderGame(playerNames, runningResult, height); + return new RequestLadderGame(names, results, height); + } + + private Ladder drawLadder(final Players players, final Height height) { + LineGenerator generator = createLineGenerator(); + LadderFactory factory = new LadderFactory(); + return factory.draw(players, height, generator); } private LineGenerator createLineGenerator() { @@ -40,13 +53,39 @@ private LineGenerator createLineGenerator() { return new RandomLineGenerator(pointGenerator); } - private void drawLadder(final Ladder ladder, final Players players) { + private void showGameScreen(final Players players, final Ladder ladder, final Results results) { OutputView.printLadderResultTitle(); + OutputView.printPlayerNames(players); + OutputView.drawLadder(ResponseLadder.from(ladder)); + OutputView.printResults(results); + } + + private void showPlayerResult(final LadderResultBoard board) { + repeatUntilDone( + InputView::inputTargetPlayer, + input -> { + if (input.equals(FINISH_KEYWORD)) { + OutputView.printAllLadderResult(board); + return true; + } - ResponseLadder responseLadder = ResponseLadder.from(ladder); - OutputView.drawLadder(responseLadder); + if (board.findResultOf(input).isEmpty()) { + System.out.println(); + System.out.println(NOT_FOUND_PLAYER_RETRY_MESSAGE); + return false; + } + + OutputView.printSingleLadderResult(board, input); + return false; + } + ); + } - ResponseLadderResult responseResult = ResponseLadderResult.of(ladder, players); - OutputView.printLadderResult(responseResult); + private void repeatUntilDone(Supplier inputSupplier, Function handler) { + boolean done = false; + while (!done) { + String input = inputSupplier.get(); + done = handler.apply(input); + } } } diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java index fa338f43..c189c5ba 100644 --- a/src/main/java/domain/dto/RequestLadderGame.java +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -20,6 +20,12 @@ public record RequestLadderGame( validateEmptyHeight(height); } + private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List results) { + if (playerCount != results.size()) { + throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다."); + } + } + private void validateEmptyPlayerNames(final String playerNames) { if (playerNames == null || playerNames.isBlank()) { throw new IllegalArgumentException("플레이어들의 이름을 입력해야 합니다."); @@ -61,10 +67,4 @@ public Results toResults(final int playerCount) { validatePlayerCountEqualsResultsCount(playerCount, results); return Results.from(results); } - - private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List results) { - if (playerCount != results.size()) { - throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다."); - } - } } diff --git a/src/main/java/domain/dto/ResponseLadderResult.java b/src/main/java/domain/dto/ResponseLadderResult.java deleted file mode 100644 index fdcc7cc5..00000000 --- a/src/main/java/domain/dto/ResponseLadderResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package domain.dto; - -import domain.ladder.Ladder; -import domain.player.Players; -import java.util.List; -import java.util.stream.IntStream; - -public record ResponseLadderResult( - List results -) { - - private static final String LADDER_RESULT_ARROW = " -> "; - - public static ResponseLadderResult of(final Ladder ladder, final Players players) { - List result = IntStream.range(0, players.values().size()) - .mapToObj(start -> start + LADDER_RESULT_ARROW + ladder.move(start)) - .toList(); - return new ResponseLadderResult(result); - } -} diff --git a/src/main/java/domain/ladder/result/LadderResult.java b/src/main/java/domain/ladder/result/LadderResult.java new file mode 100644 index 00000000..f244006d --- /dev/null +++ b/src/main/java/domain/ladder/result/LadderResult.java @@ -0,0 +1,7 @@ +package domain.ladder.result; + +public record LadderResult( + String player, + String result +) { +} diff --git a/src/main/java/domain/ladder/result/LadderResultBoard.java b/src/main/java/domain/ladder/result/LadderResultBoard.java new file mode 100644 index 00000000..2874a1fd --- /dev/null +++ b/src/main/java/domain/ladder/result/LadderResultBoard.java @@ -0,0 +1,45 @@ +package domain.ladder.result; + +import static java.util.stream.Collectors.toMap; + +import domain.ladder.Ladder; +import domain.player.Players; +import domain.runningResult.Results; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.IntStream; + +public class LadderResultBoard { + private final List ladderResults; + private final Map ladderResultCache; + + public LadderResultBoard(final List ladderResults) { + this.ladderResults = List.copyOf(ladderResults); + this.ladderResultCache = ladderResults.stream() + .collect(toMap(LadderResult::player, Function.identity())); + } + + public static LadderResultBoard of(final Players players, final Ladder ladder, final Results results) { + List ladderResults = IntStream.range(0, players.values().size()) + .mapToObj(startIndex -> { + String playerName = players.values().get(startIndex).name().value(); + int destinationIndex = ladder.move(startIndex); + String resultValue = results.asList().get(destinationIndex).value(); + return new LadderResult(playerName, resultValue); + }) + .toList(); + + return new LadderResultBoard(ladderResults); + } + + public Optional findResultOf(final String playerName) { + return Optional.ofNullable(ladderResultCache.get(playerName)) + .map(LadderResult::result); + } + + public List getAllResults() { + return ladderResults; + } +} diff --git a/src/main/java/domain/player/Player.java b/src/main/java/domain/player/Player.java index 84e737a2..a07b5db2 100644 --- a/src/main/java/domain/player/Player.java +++ b/src/main/java/domain/player/Player.java @@ -1,14 +1,6 @@ package domain.player; -public class Player { - - private final Name name; - - public Player(final Name name) { - this.name = name; - } - - public Name getName() { - return name; - } +public record Player( + Name name +) { } diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java index 413b223e..56fb37b1 100644 --- a/src/main/java/domain/player/Players.java +++ b/src/main/java/domain/player/Players.java @@ -43,7 +43,7 @@ private void validateDuplicateName(final List players) { private Set uniqueNamesFrom(final List players) { return players.stream() - .map(player -> player.getName().value()) + .map(player -> player.name().value()) .collect(toSet()); } diff --git a/src/main/java/domain/runningResult/Results.java b/src/main/java/domain/runningResult/Results.java index 44f740a3..370b8119 100644 --- a/src/main/java/domain/runningResult/Results.java +++ b/src/main/java/domain/runningResult/Results.java @@ -19,10 +19,6 @@ public static Results from(final List results) { ); } - public Result get(final int index) { - return values.get(index); - } - public List asList() { return Collections.unmodifiableList(values); } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 311f9570..8e954577 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -15,6 +15,7 @@ public static String inputPlayerNames() { } public static String inputRunningResult() { + System.out.println(); System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); return sc.nextLine(); } @@ -24,4 +25,10 @@ public static String inputLadderHeight() { System.out.println("사다리의 최대 높이는 몇 인가요?"); return sc.nextLine(); } + + public static String inputTargetPlayer() { + System.out.println(); + System.out.println("결과를 보고 싶은 사람은?"); + return sc.nextLine(); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index d8c02d4e..46e7b4ed 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,12 +1,16 @@ package view; import domain.dto.ResponseLadder; -import domain.dto.ResponseLadderResult; import domain.dto.ResponseLine; +import domain.ladder.result.LadderResultBoard; +import domain.player.Players; +import domain.runningResult.Results; public final class OutputView { - private static final String LADDER_RESULT_TITLE = "실행결과"; + private static final String LADDER_RESULT_TITLE = "사다리 결과"; + private static final String RUNNING_RESULT_TITLE = "실행 결과"; + private static final int CELL_WIDTH = 6; private static final String BLANK = " "; private static final String VERTICAL = "|"; @@ -15,6 +19,14 @@ public final class OutputView { private OutputView() { } + public static void printPlayerNames(final Players players) { + System.out.print(BLANK); + players.values().forEach(player -> + System.out.print(padding(player.name().value())) + ); + System.out.println(); + } + public static void printLadderResultTitle() { System.out.println(); System.out.println(LADDER_RESULT_TITLE); @@ -47,10 +59,30 @@ private static String drawHorizontalIfConnected(final boolean connected) { return BLANK; } - public static void printLadderResult(final ResponseLadderResult result) { + public static void printResults(final Results results) { + System.out.print(BLANK); + results.asList().forEach(result -> + System.out.print(padding(result.value())) + ); System.out.println(); - for (String line : result.results()) { - System.out.println(line); - } + } + + public static void printSingleLadderResult(final LadderResultBoard resultBoard, final String player) { + System.out.println(); + System.out.println(RUNNING_RESULT_TITLE); + String result = resultBoard.findResultOf(player) + .orElse("존재하지 않는 플레이어입니다."); + System.out.println(result); + } + + public static void printAllLadderResult(final LadderResultBoard resultBoard) { + System.out.println(); + System.out.println(RUNNING_RESULT_TITLE); + resultBoard.getAllResults().forEach(result -> + System.out.println(result.player() + " : " + result.result())); + } + + private static String padding(String text) { + return String.format("%-" + CELL_WIDTH + "s", text); } } diff --git a/src/test/java/domain/ladder/LadderFactoryTest.java b/src/test/java/domain/ladder/LadderFactoryTest.java index 499490f4..89ade7d1 100644 --- a/src/test/java/domain/ladder/LadderFactoryTest.java +++ b/src/test/java/domain/ladder/LadderFactoryTest.java @@ -1,11 +1,5 @@ package domain.ladder; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import domain.player.Name; -import domain.player.Player; -import domain.player.Players; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/ladder/LadderTest.java b/src/test/java/domain/ladder/LadderTest.java index 53b5b146..6beffdd6 100644 --- a/src/test/java/domain/ladder/LadderTest.java +++ b/src/test/java/domain/ladder/LadderTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import domain.player.Players; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 08faac5e04f313a00318290a1a9a4917cdabad08 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Thu, 12 Jun 2025 02:45:41 +0900 Subject: [PATCH 07/15] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 68 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 70fc053e..43872696 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,25 @@ ## 구현 기능 +### 플레이어(들) + +- 플레이어 이름 목록을 관리한다. +- 각 플레이어는 고유한 이름을 가진다. +- 이름 길이 제약 및 중복 방지를 검증한다. +- 사다리 결과 조회 시 이름으로 식별된다. + +### 실행 결과(들) + +- 실행 결과 값을 리스트로 관리한다. +- 플레이어 수와 결과 수가 일치하는지 검증한다. +- 결과는 순서가 보장되며, 인덱스를 기준으로 조회된다. + +### 사다리 결과 보드 + +- 사다리 구조와 실행 결과, 플레이어를 매핑하여 결과 보드를 생성한다. +- 플레이어 이름 → 결과값 을 빠르게 조회할 수 있도록 캐싱한다. +- 전체 결과 또는 특정 플레이어 결과를 제공한다. + ### 사다리 - 여러 개의 라인을 가지며 전체 사다리 구조를 나타낸다. @@ -66,23 +85,44 @@ ## 출력 예시 ```text -사다리의 넓이는 몇 인가요? -5 +참여할 플레이어의 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요) +neo,brown,brie,tommy -사다리의 높이는 몇 인가요? +실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요) +꽝,5000,꽝,3000 + +사다리의 최대 높이는 몇 인가요? 5 -실행결과 +사다리 결과 + + neo brown brie tommy + |-----| | | + |-----| |-----| + | | |-----| + | |-----| | + |-----| | | + 꽝 5000 꽝 3000 + +결과를 보고 싶은 사람은? +neo + +실행 결과 +5000 + +결과를 보고 싶은 사람은? +brie + +실행 결과 +꽝 + +결과를 보고 싶은 사람은? +all - |-----| |-----| | - | | | |-----| - |-----| | | | - | |-----| |-----| - |-----| |-----| | +실행 결과 +neo : 5000 +brown : 꽝 +brie : 꽝 +tommy : 3000 -0 -> 1 -1 -> 3 -2 -> 2 -3 -> 0 -4 -> 4 ``` From cc269c5011203c9f460e8e699954b9cfc636e188 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Fri, 13 Jun 2025 15:24:37 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refacotor:=20Player=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20=ED=9B=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/ladder/LadderFactoryTest.java | 18 ++++++++++++------ src/test/java/domain/ladder/LadderTest.java | 8 ++++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/test/java/domain/ladder/LadderFactoryTest.java b/src/test/java/domain/ladder/LadderFactoryTest.java index 89ade7d1..01a64587 100644 --- a/src/test/java/domain/ladder/LadderFactoryTest.java +++ b/src/test/java/domain/ladder/LadderFactoryTest.java @@ -1,5 +1,9 @@ package domain.ladder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import domain.player.Players; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -20,13 +24,14 @@ void shouldReturnLadder_whenValid() { new boolean[]{true, false, true, false} )); LadderFactory factory = new LadderFactory(); + List names = List.of("dd", "dd2", "dd3"); // when -// Ladder ladder = factory.draw(, Height.from(4), fixedGenerator); + Ladder ladder = factory.draw(Players.from(names), Height.from(4), fixedGenerator); // then -// assertThat(ladder).isNotNull(); -// assertThat(ladder.isFullyConnected(Players.from(4))).isTrue(); + assertThat(ladder).isNotNull(); + assertThat(ladder.isFullyConnected(Players.from(names))).isTrue(); } @Test @@ -39,10 +44,11 @@ void shouldThrowException_whenInvalidLadder() { new boolean[]{false, false, false, false}) ); LadderFactory factory = new LadderFactory(); + List names = List.of("dd", "dd2", "dd3"); // when & then -// assertThatThrownBy(() -> factory.draw(Players.from(4), Height.from(4), fixedGenerator)) -// .isInstanceOf(IllegalArgumentException.class) -// .hasMessage("유효한 사다리를 생성할 수 없습니다."); + assertThatThrownBy(() -> factory.draw(Players.from(names), Height.from(4), fixedGenerator)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("유효한 사다리를 생성할 수 없습니다."); } } diff --git a/src/test/java/domain/ladder/LadderTest.java b/src/test/java/domain/ladder/LadderTest.java index 6beffdd6..4b8bc4e9 100644 --- a/src/test/java/domain/ladder/LadderTest.java +++ b/src/test/java/domain/ladder/LadderTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import domain.player.Players; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -45,9 +46,11 @@ void shouldCheckIsFullyConnected() { ); Ladder ladder = Ladder.from(lines); + List names = List.of("dd","dd2","dd3"); + // when & then -// assertThat(ladder.isFullyConnected(Players.from(3))).isTrue(); + assertThat(ladder.isFullyConnected(Players.from(names))).isTrue(); } @Test @@ -60,9 +63,10 @@ void shouldCheckIsNotFullyConnected() { ); Ladder ladder = Ladder.from(lines); + List names = List.of("dd","dd2","dd3"); // when & then -// assertThat(ladder.isFullyConnected(Players.from(3))).isFalse(); + assertThat(ladder.isFullyConnected(Players.from(names))).isFalse(); } @Test From 6afa93e149bf7ff980a66075fe0a3716b97ae15f Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sat, 14 Jun 2025 17:20:10 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor:=20=EB=94=94=EB=AF=B8=ED=84=B0?= =?UTF-8?q?=20=EB=B2=95=EC=B9=99=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=BB=A8=EB=B2=A4=EC=85=98=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ladder/result/LadderResultBoard.java | 7 +++-- src/main/java/domain/player/Name.java | 4 +-- src/main/java/domain/player/Players.java | 8 +++++ .../java/domain/runningResult/Results.java | 4 +++ src/test/java/domain/ladder/LadderTest.java | 5 ++-- .../java/domain/runningResult/ResultTest.java | 20 +++++++++++++ .../domain/runningResult/ResultsTest.java | 29 +++++++++++++++++++ 7 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 src/test/java/domain/runningResult/ResultTest.java create mode 100644 src/test/java/domain/runningResult/ResultsTest.java diff --git a/src/main/java/domain/ladder/result/LadderResultBoard.java b/src/main/java/domain/ladder/result/LadderResultBoard.java index 2874a1fd..d09de85c 100644 --- a/src/main/java/domain/ladder/result/LadderResultBoard.java +++ b/src/main/java/domain/ladder/result/LadderResultBoard.java @@ -12,6 +12,7 @@ import java.util.stream.IntStream; public class LadderResultBoard { + private final List ladderResults; private final Map ladderResultCache; @@ -22,11 +23,11 @@ public LadderResultBoard(final List ladderResults) { } public static LadderResultBoard of(final Players players, final Ladder ladder, final Results results) { - List ladderResults = IntStream.range(0, players.values().size()) + List ladderResults = IntStream.range(0, players.size()) .mapToObj(startIndex -> { - String playerName = players.values().get(startIndex).name().value(); + String playerName = players.name(startIndex); int destinationIndex = ladder.move(startIndex); - String resultValue = results.asList().get(destinationIndex).value(); + String resultValue = results.value(destinationIndex); return new LadderResult(playerName, resultValue); }) .toList(); diff --git a/src/main/java/domain/player/Name.java b/src/main/java/domain/player/Name.java index 7d0e3493..72936117 100644 --- a/src/main/java/domain/player/Name.java +++ b/src/main/java/domain/player/Name.java @@ -11,13 +11,13 @@ public record Name( validateNameLength(value); } - private void validateEmptyName(String value) { + private void validateEmptyName(final String value) { if (value == null || value.isBlank()) { throw new IllegalArgumentException("플레이어의 이름을 입력해야 합니다."); } } - private void validateNameLength(String value) { + private void validateNameLength(final String value) { if (MAX_NAME_LENGTH < value.length()) { throw new IllegalArgumentException("플레이어의 이름이 %d를 초과합니다.".formatted(MAX_NAME_LENGTH)); } diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java index 56fb37b1..77a13dd6 100644 --- a/src/main/java/domain/player/Players.java +++ b/src/main/java/domain/player/Players.java @@ -53,6 +53,14 @@ private void validateNameCountEqualsDistinctCount(final int total, final int dis } } + public int size() { + return players.size(); + } + + public String name(final int index) { + return players.get(index).name().value(); + } + public List values() { return Collections.unmodifiableList(players); } diff --git a/src/main/java/domain/runningResult/Results.java b/src/main/java/domain/runningResult/Results.java index 370b8119..e572e6f3 100644 --- a/src/main/java/domain/runningResult/Results.java +++ b/src/main/java/domain/runningResult/Results.java @@ -19,6 +19,10 @@ public static Results from(final List results) { ); } + public String value(final int index) { + return asList().get(index).value(); + } + public List asList() { return Collections.unmodifiableList(values); } diff --git a/src/test/java/domain/ladder/LadderTest.java b/src/test/java/domain/ladder/LadderTest.java index 4b8bc4e9..ad94a573 100644 --- a/src/test/java/domain/ladder/LadderTest.java +++ b/src/test/java/domain/ladder/LadderTest.java @@ -46,8 +46,7 @@ void shouldCheckIsFullyConnected() { ); Ladder ladder = Ladder.from(lines); - List names = List.of("dd","dd2","dd3"); - + List names = List.of("dd", "dd2", "dd3"); // when & then assertThat(ladder.isFullyConnected(Players.from(names))).isTrue(); @@ -63,7 +62,7 @@ void shouldCheckIsNotFullyConnected() { ); Ladder ladder = Ladder.from(lines); - List names = List.of("dd","dd2","dd3"); + List names = List.of("dd", "dd2", "dd3"); // when & then assertThat(ladder.isFullyConnected(Players.from(names))).isFalse(); diff --git a/src/test/java/domain/runningResult/ResultTest.java b/src/test/java/domain/runningResult/ResultTest.java new file mode 100644 index 00000000..a17b7809 --- /dev/null +++ b/src/test/java/domain/runningResult/ResultTest.java @@ -0,0 +1,20 @@ +package domain.runningResult; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +class ResultTest { + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("실행 결과가 입력되지 않았을 경우 예외가 발생한다.") + void shouldThrowException_whenEmptyResult(String value) { + // given & when & then + assertThatThrownBy(() -> new Result(value)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행 결과를 입력해야 합니다."); + } +} diff --git a/src/test/java/domain/runningResult/ResultsTest.java b/src/test/java/domain/runningResult/ResultsTest.java new file mode 100644 index 00000000..f6ef605d --- /dev/null +++ b/src/test/java/domain/runningResult/ResultsTest.java @@ -0,0 +1,29 @@ +package domain.runningResult; + + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ResultsTest { + + @Test + @DisplayName("실행 결과가 입력되면 정상적으로 객체를 생성한다.") + void shouldCreateResults_whenValidInputValues() { + // given + List inputValues = List.of("4000", "꽝", "3000"); + + // when + Results results = Results.from(inputValues); + + // then + List actual = results.asList().stream() + .map(Result::value) + .toList(); + + assertThat(actual).isEqualTo(inputValues); + } + +} From 1286d2d69153c90732308ecb42b92923f268059c Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 02:07:24 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20=EB=AA=85=ED=99=95=ED=95=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/dto/ResponseLine.java | 2 +- src/main/java/domain/ladder/Line.java | 6 +++--- src/main/java/domain/ladder/Point.java | 4 ++-- src/main/java/domain/ladder/result/LadderResult.java | 2 +- src/main/java/view/OutputView.java | 10 +++++----- src/test/java/domain/ladder/LineTest.java | 2 +- src/test/java/domain/ladder/PointTest.java | 10 +++++----- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/domain/dto/ResponseLine.java b/src/main/java/domain/dto/ResponseLine.java index 7cfde70d..4cec0c28 100644 --- a/src/main/java/domain/dto/ResponseLine.java +++ b/src/main/java/domain/dto/ResponseLine.java @@ -11,7 +11,7 @@ public record ResponseLine( public static ResponseLine from(final Line line) { List connections = line.getPoints().stream() .limit(line.getPoints().size() - 1) - .map(Point::right) + .map(Point::isConnectRight) .toList(); return new ResponseLine(connections); } diff --git a/src/main/java/domain/ladder/Line.java b/src/main/java/domain/ladder/Line.java index 53f3aa8e..f77d7c50 100644 --- a/src/main/java/domain/ladder/Line.java +++ b/src/main/java/domain/ladder/Line.java @@ -15,7 +15,7 @@ public static Line from(final List points) { } public boolean hasConnectionAt(final int index) { - return points.get(index).right(); + return points.get(index).isConnectRight(); } public Direction directionAt(final int index) { @@ -29,11 +29,11 @@ public Direction directionAt(final int index) { } private boolean canMoveRight(final int index) { - return index < points.size() - 1 && points.get(index).right(); + return index < points.size() - 1 && points.get(index).isConnectRight(); } private boolean canMoveLeft(final int index) { - return 0 < index && points.get(index - 1).right(); + return 0 < index && points.get(index - 1).isConnectRight(); } public List getPoints() { diff --git a/src/main/java/domain/ladder/Point.java b/src/main/java/domain/ladder/Point.java index 8c99c759..24208044 100644 --- a/src/main/java/domain/ladder/Point.java +++ b/src/main/java/domain/ladder/Point.java @@ -1,7 +1,7 @@ package domain.ladder; public record Point( - boolean right + boolean isConnectRight ) { public static Point from(final boolean right) { @@ -9,7 +9,7 @@ public static Point from(final boolean right) { } public Point connectNext(final boolean canConnectRight) { - if (this.right) { + if (this.isConnectRight) { return new Point(false); } return new Point(canConnectRight); diff --git a/src/main/java/domain/ladder/result/LadderResult.java b/src/main/java/domain/ladder/result/LadderResult.java index f244006d..eb52eaa7 100644 --- a/src/main/java/domain/ladder/result/LadderResult.java +++ b/src/main/java/domain/ladder/result/LadderResult.java @@ -1,7 +1,7 @@ package domain.ladder.result; public record LadderResult( - String player, + String playerName, String result ) { } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 46e7b4ed..4292450e 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -67,10 +67,10 @@ public static void printResults(final Results results) { System.out.println(); } - public static void printSingleLadderResult(final LadderResultBoard resultBoard, final String player) { + public static void printSingleLadderResult(final LadderResultBoard resultBoard, final String playerName) { System.out.println(); System.out.println(RUNNING_RESULT_TITLE); - String result = resultBoard.findResultOf(player) + String result = resultBoard.findResultOf(playerName) .orElse("존재하지 않는 플레이어입니다."); System.out.println(result); } @@ -78,11 +78,11 @@ public static void printSingleLadderResult(final LadderResultBoard resultBoard, public static void printAllLadderResult(final LadderResultBoard resultBoard) { System.out.println(); System.out.println(RUNNING_RESULT_TITLE); - resultBoard.getAllResults().forEach(result -> - System.out.println(result.player() + " : " + result.result())); + resultBoard.getAllResults().forEach(ladderResult -> + System.out.println(ladderResult.playerName() + " : " + ladderResult.result())); } - private static String padding(String text) { + private static String padding(final String text) { return String.format("%-" + CELL_WIDTH + "s", text); } } diff --git a/src/test/java/domain/ladder/LineTest.java b/src/test/java/domain/ladder/LineTest.java index a13b6a20..23cdab8e 100644 --- a/src/test/java/domain/ladder/LineTest.java +++ b/src/test/java/domain/ladder/LineTest.java @@ -24,7 +24,7 @@ void shouldGeneratePoint_whenGivenWidth() { // then assertThat(points) - .extracting(Point::right) + .extracting(Point::isConnectRight) .containsExactly(true, false, true, false); } diff --git a/src/test/java/domain/ladder/PointTest.java b/src/test/java/domain/ladder/PointTest.java index 8bbf6197..453f5266 100644 --- a/src/test/java/domain/ladder/PointTest.java +++ b/src/test/java/domain/ladder/PointTest.java @@ -19,8 +19,8 @@ void shouldCreatePoint_whenFromRightStatus() { Point falsePoint = Point.from(isRightFalse); // then - assertThat(truePoint.right()).isTrue(); - assertThat(falsePoint.right()).isFalse(); + assertThat(truePoint.isConnectRight()).isTrue(); + assertThat(falsePoint.isConnectRight()).isFalse(); } @Test @@ -33,7 +33,7 @@ void shouldReturnNextPointFalse_whenPointRightTrue() { Point next = point.connectNext(true); // then - assertThat(next.right()).isFalse(); + assertThat(next.isConnectRight()).isFalse(); } @Test @@ -47,7 +47,7 @@ void shouldReturnNextPointTrueOrFalse_whenPointRightFalse() { Point nextFalse = point.connectNext(false); // then - assertThat(nextTrue.right()).isTrue(); - assertThat(nextFalse.right()).isFalse(); + assertThat(nextTrue.isConnectRight()).isTrue(); + assertThat(nextFalse.isConnectRight()).isFalse(); } } From 7c656c3cfa6afc89712e4205636c965ff20c842f Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 02:08:08 +0900 Subject: [PATCH 11/15] =?UTF-8?q?refactor:=20=EC=A4=91=EB=B3=B5=EB=90=9C?= =?UTF-8?q?=20=EC=9E=90=EB=A3=8C=EA=B5=AC=EC=A1=B0=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 List와 Map을 이용해 결과를 저장하였는데, 중복되는 저장 방식으로 Map만을 사용하게 변경하였습니다. --- .../ladder/result/LadderResultBoard.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/domain/ladder/result/LadderResultBoard.java b/src/main/java/domain/ladder/result/LadderResultBoard.java index d09de85c..ce3e3ca2 100644 --- a/src/main/java/domain/ladder/result/LadderResultBoard.java +++ b/src/main/java/domain/ladder/result/LadderResultBoard.java @@ -13,34 +13,30 @@ public class LadderResultBoard { - private final List ladderResults; - private final Map ladderResultCache; + private final Map playerResultMap; - public LadderResultBoard(final List ladderResults) { - this.ladderResults = List.copyOf(ladderResults); - this.ladderResultCache = ladderResults.stream() - .collect(toMap(LadderResult::player, Function.identity())); + private LadderResultBoard(final Map playerResultMap) { + this.playerResultMap = Map.copyOf(playerResultMap); } public static LadderResultBoard of(final Players players, final Ladder ladder, final Results results) { - List ladderResults = IntStream.range(0, players.size()) + Map playerResultMap = IntStream.range(0, players.size()) .mapToObj(startIndex -> { String playerName = players.name(startIndex); int destinationIndex = ladder.move(startIndex); String resultValue = results.value(destinationIndex); return new LadderResult(playerName, resultValue); }) - .toList(); - - return new LadderResultBoard(ladderResults); + .collect(toMap(LadderResult::playerName, Function.identity())); + return new LadderResultBoard(playerResultMap); } public Optional findResultOf(final String playerName) { - return Optional.ofNullable(ladderResultCache.get(playerName)) + return Optional.ofNullable(playerResultMap.get(playerName)) .map(LadderResult::result); } public List getAllResults() { - return ladderResults; + return List.copyOf(playerResultMap.values()); } } From fd5e48c2e90df9cf7160b3e4fc30ba4c6ed90c5c Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 15:39:01 +0900 Subject: [PATCH 12/15] =?UTF-8?q?refactor:=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A0=9C=EC=96=B4=EC=9E=90=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=BB=A8=EB=B2=A4=EC=85=98=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LadderController.java | 2 +- src/main/java/domain/ladder/Height.java | 4 ++-- src/main/java/domain/ladder/Line.java | 2 +- src/main/java/domain/ladder/Point.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 02fbf89e..858f4edf 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -26,7 +26,7 @@ public void play() { RequestLadderGame request = inputLadderSettings(); Players players = request.toPlayers(); Height height = request.toHeight(); - Results results = request.toResults(players.values().size()); + Results results = request.toResults(players.size()); Ladder ladder = drawLadder(players, height); LadderResultBoard resultBoard = LadderResultBoard.of(players, ladder, results); diff --git a/src/main/java/domain/ladder/Height.java b/src/main/java/domain/ladder/Height.java index 9d7a0167..6c8314ed 100644 --- a/src/main/java/domain/ladder/Height.java +++ b/src/main/java/domain/ladder/Height.java @@ -4,8 +4,8 @@ public record Height( int value ) { - static final int MIN_LADDER_HEIGHT_SIZE = 2; - static final int MAX_LADDER_HEIGHT_SIZE = 24; + private static final int MIN_LADDER_HEIGHT_SIZE = 2; + private static final int MAX_LADDER_HEIGHT_SIZE = 24; public Height { validateHeightSize(value); diff --git a/src/main/java/domain/ladder/Line.java b/src/main/java/domain/ladder/Line.java index f77d7c50..db56e9c0 100644 --- a/src/main/java/domain/ladder/Line.java +++ b/src/main/java/domain/ladder/Line.java @@ -4,7 +4,7 @@ public class Line { - final List points; + private final List points; private Line(final List points) { this.points = List.copyOf(points); diff --git a/src/main/java/domain/ladder/Point.java b/src/main/java/domain/ladder/Point.java index 24208044..c93d2bab 100644 --- a/src/main/java/domain/ladder/Point.java +++ b/src/main/java/domain/ladder/Point.java @@ -4,8 +4,8 @@ public record Point( boolean isConnectRight ) { - public static Point from(final boolean right) { - return new Point(right); + public static Point from(final boolean isConnectRight) { + return new Point(isConnectRight); } public Point connectNext(final boolean canConnectRight) { From fcd2ded774234522060c2169530c3781343edaa5 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 15:40:04 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=20=EC=9D=BC=EA=B4=80=EB=90=98?= =?UTF-8?q?=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/dto/RequestLadderGame.java | 8 +++--- src/main/java/domain/player/Name.java | 6 ++--- src/main/java/domain/player/Players.java | 6 ++--- .../java/domain/runningResult/Result.java | 2 +- .../domain/dto/RequestLadderGameTest.java | 27 +++++++++++++++---- src/test/java/domain/ladder/HeightTest.java | 4 +-- src/test/java/domain/player/NameTest.java | 5 ++-- src/test/java/domain/player/PlayersTest.java | 6 ++--- .../java/domain/runningResult/ResultTest.java | 2 +- 9 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java index c189c5ba..d264dbb8 100644 --- a/src/main/java/domain/dto/RequestLadderGame.java +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -12,7 +12,7 @@ public record RequestLadderGame( String height ) { - static final String INPUT_DELIMITER = ","; + private static final String INPUT_DELIMITER = ","; public RequestLadderGame { validateEmptyPlayerNames(playerNames); @@ -28,19 +28,19 @@ private static void validatePlayerCountEqualsResultsCount(final int playerCount, private void validateEmptyPlayerNames(final String playerNames) { if (playerNames == null || playerNames.isBlank()) { - throw new IllegalArgumentException("플레이어들의 이름을 입력해야 합니다."); + throw new IllegalArgumentException("플레이어들의 이름은 공백이 아니어야 합니다."); } } private void validateEmptyResults(final String results) { if (results == null || results.isBlank()) { - throw new IllegalArgumentException("실행 결과를 입력해야 합니다."); + throw new IllegalArgumentException("실행 결과는 공백이 아니어야 합니다."); } } private void validateEmptyHeight(final String height) { if (height == null || height.isBlank()) { - throw new IllegalArgumentException("사다리의 높이를 입력해야 합니다."); + throw new IllegalArgumentException("사다리의 높이는 공백이 아니어야 합니다."); } } diff --git a/src/main/java/domain/player/Name.java b/src/main/java/domain/player/Name.java index 72936117..6a6f794f 100644 --- a/src/main/java/domain/player/Name.java +++ b/src/main/java/domain/player/Name.java @@ -4,7 +4,7 @@ public record Name( String value ) { - static final int MAX_NAME_LENGTH = 5; + private static final int MAX_NAME_LENGTH = 5; public Name { validateEmptyName(value); @@ -13,13 +13,13 @@ public record Name( private void validateEmptyName(final String value) { if (value == null || value.isBlank()) { - throw new IllegalArgumentException("플레이어의 이름을 입력해야 합니다."); + throw new IllegalArgumentException("플레이어의 이름은 공백이 아니어야 합니다."); } } private void validateNameLength(final String value) { if (MAX_NAME_LENGTH < value.length()) { - throw new IllegalArgumentException("플레이어의 이름이 %d를 초과합니다.".formatted(MAX_NAME_LENGTH)); + throw new IllegalArgumentException("플레이어의 이름은 %d자 이하여야 합니다.".formatted(MAX_NAME_LENGTH)); } } } diff --git a/src/main/java/domain/player/Players.java b/src/main/java/domain/player/Players.java index 77a13dd6..4f231a72 100644 --- a/src/main/java/domain/player/Players.java +++ b/src/main/java/domain/player/Players.java @@ -8,8 +8,8 @@ public class Players { - static final int MIN_PLAYER_SIZE = 2; - static final int MAX_PLAYER_SIZE = 24; + private static final int MIN_PLAYER_SIZE = 2; + private static final int MAX_PLAYER_SIZE = 24; private final List players; @@ -49,7 +49,7 @@ private Set uniqueNamesFrom(final List players) { private void validateNameCountEqualsDistinctCount(final int total, final int distinct) { if (total != distinct) { - throw new IllegalArgumentException("플레이어의 이름은 중복될 수 없습니다."); + throw new IllegalArgumentException("플레이어의 이름은 중복이 아니어야 합니다."); } } diff --git a/src/main/java/domain/runningResult/Result.java b/src/main/java/domain/runningResult/Result.java index a267bcac..f21a4b82 100644 --- a/src/main/java/domain/runningResult/Result.java +++ b/src/main/java/domain/runningResult/Result.java @@ -10,7 +10,7 @@ public record Result( private void validateEmptyResult(final String value) { if (value == null || value.isBlank()) { - throw new IllegalArgumentException("실행 결과를 입력해야 합니다."); + throw new IllegalArgumentException("실행 결과는 공백이 아니어야 합니다."); } } } diff --git a/src/test/java/domain/dto/RequestLadderGameTest.java b/src/test/java/domain/dto/RequestLadderGameTest.java index a7791025..25471454 100644 --- a/src/test/java/domain/dto/RequestLadderGameTest.java +++ b/src/test/java/domain/dto/RequestLadderGameTest.java @@ -20,7 +20,7 @@ void shouldThrowException_whenEmptyPlayerNames(String playerNames) { // given & when & then assertThatThrownBy(() -> new RequestLadderGame(playerNames, "꽝,5000,꽝,2000", "5")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어들의 이름을 입력해야 합니다."); + .hasMessage("플레이어들의 이름은 공백이 아니어야 합니다."); } @ParameterizedTest @@ -30,7 +30,7 @@ void shouldThrowException_whenEmptyRunningResults(String runningResults) { // given & when & then assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", runningResults, "5")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("실행 결과를 입력해야 합니다."); + .hasMessage("실행 결과는 공백이 아니어야 합니다."); } @ParameterizedTest @@ -40,7 +40,24 @@ void shouldThrowException_whenEmptyHeight(String height) { // given & when & then assertThatThrownBy(() -> new RequestLadderGame("neo,brown,brie,tommy", "꽝,5000,꽝,2000", height)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 높이를 입력해야 합니다."); + .hasMessage("사다리의 높이는 공백이 아니어야 합니다."); + } + + @Test + @DisplayName("실행 결과 수와 플레이어 수가 동일하지 않을 경우 예외가 발생한다.") + void shouldThrowException_whenNotEqualsSize() { + // given + String playerNames = "neo,brown,brie,tommy"; + String runningResults = "꽝,5000,꽝"; + RequestLadderGame requestLadderGame = new RequestLadderGame(playerNames, runningResults, "7"); + + // when + Players players = requestLadderGame.toPlayers(); + + // then + assertThatThrownBy(() -> requestLadderGame.toResults(players.size())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행 결과 수는 플레이어 수와 동일해야 합니다."); } @Test @@ -51,11 +68,11 @@ void shouldReturn_whenValidLadderGameValue() { // when Players players = requestLadderGame.toPlayers(); - Results results = requestLadderGame.toResults(players.values().size()); + Results results = requestLadderGame.toResults(players.size()); Height height = requestLadderGame.toHeight(); // then - assertThat(players.values().size()).isEqualTo(4); + assertThat(players.size()).isEqualTo(4); assertThat(results.asList().size()).isEqualTo(4); assertThat(height.value()).isEqualTo(7); } diff --git a/src/test/java/domain/ladder/HeightTest.java b/src/test/java/domain/ladder/HeightTest.java index 661f3ce2..5a750b3f 100644 --- a/src/test/java/domain/ladder/HeightTest.java +++ b/src/test/java/domain/ladder/HeightTest.java @@ -1,7 +1,5 @@ package domain.ladder; -import static domain.ladder.Height.MAX_LADDER_HEIGHT_SIZE; -import static domain.ladder.Height.MIN_LADDER_HEIGHT_SIZE; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; @@ -17,6 +15,6 @@ void shouldThrowException_whenInvalidHeight(int height) { // given & when & then assertThatThrownBy(() -> Height.from(height)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 높이는 %s 이상 %s 이하여야 합니다.".formatted(MIN_LADDER_HEIGHT_SIZE, MAX_LADDER_HEIGHT_SIZE)); + .hasMessage("사다리의 높이는 2 이상 24 이하여야 합니다."); } } diff --git a/src/test/java/domain/player/NameTest.java b/src/test/java/domain/player/NameTest.java index 460a76ce..7dedfeb9 100644 --- a/src/test/java/domain/player/NameTest.java +++ b/src/test/java/domain/player/NameTest.java @@ -1,6 +1,5 @@ package domain.player; -import static domain.player.Name.MAX_NAME_LENGTH; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; @@ -17,7 +16,7 @@ void shouldThrowException_whenEmptyOrBlank(String value) { // given & when & then assertThatThrownBy(() -> new Name(value)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어의 이름을 입력해야 합니다."); + .hasMessage("플레이어의 이름은 공백이 아니어야 합니다."); } @ParameterizedTest @@ -27,6 +26,6 @@ void shouldThrowException_whenOverMaxLength(String value) { // given & when & then assertThatThrownBy(() -> new Name(value)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어의 이름이 %d를 초과합니다.".formatted(MAX_NAME_LENGTH)); + .hasMessage("플레이어의 이름은 5자 이하여야 합니다."); } } diff --git a/src/test/java/domain/player/PlayersTest.java b/src/test/java/domain/player/PlayersTest.java index d899e12f..b526b873 100644 --- a/src/test/java/domain/player/PlayersTest.java +++ b/src/test/java/domain/player/PlayersTest.java @@ -1,7 +1,5 @@ package domain.player; -import static domain.player.Players.MAX_PLAYER_SIZE; -import static domain.player.Players.MIN_PLAYER_SIZE; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.List; @@ -25,7 +23,7 @@ void shouldThrowException_whenInvalidPlayerSize(int size) { // when & then assertThatThrownBy(() -> Players.from(names)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어 수는 %s 이상 %s 이하여야 합니다.".formatted(MIN_PLAYER_SIZE, MAX_PLAYER_SIZE)); + .hasMessage("플레이어 수는 2 이상 24 이하여야 합니다."); } @Test @@ -37,6 +35,6 @@ void shouldThrowException_whenDuplicatePlayerNames() { // when & then assertThatThrownBy(() -> Players.from(duplicateNames)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어의 이름은 중복될 수 없습니다."); + .hasMessage("플레이어의 이름은 중복이 아니어야 합니다."); } } diff --git a/src/test/java/domain/runningResult/ResultTest.java b/src/test/java/domain/runningResult/ResultTest.java index a17b7809..3036e320 100644 --- a/src/test/java/domain/runningResult/ResultTest.java +++ b/src/test/java/domain/runningResult/ResultTest.java @@ -15,6 +15,6 @@ void shouldThrowException_whenEmptyResult(String value) { // given & when & then assertThatThrownBy(() -> new Result(value)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("실행 결과를 입력해야 합니다."); + .hasMessage("실행 결과는 공백이 아니어야 합니다."); } } From 2f454321eee1a1c69becea53084a0e63f383859c Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 16:23:55 +0900 Subject: [PATCH 14/15] =?UTF-8?q?refactor:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=9D=B4=EB=A6=84=20=EC=98=88=EC=95=BD=EC=96=B4=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EB=B6=88=EA=B0=80=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/constants/ReservedWord.java | 9 +++ .../java/domain/dto/RequestLadderGame.java | 69 +++---------------- src/main/java/domain/player/Name.java | 9 +++ src/test/java/domain/player/NameTest.java | 9 +++ 4 files changed, 37 insertions(+), 59 deletions(-) create mode 100644 src/main/java/constants/ReservedWord.java diff --git a/src/main/java/constants/ReservedWord.java b/src/main/java/constants/ReservedWord.java new file mode 100644 index 00000000..e430aa1b --- /dev/null +++ b/src/main/java/constants/ReservedWord.java @@ -0,0 +1,9 @@ +package constants; + +public final class ReservedWord { + + public static final String FINISH_KEYWORD = "all"; + + private ReservedWord() { + } +} diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java index d264dbb8..2d82a539 100644 --- a/src/main/java/domain/dto/RequestLadderGame.java +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -1,70 +1,21 @@ package domain.dto; -import domain.ladder.Height; -import domain.player.Players; -import domain.runningResult.Results; -import java.util.List; -import java.util.stream.Stream; +public class RequestValidateInput { -public record RequestLadderGame( - String playerNames, - String runningResults, - String height -) { + private final String value; - private static final String INPUT_DELIMITER = ","; - - public RequestLadderGame { - validateEmptyPlayerNames(playerNames); - validateEmptyResults(runningResults); - validateEmptyHeight(height); - } - - private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List results) { - if (playerCount != results.size()) { - throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다."); - } - } - - private void validateEmptyPlayerNames(final String playerNames) { - if (playerNames == null || playerNames.isBlank()) { - throw new IllegalArgumentException("플레이어들의 이름은 공백이 아니어야 합니다."); - } - } - - private void validateEmptyResults(final String results) { - if (results == null || results.isBlank()) { - throw new IllegalArgumentException("실행 결과는 공백이 아니어야 합니다."); - } - } - - private void validateEmptyHeight(final String height) { - if (height == null || height.isBlank()) { - throw new IllegalArgumentException("사다리의 높이는 공백이 아니어야 합니다."); - } - } - - public Players toPlayers() { - List names = Stream.of(playerNames.split(INPUT_DELIMITER)) - .map(String::strip) - .toList(); - return Players.from(names); + public RequestValidateInput(final String value) { + validateEmpty(value); + this.value = value; } - public Height toHeight() { - try { - return new Height(Integer.parseInt(height.strip())); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("사다리의 높이는 숫자여야 합니다."); + private void validateEmpty(final String value) { + if (value == null || value.isBlank()) { + throw new IllegalArgumentException("입력 값은 공백이 아니어야 합니다."); } } - public Results toResults(final int playerCount) { - List results = Stream.of(runningResults.split(INPUT_DELIMITER)) - .map(String::strip) - .toList(); - - validatePlayerCountEqualsResultsCount(playerCount, results); - return Results.from(results); + protected String raw() { + return value.strip(); } } diff --git a/src/main/java/domain/player/Name.java b/src/main/java/domain/player/Name.java index 6a6f794f..a74c5138 100644 --- a/src/main/java/domain/player/Name.java +++ b/src/main/java/domain/player/Name.java @@ -1,5 +1,7 @@ package domain.player; +import static constants.ReservedWord.FINISH_KEYWORD; + public record Name( String value ) { @@ -9,6 +11,7 @@ public record Name( public Name { validateEmptyName(value); validateNameLength(value); + validateInvalidName(value); } private void validateEmptyName(final String value) { @@ -22,4 +25,10 @@ private void validateNameLength(final String value) { throw new IllegalArgumentException("플레이어의 이름은 %d자 이하여야 합니다.".formatted(MAX_NAME_LENGTH)); } } + + private void validateInvalidName(final String value) { + if (value.equals(FINISH_KEYWORD)) { + throw new IllegalArgumentException("'%s'은 예약어이므로 플레이어의 이름이 아니어야 합니다.".formatted(FINISH_KEYWORD)); + } + } } diff --git a/src/test/java/domain/player/NameTest.java b/src/test/java/domain/player/NameTest.java index 7dedfeb9..542e18bd 100644 --- a/src/test/java/domain/player/NameTest.java +++ b/src/test/java/domain/player/NameTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; @@ -28,4 +29,12 @@ void shouldThrowException_whenOverMaxLength(String value) { .isInstanceOf(IllegalArgumentException.class) .hasMessage("플레이어의 이름은 5자 이하여야 합니다."); } + + @Test + @DisplayName("이름으로 예약어를 사용했을 경우 예외가 발생한다.") + void shouldThrowException_whenUsedReservedWord() { + // given & when & then + assertThatThrownBy(() -> new Name("all")) + .isInstanceOf(IllegalArgumentException.class).hasMessage("'all'은 예약어이므로 플레이어의 이름이 아니어야 합니다."); + } } From 5d58659bce568ff5846990721e9b9a27b820ecb4 Mon Sep 17 00:00:00 2001 From: dd-jiyun Date: Sun, 15 Jun 2025 16:25:01 +0900 Subject: [PATCH 15/15] =?UTF-8?q?refactor:=20=EB=84=A4=EC=9D=B4=EB=B0=8D?= =?UTF-8?q?=20=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 15 ++-- .../java/domain/dto/RequestLadderGame.java | 69 ++++++++++++++++--- src/main/java/domain/dto/ResponseLine.java | 2 +- .../java/domain/ladder/LadderFactory.java | 2 +- src/main/java/domain/ladder/Line.java | 4 ++ .../java/domain/runningResult/Results.java | 2 +- src/main/java/view/InputView.java | 2 +- 7 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 858f4edf..cca4be3f 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,5 +1,7 @@ package controller; +import static constants.ReservedWord.FINISH_KEYWORD; + import domain.dto.RequestLadderGame; import domain.dto.ResponseLadder; import domain.ladder.Height; @@ -19,7 +21,6 @@ public class LadderController { - private static final String FINISH_KEYWORD = "all"; private static final String NOT_FOUND_PLAYER_RETRY_MESSAGE = "존재하지 않는 플레이어입니다. 다시 입력해주세요."; public void play() { @@ -62,26 +63,26 @@ private void showGameScreen(final Players players, final Ladder ladder, final Re private void showPlayerResult(final LadderResultBoard board) { repeatUntilDone( - InputView::inputTargetPlayer, - input -> { - if (input.equals(FINISH_KEYWORD)) { + InputView::inputTargetPlayerName, + name -> { + if (name.equals(FINISH_KEYWORD)) { OutputView.printAllLadderResult(board); return true; } - if (board.findResultOf(input).isEmpty()) { + if (board.findResultOf(name).isEmpty()) { System.out.println(); System.out.println(NOT_FOUND_PLAYER_RETRY_MESSAGE); return false; } - OutputView.printSingleLadderResult(board, input); + OutputView.printSingleLadderResult(board, name); return false; } ); } - private void repeatUntilDone(Supplier inputSupplier, Function handler) { + private void repeatUntilDone(final Supplier inputSupplier, final Function handler) { boolean done = false; while (!done) { String input = inputSupplier.get(); diff --git a/src/main/java/domain/dto/RequestLadderGame.java b/src/main/java/domain/dto/RequestLadderGame.java index 2d82a539..d264dbb8 100644 --- a/src/main/java/domain/dto/RequestLadderGame.java +++ b/src/main/java/domain/dto/RequestLadderGame.java @@ -1,21 +1,70 @@ package domain.dto; -public class RequestValidateInput { +import domain.ladder.Height; +import domain.player.Players; +import domain.runningResult.Results; +import java.util.List; +import java.util.stream.Stream; - private final String value; +public record RequestLadderGame( + String playerNames, + String runningResults, + String height +) { - public RequestValidateInput(final String value) { - validateEmpty(value); - this.value = value; + private static final String INPUT_DELIMITER = ","; + + public RequestLadderGame { + validateEmptyPlayerNames(playerNames); + validateEmptyResults(runningResults); + validateEmptyHeight(height); + } + + private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List results) { + if (playerCount != results.size()) { + throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다."); + } + } + + private void validateEmptyPlayerNames(final String playerNames) { + if (playerNames == null || playerNames.isBlank()) { + throw new IllegalArgumentException("플레이어들의 이름은 공백이 아니어야 합니다."); + } + } + + private void validateEmptyResults(final String results) { + if (results == null || results.isBlank()) { + throw new IllegalArgumentException("실행 결과는 공백이 아니어야 합니다."); + } + } + + private void validateEmptyHeight(final String height) { + if (height == null || height.isBlank()) { + throw new IllegalArgumentException("사다리의 높이는 공백이 아니어야 합니다."); + } + } + + public Players toPlayers() { + List names = Stream.of(playerNames.split(INPUT_DELIMITER)) + .map(String::strip) + .toList(); + return Players.from(names); } - private void validateEmpty(final String value) { - if (value == null || value.isBlank()) { - throw new IllegalArgumentException("입력 값은 공백이 아니어야 합니다."); + public Height toHeight() { + try { + return new Height(Integer.parseInt(height.strip())); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("사다리의 높이는 숫자여야 합니다."); } } - protected String raw() { - return value.strip(); + public Results toResults(final int playerCount) { + List results = Stream.of(runningResults.split(INPUT_DELIMITER)) + .map(String::strip) + .toList(); + + validatePlayerCountEqualsResultsCount(playerCount, results); + return Results.from(results); } } diff --git a/src/main/java/domain/dto/ResponseLine.java b/src/main/java/domain/dto/ResponseLine.java index 4cec0c28..0e287ffc 100644 --- a/src/main/java/domain/dto/ResponseLine.java +++ b/src/main/java/domain/dto/ResponseLine.java @@ -10,7 +10,7 @@ public record ResponseLine( public static ResponseLine from(final Line line) { List connections = line.getPoints().stream() - .limit(line.getPoints().size() - 1) + .limit(line.size() - 1) .map(Point::isConnectRight) .toList(); return new ResponseLine(connections); diff --git a/src/main/java/domain/ladder/LadderFactory.java b/src/main/java/domain/ladder/LadderFactory.java index 27030bcd..c64c696f 100644 --- a/src/main/java/domain/ladder/LadderFactory.java +++ b/src/main/java/domain/ladder/LadderFactory.java @@ -27,7 +27,7 @@ private Optional findDrawableLadder(final Players players, final Height private Ladder drawLadder(final Players players, final Height height, final LineGenerator lineGenerator) { List lines = new ArrayList<>(); for (int i = 0; i < height.value(); i++) { - lines.add(lineGenerator.generate(players.values().size())); + lines.add(lineGenerator.generate(players.size())); } return Ladder.from(lines); } diff --git a/src/main/java/domain/ladder/Line.java b/src/main/java/domain/ladder/Line.java index db56e9c0..a75cd1d4 100644 --- a/src/main/java/domain/ladder/Line.java +++ b/src/main/java/domain/ladder/Line.java @@ -36,6 +36,10 @@ private boolean canMoveLeft(final int index) { return 0 < index && points.get(index - 1).isConnectRight(); } + public int size() { + return points.size(); + } + public List getPoints() { return points; } diff --git a/src/main/java/domain/runningResult/Results.java b/src/main/java/domain/runningResult/Results.java index e572e6f3..f93e2328 100644 --- a/src/main/java/domain/runningResult/Results.java +++ b/src/main/java/domain/runningResult/Results.java @@ -20,7 +20,7 @@ public static Results from(final List results) { } public String value(final int index) { - return asList().get(index).value(); + return values.get(index).value(); } public List asList() { diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 8e954577..a7b45144 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -26,7 +26,7 @@ public static String inputLadderHeight() { return sc.nextLine(); } - public static String inputTargetPlayer() { + public static String inputTargetPlayerName() { System.out.println(); System.out.println("결과를 보고 싶은 사람은?"); return sc.nextLine();