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

Step3 #1853

Open
wants to merge 21 commits into
base: hoyeoon
Choose a base branch
from
Open

Step3 #1853

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
97f2c06
docs: 3단계 - 사다리(게임 실행) 기능 요구사항 작성
hoyeoon May 28, 2023
7e1b66c
test: 실행결과 생성, 글자수 예외 테스트
hoyeoon May 28, 2023
0796fcd
feat: 실행 결과 입력 추가
hoyeoon May 28, 2023
7db91d9
feat: 사다리 출력시 실행 결과 포함
hoyeoon May 28, 2023
56f35bb
test: 특정인의 결과 확인
hoyeoon May 28, 2023
c9688d4
refactor: 클래스 분리
hoyeoon May 29, 2023
fb04575
refactor: 인스턴스 변수명 수정
hoyeoon May 29, 2023
17e3d2e
feat: 사다리 2차원 배열 만들기
hoyeoon May 29, 2023
02d71a8
fix: 실행결과 출력 수정
hoyeoon May 29, 2023
d2c1b02
refactor: 테스트 수정, 클래스명 수정
hoyeoon May 29, 2023
5ce386b
refactor: 사다리 출력 방식 수정
hoyeoon May 29, 2023
85628d9
refactor: 공백 출력 방식 수정
hoyeoon May 29, 2023
9cfc315
feat: 시작인덱스를 넣었을 때 도착인덱스를 반환하는 메서드 구현
hoyeoon May 29, 2023
c457816
refactor: 메서드 분리
hoyeoon May 29, 2023
4fd74e1
test: 사다리 결과
hoyeoon May 29, 2023
35046c7
feat: 사다리 결과
hoyeoon May 29, 2023
1103791
feat: 입력받은 사람에 대한 결과 출력
hoyeoon May 29, 2023
b91f2b2
feat: 입력 받은 사람 이름이 참여할 사람 이름 목록에 없을 경우 예외처리
hoyeoon May 29, 2023
74beb37
test: 입력 받은 사람 이름이 참여할 사람 이름 목록에 없을 경우 예외처리
hoyeoon May 29, 2023
42f3c43
refactor: 테스트 수정
hoyeoon May 29, 2023
5aea879
refactor: 테스트 수정
hoyeoon May 29, 2023
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
20 changes: 17 additions & 3 deletions src/main/java/nextstep/ladder/Main.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
package nextstep.ladder;

import nextstep.ladder.domain.Ladder;
import nextstep.ladder.domain.*;
import nextstep.ladder.view.InputView;
import nextstep.ladder.view.ResultView;

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

Ladder ladder = new Ladder(inputView.people(), inputView.height());
ResultView.printResult(ladder);
People people = inputView.people();
ExecuteResults executeResults = inputView.executeResults();
InputOutput inputOutput = new InputOutput(people, executeResults);

int verticalLineCount = people.value().size();
int height = inputView.height();

Ladder ladder = new Ladder(verticalLineCount, height);

ResultView.printLadder(inputOutput, ladder);

Match match = new Match(inputOutput, ladder);
Result result = match.makeResult();
String person = inputView.person();

ResultView.printResult(result, person);

inputView.close();
}
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/nextstep/ladder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@
-[x] 라인을 생성 할지/말지 판단하는 1/2 랜덤 함수 사용
-[x] 가로 라인 확인 (겹치지 않기 위해)
-[x] 사다리(Ladder) 객체 구현
-[ ] 실행결과 출력
-[x] 실행결과 출력
- [x] 이름 출력
- [x] 사다리 출력

## 3단계 - 사다리(게임 실행)

-[x] 실행 결과 입력 추가 (,로 구분)
- [x] 입력받은 실행 결과 수와 참여할 사람 이름의 수가 불일치 할 경우 예외처리
-[x] 사다리 출력시 입력 받은 실행 결과를 포함하여 출력
-[x] 사다리 결과 로직 구현
-[x] 결과를 보고 싶은 사람 입력
- all 아닐 경우
- [x] 입력받은 결과를 보고 싶은 사람의 실행 결과 출력
- [x] 입력 받은 사람 이름이 참여할 사람 이름 목록에 없을 경우 예외처리
- all 일 경우
- [x] 모든 사람의 실행 결과 출력
25 changes: 25 additions & 0 deletions src/main/java/nextstep/ladder/domain/ExecuteResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package nextstep.ladder.domain;

public class ExecuteResult {
private static final int NAME_LENGTH_MAX = 5;

private final String name;

public ExecuteResult(String name) {
if (name.length() > NAME_LENGTH_MAX) {
throw new IllegalArgumentException("글자수는 최대 5글자까지 부여할 수 있습니다.");
}
this.name = name;
}

public String name() {
return this.name;
}

@Override
public String toString() {
return "ExecuteResult{" +
"name='" + name + '\'' +
'}';
}
}
23 changes: 23 additions & 0 deletions src/main/java/nextstep/ladder/domain/ExecuteResults.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nextstep.ladder.domain;

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

