Skip to content

[4,5단계-사다리] 이지윤 미션 제출합니다. #73

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

Merged
merged 15 commits into from
Jun 15, 2025
Merged
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
96 changes: 79 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,53 @@

## 요구사항

- 사다리의 높이와 넓이를 입력받아 생성한다.
- 넓이와 높이는 2 이상 24 이하 여야한다.
- 사다리의 시작 지점과 도착 지점을 출력한다.
- 참여할 사람 이름 (쉼표 기준)
- 이름은 최대 5자까지 가능하다.
- 실행 결과 ex) 꽝, 5000, 꽝, 3000
- 최대 사다리 높이
- 높이는 2 이상 24 이하 여야한다.
- 결과를 볼 사람의 이름
- 참여할 사람을 입력할 시 결과만 출력
```text
결과를 보고 싶은 사람은?
neo

실행 결과
```
- `all`을 입력할 시 전체 출력 후 종료
```text
결과를 보고 싶은 사람은?
all

실행 결과
neo : 꽝
brown : 3000
brie : 꽝
tommy : 5000
```

## 구현 기능

### 플레이어(들)

- 플레이어 이름 목록을 관리한다.
- 각 플레이어는 고유한 이름을 가진다.
- 이름 길이 제약 및 중복 방지를 검증한다.
- 사다리 결과 조회 시 이름으로 식별된다.

### 실행 결과(들)

- 실행 결과 값을 리스트로 관리한다.
- 플레이어 수와 결과 수가 일치하는지 검증한다.
- 결과는 순서가 보장되며, 인덱스를 기준으로 조회된다.

### 사다리 결과 보드

- 사다리 구조와 실행 결과, 플레이어를 매핑하여 결과 보드를 생성한다.
- 플레이어 이름 → 결과값 을 빠르게 조회할 수 있도록 캐싱한다.
- 전체 결과 또는 특정 플레이어 결과를 제공한다.

### 사다리

- 여러 개의 라인을 가지며 전체 사다리 구조를 나타낸다.
Expand Down Expand Up @@ -44,23 +85,44 @@
## 출력 예시

```text
사다리의 넓이는 몇 인가요?
5
참여할 플레이어의 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)
neo,brown,brie,tommy

사다리의 높이는 몇 인가요?
실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)
꽝,5000,꽝,3000

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

실행결과
사다리 결과

neo brown brie tommy
|-----| | |
|-----| |-----|
| | |-----|
| |-----| |
|-----| | |
꽝 5000 꽝 3000

결과를 보고 싶은 사람은?
neo

실행 결과
5000

결과를 보고 싶은 사람은?
brie

실행 결과

결과를 보고 싶은 사람은?
all

|-----| |-----| |
| | | |-----|
|-----| | | |
| |-----| |-----|
|-----| |-----| |
실행 결과
neo : 5000
brown : 꽝
brie : 꽝
tommy : 3000

0 -> 1
1 -> 3
2 -> 2
3 -> 0
4 -> 4
```
9 changes: 9 additions & 0 deletions src/main/java/constants/ReservedWord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package constants;

public final class ReservedWord {

public static final String FINISH_KEYWORD = "all";

private ReservedWord() {
}
}
79 changes: 60 additions & 19 deletions src/main/java/controller/LadderController.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package controller;

import domain.Height;
import domain.Width;
import domain.dto.RequestLadder;
import static constants.ReservedWord.FINISH_KEYWORD;

import domain.dto.RequestLadderGame;
import domain.dto.ResponseLadder;
import domain.dto.ResponseLadderResult;
import domain.ladder.Height;
import domain.ladder.Ladder;
import domain.ladder.LadderFactory;
import domain.ladder.result.LadderResultBoard;
import domain.player.Players;
import domain.runningResult.Results;
import java.util.function.Function;
import java.util.function.Supplier;
import strategy.LineGenerator;
import strategy.PointGenerator;
import strategy.RandomLineGenerator;
Expand All @@ -16,36 +21,72 @@

