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

[다리 건너기] 김민겸 미션 제출합니다. #9

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e298f02
docs: 구현 기능 목록 생성
Mingyum-Kim Dec 12, 2023
4ee7441
feat: 커스텀 예외처리를 위한 클래스 생성
Mingyum-Kim Dec 12, 2023
fb08f8b
feat: 콘솔의 입출력을 담당하는 클래스 생성
Mingyum-Kim Dec 12, 2023
cfb112c
feat: 게임 시작 문구를 출력하는 기능 구현
Mingyum-Kim Dec 12, 2023
1b0c027
feat: 무작위 값을 통해 다리를 생성하는 기능 구현
Mingyum-Kim Dec 12, 2023
ae08f39
feat: `다리의 길이를 입력해주세요.` 출력하는 기능 구현
Mingyum-Kim Dec 12, 2023
a617354
feat: 전역으로 사용되는 Vaildator 생성
Mingyum-Kim Dec 12, 2023
9911473
feat: 다리의 길이를 입력받는 기능 구현
Mingyum-Kim Dec 12, 2023
67f1e0b
feat: 플레이어가 이동할 칸을 입력하는 기능 구현
Mingyum-Kim Dec 12, 2023
4717b5e
docs: 구현 기능 목록 수정
Mingyum-Kim Dec 12, 2023
4bec71e
feat: 플레이어가 이동한 결과를 출력하기 위한 DTO 클래스 생성
Mingyum-Kim Dec 12, 2023
6ba9d3a
feat: 플레이어가 다리를 이동하는 기능 구현
Mingyum-Kim Dec 12, 2023
b9867bd
feat: 현재 다리 이동 상태를 출력하는 기능 구현
Mingyum-Kim Dec 12, 2023
6c73a48
feat: 게임을 종료하고 결과를 출력하는 기능 구현
Mingyum-Kim Dec 12, 2023
10d5d91
feat: 게임의 재시도 혹은 종료 여부를 입력하는 기능 구현
Mingyum-Kim Dec 12, 2023
7a1d7cd
feat: 기능 구현 목록 체크 및 게임 실행
Mingyum-Kim Dec 12, 2023
9d0d6bd
feat: 오류 발생 시 다시 입력받는 기능 구현
Mingyum-Kim Dec 12, 2023
d4a55e8
feat: record를 class로 구현
Mingyum-Kim Dec 12, 2023
a1de624
feat: 공백 메시지 추가
Mingyum-Kim Dec 12, 2023
fbac95b
refactor: 처음 시작을 1로 하도록 수정
Mingyum-Kim Dec 12, 2023
5997c44
refactor: 문자열 일치 여부를 equals 메소드를 사용해 구현
Mingyum-Kim Dec 12, 2023
91c8d37
fix: build.gradle의 자바를 11 버전으로 수정
Mingyum-Kim Dec 12, 2023
1c3b05b
refactor: 코드 가독성 향상
Mingyum-Kim Dec 12, 2023
4b79477
refactor: SingleMove 네이밍을 Move로 변경
Mingyum-Kim Dec 12, 2023
75eb1b3
feat: BridgeGame의 Move 함수를 분리
Mingyum-Kim Dec 12, 2023
adcb58d
feat: BridgeGame의 역할을 두 개의 Controller로 분산
Mingyum-Kim Dec 12, 2023
5890c96
fix: 출력 상의 오류 수정
Mingyum-Kim Dec 12, 2023
523cf65
test: BridgeMaker의 Bridge 생성 테스트
Mingyum-Kim Dec 12, 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
50 changes: 50 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 💪 프로젝트 개요

건널 수 있는 다리를 생성하고, 플레이어가 다리를 건너는 게임을 구현한다.

# 📝 구현 기능 목록

### 게임 시작 문구를 출력하는 기능

- [x] `다리 건너기 게임을 시작합니다.`를 출력한다.

### 자동으로 다리를 생성하는 기능

- [x] 다리의 길이를 입력한다.
- [x] `다리의 길이를 입력해주세요.`를 출력한다.
- [x] 다리의 길이를 입력받는다.
- [x] 빈 문자열이 아님을 검증한다.
- [x] 숫자 입력임을 검증한다.
- [x] 3 이상 20이하임을 검증한다.
- [x] 다리를 생성한다.
- [x] 다리의 길이만큼 0과 1 중 무작위 값을 생성한다.
- [x] 0인 경우 아래 칸, 1인 경우 위 칸을 건널 수 있는 칸으로 저장한다.

