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입니다!] - 재구현 스터디 #248

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fbeb443
docs/README.md 생성
Oct 19, 2023
563d670
Update README.md
getupminaaa Oct 19, 2023
27c0fd4
feat: 사용자 입력 기능 구현
Oct 20, 2023
1087ebe
feat: 플레이어가 입력한 값 검사 기능 구현
Oct 20, 2023
fbcefd2
feat: 플레이어의 잘못된 값 입력 시 예외를 발생하는 기능 구현
Oct 20, 2023
5982e61
feat: 난수를 생성하는 기능 구현
Oct 20, 2023
7031314
feat: 난수와 사용자의 입력값을 비교해 힌트를 결정하는 기능 구현
Oct 20, 2023
a8a0177
Revert "feat: 난수와 사용자의 입력값을 비교해 힌트를 결정하는 기능 구현"
Oct 20, 2023
ffc60cf
feat: 난수와 사용자의 입력값을 비교해 힌트를 결정하는 기능 구현
Oct 20, 2023
53d6d0b
feat: 힌트 출력하는 기능 구현
Oct 20, 2023
e4ceee5
feat: 힌트와 게임 종료 조건을 비교해 종료 하는 기능 구현
Oct 20, 2023
29fbb0b
feat: 플레이어 입력으로 게임 재시작 여부를 결정하는 기능 구현
Oct 20, 2023
8e1ebce
feat: 게임 시작 멘트 출력
Oct 20, 2023
5bbfafc
refactor: separate function make randomNumber from main
Oct 21, 2023
3109358
refactor: separate function get game result from main
Oct 21, 2023
5ec8f5a
refactor: change if/else to when
Oct 21, 2023
ecdc227
refactor: separate function print game result from main
Oct 21, 2023
bae4f2c
refactor: separate function restart game from main
Oct 21, 2023
a3315d3
refactor: separate function get user's Input from main
Oct 21, 2023
98afa52
refactor: separate function check user's input validation from main
Oct 21, 2023
6eda278
refactor: change if/else of ''checkUserInputValid' function into if …
Oct 21, 2023
167cfbe
refactor: create Computer, System classes
Oct 21, 2023
5c8ee0f
refactor: Distributes functions of Application.kt to the System class…
Oct 21, 2023
21d9d3c
refactor: Distributes functions of Application.kt to the Computer cla…
Oct 21, 2023
95ba52c
refactor: update end-game logic
Oct 21, 2023
49f2120
refactor: 게임 시작 출력문 init에 추가 및 finish 변수를 companion object로 수정
Oct 21, 2023
e66299b
style: finish 변수를 isFinished로 변수명 수정
Oct 21, 2023
afdf4c2
refactor: 난수 생성 함수 로직 수정
Oct 21, 2023
78f0763
refactor: 매개변수 타입 수정
Oct 21, 2023
93f47cd
refactor: 필요없는 변수(strike, ball) 제거
Oct 21, 2023
e8d7eee
refactor: Application의 로직을 System으로 분리
Oct 22, 2023
f35bf5f
comment: 각 함수 설명 주석 추가
Oct 22, 2023
9e78c64
refactor: 하드코딩된 텍스트를 C.kt 클래스로 분리
Oct 22, 2023
6ad661b
refactor: pakage 추가 및 디렉터리 구조 변경
Nov 1, 2023
43de2d9
refactor: outputView 클래스를 만들고 출력과 관련한 메서드들 분리
Nov 1, 2023
bcff196
refactor: computer이라는 모델 클래스를 생성한 뒤 관련 비즈니스 로직을 분리
Nov 1, 2023
cbfb946
refactor: validator 클래스를 만들어 입력값 검증 메서드들을 분리
Nov 1, 2023
786b7e0
refactor: const 변수들 중 String 변수들을 MSG를 붙여 표시
Nov 1, 2023
0b68cf7
refactor: 게임 종료 조건을 constant 클래스로 분리
Nov 1, 2023
d475be5
refactor: System 컨트롤러에 Depth를 2로 줄임
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
113 changes: 113 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -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)
- **시스템)** 전달받은 힌트 출력

