Skip to content
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

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
24dcdb9
docs: add function list
lh99j Nov 1, 2023
d3ba943
feat: 게임시작 메세지 출력 기능 구현
lh99j Nov 1, 2023
8b96a54
feat: 사용자의 입력을 가져오는 기능 구현
lh99j Nov 1, 2023
9db15cb
feat: 사용자 입력이 3자리 숫자인지 검증 기능 구현
lh99j Nov 1, 2023
bed346b
test: 사용자 입력이 3자리인지 확인하는 테스트케이스 작성
lh99j Nov 1, 2023
c8e983b
feat: 사용자의 입력이 정수인지 확인하는 기능 구현
lh99j Nov 1, 2023
27dfd09
test: 사용자의 입력이 정수인지 확인하는 테스트케이스 작성
lh99j Nov 1, 2023
71bfffa
feat: 사용자의 입력 중 중복된 수가 있는지 검증 기능 구현
lh99j Nov 1, 2023
96fcfa8
test: 사용자의 입력 중 중복된 수가 있는지 테스트케이스 작성
lh99j Nov 1, 2023
88db398
feat: 사용자의 입력의 각 자리수가 범위에 맞는 수인지 검증 기능 구현
lh99j Nov 1, 2023
64e681c
test: 사용자의 입력의 각 자리수가 범위에 있는지 확인 기능 테스트
lh99j Nov 1, 2023
fb1bf71
refactor: Validator 클래스를 생성하여 메서드 이동
lh99j Nov 1, 2023
df3561d
feat: 컴퓨터 고유의 숫자 정하는 기능 구현
lh99j Nov 1, 2023
0335f41
feat: 사용자 입력 문자열 정수형 리스트로 반환 기능 구현
lh99j Nov 1, 2023
31f0b2d
test: 사용자 입력 문자열 정수형 리스트로 반환 기능 테스트
lh99j Nov 1, 2023
04d84c3
refactor: 사용자 입력 관련 함수들 하나의 함수로 묶어서 호출
lh99j Nov 1, 2023
1a67b7d
feat: 사용자와 컴퓨터의 숫자를 비교하여 반환 기능 구현
lh99j Nov 1, 2023
06c35cd
test: 사용자와 컴퓨터의 숫자를 비교하여 반환 기능 테스트
lh99j Nov 1, 2023
40284f1
feat: 힌트 출력 기능 구현
lh99j Nov 1, 2023
d8c9b9b
feat: 게임 로직 구현
lh99j Nov 1, 2023
696fe2b
feat: 게임 종료/재시작 정하는 기능 구현
lh99j Nov 1, 2023
adc10ec
feat: 사용자의 입력이 1또는 2인지 검증 기능 구현
lh99j Nov 1, 2023
a86cd5f
test: 사용자의 입력이 1또는 2인지 검증 기능 테스트
lh99j Nov 1, 2023
493d521
feat: 전체 로직 구현
lh99j Nov 1, 2023
5bc1d0a
feat: 필요한 프린트문 추가
lh99j Nov 1, 2023
033f252
fix: print -> println
lh99j Nov 1, 2023
7437821
refactor: View 클래스 생성
lh99j Nov 1, 2023
b7183e8
refactor: Controller 클래스 생성
lh99j Nov 1, 2023
0e3a7fe
refactor: Computer 모델 생성
lh99j Nov 1, 2023
68da95d
refactor: BaseBall 모델 생성
lh99j Nov 1, 2023
aa9d923
test: 테스트케이스 수정
lh99j Nov 1, 2023
c838f92
refactor: 게임 초기화 부분 함수로 분리
lh99j Nov 1, 2023
2b5276c
refactor: 게임시작 부분 함수로 분리
lh99j Nov 1, 2023
b1f1f2a
refactor: 게임종료 부분 함수로 분리
lh99j Nov 1, 2023
f9db5ba
refactor: while -> do-while
lh99j Nov 1, 2023
f7777ad
fix: 게임이 한번만 실행되고 바로 종료되는 버그 수정
lh99j Nov 1, 2023
c21e8ac
refactor: Constants 클래스 생성하여 불변값 관리
lh99j Nov 1, 2023
5b2e50b
refactor: InputView의 출력문 분리하여 OutputView로 이동
lh99j Nov 1, 2023
260a06d
refactor: 게임 재시작 부분 함수로 분리
lh99j Nov 1, 2023
c4818ed
refactor: 한 사이클의 게임 로직 함수로 분리
lh99j Nov 1, 2023
1bc2d99
refactor: 안쓰는 import문, 외부 호출 없는 함수 private
lh99j Nov 1, 2023
02398f8
refactor: Exception enum class 생성
lh99j Nov 1, 2023
e450ee3
refactor: 외부 호출 없는 함수 private로 처리
lh99j Nov 1, 2023
c31fe8e
refactor: 함수 분리
lh99j Nov 1, 2023
f9c9379
refactor: 스트라이크, 볼 카운트 올리는 부분 함수로 분리
lh99j Nov 1, 2023
5da3201
refactor: 패키지명 전부 수정(시작 문자 대문자 -> 소문자)
lh99j Nov 1, 2023
61c3c69
fix: 이중 print구문 제거
lh99j Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/README.md
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>
11 changes: 9 additions & 2 deletions src/main/kotlin/baseball/Application.kt
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()
}
55 changes: 55 additions & 0 deletions src/main/kotlin/baseball/controller/GameController.kt
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()
Comment on lines +14 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