### 플레이어가 다리를 이동하는 기능

- [x] `이동할 칸을 선택해주세요. (위: U, 아래: D)`를 출력한다.
- [x] 플레이어가 이동할 칸을 입력한다.
- [x] 빈 문자열이 아님을 검증한다.
- [x] U 혹은 D의 입력임을 검증한다.
- [x] 플레이어가 이동한 칸이 이동할 수 있는 칸인지 검사한다.
- [x] 이동할 수 있는 칸을 선택한 경우 O를 표시한다.
- [x] 모든 다리를 이동한 경우 결과를 반환한다.
- [x] 이동할 수 없는 칸을 선택한 경우
- [x] 재시도 혹은 종료 여부를 선택한다.
- [x] 종료를 선택한 경우 결과를 반환한다.

### 게임을 종료하는 기능

- [x] `최종 게임 결과`를 출력한다.
- [x] 최종적으로 만들어진 다리의 상태를 출력한다.
- [x] `게임 성공 여부: 성공`와 같이 게임 성공 여부를 출력한다.
- [x] `총 시도한 횟수: 2`와 같이 총 시도한 횟수를 출력한다.

### 칸 이동에 실패한 경우 재시도 혹은 종료 여부를 선택하는 기능

- [x] `게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)`를 출력한다.
- [x] 플레이어는 재시도 혹은 종료 여부를 입력한다.
- [x] 빈 문자열이 아님을 검증한다.
- [x] R 혹은 Q의 입력임을 검증한다.
- [x] 재시도를 선택한 경우, 처음부터 다시 다리를 이동한다.
- [x] 종료를 선택한 경우, 게임을 종료한다.
36 changes: 35 additions & 1 deletion src/main/java/bridge/Application.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,42 @@
package bridge;

import bridge.controller.BridgeController;
import bridge.controller.BridgeGame;
import bridge.controller.MoveController;
import bridge.domain.BridgeMaker;
import bridge.util.BridgeRandomNumberGenerator;
import bridge.view.InputView;
import bridge.view.OutputView;

public class Application {

public static void main(String[] args) {
// TODO: 프로그램 구현
InputView inputView = new InputView();
BridgeController bridgeController = getBridgeController(inputView);
MoveController moveController = getMoveController(inputView);
BridgeGame bridgeGame = getBridgeGame(bridgeController, moveController);
bridgeGame.run();
}

private static BridgeController getBridgeController(InputView inputView) {
return new BridgeController(
inputView,
new BridgeMaker(new BridgeRandomNumberGenerator())
);
}

private static MoveController getMoveController(InputView inputView) {
return new MoveController(
inputView,
new OutputView()
);
}

private static BridgeGame getBridgeGame(BridgeController bridgeController, MoveController moveController) {
return new BridgeGame(
new OutputView(),
bridgeController,
moveController
);
}
}
23 changes: 0 additions & 23 deletions src/main/java/bridge/BridgeGame.java

This file was deleted.

28 changes: 0 additions & 28 deletions src/main/java/bridge/InputView.java

This file was deleted.

23 changes: 0 additions & 23 deletions src/main/java/bridge/OutputView.java

This file was deleted.

23 changes: 23 additions & 0 deletions src/main/java/bridge/controller/BridgeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package bridge.controller;

import bridge.domain.BridgeMaker;
import bridge.util.RetryExecutor;
import bridge.view.InputView;
import java.util.List;

public class BridgeController {
private final InputView inputView;
private final BridgeMaker bridgeMaker;

public BridgeController(InputView inputView, BridgeMaker bridgeMaker) {
this.inputView = inputView;
this.bridgeMaker = bridgeMaker;
}

public List<String> prepare() {
int bridgeSize = RetryExecutor.retryUntilSuccess(() -> {
return inputView.readBridgeSize();
});
return bridgeMaker.makeBridge(bridgeSize);
}
}
31 changes: 31 additions & 0 deletions src/main/java/bridge/controller/BridgeGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package bridge.controller;

import bridge.controller.dto.MoveResult;
import bridge.view.OutputView;
import java.util.List;

