diff --git a/docs/README.md b/docs/README.md index e69de29bb2d..0539a1e77ed 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,56 @@ +# 기능 목록 + +## BridgeGameController + - [x] 게임 시작 메서드(gameStart) + +## InputManager +- [x] bridge 길이 반환(makeBridge) +- [x] 게임 성공/실패 여부 반환(isClearMoveBridge) +- [x] 게임 재시작/종료 여부 반환(isRetryGame) + +## InputView +- [x] 길이 입력 에러 발생 시 이 부분에서 다시 시작(readBridgeSize) +- [x] 이동할 칸 입력 에러 발생 시 이 부분에서 다시 시작(readMoving) +- [x] 게임 재시도 여부 입력 에러 발생 시 이 부분에서 다시 시작(readGameCommand) +- [x] bridge 길이 입력(inputBridgeSize) +- [x] 사용자가 이동할 칸 입력(inputBridgeMoveStep) +- [x] 사용자가 게임을 재시도 여부 입력(inputRetryCommand) + +## InputValidator +- [x] bridge 길이 validate(validateBridgeSize) +- [x] bridge 이동 명령어 validate(validateBridgeMoveStep) +- [x] bridge 재시작 명령어 validate(validateBridgeStartCommand) +- [x] bridge 길이 숫자 validate(validateInputNumber) +- [x] 명령어 대문자 영어 validate(validateInputUpperEnglish) + +## BridgeGame +- [x] 칸 이동 성공/실패 반환(move) +- [x] bridge 재시도 여부 반환(retry) +- [x] bridge 길이(단계) 반환(stages) + +## BridgeMaker +- [x] 생성된 bridge 반환(makeBridge) + +## BridgeStatus +- [x] bridge 성공 시 게임화면 추가(successStair) +- [x] bridge 실패 시 게임 화면 추가(failStair) +- [x] bridge 중간 괄호 추가(inputDivision) +- [x] bridge 게임 화면 초기세팅(init) +- [x] bridge 게임 화면 초기화(reset) + +## GameResultManager +- [x] bridge 실패 시 게임화면 출력(printFailBridge) +- [x] bridge 성공 시 게임화면 출력(printSuccessBridge) +- [x] bridge 게임 횟수 증가(upAttemptCount) +- [x] bridge 최종 게임 결과 출력(printGameResult) +- [x] bridge 게임 실패 여부(gameClearFail) + +## OutputView +- [x] 진행 상황 게임 화면 출력(printMap) +- [x] 최종 게임 결과 출력(printResult) + +## 열거형 목록 +- [x] 게임 화면 요소(BridgeWindow) +- [x] 에러 메시지(ErrorMessage) +- [x] 게임 명령어(GameCommand) +- [x] 게임 진행 명령어(GameProgressMessage) \ No newline at end of file diff --git a/src/main/java/bridge/Application.java b/src/main/java/bridge/Application.java index 5cb72dfd3de..960777f3630 100644 --- a/src/main/java/bridge/Application.java +++ b/src/main/java/bridge/Application.java @@ -1,8 +1,11 @@ package bridge; +import bridge.controller.BridgeGameController; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + BridgeGameController bridgeGameController = new BridgeGameController(); + bridgeGameController.gameStart(); } } diff --git a/src/main/java/bridge/BridgeGame.java b/src/main/java/bridge/BridgeGame.java deleted file mode 100644 index 834c1c8362b..00000000000 --- a/src/main/java/bridge/BridgeGame.java +++ /dev/null @@ -1,23 +0,0 @@ -package bridge; - -/** - * 다리 건너기 게임을 관리하는 클래스 - */ -public class BridgeGame { - - /** - * 사용자가 칸을 이동할 때 사용하는 메서드 - *