게임을 세부분으로 나누어 구현하니까 가독성이 좋은 것 같아요! 배워갈게요!

}

private fun gameInit() {
outputView.printGameStart()
computer.setComputerNumber()
}

private fun gameStart() {
do {
oneCycleGame()
} while (baseBall.gameStatus())
Comment on lines +25 to +27

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do-while문을 사용하니까 코드가 엄청 간경하네요,,, 저도 배워갑니다!!

Copy link
Author

Choose a reason for hiding this comment

The 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()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map의 반환값이 List라 굳이 toList()를 할 필요는 없어 보입니다!

Copy link
Author

Choose a reason for hiding this comment

The 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)
}
}
44 changes: 44 additions & 0 deletions src/main/kotlin/baseball/model/BaseBall.kt
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

Choose a reason for hiding this comment

The 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++
}
24 changes: 24 additions & 0 deletions src/main/kotlin/baseball/model/Computer.kt
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()
}
10 changes: 10 additions & 0 deletions src/main/kotlin/baseball/util/Constants.kt
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 object를 사용하였는데, 클래스와 같은 곳에 배치하니 가독성이 떨어져서 고민이 많았습니다. 근데 다른 패키지로 빼서 표현할 수도 있다는 것은 아는게 적어서 전혀 생각도 못한 방법이었는데...와 정말 좋은 아이디어 인 것 같아요

11 changes: 11 additions & 0 deletions src/main/kotlin/baseball/util/Exception.kt
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
}
35 changes: 35 additions & 0 deletions src/main/kotlin/baseball/util/Validator.kt
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 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 require() 문을 사용하는 것이 더 좋아보여요!

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())
}
}
25 changes: 25 additions & 0 deletions src/main/kotlin/baseball/view/InputView.kt
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()
}
}
32 changes: 32 additions & 0 deletions src/main/kotlin/baseball/view/OutputView.kt
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

볼, 스트라이크, 낫싱 문자열로 Constants 클래스로 관리하면 좋을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗,, 이 부분을 놓쳤네요ㅠㅠ 감사합니다

}

println(result)
}

fun printGameStart() {
println("숫자 야구 게임을 시작합니다.")
}

fun printInputNumberMessage() {
print("숫자를 입력해주세요 : ")
}
}
Loading