/**
* 다리 건너기 게임을 관리하는 클래스
*/
public class BridgeGame {
private final OutputView outputView;
private final BridgeController bridgeController;
private final MoveController moveController;

public BridgeGame(
OutputView outputView,
BridgeController bridgeController,
MoveController moveController
) {
this.outputView = outputView;
this.bridgeController = bridgeController;
this.moveController = moveController;
this.outputView.printStartMessage();
}

public void run() {
List<String> bridges = bridgeController.prepare();
MoveResult moveResult = moveController.retry(bridges);
outputView.printResult(moveResult);
}
}
80 changes: 80 additions & 0 deletions src/main/java/bridge/controller/MoveController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package bridge.controller;

import bridge.controller.dto.Move;
import bridge.controller.dto.MoveResult;
import bridge.domain.constants.Result;
import bridge.util.RetryExecutor;
import bridge.view.InputView;
import bridge.view.OutputView;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class MoveController {
private final InputView inputView;
private final OutputView outputView;

public MoveController(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

/**
* 사용자가 게임을 다시 시도할 때 사용하는 메서드
*/
public MoveResult retry(List<String> bridges) {
int count = 1;
while (true) {
List<Move> moves = move(bridges);
Optional<MoveResult> moveResult = createMoveResult(moves, count);
if (moveResult.isPresent()) {
return moveResult.get();
}
count++;
}
}

private Optional<MoveResult> createMoveResult(List<Move> moves, int count) {
if (isSucceed(moves)) { // 끝까지 이동에 성공한 경우
return Optional.of(new MoveResult(moves, Result.SUCCESS, count));
}
String retry = RetryExecutor.retryUntilSuccess(inputView::readGameCommand);
if ("Q".equals(retry)) { // 종료
return Optional.of(new MoveResult(moves, Result.FAIL, count));
}
return Optional.empty(); // 재시작
}

private boolean isSucceed(List<Move> result) {
int size = result.size();
return result.get(size - 1).success().equals("O");
}

/**
* 사용자가 칸을 이동할 때 사용하는 메서드
*/
public List<Move> move(List<String> bridges) {
List<Move> moves = new ArrayList<>();
for (String bridge : bridges) {
Move move = createSingleMove(bridge);
moves.add(move);
outputView.printMap(moves);
if (move.success().equals("X")) {
return moves;
}
}
return moves;
}

private Move createSingleMove(String bridge) {
String direction = RetryExecutor.retryUntilSuccess(inputView::readMoving);
if (cannotMove(bridge, direction)) {
return new Move(direction, "X");
}
return new Move(direction, "O");
Comment on lines +72 to +74
Copy link
Author

Choose a reason for hiding this comment

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

컨트롤러에서 뷰 단의 출력까지 책임지고 있는 형태이다.
boolean 등의 변수로 넘긴 다음에 뷰에서 분기하여 O, X를 출력하는 것이 바람직하다

}

private boolean cannotMove(String bridge, String direction) {
return !bridge.equals(direction);
}
}
19 changes: 19 additions & 0 deletions src/main/java/bridge/controller/dto/Move.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package bridge.controller.dto;

public class Move {
private String direction; // U, D
private String success; // O, X

public Move(String direction, String success) {
this.direction = direction;
this.success = success;
}

public String direction() {
return direction;
}

public String success() {
return success;
}
}
28 changes: 28 additions & 0 deletions src/main/java/bridge/controller/dto/MoveResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package bridge.controller.dto;

import bridge.domain.constants.Result;
import java.util.List;

public class MoveResult {
private List<Move> moves;
private Result success;
private int count;

public MoveResult(List<Move> moves, Result success, int count) {
this.moves = moves;
this.success = success;
this.count = count;
}

public List<Move> singleMoves() {
return moves;
}

public Result success() {
return success;
}

public int count() {
return count;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package bridge;
package bridge.domain;

import bridge.util.BridgeNumberGenerator;
import java.util.ArrayList;
import java.util.List;

/**
Expand All @@ -18,6 +20,16 @@ public BridgeMaker(BridgeNumberGenerator bridgeNumberGenerator) {
* @return 입력받은 길이에 해당하는 다리 모양. 위 칸이면 "U", 아래 칸이면 "D"로 표현해야 한다.
*/
public List<String> makeBridge(int size) {
return null;
List<String> result = new ArrayList<>();
for (int i = 0; i < size; i++) {
int number = bridgeNumberGenerator.generate();
if (number == 1) { // 위
result.add("U");
}
if (number == 0) { // 아래
result.add("D");
}
}
return result;
}
}
Loading