- * 이동을 위해 필요한 메서드의 반환 타입(return type), 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. - */ - public void move() { - } - - /** - * 사용자가 게임을 다시 시도할 때 사용하는 메서드 - *

- * 재시작을 위해 필요한 메서드의 반환 타입(return type), 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. - */ - public void retry() { - } -} diff --git a/src/main/java/bridge/BridgeMaker.java b/src/main/java/bridge/BridgeMaker.java deleted file mode 100644 index 27e9f2cfa7f..00000000000 --- a/src/main/java/bridge/BridgeMaker.java +++ /dev/null @@ -1,23 +0,0 @@ -package bridge; - -import java.util.List; - -/** - * 다리의 길이를 입력 받아서 다리를 생성해주는 역할을 한다. - */ -public class BridgeMaker { - - private final BridgeNumberGenerator bridgeNumberGenerator; - - public BridgeMaker(BridgeNumberGenerator bridgeNumberGenerator) { - this.bridgeNumberGenerator = bridgeNumberGenerator; - } - - /** - * @param size 다리의 길이 - * @return 입력받은 길이에 해당하는 다리 모양. 위 칸이면 "U", 아래 칸이면 "D"로 표현해야 한다. - */ - public List makeBridge(int size) { - return null; - } -} diff --git a/src/main/java/bridge/InputView.java b/src/main/java/bridge/InputView.java deleted file mode 100644 index c3911c8a8e7..00000000000 --- a/src/main/java/bridge/InputView.java +++ /dev/null @@ -1,28 +0,0 @@ -package bridge; - -/** - * 사용자로부터 입력을 받는 역할을 한다. - */ -public class InputView { - - /** - * 다리의 길이를 입력받는다. - */ - public int readBridgeSize() { - return 0; - } - - /** - * 사용자가 이동할 칸을 입력받는다. - */ - public String readMoving() { - return null; - } - - /** - * 사용자가 게임을 다시 시도할지 종료할지 여부를 입력받는다. - */ - public String readGameCommand() { - return null; - } -} diff --git a/src/main/java/bridge/OutputView.java b/src/main/java/bridge/OutputView.java deleted file mode 100644 index 69a433a6285..00000000000 --- a/src/main/java/bridge/OutputView.java +++ /dev/null @@ -1,23 +0,0 @@ -package bridge; - -/** - * 사용자에게 게임 진행 상황과 결과를 출력하는 역할을 한다. - */ -public class OutputView { - - /** - * 현재까지 이동한 다리의 상태를 정해진 형식에 맞춰 출력한다. - *

- * 출력을 위해 필요한 메서드의 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. - */ - public void printMap() { - } - - /** - * 게임의 최종 결과를 정해진 형식에 맞춰 출력한다. - *

- * 출력을 위해 필요한 메서드의 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. - */ - public void printResult() { - } -} diff --git a/src/main/java/bridge/constant/BridgeWindow.java b/src/main/java/bridge/constant/BridgeWindow.java new file mode 100644 index 00000000000..aaa577b7648 --- /dev/null +++ b/src/main/java/bridge/constant/BridgeWindow.java @@ -0,0 +1,22 @@ +package bridge.constant; + +public enum BridgeWindow { + + START("[ "), + SUCCESS("O"), + FAIL("X"), + DIVISION(" | "), + BLANK(" "), + END(" ]"); + + private final String value; + + BridgeWindow(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/src/main/java/bridge/constant/ErrorMessage.java b/src/main/java/bridge/constant/ErrorMessage.java new file mode 100644 index 00000000000..3765f61e23a --- /dev/null +++ b/src/main/java/bridge/constant/ErrorMessage.java @@ -0,0 +1,19 @@ +package bridge.constant; + +public enum ErrorMessage { + NOT_RANGE("다리의 길이는 %d~%d 사이의 숫자입니다."), + NOT_MOVE_STAGE("이동할 칸은 '%s' 혹은 '%s' 입니다."), + NOT_RETRY_COMMAND("게임을 다시 시도할 명령어는 '%s' 혹은 '%s' 입니다."), + NOT_NUMBER_STRING("숫자로된 문자열이 아닙니다."), + NOT_UPPER_ENGLISH("대문자 영어가 아닙니다."); + + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return "[ERROR]" + message; + } +} diff --git a/src/main/java/bridge/constant/GameCommand.java b/src/main/java/bridge/constant/GameCommand.java new file mode 100644 index 00000000000..2faaf7f64dc --- /dev/null +++ b/src/main/java/bridge/constant/GameCommand.java @@ -0,0 +1,31 @@ +package bridge.constant; + +public enum GameCommand { + + UP_BRIDGE("U"), + DOWN_BRIDGE("D"), + RETRY("R"), + QUIT("Q"); + + private final String command; + + GameCommand(String command) { + this.command = command; + } + + public String getCommand() { + return command; + } + + public static String bridgeStageCase(int num){ + if (num == 0){ + return GameCommand.DOWN_BRIDGE.getCommand(); + } + return GameCommand.UP_BRIDGE.getCommand(); + } + + @Override + public String toString() { + return command; + } +} diff --git a/src/main/java/bridge/constant/GameProgressMessage.java b/src/main/java/bridge/constant/GameProgressMessage.java new file mode 100644 index 00000000000..586d1c7ceaa --- /dev/null +++ b/src/main/java/bridge/constant/GameProgressMessage.java @@ -0,0 +1,25 @@ +package bridge.constant; + +public enum GameProgressMessage { + + START_BRIDGE_GAME("다리 건너기 게임을 시작합니다.\n"), + INPUT_BRIDGE_LENGTH("다리의 길이를 입력해주세요."), + INPUT_MOVE_STAIR("이동할 칸을 선택해주세요. (위: %s, 아래: %s)"), + INPUT_RETRY_GAME("게임을 다시 시도할지 여부를 입력해주세요. (재시도: %s, 종료: %s)"), + BLANK(" "); + + private final String message; + + GameProgressMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/bridge/controller/BridgeGameController.java b/src/main/java/bridge/controller/BridgeGameController.java new file mode 100644 index 00000000000..b8da754b975 --- /dev/null +++ b/src/main/java/bridge/controller/BridgeGameController.java @@ -0,0 +1,28 @@ +package bridge.controller; + +import bridge.model.BridgeGame; +import bridge.constant.GameProgressMessage; + +public class BridgeGameController { + + private final InputManager inputManager; + private final GameResultManager gameResultManager; + public BridgeGameController() { + this.inputManager = new InputManager(); + this.gameResultManager = new GameResultManager(); + } + + public void gameStart(){ + System.out.println(GameProgressMessage.START_BRIDGE_GAME); + BridgeGame bridgeGame = new BridgeGame(inputManager.makeBridge()); + boolean isProceed = true; + while (isProceed) { + gameResultManager.upAttemptCount(); + if (inputManager.isSuccessMoveStage(bridgeGame,gameResultManager)){ + break; + } + isProceed = inputManager.isRetryGame(bridgeGame, gameResultManager); + } + } + +} diff --git a/src/main/java/bridge/controller/GameResultManager.java b/src/main/java/bridge/controller/GameResultManager.java new file mode 100644 index 00000000000..d1a5afa0fb2 --- /dev/null +++ b/src/main/java/bridge/controller/GameResultManager.java @@ -0,0 +1,26 @@ +package bridge.controller; + +public class GameResultManager { + + private static final String GAME_SUCCESS = "성공"; + private static final String GAME_FAIL = "실패"; + private int attemptCount = 0; + private String gameClear = GAME_SUCCESS; + + + public void upAttemptCount(){ + attemptCount++; + } + + public void gameClearFail(){ + gameClear = GAME_FAIL; + } + + public String getGameClear() { + return gameClear; + } + + public int getAttemptCount() { + return attemptCount; + } +} diff --git a/src/main/java/bridge/controller/InputManager.java b/src/main/java/bridge/controller/InputManager.java new file mode 100644 index 00000000000..33a6a8ba21d --- /dev/null +++ b/src/main/java/bridge/controller/InputManager.java @@ -0,0 +1,55 @@ +package bridge.controller; + +import bridge.*; +import bridge.io.view.InputView; +import bridge.io.view.OutputView; +import bridge.model.BridgeGame; +import bridge.model.BridgeMaker; +import bridge.model.BridgeStatus; + +import java.util.List; + +public class InputManager { + + private final InputView inputView; + private final BridgeMaker bridgeMaker; + private final OutputView outputView; + + public InputManager() { + this.inputView = new InputView(); + this.bridgeMaker = new BridgeMaker(new BridgeRandomNumberGenerator()); + this.outputView = new OutputView(); + } + + public List makeBridge(){ + int bridgeSize = inputView.readBridgeSize(); + return bridgeMaker.makeBridge(bridgeSize); + } + + public boolean isSuccessMoveStage(BridgeGame bridgeGame, GameResultManager gameResultManager) { + BridgeStatus bridgeStatus = null; + for (int stage = 0; stage < bridgeGame.stages(); stage++){ + String bridgeMoveStep = inputView.readMoving(); + bridgeStatus = bridgeGame.move(bridgeMoveStep, stage); + outputView.printMap(bridgeStatus); + if (!bridgeStatus.isNextStage()){ + return false; + } + } + outputView.printResult(bridgeStatus, gameResultManager); + return true; + + } + + public boolean isRetryGame(BridgeGame bridgeGame, GameResultManager gameResultManager){ + String command = inputView.readGameCommand(); + BridgeStatus bridgeStatus = bridgeGame.retry(command); + if(bridgeStatus.isNextStage()){ + return true; + } + gameResultManager.gameClearFail(); + outputView.printResult(bridgeStatus ,gameResultManager); + return false; + } + +} diff --git a/src/main/java/bridge/io/InputValidator.java b/src/main/java/bridge/io/InputValidator.java new file mode 100644 index 00000000000..e6e6a621e1b --- /dev/null +++ b/src/main/java/bridge/io/InputValidator.java @@ -0,0 +1,58 @@ +package bridge.io; + +import bridge.constant.ErrorMessage; +import bridge.constant.GameCommand; + +import java.util.Map; + +public class InputValidator { + + private static final int MIN_SIZE = 3; + private static final int MAX_SIZE = 20; + + public void validateBridgeSize(String bridgeSize){ + validateInputNumber(bridgeSize); + int bridgeLength = Integer.parseInt(bridgeSize); + if(bridgeLength < MIN_SIZE || bridgeLength > MAX_SIZE){ + throw new IllegalArgumentException(String.format(ErrorMessage.NOT_RANGE.getMessage(), MIN_SIZE, MAX_SIZE)); + } + } + public void validateBridgeMoveStep(String bridgeMoveStep) { + validateInputUpperEnglish(bridgeMoveStep); + if (!bridgeMoveStep.equals(GameCommand.UP_BRIDGE.getCommand()) && + !bridgeMoveStep.equals(GameCommand.DOWN_BRIDGE.getCommand())){ + throw new IllegalArgumentException(String.format(ErrorMessage.NOT_MOVE_STAGE.getMessage() + , GameCommand.DOWN_BRIDGE, GameCommand.UP_BRIDGE)); + } + } + + public void validateBridgeStartCommand(String gameCommand) { + validateInputUpperEnglish(gameCommand); + if (!gameCommand.equals(GameCommand.RETRY.getCommand()) && + !gameCommand.equals(GameCommand.QUIT.getCommand())){ + throw new IllegalArgumentException(String.format(ErrorMessage.NOT_RETRY_COMMAND.getMessage(), + GameCommand.RETRY, GameCommand.QUIT)); + } + } + + private void validateInputNumber(String number) { + if (!isNumeric(number)) { + throw new IllegalArgumentException(ErrorMessage.NOT_NUMBER_STRING.getMessage()); + } + } + + private boolean isNumeric(String str) { + return str.matches("^[0-9]*$"); // 정규표현식을 사용하여 숫자 여부를 확인 + } + + private void validateInputUpperEnglish(String upperEnglish){ + if(!isUpperEnglish(upperEnglish)){ + throw new IllegalArgumentException(ErrorMessage.NOT_UPPER_ENGLISH.getMessage()); + } + } + + private boolean isUpperEnglish(String str) { + return str.matches("^[A-Z]*$"); + } + +} diff --git a/src/main/java/bridge/io/view/InputView.java b/src/main/java/bridge/io/view/InputView.java new file mode 100644 index 00000000000..b5ef0164a88 --- /dev/null +++ b/src/main/java/bridge/io/view/InputView.java @@ -0,0 +1,84 @@ +package bridge.io.view; + +import bridge.constant.GameCommand; +import bridge.constant.GameProgressMessage; +import bridge.io.InputValidator; +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + + private final InputValidator inputValidator = new InputValidator(); + + /** + * 다리의 길이를 입력받는다. + */ + public int readBridgeSize() { + String input; + do { + input = inputBridgeSize(); + } while (input == null); + + return Integer.parseInt(input); + } + + private String inputBridgeSize() { + System.out.println(GameProgressMessage.INPUT_BRIDGE_LENGTH); + String bridgeSize = Console.readLine(); + System.out.println(GameProgressMessage.BLANK); + try { + inputValidator.validateBridgeSize(bridgeSize); + } catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return null; + } + return bridgeSize; + } + + /** + * 사용자가 이동할 칸을 입력받는다. + */ + public String readMoving(){ + String input; + do{ + input = inputBridgeMoveStep(); + }while (input == null); + return input; + } + + private String inputBridgeMoveStep() { + System.out.println(String.format(GameProgressMessage.INPUT_MOVE_STAIR.toString() + , GameCommand.UP_BRIDGE, GameCommand.DOWN_BRIDGE)); + String bridgeMoveStep = Console.readLine(); + try { + inputValidator.validateBridgeMoveStep(bridgeMoveStep); + } catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return null; + } + return bridgeMoveStep; + } + + /** + * 사용자가 게임을 다시 시도할지 종료할지 여부를 입력받는다. + */ + public String readGameCommand(){ + String input; + do{ + input = inputRetryCommand(); + }while (input == null); + return input; + } + + private String inputRetryCommand() { + System.out.println(String.format(GameProgressMessage.INPUT_RETRY_GAME.toString() + , GameCommand.RETRY, GameCommand.QUIT)); + String retryCommand = Console.readLine(); + try { + inputValidator.validateBridgeStartCommand(retryCommand); + } catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return null; + } + return retryCommand; + } +} diff --git a/src/main/java/bridge/io/view/OutputView.java b/src/main/java/bridge/io/view/OutputView.java new file mode 100644 index 00000000000..5a58c826630 --- /dev/null +++ b/src/main/java/bridge/io/view/OutputView.java @@ -0,0 +1,35 @@ +package bridge.io.view; + +import bridge.controller.GameResultManager; +import bridge.model.BridgeStatus; + +/** + * 사용자에게 게임 진행 상황과 결과를 출력하는 역할을 한다. + */ +public class OutputView { + + private static final String RESULT_GAME_MESSAGE = "최종 게임 결과"; + private static final String WHETHER_GAME_SUCCESS = "게임 성공 여부: "; + private static final String ALL_ATTEMPT_COUNT = "총 시도한 횟수: "; + + /** + * 현재까지 이동한 다리의 상태를 정해진 형식에 맞춰 출력한다. + *

+ * 출력을 위해 필요한 메서드의 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. + */ + public void printMap(BridgeStatus bridgeStatus) { + System.out.println(bridgeStatus); + } + + /** + * 게임의 최종 결과를 정해진 형식에 맞춰 출력한다. + *

+ * 출력을 위해 필요한 메서드의 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. + */ + public void printResult(BridgeStatus bridgeStatus ,GameResultManager gameResult) { + System.out.println(RESULT_GAME_MESSAGE); + printMap(bridgeStatus); + System.out.println(WHETHER_GAME_SUCCESS + gameResult.getGameClear()); + System.out.println(ALL_ATTEMPT_COUNT + gameResult.getAttemptCount()); + } +} diff --git a/src/main/java/bridge/model/BridgeGame.java b/src/main/java/bridge/model/BridgeGame.java new file mode 100644 index 00000000000..151341fadc6 --- /dev/null +++ b/src/main/java/bridge/model/BridgeGame.java @@ -0,0 +1,58 @@ +package bridge.model; + +import bridge.constant.GameCommand; + +import java.util.ArrayList; +import java.util.List; + +/** + * 다리 건너기 게임을 관리하는 클래스 + */ +public class BridgeGame { + + private final List bridge; + private final BridgeStatus bridgeStatus; + + public BridgeGame(List bridge) { + this.bridge = new ArrayList<>(bridge); + this.bridgeStatus = new BridgeStatus(); + } + + /** + * 사용자가 칸을 이동할 때 사용하는 메서드 + *

+ * 이동을 위해 필요한 메서드의 반환 타입(return type), 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. + */ + public BridgeStatus move(String bridgeMoveStep, int stage) { + if(isMoveBridge(bridgeMoveStep, stage)){ + bridgeStatus.successStair(bridgeMoveStep); + return bridgeStatus; + } + bridgeStatus.failStair(bridgeMoveStep); + return bridgeStatus; + } + + public boolean isMoveBridge(String bridgeMoveStep, int stage){ + String floor = bridge.get(stage); + return floor.equals(bridgeMoveStep); + } + + /** + * 사용자가 게임을 다시 시도할 때 사용하는 메서드 + *

+ * 재시작을 위해 필요한 메서드의 반환 타입(return type), 인자(parameter)는 자유롭게 추가하거나 변경할 수 있다. + */ + public BridgeStatus retry(String command) { + if(command.equals(GameCommand.RETRY.getCommand())){ + bridgeStatus.reset(); + return bridgeStatus; + } + bridgeStatus.stopNextStage(); + return bridgeStatus; + } + + public int stages(){ + return bridge.size(); + } + +} diff --git a/src/main/java/bridge/model/BridgeMaker.java b/src/main/java/bridge/model/BridgeMaker.java new file mode 100644 index 00000000000..0626514d579 --- /dev/null +++ b/src/main/java/bridge/model/BridgeMaker.java @@ -0,0 +1,39 @@ +package bridge.model; + +import bridge.BridgeNumberGenerator; +import bridge.constant.GameCommand; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 다리의 길이를 입력 받아서 다리를 생성해주는 역할을 한다. + */ +public class BridgeMaker { + private static final int BRIDGE_UPPER_CASE = 1; + private static final int BRIDGE_LOWER_CASE = 0; + private final BridgeNumberGenerator bridgeNumberGenerator; + + public BridgeMaker(BridgeNumberGenerator bridgeNumberGenerator) { + this.bridgeNumberGenerator = bridgeNumberGenerator; + } + + /** + * @param size 다리의 길이 + * @return 입력받은 길이에 해당하는 다리 모양. 위 칸이면 "U", 아래 칸이면 "D"로 표현해야 한다. + */ + public List makeBridge(int size) { + return IntStream.range(0, size) + .map(i -> bridgeNumberGenerator.generate()) + .filter(this::validateRandomNumber) + .boxed() + .map(GameCommand::bridgeStageCase) + .collect(Collectors.toList()); + } + + private boolean validateRandomNumber(int number){ + return number == BRIDGE_UPPER_CASE || number == BRIDGE_LOWER_CASE; + } + +} diff --git a/src/main/java/bridge/model/BridgeStatus.java b/src/main/java/bridge/model/BridgeStatus.java new file mode 100644 index 00000000000..cb835d55e91 --- /dev/null +++ b/src/main/java/bridge/model/BridgeStatus.java @@ -0,0 +1,89 @@ +package bridge.model; + +import bridge.constant.BridgeWindow; + +import java.util.ArrayList; +import java.util.List; + +public class BridgeStatus { + + private static final int INIT_SIZE = 2; + private static final int LENGTH_ONE = 1; + + private final List upStair = new ArrayList<>(); + private final List downStair = new ArrayList<>(); + private boolean isNextStage; + + public BridgeStatus(){ + init(); + } + + private void init(){ + upStair.add(BridgeWindow.START); + upStair.add(BridgeWindow.END); + downStair.add(BridgeWindow.START); + downStair.add(BridgeWindow.END); + isNextStage = true; + } + + public void reset() { + upStair.clear(); + downStair.clear(); + init(); + } + + public void successStair(String bridgeMoveStep) { + inputDivision(); + if (bridgeMoveStep.equals("U")){ + upStair.add(getInsertMiddle(upStair), BridgeWindow.SUCCESS); + downStair.add(getInsertMiddle(downStair), BridgeWindow.BLANK); + return; + } + upStair.add(getInsertMiddle(upStair), BridgeWindow.BLANK); + downStair.add(getInsertMiddle(downStair) , BridgeWindow.SUCCESS); + } + + public void failStair(String bridgeMoveStep) { + inputDivision(); + if (bridgeMoveStep.equals("U")){ + upStair.add(getInsertMiddle(upStair), BridgeWindow.FAIL); + downStair.add(getInsertMiddle(downStair), BridgeWindow.BLANK); + stopNextStage(); + return; + } + upStair.add(getInsertMiddle(upStair), BridgeWindow.BLANK); + downStair.add(getInsertMiddle(downStair), BridgeWindow.FAIL); + stopNextStage(); + } + + private void inputDivision(){ + if (upStair.size() == INIT_SIZE){ + return; + } + upStair.add(getInsertMiddle(upStair), BridgeWindow.DIVISION); + downStair.add(getInsertMiddle(downStair), BridgeWindow.DIVISION); + } + + private int getInsertMiddle(List stair){ + return stair.size() - LENGTH_ONE; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + upStair.forEach(stringBuilder::append); + stringBuilder.append("\n"); + downStair.forEach(stringBuilder::append); + stringBuilder.append("\n"); + return stringBuilder.toString(); + } + + public boolean isNextStage() { + return isNextStage; + } + + public void stopNextStage() { + isNextStage = false; + } +} + diff --git a/src/test/java/bridge/ApplicationTest.java b/src/test/java/bridge/ApplicationTest.java index 1a163ec0a2a..51b833ff850 100644 --- a/src/test/java/bridge/ApplicationTest.java +++ b/src/test/java/bridge/ApplicationTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.util.Lists.newArrayList; +import bridge.model.BridgeMaker; import camp.nextstep.edu.missionutils.test.NsTest; import java.util.List; import org.junit.jupiter.api.Test; diff --git a/src/test/java/bridge/BridgeTest.java b/src/test/java/bridge/BridgeTest.java new file mode 100644 index 00000000000..45c53deeb5d --- /dev/null +++ b/src/test/java/bridge/BridgeTest.java @@ -0,0 +1,69 @@ +package bridge; + +import bridge.model.BridgeGame; +import bridge.model.BridgeMaker; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +import java.util.List; + +class BridgeTest { + + + @Test + @DisplayName("다리가 'U', 'D' 형태로 랜덤 생성 되었는지 확인한다.") + void makeBridge(){ + //given + BridgeRandomNumberGenerator bridgeRandomNumberGenerator = new BridgeRandomNumberGenerator(); + BridgeMaker bridgeMaker = new BridgeMaker(bridgeRandomNumberGenerator); + + //when + List bridge = bridgeMaker.makeBridge(3); + + //then + assertThat(bridge).contains("U", "D"); + } + + @Test + @DisplayName("이동할 수 있는 칸을 입력했을 때 True를 반환한다.") + void moveBridge(){ + // given + BridgeGame bridgeGame = new BridgeGame(List.of("U", "D", "D")); + + //when + boolean isMove = bridgeGame.move("D", 1); + + //then + assertThat(isMove).isTrue(); + } + + @Test + @DisplayName("생성된 Bridge가 BridgeGame에 저장이 되는지 확인한다.") + void saveBridgeInBridgeGame(){ + //given + BridgeGame bridgeGame = new BridgeGame(List.of("U", "D", "D")); + + //when + int countStage = bridgeGame.stages(); + + //then + assertThat(countStage).isEqualTo(3); + } + + @Test + @DisplayName("재시작/종료 명령어가 R이면 true, Q이면 false를 반환한다.") + void retryCommandIsR(){ + //given + BridgeGame bridgeGame = new BridgeGame(List.of("U", "D", "D")); + + //when + boolean isRetryTrue = bridgeGame.retry("R"); + boolean isRetryFalse = bridgeGame.retry("Q"); + + //then + assertThat(isRetryTrue).isTrue(); + assertThat(isRetryFalse).isFalse(); + + } +} diff --git a/src/test/java/bridge/GameResultTest.java b/src/test/java/bridge/GameResultTest.java new file mode 100644 index 00000000000..5d6695c03a9 --- /dev/null +++ b/src/test/java/bridge/GameResultTest.java @@ -0,0 +1,106 @@ +package bridge; + +import bridge.controller.GameResultManager; +import bridge.model.BridgeStatus; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +class GameResultTest { + + GameResultManager gameResult = new GameResultManager(); + BridgeStatus bridgeStatus = new BridgeStatus(); + + @Test + @DisplayName("게임 시도 횟수가 하나씩 증가하는지 확인한다.") + void upAttemptCount(){ + // given + gameResult.upAttemptCount(); + + //when + int attemptCount = gameResult.getAttemptCount(); + + //then + assertThat(attemptCount).isEqualTo(1); + } + + @Test + @DisplayName("윗 칸을 누르고 실패했을 때 게임 화면이 만들어지는지 확인한다.") + void upStairFail(){ + //given + bridgeStatus.failStair("U"); + + //when + String upStairSuccess = bridgeStatus.toString(); + + //then + assertThat(upStairSuccess).contains("[ X ]\n[ ]\n"); + + } + + @Test + @DisplayName("아랫 칸을 누르고 실패했을 때 게임 화면이 만들어지는지 확인한다.") + void downStairFail(){ + //given + bridgeStatus.failStair("D"); + + //when + String upStairSuccess = bridgeStatus.toString(); + + //then + assertThat(upStairSuccess).contains("[ ]\n[ X ]\n"); + + } + + @Test + @DisplayName("윗 칸을 누르고 성공했을 때 게임 화면이 만들어지는지 확인한다.") + void upStairSuccess(){ + //given + bridgeStatus.successStair("U"); + + //when + String upStairSuccess = bridgeStatus.toString(); + + //then + assertThat(upStairSuccess).contains("[ O ]\n[ ]\n"); + + } + + @Test + @DisplayName("아랫 칸을 누르고 성공했을 때 게임 화면이 만들어지는지 확인한다.") + void downStairSuccess(){ + //given + bridgeStatus.successStair("D"); + + //when + String upStairSuccess = bridgeStatus.toString(); + + //then + assertThat(upStairSuccess).contains("[ ]\n[ O ]\n"); + + } + + @Test + @DisplayName("게임 클리어 실패시 '성공'에서 '실패'로 변하는지 확인한다.") + void gameClearFail(){ + assertThat(gameResult.getGameClear()).isEqualTo("성공"); + + gameResult.gameClearFail(); + + assertThat(gameResult.getGameClear()).isEqualTo("실패"); + } + + @Test + @DisplayName("게임 재시작 시 다리는 초기화된다.") + void gameReset(){ + gameResult.restartGameSet(); + + BridgeStatus bridgeStatus = gameResult.getBridgeStatus(); + + assertThat(bridgeStatus.toString()).isEqualTo("[ ]\n[ ]\n"); + } + + + +} diff --git a/src/test/java/bridge/InputValidateTest.java b/src/test/java/bridge/InputValidateTest.java new file mode 100644 index 00000000000..ab13af7392d --- /dev/null +++ b/src/test/java/bridge/InputValidateTest.java @@ -0,0 +1,56 @@ +package bridge; + +import bridge.io.InputValidator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class InputValidateTest { + + InputValidator inputValidator = new InputValidator(); + + + @Test + @DisplayName("다리의 길이가 3~20사이의 숫자가 아니면 에러가 발생한다.") + void validateBridgeSize(){ + assertThatThrownBy(() -> inputValidator.validateBridgeSize("1")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("다리의 길이가 숫자가 아니면 에러가 발생한다.") + void validateBridgeIsNumber(){ + assertThatThrownBy(() -> inputValidator.validateBridgeSize("ㅁ")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("이동할 칸이 'U' 또는 'D'가 아니면 에러가 발생한다.") + void validateBridgeMoveStep(){ + assertThatThrownBy(() -> inputValidator.validateBridgeMoveStep("Z")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("게임을 다시 시도 입력이 'R', 'Q'가 아니면 에러가 발생한다.") + void validateBridgeRestartCommand(){ + assertThatThrownBy(() -> inputValidator.validateBridgeStartCommand("Z")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("이동할 칸이 대문자 영어가 아니면 에러가 발생한다.") + void validateBridgeMoveStepIsUpperEnglish(){ + assertThatThrownBy(() -> inputValidator.validateBridgeMoveStep("u")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("게임을 다시 시도 입력이 대문자 영어가 아니면 에러가 발생한다.") + void validateBridgeRestartCommandIsUpperEnglish(){ + assertThatThrownBy(() -> inputValidator.validateBridgeStartCommand("r")) + .isInstanceOf(IllegalArgumentException.class); + } + +}