public class ExecuteResults {

Choose a reason for hiding this comment

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

일급 컬렉션이나 클래스 분리, 제약 등을 깔끔하게 잘 정의해주셨네요 👍


private final List<ExecuteResult> executeResults;

public ExecuteResults(String[] executeResults) {
if (executeResults.length == 0) {
throw new IllegalStateException("실행 결과가 입력되지 않았습니다.");
}
this.executeResults = Arrays.stream(executeResults).
map(ExecuteResult::new).
collect(Collectors.toList());
}

public List<ExecuteResult> value() {
return executeResults;
}
Comment on lines +20 to +22

Choose a reason for hiding this comment

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

지금과 같은 복잡도와 혼자 작업하는 상황에서라면 상관없겠지만.

이렇게 List의 참조가 외부에 노출되게 되면 외부에서 의도하지 않게 값을 추가하거나 삭제할 수 있게 됩니다.

Collections.unmodifiableList와 같은걸로 감싸서 반환하는 것을 고려해보셔도 좋겠네요.

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

public class InputOutput {

Choose a reason for hiding this comment

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

InputOutput의 이름만 보면 어떤 의도를 가진 클래스인지 알기 어려워보여요.

사다리 게임의 결과가 담겨있다는 의미를 나타낼 수 있는 클래스명으로 변경해보시면 어떨까요?


private final People people;
private final ExecuteResults executeResults;

public InputOutput(People people, ExecuteResults executeResults) {
if (people.value().size() != executeResults.value().size()) {
throw new IllegalArgumentException("참여할 사람 수와 실행 결과 수는 일치해야 합니다.");
}
this.people = people;
this.executeResults = executeResults;
}

public People people() {
return people;
}

public ExecuteResults executeResults() {
return executeResults;
}
}
54 changes: 44 additions & 10 deletions src/main/java/nextstep/ladder/domain/Ladder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,63 @@

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

public class Ladder {

private final People people;
private static final int BEGIN_INDEX = 0;

private final int verticalLineCount;
private final Lines lines;

public Ladder(People people, int height) {
this.people = people;
this.lines = new Lines(generateLadder(height));
public Ladder(int verticalLineCount, Lines lines) {
this.verticalLineCount = verticalLineCount;
this.lines = lines;
}

private List<Line> generateLadder(int height) {
return Stream.generate(() -> new Line(people.value().size()))
.limit(height)
.collect(Collectors.toList());
public Ladder(int verticalLineCount, int height) {
this(verticalLineCount, new Lines(generateLines(verticalLineCount, height)));
}

public People people() {
return people;
private static List<Line> generateLines(int verticalLineCount, int height) {
return Stream.generate(() -> new Line(verticalLineCount))
.limit(height)
.collect(Collectors.toList());
}

public Lines lines() {
return lines;
}

public String[][] result() {
List<Line> lines = this.lines.value();

int width = verticalLineCount * 2 - 1;
int height = this.lines.value().size();

String[][] ladder = new String[height][width];

IntStream.range(BEGIN_INDEX, height)
.forEach(i -> IntStream.range(BEGIN_INDEX, width)
.forEach(j -> {
if (isVerticalLine(j)) {
ladder[i][j] = "v";
return;
}
if (isHorizontalLine(lines, i, j)) {
ladder[i][j] = "h";
}
}));
return ladder;
}
Comment on lines +34 to +54

Choose a reason for hiding this comment

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

Collection에 여러 편의 메서드들이 존재하는데 다시 이차원 배열을 활용하는게 좋은 선택일지 고민이 필요할 것 같아요.
vertical인지 horizontal인지는 메서드로 검증할 수 있으므로 v, h가 기록된 String[][] 타입의 이차원 배열을 만들 필요가 있을까요?


private boolean isVerticalLine(int j) {
return j % 2 == 0;
}

private Boolean isHorizontalLine(List<Line> lines, int i, int j) {
return lines.get(i).value().get((j - 1) / 2);
}

}
37 changes: 20 additions & 17 deletions src/main/java/nextstep/ladder/domain/Line.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,47 @@ public class Line {
private static final boolean EMPTY_POINT = false;
private static final double HALF = 0.5;

private final List<Boolean> points;
private final List<Boolean> horizontalLines;

public Line(int countOfPerson) {
points = generateLine(countOfPerson);
public Line(List<Boolean> horizontalLines) {
this.horizontalLines = horizontalLines;
}

public List<Boolean> generateLine(int countOfPerson) {
List<Boolean> points = new ArrayList<>();
public Line(int countOfPerson) {
this(generateLine(countOfPerson));
}

IntStream.range(BEGIN_INDEX, countOfPerson)
.forEach(idx -> points.add(createPoint(idx, points)));
public static List<Boolean> generateLine(int countOfPerson) {
List<Boolean> horizontalLines = new ArrayList<>();

return points;
IntStream.range(BEGIN_INDEX, countOfPerson - 1)
.forEach(idx -> horizontalLines.add(createPoint(idx, horizontalLines)));
return horizontalLines;
}

private Boolean createPoint(int idx, List<Boolean> points) {
private static Boolean createPoint(int idx, List<Boolean> horizontalLines) {
if (BEGIN_INDEX == idx) {
return EMPTY_POINT;
return isCurrPointNonEmpty();
}
return isPrevPointEmpty(idx, points) && isCurrPointNonEmpty();
return isPrevPointEmpty(idx, horizontalLines) && isCurrPointNonEmpty();
}

private boolean isPrevPointEmpty(int idx, List<Boolean> points) {
return EMPTY_POINT == points.get(idx - 1);
private static boolean isPrevPointEmpty(int idx, List<Boolean> horizontalLines) {
return EMPTY_POINT == horizontalLines.get(idx - 1);
}

private boolean isCurrPointNonEmpty() {
private static boolean isCurrPointNonEmpty() {
return HALF < Math.random();
}

public List<Boolean> points() {
return points;
public List<Boolean> value() {
return horizontalLines;
}

@Override
public String toString() {
return "Line{" +
"points=" + points +
"horizontalLines=" + horizontalLines +
'}';
}
}
61 changes: 61 additions & 0 deletions src/main/java/nextstep/ladder/domain/Match.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nextstep.ladder.domain;

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

public class Match {

private static final int BEGIN_IDX = 0;

private final InputOutput inputOutput;
private final Ladder ladder;

public Match(InputOutput inputOutput, Ladder ladder) {
this.inputOutput = inputOutput;
this.ladder = ladder;
}

public Match(Ladder ladder) {
this(null, ladder);
}

public Result makeResult() {
List<Person> people = inputOutput.people().value();
List<ExecuteResult> executeResults = inputOutput.executeResults().value();

return new Result(IntStream.range(BEGIN_IDX, people.size())
.boxed()
.collect(Collectors.toMap(i -> people.get(i).name(), i -> executeResults.get(findOutputIdx(i)).name(),
(v1, v2) -> v1, LinkedHashMap::new)));
}

int findOutputIdx(int startIdx) {

Choose a reason for hiding this comment

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

여기에 접근 제한자가 빠진 이유가 있을까요~?

makeResult에서만 활용하는거라면 private 메서드로 만들어주시면 좋겠습니다.

int currentIdx = startIdx * 2;
String[][] ladder = this.ladder.result();
int rowCount = ladder.length;
int columnLength = ladder[BEGIN_IDX].length;

currentIdx = IntStream.range(BEGIN_IDX, rowCount)
.reduce(currentIdx, (idx, i) -> {
String[] row = ladder[i];
if (isMovableToLeft(idx, row)) {
return idx - 2;
}
if (isMovableToRight(idx, row, columnLength)) {
return idx + 2;
}
return idx;
});
Comment on lines +41 to +50

Choose a reason for hiding this comment

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

여기 로직이 복잡한데 메서드로 추출해보는건 어떨까요?

Choose a reason for hiding this comment

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

전체적으로 클래스도, 책임도 잘 나누어 주셨는데 이 부분의 복잡도가 높은 것 같습니다.

메서드 추출 혹은 리팩토링으로 조금 더 로직을 가독성 좋게 만들어보시면 좋겠습니다.

return currentIdx / 2;
}

private boolean isMovableToLeft(int idx, String[] row) {
return idx > BEGIN_IDX && "h".equals(row[idx - 1]);
}

private boolean isMovableToRight(int idx, String[] row, int columnLength) {
return idx < columnLength - 1 && "h".equals(row[idx + 1]);
}
}
15 changes: 15 additions & 0 deletions src/main/java/nextstep/ladder/domain/Person.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package nextstep.ladder.domain;

import java.util.Objects;

public class Person {

private static final int NAME_LENGTH_MAX = 5;
Expand All @@ -17,6 +19,19 @@ public String name() {
return this.name;
}

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

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

@Override
public String toString() {
return "Person{" +
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/nextstep/ladder/domain/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nextstep.ladder.domain;

import java.util.Map;

public class Result {

private final Map<String, String> result;

public Result(Map<String, String> result) {
this.result = result;
}

public String get(String person) {
if (result.get(person) == null) {
throw new IllegalArgumentException("해당하는 사람이 존재하지 않습니다.");
}
return result.get(person);
}

public Map<String, String> value() {
return this.result;
}
}
Loading