Skip to content

Commit 2347786

Browse files
authored
고생하셨습니다.
🎉 PR 머지 완료! 🎉
1 parent fa13b03 commit 2347786

26 files changed

+810
-0
lines changed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# java-ladder-func-playground
2+
3+
사다리 미션
4+
5+
## 개요
6+
사다리 미션은 간단한 콘솔 애플리케이션으로, 사용자로부터 참여할 사람의 이름과 실행 결과, 최대 사다리 높이를 입력 받습니다.\
7+
그리고 생성된 사다리에 대해 사용자는 참가자의 이름을 입력하여 해당 참가자에 대한 실행 결과를 확인할 수 있고, `all`을 입력하여 전체 결과를 확인할 수 있습니다.
8+
9+
## 프로젝트 구조
10+
```
11+
controller/
12+
- LadderController.java : 전반적인 게임 Flow(입력, 실행, 출력)를 담당하는 클래스
13+
model/
14+
- ladder/
15+
- Connection.java : 사다리 가로 줄의 지점 간 연결을 정의하는 클래스
16+
- Ladder.java : 전체 사다리를 정의하는 클래스
17+
- LadderFactory.java : 사다리 생성을 담당하는 클래스
18+
- Line.java : 사다리의 가로 줄을 정의하는 클래스
19+
- Game.java : 게임 실행을 담당하는 클래스
20+
- GameConfiguration.java : 게임 설정을 정의하는 클래스
21+
- GameConfigurationBuilder.java : 게임 설정 Builder 클래스
22+
- GameResult.java : 게임 결과를 정의하는 클래스
23+
- Participant.java : 각 참가자를 정의하는 클래스
24+
view/
25+
- InputView.java : 사용자 입력 처리 기능 수행
26+
- OutputView.java : 사용자에게 정보 출력 기능 수행
27+
Main.java : Main entrypoint
28+
```

