위
,아래
두 칸으로 이루어진 다리를 끝까지 건너면 성공하는 게임
다리
를 생성한다.플레이어
가 한칸씩 다리를 건넌다.U
혹은 D
를 입력하여 선택한다.지금 까지 건넌 경로
를 표시한다.R
을 선택하면 처음부터 재시작Q
를 선택하면 실패인 상태로 게임 종료총 시도 횟수
와 결과를 출력다리 건너기 게임을 시작합니다.
다리의 길이를 입력해주세요.
7
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[ ]
이동할 칸을 선택해주세요. (위: U, 아래: D)
D
[ O | ]
[ | O ]
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O | | X ]
[ | O | ]
게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)
R
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[ ]
...
이동할 칸을 선택해주세요. (위: U, 아래: D)
D
[ O | | | O | | O | ]
[ | O | O | | O | | X ]
게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)
R
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[ ]
...
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O | | | O | | O | O ]
[ | O | O | | O | | ]
최종 게임 결과
[ O | | | O | | O | O ]
[ | O | O | | O | | ]
게임 성공 여부: 성공
총 시도한 횟수: 2
InputView
, OutputView
, BridgeGame
, BridgeMaker
, BridgeRandomNumberGenerator
클래스 요구사항에 맞춰 각 클래스 활용하여 프로그램 구현BridgeGame
에서 View
사용하지 않음├── controller
│ └── BridgeGameController.java
├── model
│ ├── Bridge.java
│ ├── BridgeGame.java
│ ├── PlayerPath.java
│ ├── PlayerStatus.java
│ ├── Tile.java
│ └── TryCount.java
├── util
│ ├── Errors.java
│ ├── Rules.java
│ └── Validator.java
├── view
│ ├── InputView.java
│ └── OutputView.java
├── Application.java
├── BridgeMaker.java
├── BridgeNumberGenerator.java
└── BridgeRandomNumberGenerator.java
컨트롤러의 역할을 넘어버린 것 같다..
하지만...
다리 선택 건너기
를 반복해서 호출해야한다.// controller에서 재귀 함수의 형식으로 구현
public void playRound() {
selectTile();
if (isSuccessAndNotVictory()) {
// 재귀 호출
playRound();
}
}
private boolean isSuccessAndNotVictory() {
return (bridgeGame.checkPlayerStatus() != PlayerStatus.COMPLETE_CROSSING_BRIDGE)
&& (bridgeGame.possibleNextStep());
}
public void selectTile() {
String nextStep = inputView.readMoving();
moveBridge(nextStep);
}
public void moveBridge(String nextStep) {
bridgeGame.move(nextStep);
outputView.printMap(bridgeGame.possibleNextStep(), bridgeGame.getPlayerPath());
}
public void playGame() {
playRound();
if (bridgeGame.checkPlayerStatus() != PlayerStatus.COMPLETE_CROSSING_BRIDGE) {
askRetry();
}
}
public void askRetry() {
try {
String retryRorQ = inputView.readGameCommand();
decideRetryOrQuit(retryRorQ);
} catch (IllegalArgumentException illegalArgumentException) {
outputView.printErrorMessage(illegalArgumentException);
askRetry();
}
}
// 3-6. 재시작 선택시 재시작하는 메소드 호출
private void decideRetryOrQuit(String retryRorQ) {
if (bridgeGame.retry(retryRorQ)) {
playGame();
}
}
이상적이라고 생각했던 컨트롤러의 역할은 이런 것이었다.
public void gameResult() {
PlayerStatus playerStatus = bridgeGame.checkPlayerStatus();
int tryCount = bridgeGame.getTryCount();
List<Tile> playerPath = bridgeGame.getPlayerPath();
outputView.printResult(playerStatus, tryCount, playerPath);
}
InputView
는 큰 무리 없이 입력 시 지켜야할 검증 사항과 Console.readLine()
으로 입력 받은 값을 적절한 타입으로 파싱해서 넘겨주는 역할을 부여하였다.OutputView
였다...View에 어떤 값을 전달해줘야 되지?
모양
보다는 모델에서 로직이 끝난 결과
를 전달 받아서 그 결과를 뷰가 어느 정도 판별
하여 페이지의 출력할 수 있도록 하였다.판별
하는 부분이 맞는지 아직 잘 모르겠다...public void printMap(boolean possibleNextStep, List<Tile> playerPath) {
// 윗쪽 타일을 출력
System.out.println(tracePathByTile(possibleNextStep, playerPath, Tile.UP_TILE));
// 아랫쪽 타일을 출력
System.out.println(tracePathByTile(possibleNextStep, playerPath, Tile.DOWN_TILE));
System.out.println();
}
// 위나 아래의 다리를 String으로 그리는 부분
private String tracePathByTile(boolean possibleNextStep, List<Tile> playerPath, Tile bridgeTile) {
StringBuilder tileRecord = new StringBuilder(MAP_PREFIX);
for (int pathIndex = 0; pathIndex < playerPath.size() - 1; pathIndex++) {
tileRecord.append(getStringTile(playerPath.get(pathIndex), bridgeTile));
tileRecord.append(MAP_SEPARATOR);
}
tileRecord.append(getLastTile(possibleNextStep, playerPath.get(playerPath.size() - 1), bridgeTile));
tileRecord.append(MAP_SUFFIX);
return tileRecord.toString();
}
// "O","X"," "인지를 판별하는 부분 (이 부분이 헷갈린다)
private String getStringTile(Tile playerStep, Tile bridgeTile) {
if (playerStep.equals(bridgeTile)) {
return MAP_SUCCESS_STEP;
}
return MAP_NOT_STEP;
}
O
,X
,
를 판별하는 부분이 제일 헷갈렸다.클래스 | 내용 |
BridgeGame | 게임 진행 상황을 관리하는 클래스 |
Bridge | 다리의 Up Down 여부를 List로 갖고 있는 일급 컬렉션 |
PlatyerPath | 플레이어가 지나간 길이 Up Down인지 List로 갖고 있는 일급컬렉션 |
Tile | 다리의 위치가 Up인지 Down인지 값을 나타내는 enum |
TryCount | 게임이 시작되고 시도한 횟수(int)를 관리하는 클래스 |
PlayerStatus | 플레이어의 성공 여부를 값을 나타내는 enum |
고민했던 몇가지..
예외가 발생이 되면 입력을 다시 받는다
였다.while문이나 재귀함수를 쓰면 되겠다.
였다.
검증
처리를 하는 위치는InputView
와 각Model
클래스로 정했다.
//InputView.java 의 입력받는 메소드
public int readBridgeSize() {
System.out.println(ASK_BRIDGE_SIZE);
String input = readString();
// 타입 검증
Validator.validateNumberType(input);
int inputNumber = Integer.parseInt(input);
// 사이즈 검증
Validator.validateBridgeSize(inputNumber);
System.out.println();
return inputNumber;
}
//Bridge.java 의 생성자
public Bridge(int bridgeLength) {
// 사이즈 검증
Validator.validateBridgeSize(bridgeLength);
BridgeRandomNumberGenerator bridgeRandomNumberGenerator = new BridgeRandomNumberGenerator();
BridgeMaker bridgeMaker = new BridgeMaker(bridgeRandomNumberGenerator);
List<String> makeBridge = bridgeMaker.makeBridge(bridgeLength);
bridge = bridgeStringToTile(makeBridge);
}
그렇다면, 이 예외 처리를 어디서 해야될까?
//BridgeGameController.java 에서 다리를 만드는 과정
public void createNewBridge() {
try {
int bridgeLength = inputView.readBridgeSize();
bridgeGame.newBridge(bridgeLength);
} catch (IllegalArgumentException illegalArgumentException) {
// 예외 메세지 출력
outputView.printErrorMessage(illegalArgumentException);
// 다시 해당 메소드 실행
createNewBridge();
}
}
public static void main(String[] args) {
try {
BridgeGameController controller = new BridgeGameController();
controller.run();
} catch (Exception exception) {
// 예측 못한 에러 발생 시 메세지 출력 후 프로그램 종료
OutputView.printUnExpectedErrorMessage(exception);
}
}
private static final String UNEXPECTED_EXCEPTION = "예상치 못한 오류가 발생하여 프로그램 종료합니다.";
public static void printUnExpectedErrorMessage(Exception exception) {
System.out.println(UNEXPECTED_EXCEPTION);
System.out.println(exception.getMessage());
}
Exception
으로 뭉틍그려 처리해놨다.이번 주는 MVC 패턴에 대한 고민을 많이 하였다.
컨트롤러가 해야될 역할, 뷰가 해야될 역할, 검증과 예외처리를 어디서 해야될 지, ...
이 글을 쓰며, 이전의 과제들에 대해서 많이 생각하게 되었다.
2~3주 전과 비교해 지금 실력이 훨씬 향상되었다는 생각이 든다. 이전 과제들의 코드를 보면 정말 내멋대로 코드를 짯다...
피어리뷰에 올리신 코드들을 보면 너무나 잘하는 분들이 많아 위축이 된다.
하지만 이 프리코스라는 과정을 통해서 어떻게 생각해야 되는지, 어떻게 성장해야 되는지... 성장 방향성에 대해서 감을 잡을 수 있는 시간이어서 너무 감사한 마음이 크다.
최종 코딩 테스트에 가게될 지는 모르겠지만, 지금까지 푼 과제들을 다시 수정해보고 다른 분들의 코딩을 보며 배우면서 다시 복기하는 과정을 보낼 예정이다.
그러다 보면 결과와는 상관없이 성장할 수 있을 것이다.
다들 너무 고생많으셨고, 많이 가르침 주셔서 감사하다는 말씀 전해드리고 싶습니다.
잘보고갑니다!
한달간 고생많으셨어요!!