diff --git a/README.md b/README.md index 70e61dd573..87c7a36170 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,21 @@ -# STEP-01 +## STEP-02 + +### 입력 + +* [X] 사람의 이름은 최대 5글자이다 +* [X] 쉼표(,) 를 기준으로 이름을 구분한다 + +### 출력 + +* [X] 5자 기준으로 사용자 이름을 출력한다 +* [X] 사다리를 출력 한다 + +### 기능 + +* [X] 사다리 타기가 정상적으로 동작하기 위해 라인이 겹치지 않도록 한다 +* [X] 높이에 맞는 사다리 생성한다 + +## STEP-01 * [X] 람다 실습 1 - 익명 클래스를 람다로 전환 * [X] 람다 실습 2 - 람다를 활용해 중복 제거 diff --git a/src/main/java/nextstep/fp/Conditional.java b/src/main/java/nextstep/fp/Conditional.java new file mode 100644 index 0000000000..d9238106e2 --- /dev/null +++ b/src/main/java/nextstep/fp/Conditional.java @@ -0,0 +1,7 @@ +package nextstep.fp; + +@FunctionalInterface +public interface Conditional { + + boolean test(Integer number); +} diff --git a/src/main/java/nextstep/fp/Lambda.java b/src/main/java/nextstep/fp/Lambda.java index 2036517d45..6b7b833378 100644 --- a/src/main/java/nextstep/fp/Lambda.java +++ b/src/main/java/nextstep/fp/Lambda.java @@ -28,22 +28,21 @@ public void run() { } public static int sumAll(List numbers) { - return numbers.stream() - .mapToInt(e -> e) - .sum(); + return sum(numbers, (number) -> true); } public static int sumAllEven(List numbers) { - return numbers.stream() - .filter(e -> e % 2 == 0) - .mapToInt(e -> e) - .sum(); + return sum(numbers, (number) -> number % 2 == 0); } public static int sumAllOverThree(List numbers) { + return sum(numbers, (number) -> number > 3); + } + + private static int sum(List numbers, Conditional conditional) { return numbers.stream() - .filter(e -> e > 3) - .mapToInt(e -> e) + .filter(conditional::test) + .mapToInt(number -> number) .sum(); } } diff --git a/src/main/java/nextstep/ladder/controller/MainController.java b/src/main/java/nextstep/ladder/controller/MainController.java new file mode 100644 index 0000000000..4ed61d7805 --- /dev/null +++ b/src/main/java/nextstep/ladder/controller/MainController.java @@ -0,0 +1,35 @@ +package nextstep.ladder.controller; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import nextstep.ladder.model.Ladder; +import nextstep.ladder.model.LadderHeight; +import nextstep.ladder.model.Name; +import nextstep.ladder.model.PersonCount; +import nextstep.ladder.model.RandomTrueOrFalse; +import nextstep.ladder.view.InputView; +import nextstep.ladder.view.OutputView; + +public class MainController { + + public static void main(String[] args) { + InputView inputView = new InputView(); + + String namesText = inputView.inputUserNames(); + List names = Arrays.stream(namesText.split(",")) + .map(Name::new) + .collect(Collectors.toList()); + + PersonCount countOfPerson = new PersonCount(names.size()); + + String heightOfLadderText = inputView.inputHeightOfLadder(); + LadderHeight heightOfLadder = new LadderHeight(Integer.parseInt(heightOfLadderText)); + + Ladder ladder = new Ladder(heightOfLadder, countOfPerson, new RandomTrueOrFalse()); + + OutputView outputView = new OutputView(); + outputView.print(ladder, names); + } + +} diff --git a/src/main/java/nextstep/ladder/model/Ladder.java b/src/main/java/nextstep/ladder/model/Ladder.java new file mode 100644 index 0000000000..4062ee514e --- /dev/null +++ b/src/main/java/nextstep/ladder/model/Ladder.java @@ -0,0 +1,22 @@ +package nextstep.ladder.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.stream.IntStream; + +public class Ladder { + + private final List lines; + + public Ladder(LadderHeight heightOfLadder, PersonCount countOfPerson, Random random) { + this.lines = new ArrayList<>(); + IntStream.range(0, heightOfLadder.getHeightOfLadder()) + .mapToObj(line -> new Line(countOfPerson.getCountOfPerson(), random)) + .forEach(this.lines::add); + } + + public List getLines() { + return lines; + } +} diff --git a/src/main/java/nextstep/ladder/model/LadderHeight.java b/src/main/java/nextstep/ladder/model/LadderHeight.java new file mode 100644 index 0000000000..5f0119314f --- /dev/null +++ b/src/main/java/nextstep/ladder/model/LadderHeight.java @@ -0,0 +1,23 @@ +package nextstep.ladder.model; + +public class LadderHeight { + + private static final int MIN_HEIGHT = 1; + + private final Integer heightOfLadder; + + public LadderHeight(Integer heightOfLadder) { + validateHeight(heightOfLadder); + this.heightOfLadder = heightOfLadder; + } + + private void validateHeight(Integer heightOfLadder) { + if (heightOfLadder < MIN_HEIGHT) { + throw new IllegalArgumentException("높이는 1 이상 이어야 합니다."); + } + } + + public Integer getHeightOfLadder() { + return heightOfLadder; + } +} diff --git a/src/main/java/nextstep/ladder/model/LadderService.java b/src/main/java/nextstep/ladder/model/LadderService.java new file mode 100644 index 0000000000..58fa3511f2 --- /dev/null +++ b/src/main/java/nextstep/ladder/model/LadderService.java @@ -0,0 +1,15 @@ +package nextstep.ladder.model; + +import java.util.List; +import java.util.Random; + +public class LadderService { + + private final List names; + private final Ladder ladder; + + public LadderService(LadderHeight heightOfLadder, PersonCount countOfPerson, List names, Random random) { + ladder = new Ladder(heightOfLadder, countOfPerson, random); + this.names = names; + } +} diff --git a/src/main/java/nextstep/ladder/model/Line.java b/src/main/java/nextstep/ladder/model/Line.java new file mode 100644 index 0000000000..fe3c8da20e --- /dev/null +++ b/src/main/java/nextstep/ladder/model/Line.java @@ -0,0 +1,47 @@ +package nextstep.ladder.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.stream.IntStream; + +public class Line { + + private final List points; + + public Line(int countOfPerson, Random random) { + this.points = new ArrayList<>(); + this.points.add(random.nextBoolean()); + IntStream.range(0, countOfPerson - 2) + .forEach(index -> initPoint(index, random.nextBoolean())); + validateLine(countOfPerson); + } + + private void validateLine(int countOfPerson) { + IntStream.range(0, countOfPerson - 2) + .filter(index -> points.get(index) && points.get(index + 1)) + .forEach(point -> { + throw new IllegalArgumentException("사다리 라인이 겹칩니다"); + }); + } + + private void initPoint(int index, boolean nextBoolean) { + if (this.points.get(index) && nextBoolean || this.points.get(index) && !nextBoolean + || !this.points.get(index) && !nextBoolean) { + this.points.add(false); + return; + } + if (!this.points.get(index) && nextBoolean) { + this.points.add(true); + } + } + + public List getPoints() { + return this.points; + } + + @Override + public String toString() { + return this.points.toString(); + } +} diff --git a/src/main/java/nextstep/ladder/model/Name.java b/src/main/java/nextstep/ladder/model/Name.java new file mode 100644 index 0000000000..7d1792cfe6 --- /dev/null +++ b/src/main/java/nextstep/ladder/model/Name.java @@ -0,0 +1,30 @@ +package nextstep.ladder.model; + +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class Name { + + private static final int MIN_LENGTH = 1; + private static final int MAX_LENGTH = 5; + private static final String SPACE = " "; + private final String name; + + public Name(String name) { + validateNameLength(name); + this.name = name; + } + + private void validateNameLength(String name) { + if (name.length() < MIN_LENGTH || name.length() > MAX_LENGTH) { + throw new IllegalArgumentException("이름의 길이는 1자 ~ 5자 입니다"); + } + } + + @Override + public String toString() { + return IntStream.range(0, MAX_LENGTH - name.length()) + .mapToObj(i -> SPACE) + .collect(Collectors.joining("", name, "")); + } +} diff --git a/src/main/java/nextstep/ladder/model/PersonCount.java b/src/main/java/nextstep/ladder/model/PersonCount.java new file mode 100644 index 0000000000..da5172d422 --- /dev/null +++ b/src/main/java/nextstep/ladder/model/PersonCount.java @@ -0,0 +1,22 @@ +package nextstep.ladder.model; + +public class PersonCount { + + private static final int MIN_COUNT = 1; + private final Integer countOfPerson; + + public PersonCount(Integer countOfPerson) { + validateCountOfPerson(countOfPerson); + this.countOfPerson = countOfPerson; + } + + private void validateCountOfPerson(Integer countOfPerson) { + if (countOfPerson < MIN_COUNT) { + throw new IllegalArgumentException("사람의 수는 1 이상 이어야 합니다."); + } + } + + public Integer getCountOfPerson() { + return countOfPerson; + } +} diff --git a/src/main/java/nextstep/ladder/model/RandomTrueOrFalse.java b/src/main/java/nextstep/ladder/model/RandomTrueOrFalse.java new file mode 100644 index 0000000000..5f4668e3a4 --- /dev/null +++ b/src/main/java/nextstep/ladder/model/RandomTrueOrFalse.java @@ -0,0 +1,11 @@ +package nextstep.ladder.model; + +import java.util.Random; + +public class RandomTrueOrFalse extends Random { + + @Override + public boolean nextBoolean() { + return super.nextBoolean(); + } +} 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..3c045119d3 --- /dev/null +++ b/src/main/java/nextstep/ladder/view/InputView.java @@ -0,0 +1,19 @@ +package nextstep.ladder.view; + +import java.util.Scanner; + +public class InputView { + + private static final Scanner SCANNER = new Scanner(System.in); + + public String inputUserNames() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + return SCANNER.nextLine(); + } + + public String inputHeightOfLadder() { + System.out.println("\n최대 사다리 높이는 몇 개인가요?"); + return SCANNER.nextLine(); + } + +} 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..eb90ef186b --- /dev/null +++ b/src/main/java/nextstep/ladder/view/OutputView.java @@ -0,0 +1,44 @@ +package nextstep.ladder.view; + +import java.util.List; +import java.util.stream.Collectors; +import nextstep.ladder.model.Ladder; +import nextstep.ladder.model.Name; + +public class OutputView { + + private static final String FOUR_SPACE = " "; + private static final String LADDER = "|"; + private static final String LINE = "----"; + + public OutputView() { + System.out.println("\n실행결과\n"); + } + + public void print(Ladder ladder, List names) { + printNames(names); + printLadder(ladder); + } + + private void printLadder(Ladder ladder) { + StringBuilder stringBuilder = new StringBuilder(); + ladder.getLines().forEach(line -> { + stringBuilder.append(FOUR_SPACE); + stringBuilder.append(line.getPoints() + .stream() + .map(point -> point ? LADDER + LINE : LADDER + FOUR_SPACE) + .collect(Collectors.joining())); + stringBuilder.append(LADDER) + .append("\n"); + }); + System.out.println(stringBuilder); + } + + private void printNames(List names) { + names.stream() + .map(name -> name + " ") + .forEach(System.out::print); + System.out.println(); + } +} + diff --git a/src/test/java/nextstep/ladder/model/LadderHeightTest.java b/src/test/java/nextstep/ladder/model/LadderHeightTest.java new file mode 100644 index 0000000000..91eba189b3 --- /dev/null +++ b/src/test/java/nextstep/ladder/model/LadderHeightTest.java @@ -0,0 +1,24 @@ +package nextstep.ladder.model; + +import static org.junit.jupiter.api.Assertions.*; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class LadderHeightTest { + + @Test + @DisplayName("사다리의 높의는 1 이상이다") + void ladder_height() { + Assertions.assertThatThrownBy(() -> { + new LadderHeight(0); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("높이는 1 이상 이어야 합니다."); + + Assertions.assertThatThrownBy(() -> { + new LadderHeight(-1); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("높이는 1 이상 이어야 합니다."); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/model/LadderTest.java b/src/test/java/nextstep/ladder/model/LadderTest.java new file mode 100644 index 0000000000..ffc3b0cd69 --- /dev/null +++ b/src/test/java/nextstep/ladder/model/LadderTest.java @@ -0,0 +1,21 @@ +package nextstep.ladder.model; + +import java.util.Random; +import org.junit.jupiter.api.Test; + +class LadderTest { + + static class AlwaysReturnTrue extends Random { + + @Override + public boolean nextBoolean() { + return true; + } + } + + @Test + void ladder() { + Ladder ladder = new Ladder(new LadderHeight(5), new PersonCount(4), new AlwaysReturnTrue()); + } + +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/model/LineTest.java b/src/test/java/nextstep/ladder/model/LineTest.java new file mode 100644 index 0000000000..194de052c2 --- /dev/null +++ b/src/test/java/nextstep/ladder/model/LineTest.java @@ -0,0 +1,28 @@ +package nextstep.ladder.model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Random; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class LineTest { + + static class AlwaysReturnTrue extends Random { + + @Override + public boolean nextBoolean() { + return true; + } + } + + @Test + @DisplayName("사다리의 라인 하나를 생성한다") + void line() { + int countOfPerson = 5; + Line line = new Line(countOfPerson, new AlwaysReturnTrue()); + + assertThat(line.getPoints()).hasSize(countOfPerson - 1) + .containsExactly(true, false, true, false); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/model/NameTest.java b/src/test/java/nextstep/ladder/model/NameTest.java new file mode 100644 index 0000000000..a1018732f2 --- /dev/null +++ b/src/test/java/nextstep/ladder/model/NameTest.java @@ -0,0 +1,24 @@ +package nextstep.ladder.model; + +import static org.junit.jupiter.api.Assertions.*; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class NameTest { + + @Test + @DisplayName("이름의 길이는 1자 ~ 5자 이다") + void name_length() { + Assertions.assertThatThrownBy(() -> { + new Name("123456"); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("이름의 길이는 1자 ~ 5자 입니다"); + + Assertions.assertThatThrownBy(() -> { + new Name(""); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("이름의 길이는 1자 ~ 5자 입니다"); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/model/PersonCountTest.java b/src/test/java/nextstep/ladder/model/PersonCountTest.java new file mode 100644 index 0000000000..90b0022100 --- /dev/null +++ b/src/test/java/nextstep/ladder/model/PersonCountTest.java @@ -0,0 +1,23 @@ +package nextstep.ladder.model; + + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PersonCountTest { + + @Test + @DisplayName("사람의 수는 1 이상 이어야 합니다.") + void person_count() { + Assertions.assertThatThrownBy(() -> { + new PersonCount(0); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("사람의 수는 1 이상 이어야 합니다."); + + Assertions.assertThatThrownBy(() -> { + new PersonCount(-1); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("사람의 수는 1 이상 이어야 합니다."); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/ladder/view/OutputViewTest.java b/src/test/java/nextstep/ladder/view/OutputViewTest.java new file mode 100644 index 0000000000..8abe9d0ad3 --- /dev/null +++ b/src/test/java/nextstep/ladder/view/OutputViewTest.java @@ -0,0 +1,20 @@ +package nextstep.ladder.view; + +import nextstep.ladder.model.Ladder; +import nextstep.ladder.model.LadderHeight; +import nextstep.ladder.model.PersonCount; +import nextstep.ladder.model.RandomTrueOrFalse; +import org.junit.jupiter.api.Test; + +class OutputViewTest { + + @Test + void print_ladder() { + Ladder ladder = new Ladder(new LadderHeight(10), new PersonCount(5), + new RandomTrueOrFalse()); + OutputView outputView = new OutputView(); +// outputView.printLadder(ladder); + + } + +} \ No newline at end of file