diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..f3bc0b0dc --- /dev/null +++ b/docs/README.md @@ -0,0 +1,113 @@ +# 기능 목록(순서 무관) + +- 난수 생성 기능 +- 힌트 결정(= 난수와 플레이어 입력값 비교) 기능 +- 플레이어 입력 받는 기능 (“숫자를 입력해주세요: “) +- 입력받은 값의 유효성 검사 기능 (플레이어의 입력에 문제가 있는지) +- `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료하는 기능 +- 힌트와 게임 종료 조건 비교 기능 (힌트가 3스트라이크와 같은지 아닌지) +- 게임 재시작 여부 결정 기능(= 사용자에게 1 또는 2를 입력받아 재시작 여부를 결정하는 기능) +- 힌트를 출력하는 기능 +- 게임 종료 멘트 출력 기능 (”3개의 숫자를 모두 맞히셨습니다! 게임 종료”) +- 게임 시작 멘트 출력 기능 (”숫자 야구 게임을 시작합니다.”) + +# 🌱 정리 + + +### 플레이어 + +- 1~9 사이의 숫자로 구성된 서로 다른 세 자리 수로 구성된 수를 시스템에 입력 +- 게임 종료 후, 재시작 여부를 시스템에 입력 + +### 상대방(컴퓨터) + +- 난수 생성 후 저장 +- 시스템으로 받은 값으로 스트라이크, 볼, 낫싱 힌트 결정 + - 저장된 난수와 비교 + - 힌트 결정 +- 힌트를 시스템에 전달 + +### 시스템 + +- 게임 시작 문구 출력 + + `숫자 야구 게임을 시작합니다.` + +- 플레이어의 입력을 받음 + + `숫자를 입력해주세요 : ㅇㅇㅇ` + +- 플레이어의 입력값 유효성 검사 + - 플레이어가 문제없는 값을 입력한 경우, 값을 상대방(컴퓨터)에게 전달 + + (문제가 없는 값 ⇒ 1~9 사이의 숫자로 구성된 서로 다른 세 자리 수) + + - 플레이어가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료 +- 전달받은 힌트 확인 + + if) 힌트 == 3스트라이크 + + - 게임종료 멘트 출력 + + `3개의 숫자를 모두 맞히셨습니다! 게임 종료` + + - 종료할 지, 재시작할 지 사용자에게 입력 받음 + + `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` + + else) 힌트 출력 기능 실행 + +- 힌트 출력 + + ex) `1볼 2스트라이크` + + +# 프로그램 흐름 + + +**시스템)** 게임 시작 출력 + +- `숫자 야구 게임을 시작합니다.` + +**컴퓨터) 난수 생성 후 저장** + +**시스템) 플레이어에게 입력을 받음** + +- `숫자를 입력해주세요 :` + +**플레이어)** 3자리수 입력 + +**시스템)** 입력 값이 유효한 지 검사 + +- 유효하지 않을 경우 ⇒  `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료 +- 유효한 경우 ⇒ 컴퓨터에게 전달 + +**컴퓨터)** 저장된 난수와 비교 후 힌트 결정 (힌트 - 낫싱, 볼, 스트라이크) + +**컴퓨터)** 시스템에게 힌트 전달 + +**시스템)** 전달받은 힌트 확인 + +- if) 힌트 == 3스트라이크 + + - **시스템)** 종료 프로세스 시작 + + - 종료 프로세스 [ + - **시스템)** 게임종료 멘트 출력 + - `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` + - **플레이어)** 1 또는 2 입력 + + if) 1 입력 + + - **[ 컴퓨터) 난수 생성 후 저장 ] 단계**로 돌아감 + + if) 2 입력 + + - 프로그램 종료 + + ] + +- else) + - **시스템)** 전달받은 힌트 출력 + + - **시스템)** **[ 시스템) 플레이어에게 입력을 받음 ] 단계**로 돌아감 diff --git a/src/main/kotlin/baseball/Application.kt b/src/main/kotlin/baseball/Application.kt index 148d75cc3..18951a016 100644 --- a/src/main/kotlin/baseball/Application.kt +++ b/src/main/kotlin/baseball/Application.kt @@ -1,5 +1,11 @@ package baseball +import baseball.controller.System + fun main() { - TODO("프로그램 구현") + val system = System() + system.gameStart() } + + + diff --git a/src/main/kotlin/baseball/controller/System.kt b/src/main/kotlin/baseball/controller/System.kt new file mode 100644 index 000000000..984b6e495 --- /dev/null +++ b/src/main/kotlin/baseball/controller/System.kt @@ -0,0 +1,55 @@ +package baseball.controller + +import baseball.model.Computer +import baseball.util.C.FINISH_CONDITION +import baseball.util.Validator.checkUserInputValid +import baseball.view.GameInputView +import baseball.view.GameOutputView + +class System { + + private var userInputList: List = listOf() + private var userInput: String = "" + private var isFinished = false + private var result: Pair = Pair(0, 0) + private val computer = Computer() + private val gamerOutputView = GameOutputView() + private val gameInputView = GameInputView() + + init { + gamerOutputView.printGameStart() + computer.makeRandomNums() + } + + //게임 실행 함수 + fun gameStart() { + while (!isFinished) { + handleGameStart() + handleGameResult() + if (isGameFinished()) { + handleGameEnd() + } + } + } + + private fun handleGameStart() { + gamerOutputView.printInput().apply { + userInput = gameInputView.getUserInput() + checkUserInputValid(userInput) + userInputList = gameInputView.makeUserInputList(userInput) + } + } + + private fun handleGameResult() { + result = computer.getGameResult(userInputList) + gamerOutputView.printGameResult(result) + } + + private fun handleGameEnd() { + gamerOutputView.printGameEnded() + if (gameInputView.endGame()) isFinished = true + else computer.makeRandomNums() + } + + private fun isGameFinished() = result.first == FINISH_CONDITION +} diff --git a/src/main/kotlin/baseball/model/Ball.kt b/src/main/kotlin/baseball/model/Ball.kt new file mode 100644 index 000000000..403ba94cf --- /dev/null +++ b/src/main/kotlin/baseball/model/Ball.kt @@ -0,0 +1,6 @@ +package baseball.model + +data class Ball( + var strike:Int = 0, + var ball:Int = 0 +) diff --git a/src/main/kotlin/baseball/model/Computer.kt b/src/main/kotlin/baseball/model/Computer.kt new file mode 100644 index 000000000..e8dbec6fb --- /dev/null +++ b/src/main/kotlin/baseball/model/Computer.kt @@ -0,0 +1,30 @@ +package baseball.model + +import baseball.util.C.RANDOM_SIZE +import camp.nextstep.edu.missionutils.Randoms + +data class Computer( + var randomNums: MutableList = mutableListOf() +) { + fun makeRandomNums() { + var temp = "" + randomNums = mutableListOf() + while (randomNums.size < RANDOM_SIZE) { + temp = Randoms.pickNumberInRange(1, 9).toString() + if (!randomNums.contains(temp)) { + randomNums.add(temp) + } + } + } + + //게임 결과를 도출하는 함수 + fun getGameResult(userInputList: List): Pair { + var (strike, ball) = Pair(0, 0) + for (i in userInputList.indices) { + if (userInputList[i] == randomNums[i]) strike++ + else if ((userInputList[i] != randomNums[i]) && randomNums.contains(userInputList[i])) ball++ + } + return Pair(strike, ball) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/baseball/util/C.kt b/src/main/kotlin/baseball/util/C.kt new file mode 100644 index 000000000..fdacbac56 --- /dev/null +++ b/src/main/kotlin/baseball/util/C.kt @@ -0,0 +1,18 @@ +package baseball.util + +object C { + const val GAME_START_MSG = "숫자 야구 게임을 시작합니다." + const val GAME_END_MSG = "3개의 숫자를 모두 맞히셨습니다! 게임 종료" + const val GAME_RESTART_MSG = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요." + const val GET_INPUT_MSG = "숫자를 입력해주세요 : " + + const val STRIKE_STRING = "스트라이크" + const val BALL_STRING = "볼" + const val NOTHING = "낫싱" + + const val RANDOM_SIZE = 3 + const val FINISH_CONDITION = 3 + + const val INPUT_REGEX = "[1-9]{3}" + +} \ No newline at end of file diff --git a/src/main/kotlin/baseball/util/Validator.kt b/src/main/kotlin/baseball/util/Validator.kt new file mode 100644 index 000000000..3a0c22659 --- /dev/null +++ b/src/main/kotlin/baseball/util/Validator.kt @@ -0,0 +1,17 @@ +package baseball.util + +object Validator { + //플레이어의 입력값이 유효한 지 검사하는 함수 + fun checkUserInputValid(userInput: String) { + if (!checkRegexMatch(userInput) || !checkDiffNums(userInput)) throw IllegalArgumentException() + } + + //정규표현식과 일치하는 지 확인하는 함수 + private fun checkRegexMatch(userInput: String): Boolean { + val regex = C.INPUT_REGEX.toRegex() //1-9사이의 숫자로 구성된 세 자릿수 정규표현식 + return regex.matches(userInput) + } + + //중복된 숫자가 없는 지 확인하는 함수 + private fun checkDiffNums(userInput: String): Boolean = (userInput.length == userInput.toSet().size) +} \ No newline at end of file diff --git a/src/main/kotlin/baseball/view/GameInputView.kt b/src/main/kotlin/baseball/view/GameInputView.kt new file mode 100644 index 000000000..a9f790823 --- /dev/null +++ b/src/main/kotlin/baseball/view/GameInputView.kt @@ -0,0 +1,18 @@ +package baseball.view + +import camp.nextstep.edu.missionutils.Console + +class GameInputView { + //플레이어 입력을 받는 함수 + fun getUserInput() = Console.readLine().toString() //플레이어 입력 + //재시작 여부를 받는 함수 + fun endGame(): Boolean { + val userInput = Console.readLine() + return when (userInput) { + "1" -> false //종료 O, 재시작 X + "2" -> true //종료 X , 재시작 O + else -> throw IllegalArgumentException() + } + } + fun makeUserInputList(userInput: String) = userInput.chunked(1) +} \ No newline at end of file diff --git a/src/main/kotlin/baseball/view/GameOutputView.kt b/src/main/kotlin/baseball/view/GameOutputView.kt new file mode 100644 index 000000000..fc283bdfc --- /dev/null +++ b/src/main/kotlin/baseball/view/GameOutputView.kt @@ -0,0 +1,30 @@ +package baseball.view + +import baseball.util.C + +class GameOutputView { + //게임 시작을 출력하는 함수 + fun printGameStart() { + println(C.GAME_START_MSG) + } + fun printInput(){ + print(C.GET_INPUT_MSG) + } + + //게임 결과를 출력하는 함수 + fun printGameResult(result: Pair) { + val (strike, ball) = result + val resultText = when { + strike > 0 && ball == 0 -> "$strike${C.STRIKE_STRING}" + strike == 0 && ball > 0 -> "$ball${C.BALL_STRING}" + strike == 0 && ball == 0 -> C.NOTHING + else -> "$ball${C.BALL_STRING} $strike${C.STRIKE_STRING}" + } + println(resultText) + } + //게임 종료를 출력하는 함수 + fun printGameEnded() { + println(C.GAME_END_MSG) + println(C.GAME_RESTART_MSG) + } +} \ No newline at end of file