-
Notifications
You must be signed in to change notification settings - Fork 53
[이예진] 사다리 게임 구현 (1-5단계) #66
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
base: yaevrai
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# java-ladder : 사다리 - 함수형 프로그래밍 | ||
|
||
## Level1. 사다리 출력 | ||
|
||
### - 요구사항 | ||
|
||
- [x] 네이버 사다리 게임을 참고하여 도메인을 분석하여 구현한다. | ||
- [x] 사다리는 4x4 크기로 고정되고, 연결 여부는 랜덤으로 결정한다. | ||
- [x] 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다. | ||
- [x] 모든 엔티티를 작게 유지한다. | ||
- [x] 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. | ||
|
||
## Level2. 사다리 생성 | ||
|
||
### - 요구사항 | ||
|
||
- [x] 사다리는 크기를 입력 받아 생성할 수 있다. (넓이 & 높이) | ||
|
||
## Level3. 사다리 타기 | ||
|
||
### - 요구사항 | ||
|
||
- [x] 사다리의 시작 지점과 도착 지점을 출력한다. | ||
|
||
## Level4. 게임 실행 | ||
|
||
### - 요구사항 | ||
|
||
- [x] 사다리 게임에 참여하는 사람에 이름을 최대 5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다. | ||
- [x] 사람 이름은 쉼표(,)를 기준으로 구분한다. | ||
- [x] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다. | ||
|
||
## Level5. 리팩토링 | ||
|
||
### - 요구사항 | ||
|
||
- [x] 학습 테스트를 통해 학습한 내용을 반영한다. 자바에서 제공하는 함수형 문법을 적용해보고, 어떠한 차이가 있는지 경험한다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package ladder.controller; | ||
|
||
import ladder.view.InputView; | ||
import ladder.view.OutputView; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
InputView inputView = new InputView(); | ||
OutputView outputView = new OutputView(); | ||
LadderGame game = new LadderGame(inputView, outputView); | ||
game.play(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package ladder.controller; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
import ladder.model.GameSetup; | ||
import ladder.model.Ladder; | ||
import ladder.model.Participants; | ||
import ladder.model.ResultType; | ||
import ladder.model.Results; | ||
import ladder.view.InputView; | ||
import ladder.view.OutputView; | ||
|
||
public class LadderGame { | ||
|
||
private final InputView inputView; | ||
private final OutputView outputView; | ||
|
||
public LadderGame(InputView inputView, OutputView outputView) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
} | ||
|
||
public void play() { | ||
GameSetup setup = createGameSetup(); | ||
displayLadder(setup); | ||
processResult(setup); | ||
} | ||
|
||
private GameSetup createGameSetup() { | ||
Participants participants = inputView.inputParticipants(); | ||
List<String> results = inputView.inputResults(); | ||
int height = inputView.inputHeight(); | ||
Ladder ladder = Ladder.create(participants.size(), height); | ||
return new GameSetup(participants, results, ladder); | ||
} | ||
|
||
private void displayLadder(GameSetup setup) { | ||
outputView.printLadder(setup.getLadder(), setup.getParticipants(), setup.getResults()); | ||
} | ||
|
||
private void processResult(GameSetup setup) { | ||
String result = inputView.inputGameResult(); | ||
Results gameResults = createGameResults(setup); | ||
printGameResults(result, gameResults); | ||
} | ||
|
||
private Results createGameResults(GameSetup setup) { | ||
List<Integer> ladderResults = setup.getLadder().result(); | ||
return new Results(setup.getParticipants(), | ||
mapResults(setup.getResults(), ladderResults)); | ||
} | ||
|
||
private void printGameResults(String result, Results gameResults) { | ||
if (ResultType.ALL.equals(ResultType.from(result))) { | ||
outputView.printAllResults(gameResults); | ||
return; | ||
} | ||
outputView.printSingleResult(gameResults.getResult(result)); | ||
} | ||
|
||
private List<String> mapResults(List<String> inputResults, List<Integer> ladderResults) { | ||
return IntStream.range(0, inputResults.size()) | ||
.mapToObj(i -> inputResults.get(ladderResults.get(i))) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package ladder.model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class GameSetup { | ||
|
||
private final Participants participants; | ||
private final List<String> results; | ||
private final Ladder ladder; | ||
|
||
public GameSetup(Participants participants, List<String> results, Ladder ladder) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우선 해당 객체 때문에 하지만 이러한 시도를 해주시고, 본인이 시도한 방법에 대해 성찰해 보시는 것은 분명 성장하는데 큰 도움이 될 거에요. 우선 저였다면, 미션의 요구사항과 결과를 보고 사다리 게임을 분석했을 것 같아요. 사다리 게임을 간단하게 분석해 보면, 사다리 게임은 사용자의 입력이 완료되면 결과는 결정적이에요. 또한 사다리 게임에서 가장 중요한 것은 결과가 제대로 나오는 것인데, 이를 쉽게 테스트할 수 있도록 구조를 만들 것 같아요. 그렇다면 이를 통해, 다음과 같은 클래스를 구현했을 것 같아요. public class Ladder {
private final List<Line> lines = ...
public Ladder(List<Line> lines) {
// 유효성 체크
this.lines = lines;
}
public LadderResult calculateResult() {
// 사다리 게임 로직
}
}
public class LadderResult {
private final Map<Participant, Result> participantToResult;
...
public Result getResult(Participant participant) {
// 유효성 체크
return participantToResult.get(participant);
}
} 이 클래스를 기반으로 TDD로 구현하거나, 아니면 그저 구현해 본 뒤, 결과가 제대로 나오는 것을 확인한 뒤, 다른 요구사항을 구현하지 않았을까 싶네요. |
||
this.participants = participants; | ||
this.results = new ArrayList<>(results); | ||
this.ladder = ladder; | ||
} | ||
|
||
public Participants getParticipants() { | ||
return participants; | ||
} | ||
|
||
public List<String> getResults() { | ||
return new ArrayList<>(results); | ||
} | ||
|
||
public Ladder getLadder() { | ||
return ladder; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ladder.model; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
|
||
public class Ladder { | ||
|
||
private final List<Line> lines; | ||
|
||
private Ladder(List<Line> lines) { | ||
this.lines = lines; | ||
} | ||
|
||
public static Ladder create(int width, int height) { | ||
return new Ladder( | ||
IntStream.range(0, height) | ||
.mapToObj(i -> Line.create(width)) | ||
.collect(Collectors.toList()) | ||
); | ||
} | ||
|
||
public void draw() { | ||
for (Line line : lines) { | ||
line.draw(); | ||
} | ||
} | ||
|
||
public List<Integer> result() { | ||
int width = lines.get(0).getPoints().size() + 1; | ||
return IntStream.range(0, width) | ||
.map(this::getEndPoint) | ||
.boxed() | ||
.collect(Collectors.toList()); | ||
} | ||
Comment on lines
+29
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사다리 게임의 결과를 출력하는 메서드군요! 그런데 결과의
|
||
|
||
private int getEndPoint(int start) { | ||
int position = start; | ||
|
||
for (Line line : lines) { | ||
position = move(position, line.getPoints()); | ||
} | ||
|
||
return position; | ||
} | ||
|
||
private int move(int position, List<Boolean> points) { | ||
if (canMoveLeft(position, points)) { | ||
return position - 1; | ||
} | ||
|
||
if (canMoveRight(position, points)) { | ||
return position + 1; | ||
} | ||
|
||
return position; | ||
} | ||
|
||
private boolean canMoveLeft(int position, List<Boolean> points) { | ||
return position > 0 && points.get(position - 1); | ||
} | ||
|
||
private boolean canMoveRight(int position, List<Boolean> points) { | ||
return position < points.size() && points.get(position); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package ladder.model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Random; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
|
||
public class Line { | ||
|
||
private final List<Boolean> points; | ||
|
||
private Line(List<Boolean> points) { | ||
this.points = points; | ||
} | ||
|
||
public List<Boolean> getPoints() { | ||
return new ArrayList<>(points); | ||
} | ||
|
||
public static Line create(int width) { | ||
Random random = new Random(); | ||
List<Boolean> points = new ArrayList<>(); | ||
return new Line(IntStream.range(0, width - 1) | ||
.mapToObj(i -> shouldConnect(points, i, random)) | ||
.collect(Collectors.toList())); | ||
} | ||
|
||
private static boolean shouldConnect(List<Boolean> points, int index, Random random) { | ||
boolean connection = (index <= 0 || !points.get(index - 1)) && random.nextBoolean(); | ||
points.add(connection); | ||
return connection; | ||
} | ||
Comment on lines
+21
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사다리 미션의 요구사항 중 핵심 중 하나인 연결 여부를 랜덤으로 정하고, 라인이 겹치지 않도록 하는 곳을 구현하는 코드로 보이네요! 다만 이 코드를 보면 한 번에 보고 이해하기 어려워 보여요.
또한 5단계 미션의 요구사항 때문에 Stream을 사용하신 것 같아요. 이 경우 Stream을 사용하는 것 보다, for문을 사용하는게 더 가독성이 좋았지 않았을까 싶네요. 😂 |
||
|
||
public void draw() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line이란 객체에게 사다리 라인을 만드는 책임을 부여했는데요, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사다리 게임은 사용자의 입력이 완료되면(참여자, 결과), 출력하지 않아도 게임의 결과를 알 수 있어요. 콘솔에 출력되는 사다리의 모양은 그저 사람이 결과를 보기 쉽게 알 수 있도록 해주는 문자열에 불과해요. 그렇다면 사다리를 출력하는 로직이 그저 자신의 상태를 View에 전달해서, 이를 출력하도록 하면 되지 않을까요? |
||
for (Boolean point : points) { | ||
System.out.print("|"); | ||
printLine(point); | ||
} | ||
System.out.println("|"); | ||
} | ||
|
||
private void printLine(Boolean connected) { | ||
if (connected) { | ||
System.out.print("-----"); | ||
return; | ||
} | ||
System.out.print(" "); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package ladder.model; | ||
|
||
public class Name { | ||
|
||
private static final int MAX_LENGTH = 5; | ||
private final String name; | ||
|
||
public Name(String name) { | ||
if (name.length() > MAX_LENGTH) { | ||
throw new IllegalArgumentException("이름은 최대 5글자까지 가능합니다."); | ||
} | ||
this.name = name; | ||
} | ||
|
||
public boolean matches(String other) { | ||
return name.equals(other); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package ladder.model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Participants { | ||
|
||
private final List<Name> names; | ||
|
||
private Participants(List<Name> names) { | ||
this.names = names; | ||
} | ||
|
||
public static Participants from(String input) { | ||
return new Participants( | ||
Arrays.stream(input.split(",")) | ||
.map(String::trim) | ||
.map(Name::new) | ||
.collect(Collectors.toList()) | ||
); | ||
} | ||
Comment on lines
+16
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이 경우 입력된 문자열에 대해
이 경우 도메인이 View를 직접적으로 의존하지는 않지만, 간접적으로 의존하는 것 같아요. |
||
|
||
public int size() { | ||
return names.size(); | ||
} | ||
|
||
public List<Name> values() { | ||
return new ArrayList<>(names); | ||
} | ||
Comment on lines
+29
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
그리고 하지만 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package ladder.model; | ||
|
||
public enum ResultType { | ||
ALL("all"), | ||
SINGLE(""); | ||
|
||
private final String value; | ||
|
||
ResultType(String value) { | ||
this.value = value; | ||
} | ||
|
||
public static ResultType from(String input) { | ||
return "all".equals(input) ? ALL : SINGLE; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기존 프로그래밍 요구사항 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package ladder.model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class Results { | ||
|
||
private final Participants participants; | ||
private final List<String> results; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List results 게임 결과는 사용자에게 입력 받은 값을 그대로 출력해주는 역할 그 이외의 것을 하지 않아 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일급 컬렉션은 둘째치고, results가 가지는 이 경우 일급 컬렉션을 만들지 않았다면, |
||
|
||
public Results(Participants participants, List<String> results) { | ||
this.participants = participants; | ||
this.results = results; | ||
} | ||
|
||
public List<String> getAll() { | ||
return new ArrayList<>(results); | ||
} | ||
|
||
public List<Name> getParticipants() { | ||
return participants.values(); | ||
} | ||
|
||
public String getResult(String participant) { | ||
return participants.values().stream() | ||
.filter(name -> name.matches(participant)) | ||
.findFirst() | ||
.map(name -> results.get(participants.values().indexOf(name))) | ||
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 참가자입니다.")); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 enum을 비교할 때,
equals
보다==
을 사용하는 것을 권장해요.이유는 다음과 같은 코드로 변경하고, 어플리케이션을 실행해 보세요.
그리고 결과를 확인하신 뒤, 다음과 같이 변경해 보시고 어플리케이션을 실행해 보세요.