public class LadderController {

private static final String NOT_FOUND_PLAYER_RETRY_MESSAGE = "존재하지 않는 플레이어입니다. 다시 입력해주세요.";

public void play() {
RequestLadder requestLadder = inputLadderSettings();
Width width = requestLadder.toWidth();
Height height = requestLadder.toHeight();
RequestLadderGame request = inputLadderSettings();
Players players = request.toPlayers();
Height height = request.toHeight();
Results results = request.toResults(players.size());

LineGenerator lineGenerator = createLineGenerator();
LadderFactory factory = new LadderFactory();
Ladder ladder = factory.draw(width, height, lineGenerator);
Ladder ladder = drawLadder(players, height);
LadderResultBoard resultBoard = LadderResultBoard.of(players, ladder, results);

drawLadder(ladder, width);
showGameScreen(players, ladder, results);
showPlayerResult(resultBoard);
}

private RequestLadder inputLadderSettings() {
String width = InputView.inputLadderWidth();
private RequestLadderGame inputLadderSettings() {
String names = InputView.inputPlayerNames();
String results = InputView.inputRunningResult();
String height = InputView.inputLadderHeight();
return new RequestLadder(width, height);
return new RequestLadderGame(names, results, height);
}

private Ladder drawLadder(final Players players, final Height height) {
LineGenerator generator = createLineGenerator();
LadderFactory factory = new LadderFactory();
return factory.draw(players, height, generator);
}

private LineGenerator createLineGenerator() {
PointGenerator pointGenerator = new RandomPointGenerator();
return new RandomLineGenerator(pointGenerator);
}

private void drawLadder(final Ladder ladder, final Width width) {
private void showGameScreen(final Players players, final Ladder ladder, final Results results) {
OutputView.printLadderResultTitle();
OutputView.printPlayerNames(players);
OutputView.drawLadder(ResponseLadder.from(ladder));
OutputView.printResults(results);
}

private void showPlayerResult(final LadderResultBoard board) {
repeatUntilDone(
InputView::inputTargetPlayerName,
name -> {
if (name.equals(FINISH_KEYWORD)) {
OutputView.printAllLadderResult(board);
return true;
}

ResponseLadder responseLadder = ResponseLadder.from(ladder);
OutputView.drawLadder(responseLadder);
if (board.findResultOf(name).isEmpty()) {
System.out.println();
System.out.println(NOT_FOUND_PLAYER_RETRY_MESSAGE);
return false;
}

OutputView.printSingleLadderResult(board, name);
return false;
}
);
}

ResponseLadderResult responseResult = ResponseLadderResult.of(ladder, width);
OutputView.printLadderResult(responseResult);
private void repeatUntilDone(final Supplier<String> inputSupplier, final Function<String, Boolean> handler) {
boolean done = false;
while (!done) {
String input = inputSupplier.get();
done = handler.apply(input);
}
}
}
24 changes: 0 additions & 24 deletions src/main/java/domain/Width.java

This file was deleted.

37 changes: 0 additions & 37 deletions src/main/java/domain/dto/RequestLadder.java

This file was deleted.

70 changes: 70 additions & 0 deletions src/main/java/domain/dto/RequestLadderGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package domain.dto;

import domain.ladder.Height;
import domain.player.Players;
import domain.runningResult.Results;
import java.util.List;
import java.util.stream.Stream;

public record RequestLadderGame(
Copy link
Author

Choose a reason for hiding this comment

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

@Choi-JJunho
RequestLadderGame 하나에 모든 입력값을 한 번에 받고 있는데 이 부분에 대해서는 어떻게 생각하시는 지 궁금합니다!

Choose a reason for hiding this comment

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

구조 자체에는 문제가 없다고 생각합니다! 하지만 현재 방식으로는 값을 잘못입력한 순간이 아니라 세 값을 모두 입력받았을 때 잘못된 입력인것을 알게되는 구조가 될 것 같은데요!
개인적인 생각으로는 각 입력마다 검증을 해주면 사용자가 더 빠르게 예외를 인지할 수 있을 것 같아요

지금은 입력이 다 끝나야 예외를 알 수 있는 구조네요 :)

image

Copy link
Author

Choose a reason for hiding this comment

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

맞아요.. 저도 그 부분이 좀 신경 쓰이더라구요!
다음엔 분리해서 빠르게 알 수 있게 해야겠어요 감사합니다 😆

String playerNames,
String runningResults,
String height
) {

private static final String INPUT_DELIMITER = ",";

public RequestLadderGame {
validateEmptyPlayerNames(playerNames);
validateEmptyResults(runningResults);
validateEmptyHeight(height);
}

private static void validatePlayerCountEqualsResultsCount(final int playerCount, final List<String> results) {
if (playerCount != results.size()) {
throw new IllegalArgumentException("실행 결과 수는 플레이어 수와 동일해야 합니다.");
}
}

private void validateEmptyPlayerNames(final String playerNames) {
if (playerNames == null || playerNames.isBlank()) {
throw new IllegalArgumentException("플레이어들의 이름은 공백이 아니어야 합니다.");
}
}

private void validateEmptyResults(final String results) {
if (results == null || results.isBlank()) {
throw new IllegalArgumentException("실행 결과는 공백이 아니어야 합니다.");
}
}

private void validateEmptyHeight(final String height) {
if (height == null || height.isBlank()) {
throw new IllegalArgumentException("사다리의 높이는 공백이 아니어야 합니다.");
}
}

public Players toPlayers() {
List<String> names = Stream.of(playerNames.split(INPUT_DELIMITER))
.map(String::strip)
.toList();
return Players.from(names);
}

public Height toHeight() {
try {
return new Height(Integer.parseInt(height.strip()));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("사다리의 높이는 숫자여야 합니다.");
}
}

public Results toResults(final int playerCount) {
List<String> results = Stream.of(runningResults.split(INPUT_DELIMITER))
.map(String::strip)
.toList();

validatePlayerCountEqualsResultsCount(playerCount, results);
return Results.from(results);
}
}
20 changes: 0 additions & 20 deletions src/main/java/domain/dto/ResponseLadderResult.java

This file was deleted.

Loading