
위,아래두 칸으로 이루어진 다리를 끝까지 건너면 성공하는 게임
다리를 생성한다.플레이어가 한칸씩 다리를 건넌다.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주 전과 비교해 지금 실력이 훨씬 향상되었다는 생각이 든다. 이전 과제들의 코드를 보면 정말 내멋대로 코드를 짯다...
피어리뷰에 올리신 코드들을 보면 너무나 잘하는 분들이 많아 위축이 된다.
하지만 이 프리코스라는 과정을 통해서 어떻게 생각해야 되는지, 어떻게 성장해야 되는지... 성장 방향성에 대해서 감을 잡을 수 있는 시간이어서 너무 감사한 마음이 크다.
최종 코딩 테스트에 가게될 지는 모르겠지만, 지금까지 푼 과제들을 다시 수정해보고 다른 분들의 코딩을 보며 배우면서 다시 복기하는 과정을 보낼 예정이다.
그러다 보면 결과와는 상관없이 성장할 수 있을 것이다.
다들 너무 고생많으셨고, 많이 가르침 주셔서 감사하다는 말씀 전해드리고 싶습니다.
잘보고갑니다!
한달간 고생많으셨어요!!