diff --git a/docs/README.md b/docs/README.md index e69de29bb2d..60915dd25bf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,166 @@ +# πŸ’» ν”„λ‘œκ·Έλž¨ λ™μž‘ 방식 + +--- + +#### 1. μ‚¬μš©μžλ‘œλΆ€ν„° `InputView`μ—μ„œ 값을 μž…λ ₯ λ°›κ³  μ΄ˆκΈ°ν™” ν›„, κ²Œμž„μ„ μ‹€ν–‰ν•œλ‹€. +#### 2. `InputView`μ—μ„œ 값을 μž…λ ₯ λ°›λŠ”λ‹€. +#### 3. `Validator`λ₯Ό 톡해 μž…λ ₯값을 κ²€μ¦ν•œλ‹€. +#### 4. μ˜ˆμ™Έ λ°œμƒμ‹œ μž¬μž…λ ₯λ°›λŠ”λ‹€. +#### 5. μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•Šμ„ 경우, `Application`에 값을 λ°˜ν™˜ν•œλ‹€. +#### 6. `BridgeGame`에 ν•΄λ‹Ή 값을 λ„˜κ²¨μ£Όμ–΄ updateν•œλ‹€. +#### 7. update된 `BridgeGame`을 `Application`μ—μ„œ `OutputView`둜 λ„˜κ²¨μ€€λ‹€. +#### 8. ν•΄λ‹Ή 값을 ν™œμš©ν•΄ 좜λ ₯ν•œλ‹€. +#### 9. κ²Œμž„μ΄ μ’…λ£Œλ  λ•Œ κΉŒμ§€ 2~8λ₯Ό λ°˜λ³΅ν•œλ‹€. + + +# 🧰 κΈ°λŠ₯ λͺ©λ‘ + +--- + +### 1. κ²Œμž„ μ‹œμž‘ 문ꡬλ₯Ό 좜λ ₯ν•œλ‹€. - `View`/`InputView` + +### 2. λ‹€λ¦¬μ˜ 길이λ₯Ό 숫자λ₯Ό μž…λ ₯λ°›κ³  μƒμ„±ν•œλ‹€. + - [x] μž…λ ₯받은 숫자(λ¬Έμžμ—΄)을 μ •μˆ˜λ‘œ λ³€ν™˜ν•œλ‹€. - `Domain`/`InputConverter` + - [x] μˆ«μžκ°€ μ•„λ‹Œ μž…λ ₯일 경우(문자, 빈 λ¬Έμžμ—΄) μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€. - `Domain`/`InputValidator` + - [x] 잘λͺ»λœ μž…λ ₯일 경우, μ˜¬λ°”λ₯Έ μž…λ ₯이 될 λ•Œ κΉŒμ§€ μž…λ ₯λ°›λŠ”λ‹€. - from `Application` call `View`/`InputView` + - [x] μž…λ ₯받은 μˆ«μžκ°€ 3 이상 20 μ΄ν•˜μΈμ§€ ν™•μΈν•˜κ³  μ•„λ‹ˆλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€. - `Domain`/`InputValidator` + - [x] 0κ³Ό 1을 닀리 길이만큼 λ¬΄μž‘μœ„λ‘œ μƒμ„±ν•œλ‹€. - `BridgeMaker` from `BridgeRandomNumberGenerator` + - [x] 0인 경우 μ•„λž« 칸인 `D`, 1인 경우 μœ— 칸인 `U`인 닀리 리슀트λ₯Ό λ§Œλ“ λ‹€. - from `Domain`/`Bridge` call `BridgeMaker` +### 3.`U` λ˜λŠ” `D`λ₯Ό μž…λ ₯λ°›μ•„ 이동할 칸을 μ„ νƒν•œλ‹€. `View`/`InputView` + - [x] 정해진 λ¬Έμžκ°€ μ•„λ‹ˆκ±°λ‚˜ μž…λ ₯이 μ—†μœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€. - `Domain`/`InputValidator` + - [x] μ˜ˆμ™Έκ°€ λ°œμƒν•  경우, λ‹€μ‹œ μž…λ ₯받도둝 ν•œλ‹€. - from `Application` call `View`/`InputView` + - [x] 이동 ν›„ 생사여뢀λ₯Ό updateν•œλ‹€ - in `Domain`/`BridgeGame` update `Domain`/`Player` + +### 4. μž…λ ₯ κ²°κ³Όλ₯Ό 좜λ ₯ν•œλ‹€. + - [X] κ±΄λ„ˆμ˜¨ 칸듀은 μ „λΆ€ O둜 좜λ ₯ν•˜κ³  μΉΈ μΌμΉ˜μ—¬λΆ€μ™€ 생사여뢀에 따라 O, Xλ₯Ό 좜λ ₯을 κ²°μ •ν•œλ‹€. - from `Application` call `View`/`OutputView` + +### 5. 생사여뢀λ₯Ό νŒλ³„ ν›„, λ‹€μŒ 행동을 κ²°μ •ν•œλ‹€. + #### 5-1. μ£½μ—ˆμ„ λ•Œ + - [x] κ±΄λ„ˆλ‹€ μ‹€νŒ¨ν•˜λ©΄ μž¬μ‹œμž‘ `R`, μ’…λ£Œ `Q` ν•  수 μžˆλ‹€. `View`/`InputView` + - [x] 정해진 λ¬Έμžκ°€ μ•„λ‹ˆκ±°λ‚˜ μž…λ ₯이 μ—†μœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€ `Domain`/`InputValidator` + - [x] μ˜ˆμ™Έκ°€ λ°œμƒν•  경우, λ‹€μ‹œ μž…λ ₯받도둝 ν•œλ‹€. from `Application` call `View`/`InputView` + - [x] μž¬μ‹œμž‘μ‹œ μ²˜μŒλΆ€ν„° λ‹€μ‹œ μ§„ν–‰ν•œλ‹€. - `Application` + + #### 5-2. μ‚΄μ•˜μ„ λ•Œ +- [x] 끝에 도달할 λ•Œ κΉŒμ§€ 계속 μ§„ν–‰ν•œλ‹€. - `Application` + + +### 6. κ²Œμž„ μ’…λ£Œμ‹œ κ²°κ³Όλ₯Ό 좜λ ₯ν•œλ‹€. `OutputView`/`printResult` + - [x] 졜고 기둝을 좜λ ₯ν•œλ‹€. + - [x] κ²Œμž„ 성곡 μ—¬λΆ€λ₯Ό 좜λ ₯ν•œλ‹€. + - [x] 총 μ‹œλ„ 횟수λ₯Ό 좜λ ₯ν•œλ‹€. + + + + + +# πŸ› οΈ 클래슀 섀계 + +--- + +## BridgeMaker +``` + - Bridgeλ₯Ό λžœλ€ν•œ 길이둜 생성 +``` + +## Constant + +--- + +- ### InputValue +``` + - μ‚¬μš©μž μž…λ ₯κ°’μœΌλ‘œ 이루어진 μƒμˆ˜ 클래슀 +``` + +- ### OutputValue +``` + - 좜λ ₯κ°’μœΌλ‘œ 이루어진 μƒμˆ˜ 클래슀 +``` + + +## Util + +--- + +- ### InputConverter +``` + - μ‚¬μš©μžκ°€ μž…λ ₯ν•œ κ°’(λ¬Έμžμ—΄)을 μ •μˆ˜λ‘œ λ³€ν™˜ν•΄ return + - λ³€ν™˜ λΆˆκ°€μ‹œ μ˜ˆμ™Έλ₯Ό 던짐 +``` + +- ### InputValidator +``` + - μž…λ ₯값에 λŒ€ν•œ 검증 + - μ˜¬λ°”λ₯΄μ§€ μ•Šμ€ μž…λ ₯일 μ‹œ μ˜ˆμ™Έλ₯Ό 던짐 +``` + + +## Model + +--- + +- ### Bridge +``` + - κ²Œμž„μ— μ‚¬μš©λ˜λŠ” 닀리 정보 +``` + +- ### BridgeBlock +``` + - μ‚¬μš©μž 선택 정보λ₯Ό μ—΄κ±°ν˜• μƒμˆ˜λ‘œ μ§€μ •ν•œ enum 클래슀 +``` + +- ### Player +``` + - ν˜„μž¬ μœ„μΉ˜ + - 생사 μ—¬λΆ€ +``` + +- ### BridgeGame +``` + - κ²Œμž„ μƒνƒœ 및 μ œμ–΄μ— κ΄€λ ¨λœ 클래슀 + - 주어진 값에 λŒ€ν•œ 검증 + - 개수λ₯Ό μž…λ ₯λ°›κ³  Bridge λͺ¨λΈ μ΄ˆκΈ°ν™” + - μž…λ ₯값에 따라 μœ μ €μ˜ 생사 μ—¬λΆ€ 및 μœ„μΉ˜ κ²°μ • + - 졜고 기둝을 μ €μž₯ +``` + + +## View + +--- + +- ### InputView +``` + - κ²Œμž„ μ‹œμž‘ 문ꡬ 좜λ ₯ + - μž…λ ₯ 문ꡬ 좜λ ₯ + - μž…λ ₯받은 값을 검증 ν›„ λ°˜ν™˜ +``` +### OutputView +``` + - κ²°κ³Ό 문ꡬ 좜λ ₯ + - update된 정보λ₯Ό κ°€κ³΅ν•˜μ—¬ 좜λ ₯ +``` + + + +# ❗ μ£Όμ˜μ‚¬ν•­ 체크 리슀트 + +--- + +- [x] `Exception`이 μ•„λ‹Œ `IllegalArgumentException`κ³Ό 같이 λͺ…ν™•ν•˜κ²Œ μœ ν˜•μ„ μ²˜λ¦¬ν•˜μ˜€λŠ”κ°€? +- [x] μž…μΆœλ ₯ μš”κ΅¬ 사항을 λͺ¨λ‘ μ§€μΌ°λŠ”κ°€? + - [x] κ²Œμž„ μ‹œμž‘ 문ꡬ + - [x] 길이 μž…λ ₯ 문ꡬ + - [x] μΉΈ μž…λ ₯ 문ꡬ + - [x] μΉΈ μž…λ ₯ ν›„ 닀리 μƒνƒœ + - [x] μ‹€νŒ¨ν–ˆμ„ μ‹œ μž¬μ‹œλ„, μ’…λ£Œ μ—¬λΆ€ + - [x] κ²Œμž„ 성곡 μ—¬λΆ€ 및 μ‹œλ„ 횟수 +- [x] ν•¨μˆ˜(λ˜λŠ” λ©”μ†Œλ“œ)의 길이가 10라인 이내인가? (λΉˆμ€„ 포함) +- [x] ν•¨μˆ˜(λ˜λŠ” λ©”μ†Œλ“œ)의 νŒŒλΌλ―Έν„°κ°€ 3개 μ΄ν•˜μΈκ°€? +- [x] 클래슀 μ œμ•½ 사항듀을 λͺ¨λ‘ μ§€μΌ°λŠ”κ°€? + - [x] `OutuptView`의 λ©”μ†Œλ“œ 이름을 λ³€κ²½ν•˜λ©΄ μ•ˆλœλ‹€. (printMap, printResult) + - [x] `BridgeMaker`의 λ©”μ†Œλ“œμ˜ μ‹œκ·Έλ‹ˆμ²˜(인자, 이름)와 λ°˜ν™˜ νƒ€μž…μ„ λ³€κ²½ν•˜λ©΄ μ•ˆλœλ‹€. + - [x] `BridgeGame`의 λ©”μ†Œλ“œ 이름을 λ³€κ²½ν•˜λ©΄ μ•ˆλœλ‹€. (move, retry) + - [x] `InputView` ν΄λž˜μŠ€μ—μ„œλ§Œ `readLine()`을 μ‚¬μš©ν•œλ‹€. + - [x] `BridgeRandomNumberGenerator`, `BridgeNumberGenerator`의 λ₯Ό μˆ˜μ •ν•˜λ©΄ μ•ˆλœλ‹€. + - [x] `BridgeRandomNumberGenerator`, `BridgeNumberGenerator`의 νŒ¨ν‚€μ§€λ₯Ό μˆ˜μ •ν•˜λ©΄ μ•ˆλœλ‹€. diff --git a/src/main/java/bridge/Application.java b/src/main/java/bridge/Application.java index 5cb72dfd3de..7efd6acfb2d 100644 --- a/src/main/java/bridge/Application.java +++ b/src/main/java/bridge/Application.java @@ -1,8 +1,73 @@ package bridge; +import bridge.Model.BridgeGame; +import bridge.View.InputView; +import bridge.View.OutputView; + + + public class Application { + private static InputView inputView = new InputView(); + private static OutputView outputView = new OutputView(); + + + public static BridgeGame initiateBridgeGame() { + while (true) { + try { + int size = inputView.readBridgeSize(); + + return new BridgeGame(size); + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + } + } + } + + public static void inputMoving(BridgeGame bridgeGame) { + while (true) { + try { + String selection = inputView.readMoving(); + bridgeGame.move(selection); + + return; + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + } + } + } + + public static void inputCommand(BridgeGame bridgeGame) { + while (true) { + try { + String command = inputView.readGameCommand(); + bridgeGame.retry(command); + + return; + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + } + } + } + + public static void run(BridgeGame bridgeGame) { + while (!bridgeGame.isGameOver()) { + inputMoving(bridgeGame); + outputView.printMap(bridgeGame, bridgeGame.getPassedCount()); + bridgeGame.updatePlayer(); + + if (bridgeGame.isPlayerDead()) { + inputCommand(bridgeGame); + } + } + } public static void main(String[] args) { - // TODO: ν”„λ‘œκ·Έλž¨ κ΅¬ν˜„ + inputView.printStartMessage(); + + BridgeGame bridgeGame = initiateBridgeGame(); + + run(bridgeGame); + + outputView.printResult(bridgeGame); } } 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 index 27e9f2cfa7f..07341e08dce 100644 --- a/src/main/java/bridge/BridgeMaker.java +++ b/src/main/java/bridge/BridgeMaker.java @@ -1,10 +1,14 @@ package bridge; +import bridge.Model.BridgeBlock; + +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; + + -/** - * λ‹€λ¦¬μ˜ 길이λ₯Ό μž…λ ₯ λ°›μ•„μ„œ 닀리λ₯Ό μƒμ„±ν•΄μ£ΌλŠ” 역할을 ν•œλ‹€. - */ public class BridgeMaker { private final BridgeNumberGenerator bridgeNumberGenerator; @@ -13,11 +17,24 @@ public BridgeMaker(BridgeNumberGenerator bridgeNumberGenerator) { this.bridgeNumberGenerator = bridgeNumberGenerator; } - /** - * @param size λ‹€λ¦¬μ˜ 길이 - * @return μž…λ ₯받은 길이에 ν•΄λ‹Ήν•˜λŠ” 닀리 λͺ¨μ–‘. μœ„ 칸이면 "U", μ•„λž˜ 칸이면 "D"둜 ν‘œν˜„ν•΄μ•Ό ν•œλ‹€. - */ + public List makeBridge(int size) { - return null; + List bridgeNumbers = generateBridgeNumbers(size); + List bridge = bridgeNumbers.stream() + .map(bridgeNumber -> BridgeBlock.getBlockIdentifier((bridgeNumber))) + .collect(Collectors.toList()); + + return Collections.unmodifiableList(bridge); + } + + private List generateBridgeNumbers(int size) { + List bridgeNumbers = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + int blockNumber = bridgeNumberGenerator.generate(); + bridgeNumbers.add(blockNumber); + } + + return bridgeNumbers; } } diff --git a/src/main/java/bridge/BridgeNumberGenerator.java b/src/main/java/bridge/BridgeNumberGenerator.java index 56187b71d2d..f201d1b1438 100644 --- a/src/main/java/bridge/BridgeNumberGenerator.java +++ b/src/main/java/bridge/BridgeNumberGenerator.java @@ -1,7 +1,8 @@ package bridge; + + @FunctionalInterface public interface BridgeNumberGenerator { - int generate(); } diff --git a/src/main/java/bridge/BridgeRandomNumberGenerator.java b/src/main/java/bridge/BridgeRandomNumberGenerator.java index 4c9cb53e03a..35915c4d98a 100644 --- a/src/main/java/bridge/BridgeRandomNumberGenerator.java +++ b/src/main/java/bridge/BridgeRandomNumberGenerator.java @@ -2,6 +2,8 @@ import camp.nextstep.edu.missionutils.Randoms; + + public class BridgeRandomNumberGenerator implements BridgeNumberGenerator { private static final int RANDOM_LOWER_INCLUSIVE = 0; diff --git a/src/main/java/bridge/Constant/InputValue.java b/src/main/java/bridge/Constant/InputValue.java new file mode 100644 index 00000000000..cc21fe617f7 --- /dev/null +++ b/src/main/java/bridge/Constant/InputValue.java @@ -0,0 +1,10 @@ +package bridge.Constant; + + + +public class InputValue { + public static final String SELECTION_UP = "U"; + public static final String SELECTION_DOWN = "D"; + public static final String COMMAND_RETRY = "R"; + public static final String COMMAND_QUIT = "Q"; +} diff --git a/src/main/java/bridge/Constant/OutputValue.java b/src/main/java/bridge/Constant/OutputValue.java new file mode 100644 index 00000000000..cba86ea61d7 --- /dev/null +++ b/src/main/java/bridge/Constant/OutputValue.java @@ -0,0 +1,12 @@ +package bridge.Constant; + + + +public class OutputValue { + public static final String SEPARATOR = "|"; + public static final String NOT_SELECTION = " "; + public static final String WRONG_SELECTION = " X "; + public static final String RIGHT_SELECTION = " O "; + public static final String SUCCESS = "성곡"; + public static final String FAIL = "μ‹€νŒ¨"; +} 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/Model/Bridge.java b/src/main/java/bridge/Model/Bridge.java new file mode 100644 index 00000000000..31a0b608980 --- /dev/null +++ b/src/main/java/bridge/Model/Bridge.java @@ -0,0 +1,49 @@ +package bridge.Model; + +import bridge.BridgeMaker; +import bridge.BridgeNumberGenerator; +import bridge.BridgeRandomNumberGenerator; + +import java.util.List; + + + +public class Bridge { + private final static int MIN_BRIDGE_SIZE = 3; + private final static int MAX_BRIDGE_SIZE = 20; + private final static String WRONG_RANGE_INPUT = "[ERROR] 닀리 κΈΈμ΄λŠ” %dλΆ€ν„° %d μ‚¬μ΄μ˜ μˆ«μžμ—¬μ•Ό ν•©λ‹ˆλ‹€." + System.lineSeparator(); + + + private final List bridgeStates; + + + public Bridge(int bridgeSize) throws IllegalArgumentException { + try { + validate(bridgeSize); + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + + BridgeNumberGenerator bridgeRandomNumberGenerator = new BridgeRandomNumberGenerator(); + BridgeMaker bridgeMaker = new BridgeMaker(bridgeRandomNumberGenerator); + + bridgeStates = bridgeMaker.makeBridge(bridgeSize); + } + + + public void validate(int bridgeSize) throws IllegalArgumentException { + if (bridgeSize < MIN_BRIDGE_SIZE || MAX_BRIDGE_SIZE < bridgeSize) { + String rangeError = String.format(WRONG_RANGE_INPUT, MIN_BRIDGE_SIZE, MAX_BRIDGE_SIZE); + + throw new IllegalArgumentException(rangeError); + } + } + + public List getBridgeStates() { + return bridgeStates; + } + + public String getBridgeState(int bridgeLocation) { + return bridgeStates.get(bridgeLocation); + } +} diff --git a/src/main/java/bridge/Model/BridgeBlock.java b/src/main/java/bridge/Model/BridgeBlock.java new file mode 100644 index 00000000000..a033bfc79c6 --- /dev/null +++ b/src/main/java/bridge/Model/BridgeBlock.java @@ -0,0 +1,29 @@ +package bridge.Model; + +import java.util.Arrays; + + + +public enum BridgeBlock { + UP("U", 1), + DOWN("D", 0); + + + private final String blockIdentifier; + private final int blockNumber; + + + BridgeBlock(String blockIdentifier, int blockNumber) { + this.blockIdentifier = blockIdentifier; + this.blockNumber = blockNumber; + } + + + public static String getBlockIdentifier(int blockNumber) { + return Arrays.stream(BridgeBlock.values()) + .filter(block -> block.blockNumber == blockNumber) + .findAny() + .get() + .blockIdentifier; + } +} diff --git a/src/main/java/bridge/Model/BridgeGame.java b/src/main/java/bridge/Model/BridgeGame.java new file mode 100644 index 00000000000..285246b5e59 --- /dev/null +++ b/src/main/java/bridge/Model/BridgeGame.java @@ -0,0 +1,105 @@ +package bridge.Model; + +import static bridge.Constant.InputValue.COMMAND_RETRY; + +import java.util.List; + + + +public class BridgeGame { + private final Bridge bridge; + private final Player player; + private int retryCount; + private int maxPassedCount; + + + public BridgeGame(int size) throws IllegalArgumentException { + try { + this.bridge = new Bridge(size); + this.player = new Player(); + this.retryCount = 1; + this.maxPassedCount = 0; + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + } + + + public void move(String playerSelection) { + int nextPlayerLocation = player.getPassedCount(); + String nextBridgeState = bridge.getBridgeState(nextPlayerLocation); + + if (!playerSelection.equals(nextBridgeState)) { + player.die(); + } + } + + public void retry(String command) { + updateMaxPassedCount(); + + if (command.equals(COMMAND_RETRY)) { + player.revive(); + retryCount++; + } + } + + public void updateMaxPassedCount() { + int passedCount = player.getPassedCount(); + + if (maxPassedCount < passedCount) { + maxPassedCount = passedCount; + } + } + + public boolean winGame() { + int playerNextLocation = player.getPassedCount(); + List bridgeStates = bridge.getBridgeStates(); + + if (bridgeStates.size() <= playerNextLocation) { // λ‹€μŒμ— 이동할 곳이 인덱슀λ₯Ό λ²—μ–΄λ‚  경우 끝에 λ„λ‹¬ν•œ 것 + maxPassedCount = playerNextLocation - 1; + + return true; + } + + return false; + } + + public boolean isGameOver() { + if (isPlayerDead() || winGame()) { + return true; + } + + return false; + } + + public boolean isPlayerDead() { + if (player.isAlive()) { + return false; + } + + return true; + } + + public void updatePlayer() { + if (player.isAlive()) { + player.success(); + } + } + + //getter + public List getBridgeStates() { + return bridge.getBridgeStates(); + } + + public int getRetryCount() { + return retryCount; + } + + public int getMaxPassedCount() { + return maxPassedCount; + } + + public int getPassedCount() { + return player.getPassedCount(); + } +} diff --git a/src/main/java/bridge/Model/Player.java b/src/main/java/bridge/Model/Player.java new file mode 100644 index 00000000000..c062b4753f7 --- /dev/null +++ b/src/main/java/bridge/Model/Player.java @@ -0,0 +1,37 @@ +package bridge.Model; + + + +public class Player { + private int passedCount; + private boolean alive; + + + public Player() { + this.passedCount = 0; + this.alive = true; + } + + + public void die() { + alive = false; + } + + public void success() { + passedCount++; + } + + public void revive() { + alive = true; + passedCount = 0; + } + + // getter + public boolean isAlive() { + return alive; + } + + public int getPassedCount() { + return passedCount; + } +} 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/Util/InputConverter.java b/src/main/java/bridge/Util/InputConverter.java new file mode 100644 index 00000000000..1fe2b7de4c9 --- /dev/null +++ b/src/main/java/bridge/Util/InputConverter.java @@ -0,0 +1,15 @@ +package bridge.Util; + + + +public class InputConverter { + public static int convertToInt(String input) throws IllegalArgumentException { + try { + InputValidator.validateNumberInput(input); + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + + return Integer.parseInt(input); + } +} diff --git a/src/main/java/bridge/Util/InputValidator.java b/src/main/java/bridge/Util/InputValidator.java new file mode 100644 index 00000000000..0f04945f114 --- /dev/null +++ b/src/main/java/bridge/Util/InputValidator.java @@ -0,0 +1,50 @@ +package bridge.Util; + +import static bridge.Constant.InputValue.COMMAND_QUIT; +import static bridge.Constant.InputValue.COMMAND_RETRY; +import static bridge.Constant.InputValue.SELECTION_DOWN; +import static bridge.Constant.InputValue.SELECTION_UP; + + + +public class InputValidator { + private static final String ERROR_PREFIX = "[ERROR]"; + private static final String EMPTY_INPUT = ERROR_PREFIX + "빈 λ¬Έμžμž…λ‹ˆλ‹€."; + private static final String WRONG_SIZE_INPUT = ERROR_PREFIX + "숫자만 μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€."; + private static final String WRONG_SELECTION_INPUT = ERROR_PREFIX + "'U' λ˜λŠ” 'D'만 μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€."; + private static final String WRONG_COMMAND_INPUT = ERROR_PREFIX + "μ’…λ£Œλ₯Ό μœ„ν•΄μ„œλŠ” 'Q', μž¬μ‹œμž‘μ„ μœ„ν•΄μ„œλŠ” 'R을 μž…λ ₯ν•΄μ£Όμ„Έμš”."; + + + public static void validateNumberInput(String input) throws IllegalArgumentException { + final String NUMBER_REGEX = "[0-9]+"; + + if (input.isBlank()) { + throw new IllegalArgumentException(EMPTY_INPUT); + } + + if (!input.matches(NUMBER_REGEX)) { + throw new IllegalArgumentException(WRONG_SIZE_INPUT); + } + } + + public static void validateSelectionInput(String input) throws IllegalArgumentException { + if (input.isBlank()) { + throw new IllegalArgumentException(EMPTY_INPUT); + } + + if (!input.equals(SELECTION_UP) && !input.equals(SELECTION_DOWN)) { + throw new IllegalArgumentException(WRONG_SELECTION_INPUT); + } + } + + public static void validateCommandInput(String input) throws IllegalArgumentException { + if (input.isBlank()) { + throw new IllegalArgumentException(EMPTY_INPUT); + } + + if (!input.equals(COMMAND_RETRY) && !input.equals(COMMAND_QUIT)) { + throw new IllegalArgumentException(WRONG_COMMAND_INPUT); + } + } + +} diff --git a/src/main/java/bridge/View/InputView.java b/src/main/java/bridge/View/InputView.java new file mode 100644 index 00000000000..c53c894a0aa --- /dev/null +++ b/src/main/java/bridge/View/InputView.java @@ -0,0 +1,60 @@ +package bridge.View; + +import static camp.nextstep.edu.missionutils.Console.readLine; + +import bridge.Util.InputConverter; +import bridge.Util.InputValidator; + + + +public class InputView { + private static final String START_GAME = "닀리 κ±΄λ„ˆκΈ° κ²Œμž„μ„ μ‹œμž‘ν•©λ‹ˆλ‹€."; + private static final String INPUT_BRIDGE_SIZE = "λ‹€λ¦¬μ˜ 길이λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”."; + private static final String INPUT_SELECTION = "이동할 칸을 μ„ νƒν•΄μ£Όμ„Έμš”. (μœ„: U, μ•„λž˜: D)"; + private static final String INPUT_COMMAND = "κ²Œμž„μ„ λ‹€μ‹œ μ‹œλ„ν• μ§€ μ—¬λΆ€λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”. (μž¬μ‹œλ„: R, μ’…λ£Œ: Q)"; + + + public void printStartMessage() { + System.out.println(START_GAME); + System.out.println(); + } + + public int readBridgeSize() throws IllegalArgumentException { + System.out.println(INPUT_BRIDGE_SIZE); + String input = readLine(); + + try { + int bridgeSize = InputConverter.convertToInt(input); + + return bridgeSize; + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + } + + public String readMoving() throws IllegalArgumentException { + System.out.println(INPUT_SELECTION); + String input = readLine(); + + try { + InputValidator.validateSelectionInput(input); + + return input; + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + } + + public String readGameCommand() throws IllegalArgumentException { + System.out.println(INPUT_COMMAND); + String input = readLine(); + + try { + InputValidator.validateCommandInput(input); + + return input; + } catch (IllegalArgumentException illegalArgumentException) { + throw illegalArgumentException; + } + } +} diff --git a/src/main/java/bridge/View/OutputView.java b/src/main/java/bridge/View/OutputView.java new file mode 100644 index 00000000000..5818db745c0 --- /dev/null +++ b/src/main/java/bridge/View/OutputView.java @@ -0,0 +1,89 @@ +package bridge.View; + +import static bridge.Constant.InputValue.SELECTION_DOWN; +import static bridge.Constant.InputValue.SELECTION_UP; + +import static bridge.Constant.OutputValue.*; + +import bridge.Model.BridgeGame; + +import java.util.List; + + + +public class OutputView { + private static final String RESULT_MESSAGE = "μ΅œμ’… κ²Œμž„ κ²°κ³Ό"; + private static final String BRIDGE_MAP = "[%s]" + System.lineSeparator(); + private static final String IS_SUCCESS = "κ²Œμž„ 성곡 μ—¬λΆ€: %s" + System.lineSeparator(); + private static final String RETRY_COUNT = "총 μ‹œλ„ν•œ 횟수: %d" + System.lineSeparator(); + + + private String getIsPassedStair(String bridgeState, String stair) { + if (bridgeState.equals(stair)) { + return RIGHT_SELECTION; + } + + return NOT_SELECTION; + } + + private String getPassedStair(List bridgeStates, int passedCount, String stair) { + String result = ""; + + for (int bridgeLocation = 0; bridgeLocation < passedCount; bridgeLocation++) { + String bridgeState = bridgeStates.get(bridgeLocation); + + result += getIsPassedStair(bridgeState, stair); + result += SEPARATOR; + } + + return result; + } + + private void printStair(BridgeGame bridgeGame, int passedCount, String stair) { + List bridgeStates = bridgeGame.getBridgeStates(); + String selectedBridgeState = bridgeStates.get(passedCount); + boolean playerDead = bridgeGame.isPlayerDead(); + + String result = getPassedStair(bridgeStates, passedCount, stair) + + getSelectResult(playerDead, selectedBridgeState, stair); + + System.out.printf(BRIDGE_MAP, result); + } + + private String getIsSuccess(boolean playerDead) { + if (playerDead) { + return FAIL; + } + + return SUCCESS; + } + + private String getSelectResult(boolean playerDead, String bridgeState, String stair) { + if (!playerDead && bridgeState.equals(stair)) { + return RIGHT_SELECTION; + } + + if (playerDead && !bridgeState.equals(stair)) { + return WRONG_SELECTION; + } + + return NOT_SELECTION; + } + + public void printMap(BridgeGame bridgeGame, int passedCount) { + printStair(bridgeGame, passedCount, SELECTION_UP); + printStair(bridgeGame, passedCount, SELECTION_DOWN); + System.out.println(); + } + + public void printResult(BridgeGame bridgeGame) { + int maxPassedCount = bridgeGame.getMaxPassedCount(); + + System.out.println(RESULT_MESSAGE); + + printMap(bridgeGame, maxPassedCount); + + System.out.printf(IS_SUCCESS, getIsSuccess(bridgeGame.isPlayerDead())); + System.out.printf(RETRY_COUNT, bridgeGame.getRetryCount()); + } +} diff --git a/src/test/java/bridge/ApplicationTest.java b/src/test/java/bridge/ApplicationTest.java index 1a163ec0a2a..13ba1d376b3 100644 --- a/src/test/java/bridge/ApplicationTest.java +++ b/src/test/java/bridge/ApplicationTest.java @@ -7,6 +7,7 @@ import camp.nextstep.edu.missionutils.test.NsTest; import java.util.List; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class ApplicationTest extends NsTest { @@ -39,6 +40,62 @@ class ApplicationTest extends NsTest { }, 1, 0, 1); } + + @Test + void κΈ°λŠ₯_ν…ŒμŠ€νŠΈ_μ‹€νŒ¨_ν›„_성곡() { + assertRandomNumberInRangeTest(() -> { + run("3", "U", "U", "R", "D", "R", "U", "D", "U"); + assertThat(output()).contains( + "[ O | X ]", + "[ | ]", + "[ ]", + "[ X ]", + "μ΅œμ’… κ²Œμž„ κ²°κ³Ό", + "[ O | | O ]", + "[ | O | ]", + "κ²Œμž„ 성곡 μ—¬λΆ€: 성곡", + "총 μ‹œλ„ν•œ 횟수: 3" + ); + }, 1, 0, 1); + } + @DisplayName("μž¬μ‹œμž‘ μ „ν›„λ‘œ μ„œλ‘œ λ‹€λ₯Έ 값일 경우") + @Test + void κΈ°λŠ₯_ν…ŒμŠ€νŠΈ_μ‹€νŒ¨_ν›„_μ’…λ£Œ_λ‹€λ₯Έκ°’() { + assertRandomNumberInRangeTest(() -> { + run("3", "U", "U", "R", "D", "Q"); + assertThat(output()).containsSubsequence( + "[ O | X ]", + "[ | ]", + "[ ]", + "[ X ]", + "μ΅œμ’… κ²Œμž„ κ²°κ³Ό", + "[ O | X ]", + "[ | ]", + "κ²Œμž„ 성곡 μ—¬λΆ€: μ‹€νŒ¨", + "총 μ‹œλ„ν•œ 횟수: 2" + ); + }, 1, 0, 1); + } + + @DisplayName("μž¬μ‹œμž‘ μ „ν›„λ‘œ μ„œλ‘œ 같은 값일 경우") + @Test + void κΈ°λŠ₯_ν…ŒμŠ€νŠΈ_μ‹€νŒ¨_ν›„_μ’…λ£Œ_같은값() { + assertRandomNumberInRangeTest(() -> { + run("3", "U", "D", "R", "D", "Q"); + assertThat(output()).containsSubsequence( + "[ O | ]", + "[ | X ]", + "[ ]", + "[ X ]", + "μ΅œμ’… κ²Œμž„ κ²°κ³Ό", + "[ O | ]", + "[ | X ]", + "κ²Œμž„ 성곡 μ—¬λΆ€: μ‹€νŒ¨", + "총 μ‹œλ„ν•œ 횟수: 2" + ); + }, 1, 1, 1); + } + @Test void μ˜ˆμ™Έ_ν…ŒμŠ€νŠΈ() { assertSimpleTest(() -> { diff --git a/src/test/java/bridge/Model/BridgeBlockTest.java b/src/test/java/bridge/Model/BridgeBlockTest.java new file mode 100644 index 00000000000..e24340a0291 --- /dev/null +++ b/src/test/java/bridge/Model/BridgeBlockTest.java @@ -0,0 +1,30 @@ +package bridge.Model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static bridge.Constant.InputValue.SELECTION_DOWN; +import static bridge.Constant.InputValue.SELECTION_UP; + +import static org.assertj.core.api.Assertions.assertThat; + + + +class BridgeBlockTest { + private static final int SELECTION_UP_NUMBER = 1; + private static final int SELECTION_DOWN_NUMBER = 0; + + @DisplayName("생성 λ²ˆν˜Έμ— λ”°λ₯Έ μ˜¬λ°”λ₯Έ 문자 λ°˜ν™˜ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈ") + @Nested + class StringReturnTest { + @Test + void λ°˜ν™˜_μ˜¬λ°”λ₯Έ_문자_UP() { + assertThat(BridgeBlock.getBlockIdentifier(SELECTION_UP_NUMBER)).isEqualTo(SELECTION_UP); + } + @Test + void λ°˜ν™˜_μ˜¬λ°”λ₯Έ_문자_DOWN() { + assertThat(BridgeBlock.getBlockIdentifier(SELECTION_DOWN_NUMBER)).isEqualTo(SELECTION_DOWN); + } + } +} \ No newline at end of file diff --git a/src/test/java/bridge/Model/BridgeGameTest.java b/src/test/java/bridge/Model/BridgeGameTest.java new file mode 100644 index 00000000000..1571dc6db61 --- /dev/null +++ b/src/test/java/bridge/Model/BridgeGameTest.java @@ -0,0 +1,28 @@ +package bridge.Model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest; + +import static org.assertj.core.api.Assertions.assertThat; + + + +class BridgeGameTest { + private static final String SELECTION_UP = "U"; + private static final int SELECTION_UP_NUMBER = 1; + private static final String SELECTION_DOWN = "D"; + private static final int SELECTION_DOWN_NUMBER = 0; + @DisplayName("잘λͺ»λœ λ°œνŒμ„ λ°Ÿμ•˜μ„ λ•Œ μ£½λŠ”μ§€ 확인") + @Test + void 잘λͺ»_움직여_사망() { + assertRandomNumberInRangeTest(() -> { + BridgeGame bridgeGame = new BridgeGame(3); + bridgeGame.move(SELECTION_DOWN); + + assertThat(bridgeGame.isPlayerDead()).isTrue(); + }, SELECTION_UP_NUMBER, SELECTION_DOWN_NUMBER, SELECTION_DOWN_NUMBER); + + } +} \ No newline at end of file diff --git a/src/test/java/bridge/Model/BridgeTest.java b/src/test/java/bridge/Model/BridgeTest.java new file mode 100644 index 00000000000..1010d33bc3b --- /dev/null +++ b/src/test/java/bridge/Model/BridgeTest.java @@ -0,0 +1,43 @@ +package bridge.Model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + + + +class BridgeTest { + private static final String ERROR = "[ERROR]"; + private static final int MIN_RANGE = 3; + private static final int MAX_RANGE = 20; + + + @DisplayName("λ²”μœ„ μ™Έμ˜ 숫자 μž…λ ₯ μ‹œ μ˜ˆμ™Έ throw") + @ParameterizedTest + @ValueSource(ints = {1, 2, 55, 101}) + void μ˜ˆμ™Έ_λ²”μœ„λ₯Ό_λ²—μ–΄λ‚œ_숫자(int size) { + assertThatThrownBy(() -> assertThat(new Bridge(size))) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("λ²”μœ„ μ™Έμ˜ 숫자 μž…λ ₯ μ‹œ μ˜ˆμ™Έ 메세지 확인") + @ParameterizedTest + @ValueSource(ints = {1, 2, 55, 101}) + void μ—λŸ¬_λ²”μœ„λ₯Ό_λ²—μ–΄λ‚œ_숫자(int size) { + assertThatThrownBy(() -> assertThat(new Bridge(size))) + .hasMessageContaining(ERROR); + } + + @DisplayName("λ²”μœ„ λ‚΄μ˜ μˆ«μžκ°€ μ˜ˆμ™Έλ₯Ό λ°œμƒν•˜μ§€ μ•ŠλŠ”μ§€ 확인") + @ParameterizedTest + @ValueSource(ints = {MIN_RANGE, 5, MAX_RANGE}) + void μž…λ ₯_λ²”μœ„_λ‚΄μ˜_숫자(int size) { + assertDoesNotThrow(() -> new Bridge(size)); + + } +} \ No newline at end of file diff --git a/src/test/java/bridge/Util/InputConverterTest.java b/src/test/java/bridge/Util/InputConverterTest.java new file mode 100644 index 00000000000..58b0fece9fe --- /dev/null +++ b/src/test/java/bridge/Util/InputConverterTest.java @@ -0,0 +1,42 @@ +package bridge.Util; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + + + +class InputConverterTest { + private static final String ERROR = "[ERROR]"; + + @DisplayName("정상적인 κ°’μ˜ λ¬Έμžμ—΄μ„ μ •μˆ˜λ‘œ λ³€ν™˜ν•˜λŠ”μ§€ 확인") + @ParameterizedTest + @ValueSource(strings = {"12", "1", "5", "4", "10"}) + void λ¬Έμžμ—΄μ„_μ •μˆ˜λ‘œ_λ³€ν™˜(String input) { + int convertedNumber = InputConverter.convertToInt(input); + int expectedNumber = Integer.parseInt(input); + + assertThat(convertedNumber).isEqualTo(expectedNumber); + } + + @DisplayName("잘λͺ»λœ μž…λ ₯값이 μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ”μ§€ 확인") + @ParameterizedTest + @ValueSource(strings = {" ", "", "1a", "1,0"}) + void μ˜ˆμ™Έ_μ •μˆ˜_λ³€ν™˜(String input) { + assertThatThrownBy(() -> + InputConverter.convertToInt((input))) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("잘λͺ»λœ μž…λ ₯값에 λŒ€ν•΄ [Error]λ₯Ό ν¬ν•¨ν•œ μ˜ˆμ™Έ 메세지λ₯Ό λ˜μ§€λŠ”μ§€ 확인") + @ParameterizedTest + @ValueSource(strings = {" ", "", "1a", "1,0"}) + void μ—λŸ¬_μ •μˆ˜_λ³€ν™˜(String input) { + assertThatThrownBy(() -> + InputConverter.convertToInt((input))) + .hasMessageContaining(ERROR); + } +} \ No newline at end of file diff --git a/src/test/java/bridge/Util/InputValidatorTest.java b/src/test/java/bridge/Util/InputValidatorTest.java new file mode 100644 index 00000000000..c6ce7ef7703 --- /dev/null +++ b/src/test/java/bridge/Util/InputValidatorTest.java @@ -0,0 +1,45 @@ +package bridge.Util; + +import bridge.Constant.InputValue; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + + + +class InputValidatorTest { + @DisplayName("잘λͺ»λœ μœ„, μ•„λž˜ μž…λ ₯ μ˜ˆμ™Έ throw") + @ParameterizedTest + @ValueSource(strings = {"aaa", "bb", "d", "u", "", " "}) + void validateSelectionInput(String input) { + assertThatThrownBy(() -> InputValidator.validateSelectionInput(input)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("μ˜¬λ°”λ₯Έ μœ„, μ•„λž˜ μž…λ ₯ 체크") + @ParameterizedTest + @ValueSource(strings = {InputValue.SELECTION_DOWN, InputValue.SELECTION_UP}) + void assignSelectionInput(String input) { + assertDoesNotThrow(() -> InputValidator.validateSelectionInput(input)); + } + + @DisplayName("잘λͺ»λœ μž¬μ‹œμž‘/μ’…λ£Œ λͺ…λ Ήμ–΄ μž…λ ₯ μ˜ˆμ™Έ throw") + @ParameterizedTest + @ValueSource(strings = {"aaa", "bb", "d1", "5", "", " ", "Q3", "3Q"}) + void validateCommandInput(String input) { + assertThatThrownBy(() -> InputValidator.validateCommandInput(input)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("μ˜¬λ°”λ₯Έ μž¬μ‹œμž‘/μ’…λ£Œ λͺ…λ Ήμ–΄ 체크") + @ParameterizedTest + @ValueSource(strings = {InputValue.COMMAND_QUIT, InputValue.COMMAND_RETRY}) + void assignCommandInput(String input) { + assertDoesNotThrow(() -> InputValidator.validateCommandInput(input)); + } +} \ No newline at end of file