Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step2 - 사다리(생성) #2315

Open
wants to merge 15 commits into
base: minji-go
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
> - 익명 클래스를 람다로 전환 : nextstep.fp.CarTest 이동, 정지 method
- [x] 람다 실습 2
> - 람다를 활용해 중복 제거 : nextstep.fp.Lambda의 sumAll, sumAllEven, sumAllOverThree method
- [x] 흰트
- [x] 힌트
> - 변경되는 부분과 변경되지 않는 부분의 코드를 분리한다.
> - 변경되는 부분을 인터페이스로 추출한다.
> - 인터페이스에 대한 구현체를 익명 클래스(anonymous class)로 구현해 메소드의 인자로 전달한다.
Expand Down Expand Up @@ -76,3 +76,71 @@
> - Arrays.stream()을 이용해 배열을 stream으로 생성할 수 있다.
> - 일치하는 값 하나를 추출할 때 findFirst() 메소드를 활용 가능하다.
> - Optional의 orElseThrow() 메소드 활용해 구현한다.

### 코멘트
- [x] 함수형 인터페이스는 애너테이션 `@FunctionalInterface`으로 선언

---
## STEP2. 사다리(생성)
### 기능 요구사항
> - 사다리 게임에 참여하는 사람에 이름을 최대5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다.
> - 사람 이름은 쉼표(,)를 기준으로 구분한다.
> - 사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다.
> - 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다.
> - |-----|-----| 모양과 같이 가로 라인이 겹치는 경우 어느 방향으로 이동할지 결정할 수 없다.

- [x] 사다리 게임에 참여하는 사람의 이름은 최대 5글자이다.
- [x] 사다리 게임에 참여하는 사람의 이름은 쉼표(,)를 기준으로 구분한다.
- [x] 사다리 게임은 참여하는 사람의 이름과 최대 사다리 높이를 전달받는다.
- [x] 사다리 타기는 (참여하는 사람의 수 - 1) 만큼 라인이 생성된다.
- [x] 사다리 타기는 라인이 겹치지 않는다.
- [x] 사다리는 랜덤값 등 사다리 생성 전략 따라서 생성한다.
- [x] 사다리의 폭은 최대 글자 수 만큼으로 출력한다.

### 프로그래밍 요구사항
> - 자바 8의 스트림과 람다를 적용해 프로그래밍한다.
> - 규칙 6: 모든 엔티티를 작게 유지한다.

실행 결과
```
참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)
pobi,honux,crong,jk

최대 사다리 높이는 몇 개인가요?
5

실행결과

pobi honux crong jk
|-----| |-----|
| |-----| |
|-----| | |
| |-----| |
|-----| |-----|
```

### 힌트
> - 2차원 배열을 ArrayList, Generic을 적용해 구현하면 ArrayList<ArrayList<Boolean>>와 같이 이해하기 어려운 코드가 추가된다.
> - 사다리 게임에서 한 라인의 좌표 값을 가지는 객체를 추가해 구현해 본다.
> - 아래와 같이 Line 객체를 추가하면 ArrayList<ArrayList<Boolean>> 코드를 ArrayList<Line>과 같이 구현하는 것이 가능해 진다.

```java
public class Line {
private List<Boolean> points = new ArrayList<>();

public Line (int countOfPerson) {
// 라인의 좌표 값에 선이 있는지 유무를 판단하는 로직 추가
}

[...]
}
```

### 코멘트
- [x] 사소하지만 컨벤션을 준수하면 좋겠네요
- [x] InputView > `inputNames()` 입력 책임에 맞게 이름을 리스트로 제공해 주면 어떨까요? 그러면 비즈니스 로직에서 파싱할 필요가 없어져서 로직에만 집중할 수 있습니다.
- [x] OutputView > `printLadders()` depth가 깊어보이는데 스트림과 메소드 추출을 활용하면 좋겠습니다!
- [x] LineTest > `getLine()` 대신 `new Line()`으로 비교해 볼 수 있게 만들어봐도 좋겠네요
- [ ] Lines > `validLadderLength()` 양수 값 객체를 만드는 방법도 있겠네요! `규칙 6: 모든 엔티티를 작게 유지한다.`
- [ ] LadderFactory > 상태를 가지는 대신 Factory가 객체를 생성해주는 방향으로 만들어보면 어떨까요? `var ladder = factory.line(names, hieght)`
- [x] Line > `createLine()` boolean 연산 값이 참일 때 라인 요소를 false로 세팅하네요. 가독성에 신경써서 이게 어떤 작업인지 메소드 이름을 통해 표현해 보면 좋겠습니다!
18 changes: 18 additions & 0 deletions src/main/java/ladder/LadderApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ladder;

import ladder.domain.LadderFactory;
import ladder.view.InputView;
import ladder.view.OutputView;


public class LadderApplication {

public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();

LadderFactory ladderFactory = new LadderFactory(inputView.inputNames(), inputView.inputHeight());
outputView.printNames(ladderFactory.getNames());
outputView.printLadder(ladderFactory.getLadder());
}
}
25 changes: 25 additions & 0 deletions src/main/java/ladder/domain/LadderFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ladder.domain;

import java.util.List;

