From bfca787d375e777ec130026ad19847a8998c1f4f Mon Sep 17 00:00:00 2001 From: "everett.kmj" Date: Mon, 15 May 2023 19:56:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?(feat)=20step1=20-=20stream,=20lambda,=20op?= =?UTF-8?q?tional=20=EC=8A=A4=ED=84=B0=EB=94=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/fp/Lambda.java | 31 +++---------------- src/main/java/nextstep/fp/StreamStudy.java | 20 +++++++----- src/main/java/nextstep/fp/SumStrategy.java | 5 +++ .../java/nextstep/optional/Expression.java | 13 ++++---- src/main/java/nextstep/optional/User.java | 7 ++++- src/main/java/nextstep/optional/Users.java | 10 +++--- src/test/java/nextstep/fp/CarTest.java | 14 ++------- src/test/java/nextstep/fp/LambdaTest.java | 6 ++-- 8 files changed, 44 insertions(+), 62 deletions(-) create mode 100644 src/main/java/nextstep/fp/SumStrategy.java diff --git a/src/main/java/nextstep/fp/Lambda.java b/src/main/java/nextstep/fp/Lambda.java index bd68fe1ce6..fb2b88ea63 100644 --- a/src/main/java/nextstep/fp/Lambda.java +++ b/src/main/java/nextstep/fp/Lambda.java @@ -26,31 +26,10 @@ public void run() { }).start(); } - public static int sumAll(List numbers) { - int total = 0; - for (int number : numbers) { - total += number; - } - return total; - } - - public static int sumAllEven(List numbers) { - int total = 0; - for (int number : numbers) { - if (number % 2 == 0) { - total += number; - } - } - return total; - } - - public static int sumAllOverThree(List numbers) { - int total = 0; - for (int number : numbers) { - if (number > 3) { - total += number; - } - } - return total; + public static int sumAll(List numbers, SumStrategy sumStrategy) { + return numbers.stream() + .filter(sumStrategy::option) + .mapToInt(value -> value) + .sum(); } } diff --git a/src/main/java/nextstep/fp/StreamStudy.java b/src/main/java/nextstep/fp/StreamStudy.java index b446983a02..67e7c8ac67 100644 --- a/src/main/java/nextstep/fp/StreamStudy.java +++ b/src/main/java/nextstep/fp/StreamStudy.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -15,11 +16,9 @@ public static long countWords() throws IOException { .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); List words = Arrays.asList(contents.split("[\\P{L}]+")); - long count = 0; - for (String w : words) { - if (w.length() > 12) count++; - } - return count; + return words.stream() + .filter(w -> w.length() > 12) + .count(); } public static void printLongestWordTop100() throws IOException { @@ -27,7 +26,11 @@ public static void printLongestWordTop100() throws IOException { .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); List words = Arrays.asList(contents.split("[\\P{L}]+")); - // TODO 이 부분에 구현한다. + words.stream() + .filter(w -> w.length() > 12) // 단어 길이 12 이상 + .sorted((o1, o2) -> o2.length() - o1.length()) // 긴 순서 + .distinct() + .forEach(s -> System.out.println(s.toLowerCase())); } public static List doubleNumbers(List numbers) { @@ -39,6 +42,9 @@ public static long sumAll(List numbers) { } public static long sumOverThreeAndDouble(List numbers) { - return 0; + return numbers.stream() + .filter(i -> i > 3) + .map(i -> 2 * i) + .reduce(0, (x, y) -> x + y); } } \ No newline at end of file diff --git a/src/main/java/nextstep/fp/SumStrategy.java b/src/main/java/nextstep/fp/SumStrategy.java new file mode 100644 index 0000000000..a165e16fc3 --- /dev/null +++ b/src/main/java/nextstep/fp/SumStrategy.java @@ -0,0 +1,5 @@ +package nextstep.fp; + +public interface SumStrategy { + boolean option(int number); +} diff --git a/src/main/java/nextstep/optional/Expression.java b/src/main/java/nextstep/optional/Expression.java index 1c98cd6a62..9937f2711e 100644 --- a/src/main/java/nextstep/optional/Expression.java +++ b/src/main/java/nextstep/optional/Expression.java @@ -1,5 +1,7 @@ package nextstep.optional; +import java.util.Arrays; + enum Expression { PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/"); @@ -14,12 +16,9 @@ private static boolean matchExpression(Expression e, String expression) { } static Expression of(String expression) { - for (Expression v : values()) { - if (matchExpression(v, expression)) { - return v; - } - } - - throw new IllegalArgumentException(String.format("%s는 사칙연산에 해당하지 않는 표현식입니다.", expression)); + return Arrays.stream(values()) + .filter(v -> matchExpression(v, expression)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("%s는 사칙연산에 해당하지 않는 표현식입니다.", expression))); } } diff --git a/src/main/java/nextstep/optional/User.java b/src/main/java/nextstep/optional/User.java index 9614c2f43f..bc2aee7eb9 100644 --- a/src/main/java/nextstep/optional/User.java +++ b/src/main/java/nextstep/optional/User.java @@ -1,5 +1,7 @@ package nextstep.optional; +import java.util.Optional; + public class User { private String name; private Integer age; @@ -33,7 +35,10 @@ public static boolean ageIsInRange1(User user) { } public static boolean ageIsInRange2(User user) { - return false; + return Optional.ofNullable(user) + .map(User::getAge) + .filter(age -> age >= 30 && age <= 45) + .isPresent(); } @Override diff --git a/src/main/java/nextstep/optional/Users.java b/src/main/java/nextstep/optional/Users.java index 6293040de8..63815d1c28 100644 --- a/src/main/java/nextstep/optional/Users.java +++ b/src/main/java/nextstep/optional/Users.java @@ -13,11 +13,9 @@ public class Users { new User("honux", 45)); User getUser(String name) { - for (User user : users) { - if (user.matchName(name)) { - return user; - } - } - return DEFAULT_USER; + return users.stream() + .filter(user -> user.matchName(name)) + .findFirst() + .orElse(DEFAULT_USER); } } diff --git a/src/test/java/nextstep/fp/CarTest.java b/src/test/java/nextstep/fp/CarTest.java index 1ab1106fe2..ecab481aec 100644 --- a/src/test/java/nextstep/fp/CarTest.java +++ b/src/test/java/nextstep/fp/CarTest.java @@ -8,24 +8,14 @@ public class CarTest { @Test public void 이동() { Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return true; - } - }); + Car actual = car.move(() -> true); assertThat(actual).isEqualTo(new Car("pobi", 1)); } @Test public void 정지() { Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return false; - } - }); + Car actual = car.move(() -> false); assertThat(actual).isEqualTo(new Car("pobi", 0)); } } diff --git a/src/test/java/nextstep/fp/LambdaTest.java b/src/test/java/nextstep/fp/LambdaTest.java index f240ac6560..0ad1940629 100644 --- a/src/test/java/nextstep/fp/LambdaTest.java +++ b/src/test/java/nextstep/fp/LambdaTest.java @@ -33,19 +33,19 @@ public void runThread() throws Exception { @Test public void sumAll() throws Exception { - int sum = Lambda.sumAll(numbers); + int sum = Lambda.sumAll(numbers, number -> true); assertThat(sum).isEqualTo(21); } @Test public void sumAllEven() throws Exception { - int sum = Lambda.sumAllEven(numbers); + int sum = Lambda.sumAll(numbers, number -> number % 2 == 0); assertThat(sum).isEqualTo(12); } @Test public void sumAllOverThree() throws Exception { - int sum = Lambda.sumAllOverThree(numbers); + int sum = Lambda.sumAll(numbers, number -> number > 3); assertThat(sum).isEqualTo(15); } } From b1018c39bd92324a5bbc112e3cb235aa01a12e09 Mon Sep 17 00:00:00 2001 From: "everett.kmj" Date: Wed, 17 May 2023 20:48:09 +0900 Subject: [PATCH 2/3] =?UTF-8?q?(feat)=20step2=20-=20=EC=82=AC=EB=8B=A4?= =?UTF-8?q?=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../nextstep/ladder/LadderApplication.java | 23 ++++++++++ .../ladder/domain/BridgeStrategy.java | 6 +++ .../java/nextstep/ladder/domain/Ladder.java | 36 +++++++++++++++ .../java/nextstep/ladder/domain/Line.java | 45 +++++++++++++++++++ .../java/nextstep/ladder/domain/User.java | 11 +++++ .../java/nextstep/ladder/domain/Users.java | 25 +++++++++++ .../java/nextstep/ladder/view/InputView.java | 25 +++++++++++ .../java/nextstep/ladder/view/OutputView.java | 16 +++++++ .../nextstep/ladder/domain/LadderTest.java | 35 +++++++++++++++ .../java/nextstep/ladder/domain/LineTest.java | 30 +++++++++++++ 11 files changed, 254 insertions(+) create mode 100644 src/main/java/nextstep/ladder/LadderApplication.java create mode 100644 src/main/java/nextstep/ladder/domain/BridgeStrategy.java create mode 100644 src/main/java/nextstep/ladder/domain/Ladder.java create mode 100644 src/main/java/nextstep/ladder/domain/Line.java create mode 100644 src/main/java/nextstep/ladder/domain/User.java create mode 100644 src/main/java/nextstep/ladder/domain/Users.java create mode 100644 src/main/java/nextstep/ladder/view/InputView.java create mode 100644 src/main/java/nextstep/ladder/view/OutputView.java create mode 100644 src/test/java/nextstep/ladder/domain/LadderTest.java create mode 100644 src/test/java/nextstep/ladder/domain/LineTest.java diff --git a/build.gradle b/build.gradle index a0a012f579..59499314c9 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,8 @@ repositories { } dependencies { + implementation 'org.projectlombok:lombok:1.18.26' + annotationProcessor 'org.projectlombok:lombok:1.18.26' testImplementation 'org.assertj:assertj-core:3.22.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' } diff --git a/src/main/java/nextstep/ladder/LadderApplication.java b/src/main/java/nextstep/ladder/LadderApplication.java new file mode 100644 index 0000000000..12f9b74aba --- /dev/null +++ b/src/main/java/nextstep/ladder/LadderApplication.java @@ -0,0 +1,23 @@ +package nextstep.ladder; + +import nextstep.ladder.domain.Ladder; +import nextstep.ladder.domain.Users; +import nextstep.ladder.view.InputView; +import nextstep.ladder.view.OutputView; + +import java.util.List; + +public class LadderApplication { + + public static void main(String[] args) { + + List names = InputView.inputUserNames(); + Users users = new Users(names); + + int height = InputView.inputLadderHeight(); + Ladder ladder = new Ladder(users.getUsers().size(), height); + + OutputView.afterGame(); + OutputView.display(users, ladder); + } +} diff --git a/src/main/java/nextstep/ladder/domain/BridgeStrategy.java b/src/main/java/nextstep/ladder/domain/BridgeStrategy.java new file mode 100644 index 0000000000..6eb94d125a --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/BridgeStrategy.java @@ -0,0 +1,6 @@ +package nextstep.ladder.domain; + +@FunctionalInterface +public interface BridgeStrategy { + Boolean bridgeBuild(); +} diff --git a/src/main/java/nextstep/ladder/domain/Ladder.java b/src/main/java/nextstep/ladder/domain/Ladder.java new file mode 100644 index 0000000000..d8ae6a0879 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/Ladder.java @@ -0,0 +1,36 @@ +package nextstep.ladder.domain; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +import static java.lang.System.*; + +@Getter +public class Ladder { + private List lines = new ArrayList<>(); + + + public Ladder(int countOfUsers, int height) { + for (int i = 0; i < height; i++) { + Line line = new Line(countOfUsers); + lines.add(line); + } + } + + public String status() { + String result = ""; + int height = lines.size(); + for (int i = 0; i < height; i++) { + Line line = lines.get(i); + List points = line.getBridges(); + for (Boolean point : points) { + result += "|"; + result += point ? "-----" : " "; + } + result += "|\n"; + } + return result; + } +} diff --git a/src/main/java/nextstep/ladder/domain/Line.java b/src/main/java/nextstep/ladder/domain/Line.java new file mode 100644 index 0000000000..c5e1293d90 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/Line.java @@ -0,0 +1,45 @@ +package nextstep.ladder.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Random; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class Line { + + private List bridges = new ArrayList<>(); + + public Line(int countOfPerson, BridgeStrategy strategy) { + for (int i = 0; i < countOfPerson - 1; i++) { + bridges.add(build(strategy)); + } + } + + public Line(int countOfPerson) { + for (int i = 0; i < countOfPerson - 1; i++) { + Optional prevIndex = Optional.ofNullable(i) + .map(o -> o - 1); + + Boolean expected = build(() -> new Random().nextBoolean()); + bridges.add(decide(prevIndex, expected)); + } + } + + private static Boolean build(BridgeStrategy strategy) { + return strategy.bridgeBuild(); + } + + private Boolean decide(Optional prevIndex, Boolean expected) { + return prevIndex.filter(i -> i >= 0) + .map(i -> bridges.get(i)) + .map(b -> Boolean.TRUE.equals(b) ? Boolean.valueOf(false) : expected) + .orElse(expected); + } +} diff --git a/src/main/java/nextstep/ladder/domain/User.java b/src/main/java/nextstep/ladder/domain/User.java new file mode 100644 index 0000000000..e8a1f03acb --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/User.java @@ -0,0 +1,11 @@ +package nextstep.ladder.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class User { + private String name; + private int position; +} diff --git a/src/main/java/nextstep/ladder/domain/Users.java b/src/main/java/nextstep/ladder/domain/Users.java new file mode 100644 index 0000000000..b9a15993f6 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/Users.java @@ -0,0 +1,25 @@ +package nextstep.ladder.domain; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public class Users { + private List users = new ArrayList<>(); + + public Users (List names) { + for (int i = 0; i < names.size(); i++) { + users.add(new User(names.get(i), i)); + } + } + + public String status() { + String result = ""; + for (User user : users) { + result += user.getName() + " "; + } + return result; + } +} diff --git a/src/main/java/nextstep/ladder/view/InputView.java b/src/main/java/nextstep/ladder/view/InputView.java new file mode 100644 index 0000000000..25b5925e77 --- /dev/null +++ b/src/main/java/nextstep/ladder/view/InputView.java @@ -0,0 +1,25 @@ +package nextstep.ladder.view; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +import static java.lang.System.in; + +public class InputView { + private static final Scanner scanner = new Scanner(in); + public static final String ASKING_NAMES = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; + public static final String ASKING_HEIGHT = "최대 사다리 높이는 몇 개인가요?"; + + public static List inputUserNames() { + System.out.println(ASKING_NAMES); + String next = scanner.next(); + return Arrays.stream(next.split(",")).collect(Collectors.toList()); + } + + public static int inputLadderHeight() { + System.out.println(ASKING_HEIGHT); + return scanner.nextInt(); + } +} diff --git a/src/main/java/nextstep/ladder/view/OutputView.java b/src/main/java/nextstep/ladder/view/OutputView.java new file mode 100644 index 0000000000..3dab6c7751 --- /dev/null +++ b/src/main/java/nextstep/ladder/view/OutputView.java @@ -0,0 +1,16 @@ +package nextstep.ladder.view; + +import nextstep.ladder.domain.Ladder; +import nextstep.ladder.domain.Users; + +public class OutputView { + + public static void afterGame() { + System.out.println("실행 결과"); + } + + public static void display(Users users, Ladder ladder) { + System.out.println(users.status()); + System.out.println(ladder.status()); + } +} diff --git a/src/test/java/nextstep/ladder/domain/LadderTest.java b/src/test/java/nextstep/ladder/domain/LadderTest.java new file mode 100644 index 0000000000..f3f38cdfaa --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/LadderTest.java @@ -0,0 +1,35 @@ +package nextstep.ladder.domain; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class LadderTest { + + @ParameterizedTest + @CsvSource(value = { + "5, 4", + "4, 5", + "10, 10" + }) + void 사다리_확인(int height, int people) { + for (int i = 0; i < height; i++) { + Line line = new Line(people); + List bridges = line.getBridges(); + assertThat(bridges).hasSize(people - 1); + + for (Boolean point : bridges) { + System.out.print("|"); + System.out.print(point ? "-----" : " "); + } + System.out.print("|"); + System.out.println(); + } + System.out.println(); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/LineTest.java b/src/test/java/nextstep/ladder/domain/LineTest.java new file mode 100644 index 0000000000..c83f0840fa --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/LineTest.java @@ -0,0 +1,30 @@ +package nextstep.ladder.domain; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class LineTest { + + @Test + void 무조건_다리를_생성한다() { + Line line = new Line(5, () -> true); + assertThat(line.getBridges()).hasSize(4); + long count = line.getBridges().stream() + .filter(b -> b == true) + .count(); + assertThat(count).isEqualTo(4); + } + + @Test + void 무조건_다리를_생성하지_않는다() { + Line line = new Line(5, () -> false); + assertThat(line.getBridges()).hasSize(4); + long count = line.getBridges().stream() + .filter(b -> b == true) + .count(); + assertThat(count).isEqualTo(0); + } +} \ No newline at end of file From c8fb52a297810e1a4d2dabd58e9e02e120efdbda Mon Sep 17 00:00:00 2001 From: "everett.kmj" Date: Mon, 22 May 2023 09:31:53 +0900 Subject: [PATCH 3/3] =?UTF-8?q?(feat)=20step3=20-=20=EC=82=AC=EB=8B=A4?= =?UTF-8?q?=EB=A6=AC=ED=83=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/ladder/LadderApplication.java | 24 +++++- .../java/nextstep/ladder/domain/Ladder.java | 28 ++++--- .../nextstep/ladder/domain/LadderResult.java | 10 +++ .../nextstep/ladder/domain/LadderResults.java | 25 ++++++ .../java/nextstep/ladder/domain/Line.java | 84 ++++++++++++++++--- .../java/nextstep/ladder/domain/User.java | 24 +++++- .../java/nextstep/ladder/domain/Users.java | 9 +- .../java/nextstep/ladder/view/InputView.java | 18 +++- .../java/nextstep/ladder/view/OutputView.java | 24 ++++-- .../nextstep/ladder/domain/LadderTest.java | 59 +++++++++---- .../java/nextstep/ladder/domain/LineTest.java | 46 ++++++---- .../java/nextstep/ladder/domain/UserTest.java | 43 ++++++++++ 12 files changed, 326 insertions(+), 68 deletions(-) create mode 100644 src/main/java/nextstep/ladder/domain/LadderResult.java create mode 100644 src/main/java/nextstep/ladder/domain/LadderResults.java create mode 100644 src/test/java/nextstep/ladder/domain/UserTest.java diff --git a/src/main/java/nextstep/ladder/LadderApplication.java b/src/main/java/nextstep/ladder/LadderApplication.java index 12f9b74aba..c4c44b08a6 100644 --- a/src/main/java/nextstep/ladder/LadderApplication.java +++ b/src/main/java/nextstep/ladder/LadderApplication.java @@ -1,11 +1,15 @@ package nextstep.ladder; import nextstep.ladder.domain.Ladder; +import nextstep.ladder.domain.LadderResults; +import nextstep.ladder.domain.User; import nextstep.ladder.domain.Users; import nextstep.ladder.view.InputView; import nextstep.ladder.view.OutputView; import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; public class LadderApplication { @@ -14,10 +18,24 @@ public static void main(String[] args) { List names = InputView.inputUserNames(); Users users = new Users(names); + List results = InputView.inputLadderResult(); + LadderResults ladderResults = new LadderResults(results); + int height = InputView.inputLadderHeight(); - Ladder ladder = new Ladder(users.getUsers().size(), height); - OutputView.afterGame(); - OutputView.display(users, ladder); + Ladder ladder = Ladder.createLadder(users.getUsers().size(), height, () -> new Random().nextBoolean()); + OutputView.display(users, ladder, ladderResults); + + List usersAfter = users.getUsers().stream() + .map(user -> user.rideLadder(ladder)) + .collect(Collectors.toList()); + + String name = InputView.inputUserName(); + + if (name.equals("all")) { + OutputView.announceAllUsers(usersAfter, ladderResults); + return; + } + OutputView.announceUser(name, usersAfter, ladderResults); } } diff --git a/src/main/java/nextstep/ladder/domain/Ladder.java b/src/main/java/nextstep/ladder/domain/Ladder.java index d8ae6a0879..c377a0aefa 100644 --- a/src/main/java/nextstep/ladder/domain/Ladder.java +++ b/src/main/java/nextstep/ladder/domain/Ladder.java @@ -5,16 +5,17 @@ import java.util.ArrayList; import java.util.List; -import static java.lang.System.*; - @Getter public class Ladder { private List lines = new ArrayList<>(); + public static Ladder createLadder(int countOfUsers, int height, BridgeStrategy strategy) { + return new Ladder(countOfUsers, height, strategy); + } - public Ladder(int countOfUsers, int height) { + private Ladder(int countOfUsers, int height, BridgeStrategy strategy) { for (int i = 0; i < height; i++) { - Line line = new Line(countOfUsers); + Line line = Line.createLine(countOfUsers, strategy); lines.add(line); } } @@ -24,13 +25,20 @@ public String status() { int height = lines.size(); for (int i = 0; i < height; i++) { Line line = lines.get(i); - List points = line.getBridges(); - for (Boolean point : points) { - result += "|"; - result += point ? "-----" : " "; - } - result += "|\n"; + result += line.status(); } return result; } + + public int findLastPosition(int position) { + if (lines.isEmpty()) { + return position; + } + + int currentPosition = position; + for (Line line : lines) { + currentPosition = line.getNextPosition(currentPosition); + } + return currentPosition; + } } diff --git a/src/main/java/nextstep/ladder/domain/LadderResult.java b/src/main/java/nextstep/ladder/domain/LadderResult.java new file mode 100644 index 0000000000..c6ba99be7f --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/LadderResult.java @@ -0,0 +1,10 @@ +package nextstep.ladder.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class LadderResult { + private String result; +} diff --git a/src/main/java/nextstep/ladder/domain/LadderResults.java b/src/main/java/nextstep/ladder/domain/LadderResults.java new file mode 100644 index 0000000000..483e30c3d4 --- /dev/null +++ b/src/main/java/nextstep/ladder/domain/LadderResults.java @@ -0,0 +1,25 @@ +package nextstep.ladder.domain; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public class LadderResults { + private List ladderResultList = new ArrayList<>(); + + public LadderResults(List results) { + for (String result : results) { + ladderResultList.add(new LadderResult(result)); + } + } + + public String status() { + String result = ""; + for (LadderResult ladderResult : ladderResultList) { + result += ladderResult.getResult() + " "; + } + return result; + } +} diff --git a/src/main/java/nextstep/ladder/domain/Line.java b/src/main/java/nextstep/ladder/domain/Line.java index c5e1293d90..73b5e71c10 100644 --- a/src/main/java/nextstep/ladder/domain/Line.java +++ b/src/main/java/nextstep/ladder/domain/Line.java @@ -1,33 +1,34 @@ package nextstep.ladder.domain; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.Random; @Getter -@NoArgsConstructor -@AllArgsConstructor public class Line { private List bridges = new ArrayList<>(); - public Line(int countOfPerson, BridgeStrategy strategy) { - for (int i = 0; i < countOfPerson - 1; i++) { - bridges.add(build(strategy)); + public static Line createLine(int countOfPerson, BridgeStrategy strategy) { + Line line = new Line(countOfPerson, strategy); + validate(line); + return line; + } + + private static void validate(Line line) { + if (line.isInvalidBridge()) { + throw new RuntimeException("올바르지 않은 라인입니다."); } } - public Line(int countOfPerson) { + private Line(int countOfPerson, BridgeStrategy strategy) { for (int i = 0; i < countOfPerson - 1; i++) { Optional prevIndex = Optional.ofNullable(i) .map(o -> o - 1); - Boolean expected = build(() -> new Random().nextBoolean()); + Boolean expected = build(strategy); bridges.add(decide(prevIndex, expected)); } } @@ -42,4 +43,67 @@ private Boolean decide(Optional prevIndex, Boolean expected) { .map(b -> Boolean.TRUE.equals(b) ? Boolean.valueOf(false) : expected) .orElse(expected); } + + public int getNextPosition(int position) { + // bridges[position - 1] == T 이면 왼쪽으로 + Boolean toLeft = ableToLeft(position); + + // bridges[position] == T 이면 오른쪽으로 + Boolean toRight = ableToRight(position); + + if (toLeft && toRight) { + throw new RuntimeException("사다리 상태를 다시 확인해주세요."); + } + + if (toLeft) { + return position - 1; + } + + if (toRight) { + return position + 1; + } + + return position; + } + + public Boolean ableToRight(int position) { + return Optional.ofNullable(position) + .filter(o -> o < bridges.size()) + .map(o -> bridges.get(o)) + .filter(b -> b) + .orElse(false); + } + + public Boolean ableToLeft(int position) { + return Optional.ofNullable(position) + .map(o -> o - 1) + .filter(o -> o >= 0) + .map(o -> bridges.get(o)) + .filter(b -> b) + .orElse(false); + } + + public boolean isValidBridge() { + boolean valid = true; + for (int i = 0; i < bridges.size(); i++) { + if (ableToLeft(i) && ableToRight(i)) { + valid = false; + } + } + return valid; + } + public boolean isInvalidBridge() { + return !isValidBridge(); + } + + + public String status() { + String result = ""; + for (Boolean bridge : bridges) { + result += "|"; + result += bridge ? "-----" : " "; + } + result += "|\n"; + return result; + } } diff --git a/src/main/java/nextstep/ladder/domain/User.java b/src/main/java/nextstep/ladder/domain/User.java index e8a1f03acb..eb84817f27 100644 --- a/src/main/java/nextstep/ladder/domain/User.java +++ b/src/main/java/nextstep/ladder/domain/User.java @@ -1,11 +1,31 @@ package nextstep.ladder.domain; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class User { private String name; private int position; + + + public User(String name, int position) { + validateName(name); + + this.name = name; + this.position = position; + } + + private static void validateName(String name) { + if (name.length() > 5) { + throw new IllegalArgumentException("이름은 5글자까지 가능합니다."); + } + if (name.equals("all")) { + throw new IllegalArgumentException("all은 부적절한 이름입니다."); + } + } + + public User rideLadder(Ladder ladder) { + int lastPosition = ladder.findLastPosition(position); + return new User(name, lastPosition); + } } diff --git a/src/main/java/nextstep/ladder/domain/Users.java b/src/main/java/nextstep/ladder/domain/Users.java index b9a15993f6..10fad2b8af 100644 --- a/src/main/java/nextstep/ladder/domain/Users.java +++ b/src/main/java/nextstep/ladder/domain/Users.java @@ -2,16 +2,17 @@ import lombok.Getter; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @Getter public class Users { private List users = new ArrayList<>(); - public Users (List names) { + public Users(List names) { for (int i = 0; i < names.size(); i++) { - users.add(new User(names.get(i), i)); + User user = new User(names.get(i), i); + users.add(user); } } diff --git a/src/main/java/nextstep/ladder/view/InputView.java b/src/main/java/nextstep/ladder/view/InputView.java index 25b5925e77..4a1ae0c2c7 100644 --- a/src/main/java/nextstep/ladder/view/InputView.java +++ b/src/main/java/nextstep/ladder/view/InputView.java @@ -11,15 +11,31 @@ public class InputView { private static final Scanner scanner = new Scanner(in); public static final String ASKING_NAMES = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; public static final String ASKING_HEIGHT = "최대 사다리 높이는 몇 개인가요?"; + public static final String ASKING_LADDER_RESULT = "실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"; + public static final String ASKING_PLAYERS = "결과를 보고 싶은 사람은?"; public static List inputUserNames() { System.out.println(ASKING_NAMES); String next = scanner.next(); - return Arrays.stream(next.split(",")).collect(Collectors.toList()); + return Arrays.stream(next.split(",")) + .collect(Collectors.toList()); } public static int inputLadderHeight() { System.out.println(ASKING_HEIGHT); return scanner.nextInt(); } + + public static List inputLadderResult() { + System.out.println(ASKING_LADDER_RESULT); + String next = scanner.next(); + return Arrays.stream(next.split(",")) + .collect(Collectors.toList()); + + } + + public static String inputUserName() { + System.out.println(ASKING_PLAYERS); + return scanner.next(); + } } diff --git a/src/main/java/nextstep/ladder/view/OutputView.java b/src/main/java/nextstep/ladder/view/OutputView.java index 3dab6c7751..31ab1bd712 100644 --- a/src/main/java/nextstep/ladder/view/OutputView.java +++ b/src/main/java/nextstep/ladder/view/OutputView.java @@ -1,16 +1,28 @@ package nextstep.ladder.view; -import nextstep.ladder.domain.Ladder; -import nextstep.ladder.domain.Users; +import nextstep.ladder.domain.*; + +import java.util.List; public class OutputView { - public static void afterGame() { + public static void display(Users users, Ladder ladder, LadderResults ladderResults) { + System.out.println("사다리 결과\n"); + System.out.println(users.status()); + System.out.println(ladder.status()); + System.out.println(ladderResults.status()); + } + + + public static void announceAllUsers(List usersAfter, LadderResults ladderResults) { System.out.println("실행 결과"); + usersAfter.forEach(user -> System.out.println(user.getName() + " : " + ladderResults.getLadderResultList().get(user.getPosition()).getResult())); } - public static void display(Users users, Ladder ladder) { - System.out.println(users.status()); - System.out.println(ladder.status()); + public static void announceUser(String name, List usersAfter, LadderResults ladderResults) { + System.out.println("실행 결과"); + usersAfter.stream() + .filter(user -> user.getName().equals(name)) + .forEach(user -> System.out.println(user.getName() + " : " + ladderResults.getLadderResultList().get(user.getPosition()).getResult())); } } diff --git a/src/test/java/nextstep/ladder/domain/LadderTest.java b/src/test/java/nextstep/ladder/domain/LadderTest.java index f3f38cdfaa..0604078900 100644 --- a/src/test/java/nextstep/ladder/domain/LadderTest.java +++ b/src/test/java/nextstep/ladder/domain/LadderTest.java @@ -1,35 +1,58 @@ package nextstep.ladder.domain; -import org.junit.jupiter.api.Test; +import jdk.jfr.Description; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; +import java.util.Arrays; import java.util.List; +import java.util.Random; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; class LadderTest { @ParameterizedTest @CsvSource(value = { - "5, 4", - "4, 5", - "10, 10" + "1000, 1000" }) + @Description(value = "왼쪽으로도 오른쪽으로 건널 수 있는 다리는 생성되지 않음") void 사다리_확인(int height, int people) { - for (int i = 0; i < height; i++) { - Line line = new Line(people); - List bridges = line.getBridges(); - assertThat(bridges).hasSize(people - 1); - - for (Boolean point : bridges) { - System.out.print("|"); - System.out.print(point ? "-----" : " "); - } - System.out.print("|"); - System.out.println(); - } - System.out.println(); + Ladder ladder = Ladder.createLadder(people, height, () -> new Random().nextBoolean()); + ladder.getLines() + .forEach(line -> { + List bridges = line.getBridges(); + assertThat(bridges).hasSize(people - 1); + assertThat(line.isValidBridge()).isTrue(); + }); + } + + + public static Stream createSimpleLadder() { + return Stream.of( + /** + * users -> [a][b][c][d][e] + * lines -> |--| |--| | + * |--| |--| | + * |--| |--| | + * |--| |--| | + * |--| |--| | + * result ->[b][a][d][c][e] + */ + Arguments.of(Ladder.createLadder(5, 5, () -> true)) + ); + } + + @ParameterizedTest + @MethodSource(value = "createSimpleLadder") + void 다리_이동_테스트(Ladder ladder) { + assertThat(ladder.findLastPosition(0)).isEqualTo(1); + assertThat(ladder.findLastPosition(1)).isEqualTo(0); + assertThat(ladder.findLastPosition(2)).isEqualTo(3); + assertThat(ladder.findLastPosition(3)).isEqualTo(2); + assertThat(ladder.findLastPosition(4)).isEqualTo(4); } } \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/LineTest.java b/src/test/java/nextstep/ladder/domain/LineTest.java index c83f0840fa..f071996e64 100644 --- a/src/test/java/nextstep/ladder/domain/LineTest.java +++ b/src/test/java/nextstep/ladder/domain/LineTest.java @@ -1,30 +1,48 @@ package nextstep.ladder.domain; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -import java.util.List; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.*; class LineTest { - @Test - void 무조건_다리를_생성한다() { - Line line = new Line(5, () -> true); - assertThat(line.getBridges()).hasSize(4); + public static Stream preparingSeveralStrategy() { + return Stream.of( + Arguments.of((BridgeStrategy) () -> false, 5, 0), + Arguments.of((BridgeStrategy) () -> true, 5, 2), // 연속으로 다리를 놓을 수 없기 때문에 + Arguments.of((BridgeStrategy) () -> true, 1, 0) + ); + } + + @ParameterizedTest + @MethodSource(value = "preparingSeveralStrategy") + void 다리_세우기_전략에_대한_결과_테스트(BridgeStrategy strategy, int countOfPerson, int result) { + Line line = Line.createLine(countOfPerson, strategy); + assertThat(line.getBridges()).hasSize(countOfPerson - 1); + long count = line.getBridges().stream() - .filter(b -> b == true) + .filter(b -> b) // 세워져 있는 다리 .count(); - assertThat(count).isEqualTo(4); + assertThat(count).isEqualTo(result); } @Test - void 무조건_다리를_생성하지_않는다() { - Line line = new Line(5, () -> false); - assertThat(line.getBridges()).hasSize(4); - long count = line.getBridges().stream() - .filter(b -> b == true) - .count(); - assertThat(count).isEqualTo(0); + void 왼쪽으로_또는_오른쪽으로_이동한다() { + /** + * users : [a][b][c][d][e] + * liens : |--| |--| | + * results: [b][a][d][c][e] + */ + Line line = Line.createLine(5, () -> true); + assertThat(line.getNextPosition(0)).isEqualTo(1); + assertThat(line.getNextPosition(1)).isEqualTo(0); + assertThat(line.getNextPosition(2)).isEqualTo(3); + assertThat(line.getNextPosition(3)).isEqualTo(2); + assertThat(line.getNextPosition(4)).isEqualTo(4); } } \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/domain/UserTest.java b/src/test/java/nextstep/ladder/domain/UserTest.java new file mode 100644 index 0000000000..cefc3856ac --- /dev/null +++ b/src/test/java/nextstep/ladder/domain/UserTest.java @@ -0,0 +1,43 @@ +package nextstep.ladder.domain; + +import org.assertj.core.api.Assertions; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + + +class UserTest { + + + public static Stream preparingUserAndLadder() { + return Stream.of( + Arguments.of(new User("test", 0), Ladder.createLadder(1, 5, () -> true), 0), + Arguments.of(new User("test", 0), Ladder.createLadder(5, 5, () -> true), 1), + Arguments.of(new User("test", 4), Ladder.createLadder(5, 5, () -> true), 4), + Arguments.of(new User("test", 3), Ladder.createLadder(1000, 200, () -> false), 3) + ); + } + + @ParameterizedTest + @MethodSource(value = "preparingUserAndLadder") + void rideLadder(User user, Ladder ladder, int lastPosition) { + User afterRiding = user.rideLadder(ladder); + Assertions.assertThat(afterRiding.getPosition()).isEqualTo(lastPosition); + Assertions.assertThat(afterRiding.getName()).isEqualTo(user.getName()); + } + + @ParameterizedTest + @CsvSource(value = { + "tooLong", + "abcdef", + "all" + }) + void nameTest(String name) { + Assertions.assertThatThrownBy(() -> new User(name, 0)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file