src/main/java/.gitkeep

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.suhan.ladder;
2+
3+
import io.suhan.ladder.controller.LadderController;
4+
5+
public class Main {
6+
public static void main(String[] args) {
7+
LadderController controller = new LadderController();
8+
controller.run();
9+
}
10+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package io.suhan.ladder.controller;
2+
3+
import io.suhan.ladder.model.Game;
4+
import io.suhan.ladder.model.GameConfiguration;
5+
import io.suhan.ladder.model.GameConfigurationBuilder;
6+
import io.suhan.ladder.model.GameResult;
7+
import io.suhan.ladder.model.Outcome;
8+
import io.suhan.ladder.model.Participant;
9+
import io.suhan.ladder.view.InputView;
10+
import io.suhan.ladder.view.OutputView;
11+
import java.util.List;
12+
import java.util.stream.Stream;
13+
14+
public class LadderController {
15+
public void run() {
16+
try {
17+
GameConfiguration configuration = readConfiguration();
18+
Game game = Game.of(configuration);
19+
20+
GameResult result = game.execute();
21+
22+
OutputView.printLadderResult(game);
23+
24+
handleOutcomeQuery(result);
25+
} catch (Exception e) {
26+
System.out.println(e.getMessage());
27+
}
28+
}
29+
30+
private GameConfiguration readConfiguration() {
31+
// method chaining으로 구성하려고 하였으나 Input 검증으로 인해 각각 따로 받음
32+
GameConfigurationBuilder builder = new GameConfigurationBuilder();
33+
34+
List<Participant> participants = InputView.getParticipants().stream().map(Participant::new).toList();
35+
builder.participants(participants);
36+
37+
List<Outcome> outcomes = InputView.getOutcomes().stream().map(Outcome::new).toList();
38+
builder.outcomes(outcomes);
39+
40+
int height = InputView.getLadderHeight();
41+
builder.height(height);
42+
43+
return builder.build();
44+
}
45+
46+
private void handleOutcomeQuery(GameResult result) {
47+
Stream.generate(InputView::getParticipantForResult)
48+
.takeWhile((input) -> !input.equals("all"))
49+
.forEach((input) -> handleSingleQuery(result, input));
50+
51+
OutputView.printGameResult(result);
52+
}
53+
54+
private void handleSingleQuery(GameResult result, String input) {
55+
Participant participant = findParticipantByName(result, input);
56+
57+
if (participant == null) {
58+
System.out.println("존재하지 않는 참가자입니다.");
59+
return;
60+
}
61+
62+
OutputView.printGameResultOf(participant, result);
63+
}
64+
65+
private Participant findParticipantByName(GameResult result, String name) {
66+
return result.results().keySet().stream()
67+
.filter((participant -> participant.name().equals(name)))
68+
.findFirst()
69+
.orElse(null);
70+
}
71+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package io.suhan.ladder.model;
2+
3+
import io.suhan.ladder.model.ladder.Connection;
4+
import io.suhan.ladder.model.ladder.Ladder;
5+
import io.suhan.ladder.model.ladder.LadderFactory;
6+
import io.suhan.ladder.model.ladder.Line;
7+
import io.suhan.ladder.view.OutputView;
8+
import java.util.LinkedHashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Optional;
12+
13+
public class Game {
14+
private final Ladder ladder;
15+
private final GameConfiguration configuration;
16+
17+
private Game(GameConfiguration configuration, Ladder ladder) {
18+
this.configuration = configuration;
19+
this.ladder = ladder;
20+
}
21+
22+
public static Game of(GameConfiguration configuration) {
23+
return new Game(configuration, LadderFactory.createLadder(configuration.width(), configuration.height()));
24+
}
25+
26+
public static Game of(GameConfiguration configuration, Ladder ladder) {
27+
return new Game(configuration, ladder);
28+
}
29+
30+
public GameResult execute() {
31+
List<Participant> participants = configuration.participants();
32+
List<Outcome> outcomes = configuration.outcomes();
33+
Map<Participant, Outcome> result = new LinkedHashMap<>();
34+
35+
for (int start = 0; start < configuration.width(); start++) {
36+
int end = traverse(start);
37+
Participant participant = participants.get(start);
38+
Outcome outcome = outcomes.get(end);
39+
40+
result.put(participant, outcome);
41+
}
42+
43+
return new GameResult(result);
44+
}
45+
46+
private int traverse(int start) {
47+
int col = start;
48+
49+
for (Line line : ladder.lines()) {
50+
col = findNextColumn(line, col);
51+
}
52+
53+
return col;
54+
}
55+
56+
private int findNextColumn(Line line, int col) {
57+
Optional<Connection> connected = line.connections().stream()
58+
.filter((connection) -> connection.left() == col || connection.right() == col)
59+
.findFirst();
60+
61+
return connected
62+
.map((connection) -> getConnectedColumn(connection, col))
63+
.orElse(col);
64+
}
65+
66+
private int getConnectedColumn(Connection connection, int col) {
67+
if (connection.left() == col) {
68+
return connection.right();
69+
}
70+
71+
return connection.left();
72+
}
73+
74+
public Ladder getLadder() {
75+
return ladder;
76+
}
77+
78+
public GameConfiguration getConfiguration() {
79+
return configuration;
80+
}
81+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.suhan.ladder.model;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
public record GameConfiguration(List<Participant> participants, List<Outcome> outcomes, int width, int height) {
7+
@Override
8+
public List<Participant> participants() {
9+
return Collections.unmodifiableList(participants);
10+
}
11+
12+
@Override
13+
public List<Outcome> outcomes() {
14+
return Collections.unmodifiableList(outcomes);
15+
}
16+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package io.suhan.ladder.model;
2+
3+
import java.util.List;
4+
5+
public class GameConfigurationBuilder {
6+
private List<Participant> participants;
7+
private List<Outcome> outcomes;
8+
private int height;
9+
10+
public GameConfigurationBuilder participants(List<Participant> participants) {
11+
if (participants == null) {
12+
throw new IllegalStateException("참가자 목록이 설정되지 않았습니다.");
13+
}
14+
15+
if (participants.isEmpty()) {
16+
throw new IllegalArgumentException("참가자 목록은 비어 있을 수 없습니다.");
17+
}
18+
19+
this.participants = participants;
20+
21+
return this;
22+
}
23+
24+
public GameConfigurationBuilder outcomes(List<Outcome> outcomes) {
25+
if (outcomes == null) {
26+
throw new IllegalStateException("결과 목록이 설정되지 않았습니다.");
27+
}
28+
29+
if (outcomes.size() != participants.size()) {
30+
throw new IllegalArgumentException("참가자의 수와 실행 결과의 수는 같아야 합니다.");
31+
}
32+
33+
this.outcomes = outcomes;
34+
35+
return this;
36+
}
37+
38+
public GameConfigurationBuilder height(int height) {
39+
if (height <= 0) {
40+
throw new IllegalArgumentException("높이는 양수여야 합니다.");
41+
}
42+
43+
this.height = height;
44+
45+
return this;
46+
}
47+
48+
public GameConfiguration build() {
49+
return new GameConfiguration(participants, outcomes, participants.size(), height);
50+
}
51+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.suhan.ladder.model;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
public record GameResult(Map<Participant, Outcome> results) {
7+
@Override
8+
public Map<Participant, Outcome> results() {
9+
return Collections.unmodifiableMap(results);
10+
}
11+
12+
public Outcome getOutcome(Participant participant) {
13+
return results.get(participant);
14+
}
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.suhan.ladder.model;
2+
3+
public record Outcome(String value) {
4+
public Outcome {
5+
if (value.isBlank()) {
6+
throw new IllegalArgumentException("결과는 공백일 수 없습니다.");
7+
}
8+
}
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.suhan.ladder.model;
2+
3+
public record Participant(String name) {
4+
public static final int PARTICIPANT_NAME_MAX_LENGTH = 5;
5+
6+
public Participant {
7+
if (name.length() > PARTICIPANT_NAME_MAX_LENGTH) {
8+
throw new IllegalArgumentException("참가자의 이름은 최대 " + PARTICIPANT_NAME_MAX_LENGTH + "자만 가능합니다.");
9+
}
10+
11+
if (name.isBlank()) {
12+
throw new IllegalArgumentException("참가자의 이름은 공백일 수 없습니다.");
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)