public class LadderFactory {
private final Names names;
private final Lines lines;

public LadderFactory(List<String> names, int height) {
this(names, height, new RandomLineGenerator());
}

public LadderFactory(List<String> names, int height, LineGenerator lineGenerator) {
this.names = new Names(names);
this.lines = new Lines(height, this.names.connectSize(), lineGenerator);
}

public List<List<Boolean>> getLadder() {
return lines.getList();
}

public List<String> getNames() {
return names.getAll();
}
Comment on lines +18 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도
값을 풀어서 제공하고 있네요

혹시 외부에서 사용할 때 디미터 법칙을 지키기 위함일까요?

}
65 changes: 65 additions & 0 deletions src/main/java/ladder/domain/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ladder.domain;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Line {
private final List<Boolean> line;

public Line(int size, LineGenerator generator) {
this(createLine(size, generator));
}

public Line(boolean... line) {
this(createLine(line));
}

public Line(List<Boolean> line) {
this.line = line;
}

private static List<Boolean> createLine(int size, LineGenerator generator) {
if (size < 1) {
throw new IllegalArgumentException("Line size should be greater than 0");
}
return createLine(generate(size, generator));
}

private static List<Boolean> createLine(boolean[] line) {
return IntStream.range(0, line.length)
.mapToObj(i -> line[i])
.collect(Collectors.toList());
}

private static boolean[] generate(int size, LineGenerator generator) {
boolean[] line = new boolean[size];
line[0] = generator.isConnected();

for (int i = 1; i < size; i++) {
line[i] = (!line[i - 1] && generator.isConnected());
}

return line;
}

public List<Boolean> getList() {
return Collections.unmodifiableList(line);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Line line1 = (Line) o;
return Objects.equals(line, line1.line);
}

@Override
public int hashCode() {
return Objects.hashCode(line);
}

}
5 changes: 5 additions & 0 deletions src/main/java/ladder/domain/LineGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ladder.domain;

public interface LineGenerator {
boolean isConnected();
}
32 changes: 32 additions & 0 deletions src/main/java/ladder/domain/Lines.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ladder.domain;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Lines {
private final List<Line> lines;

public Lines(int height, int width, LineGenerator generator) {
validLadderLength(height);
validLadderLength(width);
this.lines = createLadder(height, width, generator);
}

private void validLadderLength(int value) {
if (value < 1)
throw new IllegalArgumentException("The ladder height should be larger than zero.");
}

private List<Line> createLadder(int height, int width, LineGenerator generator) {
return IntStream.range(0, height)
.mapToObj(i -> new Line(width, generator))
.collect(Collectors.toList());
}

public List<List<Boolean>> getList() {
return lines.stream()
.map(Line::getList)
.collect(Collectors.toUnmodifiableList());
}
Comment on lines +27 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<Line>이 아닌 List<List<Boolean>>으로 내보내는 이유가 있나요?

}
31 changes: 31 additions & 0 deletions src/main/java/ladder/domain/Names.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ladder.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Names {
private final List<String> names;

public Names(String... names) {
this(Arrays.asList(names));
}

public Names(List<String> names) {
this.names = names;
validateNameMaxLength(names);
}

private void validateNameMaxLength(List<String> names) {
if (names.stream().anyMatch(name -> name.length() > 5))
throw new IllegalArgumentException("The name should be up to 5 letters.");
}

public List<String> getAll() {
return Collections.unmodifiableList(names);
}

public int connectSize() {
return names.size() - 1;
}
}
12 changes: 12 additions & 0 deletions src/main/java/ladder/domain/RandomLineGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ladder.domain;

import java.util.Random;

public class RandomLineGenerator implements LineGenerator {
public static final Random random = new Random();

@Override
public boolean isConnected() {
return random.nextBoolean();
}
}
23 changes: 23 additions & 0 deletions src/main/java/ladder/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ladder.view;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class InputView {
private static final Scanner SCANNER = new Scanner(System.in);

public List<String> inputNames() {
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)");
String names = SCANNER.nextLine();
System.out.println();
return Arrays.asList(names.split(","));
}

public int inputHeight() {
System.out.println("최대 사다리 높이는 몇 개인가요?");
int height = SCANNER.nextInt();
SCANNER.nextLine();
return height;
}
}
33 changes: 33 additions & 0 deletions src/main/java/ladder/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ladder.view;

import java.util.List;
import java.util.stream.Collectors;

public class OutputView {
public void printNames(List<String> names) {
System.out.println("실행결과");
System.out.println();

names.stream()
.map(name -> String.format("%5s ", name))
.forEach(System.out::print);

System.out.println();
}

public void printLadder(List<List<Boolean>> ladders) {
ladders.stream()
.map(this::convertLine)
.forEach(System.out::println);
}

private String convertLine(List<Boolean> line) {
return line.stream()
.map(this::convertLineElement)
.collect(Collectors.joining("|", " |", "|"));
}

private String convertLineElement(Boolean connected) {
return Boolean.TRUE.equals(connected) ? "-----" : " ";
}
}
1 change: 1 addition & 0 deletions src/main/java/nextstep/fp/Lambda.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ private static int sumBy(List<Integer> numbers, SumCondition condition) {
.orElse(0);
}

@FunctionalInterface
public interface SumCondition {
boolean match(int number);
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/nextstep/fp/StreamStudy.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamStudy {
Expand Down
24 changes: 12 additions & 12 deletions src/main/java/nextstep/optional/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ public User(String name, Integer age) {
this.age = age;
}

public String getName() {
return name;
}

public Integer getAge() {
return age;
}

public boolean matchName(String name) {
return this.name.equals(name);
}

public static boolean ageIsInRange1(User user) {
boolean isInRange = false;

Expand All @@ -41,6 +29,18 @@ public static boolean ageIsInRange2(User user) {
.isPresent();
}

public String getName() {
return name;
}

public Integer getAge() {
return age;
}

public boolean matchName(String name) {
return this.name.equals(name);
}

@Override
public int hashCode() {
final int prime = 31;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/nextstep/optional/Users.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Users {
static final User DEFAULT_USER = new User("codesquad", 100);
Expand Down
Loading