-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[코드 리뷰용 PR입니다!] - 재구현 스터디 #247
base: main
Are you sure you want to change the base?
Changes from all commits
24dcdb9
d3ba943
8b96a54
9db15cb
bed346b
c8e983b
27dfd09
71bfffa
96fcfa8
88db398
64e681c
fb1bf71
df3561d
0335f41
31f0b2d
04d84c3
1a67b7d
06c35cd
40284f1
d8c9b9b
696fe2b
adc10ec
a86cd5f
493d521
5bc1d0a
033f252
7437821
b7183e8
0e3a7fe
68da95d
aa9d923
c838f92
2b5276c
b1f1f2a
f9db5ba
f7777ad
c21e8ac
5b2e50b
260a06d
c4818ed
1bc2d99
02398f8
e450ee3
c31fe8e
f9c9379
5da3201
61c3c69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
기존의 1주차 숫자야구 게임을 MVC 패턴을 적용해보며 풀어보는 브랜치입니다. | ||
|
||
MVC가 무엇인지 감 잡기 위해 만든 브랜치이며, 많이 부족하겠지만 편하게 누구든지 리뷰해주시면 감사하겠습니다! | ||
|
||
# 기능목록 | ||
``` | ||
∙ 게임 시작 | ||
◦ 게임시작 문구를 출력한다. | ||
◦ 컴퓨터의 규칙에 맞는 고유의 숫자를 정한다(2). | ||
|
||
∙ 게임 진행 | ||
◦ 사용자는 3자리의 숫자를 입력한다.(3) | ||
▫︎ 사용자의 입력이 3자리가 아니면 예외처리한다(1). | ||
▫︎ 사용자의 입력이 숫자가 아니면 예외처리한다(1). | ||
▫︎ 사용자의 각 자리의 숫자가 1부터 9까지의 숫자가 아닐 시 예외처리한다(1). | ||
▫︎ 사용자의 입력 중 중복된 숫자가 존재하면 예외처리한다(1). | ||
◦ 사용자의 입력과 컴퓨터의 입력을 비교한다. | ||
▫︎ 이 과정에서 같은 수가 같은 자리에 있으면 그 개수만큼 스트라이크를 출력한다. | ||
▫︎ 이 과정에서 같은 수가 다른 자리에 있으면 그 개수만큼 볼을 출력한다. | ||
▫︎ 이 과정에서 같은 수가 전혀 없다면 낫싱을 출력한다. | ||
◦ 게임 종료 여부를 확인한다. | ||
▫︎ 사용자의 숫자와 컴퓨터의 숫자가 정확히 일치하여 3스트라이크라는 문구가 출력되었다면 게임 종료로 넘어간다. | ||
▫︎ 만약 정확하게 일치하지 않았다면 사용자의 입력으로 다시 넘어간다. | ||
|
||
∙ 게임 종료 | ||
◦ 게임 종료 문구를 출력한다. | ||
◦ 사용자는 1 또는 2의 숫자를 입력한다(3). | ||
▫︎ 1을 입력하였을 시 게임을 재시작한다. | ||
▫︎ 2를 입력하였을 시 게임을 종료한다(4). | ||
▫︎ 1 또는 2의 입력이 아닐 시 예외처리한다(1). | ||
|
||
(1) 예외 처리는 IllegalArgumentException을 발생시키며 어플리케이션을 종료한다. | ||
(2) 컴퓨터의 숫자를 정하기 위해서는 camp.nextstep.edu.missionutils.Randoms의 pickNumberInRange()를 활용한다. | ||
(3) 사용자의 입력은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다. | ||
(4) 프로그램 종료 시 System.exit()를 호출하지 않는다. | ||
``` | ||
|
||
<br><br> | ||
|
||
# MVC 적용 | ||
|
||
``` | ||
Model : 데이터 관련 로직 처리 | ||
Controller : Model 과 Controller의 중재자 역할 | ||
View : 사용자에게 보여지는 부분 | ||
``` | ||
|
||
<br><br> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,12 @@ | ||
package baseball | ||
|
||
import baseball.controller.GameController | ||
import baseball.view.InputView | ||
import baseball.view.OutputView | ||
|
||
fun main() { | ||
TODO("프로그램 구현") | ||
} | ||
val inputView = InputView() | ||
val outputView = OutputView() | ||
val gameController = GameController(inputView, outputView) | ||
gameController.run() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package baseball.controller | ||
|
||
import baseball.view.InputView | ||
import baseball.model.BaseBall | ||
import baseball.model.Computer | ||
import baseball.util.Constants.RESTART | ||
import baseball.view.OutputView | ||
|
||
class GameController(private val inputView: InputView, private val outputView: OutputView) { | ||
private val computer = Computer() | ||
private val baseBall = BaseBall() | ||
|
||
fun run() { | ||
gameInit() | ||
gameStart() | ||
gameEnd() | ||
} | ||
|
||
private fun gameInit() { | ||
outputView.printGameStart() | ||
computer.setComputerNumber() | ||
} | ||
|
||
private fun gameStart() { | ||
do { | ||
oneCycleGame() | ||
} while (baseBall.gameStatus()) | ||
Comment on lines
+25
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do-while문을 사용하니까 코드가 엄청 간경하네요,,, 저도 배워갑니다!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아닙니당,,!! 칭찬 감사합니다 ㅎㅎ |
||
} | ||
|
||
private fun gameEnd() { | ||
outputView.printGameEndMessage() | ||
val status = inputView.decideGameStatus() | ||
if (status == RESTART) { | ||
gameReset() | ||
} | ||
} | ||
|
||
private fun gameReset() { | ||
computer.resetComputerNumber() | ||
computer.setComputerNumber() | ||
gameStart() | ||
} | ||
|
||
private fun makeIntList(number: String): List<Int> { | ||
return number.map { it.digitToInt() }.toList() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. map의 반환값이 List라 굳이 toList()를 할 필요는 없어 보입니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수정하겠습니다!! |
||
} | ||
|
||
private fun oneCycleGame() { | ||
outputView.printInputNumberMessage() | ||
val input = inputView.getUserInputList() | ||
val userNumber = makeIntList(input) | ||
baseBall.compareNumber(computer.numberList, userNumber) | ||
outputView.printHint(baseBall) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package baseball.model | ||
|
||
import baseball.util.Constants.GAME_NUMBER_LENGTH | ||
|
||
class BaseBall { | ||
private var _strike = 0 | ||
val strike: Int | ||
get() = _strike | ||
|
||
private var _ball = 0 | ||
val ball: Int | ||
get() = _ball | ||
|
||
|
||
Comment on lines
+5
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. get()에 대해서는 활용법을 잘 몰랐는데 정말 적확한 곳에 사용하신 것 같아요. 잘 배워갑니다 |
||
fun compareNumber(computer: List<Int>, user: List<Int>) { | ||
resetHint() | ||
for (i in user.indices) { | ||
isStrike(computer, user, index = i) | ||
isBall(computer, user, index = i) | ||
} | ||
} | ||
|
||
private fun resetHint() { | ||
_strike = 0 | ||
_ball = 0 | ||
} | ||
|
||
fun gameStatus() = strike != GAME_NUMBER_LENGTH | ||
|
||
private fun isStrike(computer: List<Int>, user: List<Int>, index: Int) { | ||
if (computer[index] == user[index]) { | ||
plusStrikeCount() | ||
} | ||
} | ||
|
||
private fun isBall(computer: List<Int>, user: List<Int>, index: Int) { | ||
if (computer[index] != user[index] && computer.contains(user[index])) { | ||
plusBallCount() | ||
} | ||
} | ||
|
||
private fun plusStrikeCount() = _strike++ | ||
private fun plusBallCount() = _ball++ | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package baseball.model | ||
|
||
import baseball.util.Constants.END_INDEX | ||
import baseball.util.Constants.GAME_NUMBER_LENGTH | ||
import baseball.util.Constants.START_INDEX | ||
import camp.nextstep.edu.missionutils.Randoms | ||
|
||
class Computer { | ||
private var _numberList = mutableListOf<Int>() | ||
val numberList: List<Int> | ||
get() = _numberList | ||
|
||
|
||
fun setComputerNumber() { | ||
while (_numberList.size < GAME_NUMBER_LENGTH) { | ||
val randomNumber = Randoms.pickNumberInRange(START_INDEX, END_INDEX) | ||
if (!_numberList.contains(randomNumber)) { | ||
_numberList.add(randomNumber) | ||
} | ||
} | ||
} | ||
|
||
fun resetComputerNumber() = _numberList.clear() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package baseball.util | ||
|
||
object Constants { | ||
const val RESTART = "1" | ||
const val QUIT = "2" | ||
const val GAME_NUMBER_LENGTH = 3 | ||
const val START_INDEX = 1 | ||
const val END_INDEX = 9 | ||
const val REGEX = "[1-9]{3}" | ||
} | ||
Comment on lines
+3
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 object를 사용하였는데, 클래스와 같은 곳에 배치하니 가독성이 떨어져서 고민이 많았습니다. 근데 다른 패키지로 빼서 표현할 수도 있다는 것은 아는게 적어서 전혀 생각도 못한 방법이었는데...와 정말 좋은 아이디어 인 것 같아요 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package baseball.util | ||
|
||
enum class Exception(private val message: String) { | ||
INVALID_NUMBER_LENGTH("사용자의 입력이 3자리수가 아닙니다."), | ||
INVALID_INTEGER("사용자의 입력이 정수가 아닙니다."), | ||
INVALID_RANGE("사용자의 입력 중 범위를 벗어난 자릿수가 존재합니다."), | ||
INVALID_UNIQUE("사용자의 입력 중 중복된 자릿수가 존재합니다."), | ||
INVALID_GAME_STATUS_NUMBER("사용자의 입력이 1 또는 2가 아닙니다."); | ||
|
||
fun getMessage() = message | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package baseball.util | ||
|
||
import baseball.util.Constants.GAME_NUMBER_LENGTH | ||
import baseball.util.Constants.QUIT | ||
import baseball.util.Constants.REGEX | ||
import baseball.util.Constants.RESTART | ||
import java.lang.IllegalArgumentException | ||
|
||
object Validator { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 전체적으로 |
||
fun validateLength(number: String) { | ||
if (number.length != GAME_NUMBER_LENGTH) throw IllegalArgumentException(Exception.INVALID_NUMBER_LENGTH.getMessage()) | ||
} | ||
|
||
fun validateInteger(number: String) { | ||
number.toIntOrNull() ?: throw IllegalArgumentException(Exception.INVALID_INTEGER.getMessage()) | ||
} | ||
|
||
fun validateRange(number: String) { | ||
val regex = REGEX.toRegex() | ||
if (!regex.matches(number)) throw IllegalArgumentException(Exception.INVALID_RANGE.getMessage()) | ||
} | ||
|
||
fun validateUniqueNumber(number: String) { | ||
val validation = number.toSet() | ||
if (validation.size != GAME_NUMBER_LENGTH) throw IllegalArgumentException(Exception.INVALID_UNIQUE.getMessage()) | ||
} | ||
|
||
fun validateGameStatus(number: String) { | ||
if (number == RESTART || number == QUIT) { | ||
return | ||
} | ||
|
||
throw IllegalArgumentException(Exception.INVALID_GAME_STATUS_NUMBER.getMessage()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package baseball.view | ||
|
||
import baseball.util.Validator | ||
import camp.nextstep.edu.missionutils.Console | ||
|
||
class InputView { | ||
fun decideGameStatus(): String { | ||
val userInput = getUserInput() | ||
Validator.validateGameStatus(userInput) | ||
return userInput | ||
} | ||
|
||
fun getUserInputList(): String { | ||
val userInput = getUserInput() | ||
Validator.validateLength(userInput) | ||
Validator.validateInteger(userInput) | ||
Validator.validateRange(userInput) | ||
Validator.validateUniqueNumber(userInput) | ||
return userInput | ||
} | ||
|
||
private fun getUserInput(): String { | ||
return Console.readLine() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package baseball.view | ||
|
||
import baseball.model.BaseBall | ||
|
||
class OutputView { | ||
fun printGameEndMessage() { | ||
println("3개의 숫자를 모두 맞히셨습니다! 게임 종료") | ||
println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.") | ||
} | ||
|
||
fun printHint(baseBall: BaseBall) { | ||
val strike = baseBall.strike | ||
val ball = baseBall.ball | ||
|
||
val result = when { | ||
strike == 0 && ball == 0 -> "낫싱" | ||
strike > 0 && ball == 0 -> "${strike}스트라이크" | ||
strike == 0 && ball > 0 -> "${ball}볼" | ||
else -> "${ball}볼 ${strike}스트라이크" | ||
Comment on lines
+16
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 볼, 스트라이크, 낫싱 문자열로 Constants 클래스로 관리하면 좋을 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗,, 이 부분을 놓쳤네요ㅠㅠ 감사합니다 |
||
} | ||
|
||
println(result) | ||
} | ||
|
||
fun printGameStart() { | ||
println("숫자 야구 게임을 시작합니다.") | ||
} | ||
|
||
fun printInputNumberMessage() { | ||
print("숫자를 입력해주세요 : ") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
게임을 세부분으로 나누어 구현하니까 가독성이 좋은 것 같아요! 배워갈게요!