- **시스템)** **[ 시스템) 플레이어에게 입력을 받음 ] 단계**로 돌아감
8 changes: 7 additions & 1 deletion src/main/kotlin/baseball/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package baseball

import baseball.controller.System

fun main() {
TODO("프로그램 구현")
val system = System()
system.gameStart()
}



55 changes: 55 additions & 0 deletions src/main/kotlin/baseball/controller/System.kt
Original file line number Diff line number Diff line change
@@ -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<String> = listOf()
private var userInput: String = ""
private var isFinished = false
private var result: Pair<Int, Int> = 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)
}
}
Comment on lines +35 to +41

Choose a reason for hiding this comment

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

저는 주로 run만을 사용하였는데 이렇게 apply를 사용하니까 이런 상황에서는 더 가독성이 좋아지네요.


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
}
6 changes: 6 additions & 0 deletions src/main/kotlin/baseball/model/Ball.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package baseball.model

data class Ball(
var strike:Int = 0,
var ball:Int = 0
)
30 changes: 30 additions & 0 deletions src/main/kotlin/baseball/model/Computer.kt
Original file line number Diff line number Diff line change
@@ -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<String> = mutableListOf()
) {
fun makeRandomNums() {
var temp = ""
randomNums = mutableListOf<String>()
while (randomNums.size < RANDOM_SIZE) {
temp = Randoms.pickNumberInRange(1, 9).toString()
if (!randomNums.contains(temp)) {
randomNums.add(temp)
}
}
}

//게임 결과를 도출하는 함수
fun getGameResult(userInputList: List<String>): Pair<Int, Int> {
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++
Copy link

Choose a reason for hiding this comment

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

이 부분에서
(userInputList[i] != randomNums[I])
부분은 지워두 될 것 같아요! 이미 if문을 통하여 확인해주었기에 그부분을 삭제해도 문제 없을 것 같아요!😀

}
return Pair(strike, ball)
}

}
18 changes: 18 additions & 0 deletions src/main/kotlin/baseball/util/C.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package baseball.util

object C {
Copy link

Choose a reason for hiding this comment

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

C라는 이름 보다는 Constants라는 이름으로 정확한 의도를 드러내는 것이 나아보여요!

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}"

}
17 changes: 17 additions & 0 deletions src/main/kotlin/baseball/util/Validator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package baseball.util

object Validator {
Copy link

Choose a reason for hiding this comment

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

1주차 피드백 내용에는 이름을 통하여 의도가 드러났다면 주석을 사용하지 않는 것이 좋다고 나와있습니다!
해당 함수들은 충분히 함수 명을 통하여 의도가 드러났기에 주석을 사용하지 않아도 될 것 같아요!😀

//플레이어의 입력값이 유효한 지 검사하는 함수
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)
}

Comment on lines +10 to +14

Choose a reason for hiding this comment

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

.toRegex()라는 내장함수이 있다는 것은 알았는데 이렇게도 활용이 가능하다는 것은 처음 알았네요.😄

//중복된 숫자가 없는 지 확인하는 함수
private fun checkDiffNums(userInput: String): Boolean = (userInput.length == userInput.toSet().size)
}
18 changes: 18 additions & 0 deletions src/main/kotlin/baseball/view/GameInputView.kt
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +12 to +13
Copy link

Choose a reason for hiding this comment

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

"!", "2" 도 C 클래스로 이동시켜 관리하는 것이 좋아보입니다!

else -> throw IllegalArgumentException()
}
}
fun makeUserInputList(userInput: String) = userInput.chunked(1)
Copy link

Choose a reason for hiding this comment

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

list.chunked() 라는 함수에 대해서 알아갑니당!! 편리한 내장 함수가 있었네요!😀

}
30 changes: 30 additions & 0 deletions src/main/kotlin/baseball/view/GameOutputView.kt
Original file line number Diff line number Diff line change
@@ -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<Int, Int>) {
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)
}
}