-
Notifications
You must be signed in to change notification settings - Fork 0
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
[숫자 야구 게임] 짱구 미션 제출합니다. #4
base: main
Are you sure you want to change the base?
Changes from all commits
e27ca20
2041c49
bd1783e
43ba740
7800830
255fefc
0782aa8
58435c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package KtInActionPractice | ||
|
||
const val UNIT_LINE_SEPARATOR = "\n" | ||
|
||
fun <T> joinToString(collection: Collection<T>, | ||
separator: String, | ||
prefix: String, | ||
postfix: String): String { | ||
val result = StringBuilder(prefix) | ||
for ((index, element) in collection.withIndex()) { | ||
if (index > 0) result.append(separator) | ||
result.append(element) | ||
} | ||
|
||
result.append(postfix) | ||
return result.toString() | ||
} | ||
|
||
fun String.lastChar(): Char = this.get(length - 1) | ||
|
||
var StringBuilder.lastChar: Char | ||
get() = get(length - 1) | ||
set(value: Char) { | ||
this.setCharAt(length - 1, value) | ||
} | ||
|
||
fun <T> Collection<T>.joinToString2( | ||
separator: String = ", ", | ||
prefix: String = "", | ||
postfix: String = "" | ||
): String { | ||
val result = StringBuilder(prefix) | ||
for ((index, element) in this.withIndex()) { | ||
if (index > 0) result.append(separator) | ||
result.append(element) | ||
} | ||
result.append(postfix) | ||
return result.toString() | ||
} | ||
|
||
fun Collection<String>.joinToString3( | ||
separator: String = ", ", | ||
prefix: String = "", | ||
postfix: String = "" | ||
) = joinToString2(separator, prefix, postfix) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package KtInActionPractice | ||
|
||
/* | ||
* 코틀린의 주요 특성 | ||
* 코틀린을 도입하면 더 적은 코드로 더 편하게 프로그래머의 목표를 달성할 수 있다. | ||
* | ||
* 정적 타입 지정 언어 | ||
* 자바랑 똑같이 타입을 컴파일 시점에 알 수 있음. | ||
* 이로 인해서 오는 장점이 성능, 신뢰성, 유지 보수성, 도구 지원 등이 있다고 함. 개인적으로는 컴파일 안 하는 언어는 왜 쓰는지 모르겠음 ㅋㅋ; | ||
* | ||
* 함수형 프로그래밍과 객체지향 프로그래밍 | ||
* 어제 자면서 본 레퍼런스에서 코틀린과 스칼라가 자주 비교됨. 이유는 스칼라가 함수형 프로그래밍 언어이기 때문인 것 같은데 코틀린도 함수형 프로그래밍 언어를 좋아함. | ||
* 함수형 프로그래밍의 장점 | ||
* 1. 간결함. 명령형(imperative) 코드에 비해 더 간결하며 우아함. | ||
* 2. 다중 스레드에도 안전함. 불변 데이터 구조를 사용하고 순수 함수를 그 데이터 구조에 적용하면 같은 데이터를 여러 스레드가 변경할 수 없음. 그래서 복잡한 동기화를 적용하지 않아도 됨. (아직 이해 x) | ||
* 3. 테스트하기 쉬움. 자바는 전체 환경을 구성하는 준비 코드가 필요한데 순수 함수는 그런 준비 없이 독립적으로 테스트가 가능하다고 함. 이번 스터디에서 이 부분에 대해 공부해 봐야 할 듯!! | ||
* | ||
* 코틀린의 철학 | ||
* 실용성 | ||
* 코틀린은 실제 문제를 해결하기 위해 만들어진 언어라고 함. 연구를 하기 위한 언어가 아니고 이미 성공적으로 검증된 해법과 기능에 의존함. 이 부분이 개인적으로 마음에 듬. | ||
* | ||
* 간결성 | ||
* 개인적으로 자바에서 쓸모없는 코드가 몇 개 보였음. private final 같은.. 자바는 쓸모 없는 코드 때문에 코드의 양이 엄청 많아짐. | ||
* 이렇게 코드의 양이 많아지면 읽기가 싫어지고 유지보수하기 싫어짐. 이는 공학작문및발표 수업에서 배웠고 매우 동의하는 바임. | ||
* 코드가 간결할수록 내용을 파악하기 더 쉬움. 코틀린은 간결하면서도 의도를 쉽게 파악할 수 있는 구문 구조를 제공함. 이 부분도 개인적으로 마음에 듬. | ||
* 하지만 책을 조금 읽어봤을 때 너무 간결해 오히려 불편함.. 조금 적응하면 나아질 수 있다고 생각함. | ||
* | ||
* 안전성 | ||
* 코틀린은 자바보다 NPE에 안전함. 보통 언어가 안전하다면 생산성이 하락하는데 코틀린에서는 ? 한 글자만 추가하면 됨. 굉장히 간결함. | ||
* 또, 타입 캐스팅을 할 때도 극도로 간결함. 자바의 필요 없는 구문들이 거의 제거 됨. | ||
* | ||
* */ | ||
|
||
class KtInActionPart1 { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,12 @@ | ||
package baseball | ||
|
||
import step1.* | ||
import step2.api.BaseballController | ||
import step2.application.BaseballService | ||
import step2.global.BaseballApplication | ||
import step2.view.BaseballView | ||
|
||
fun main() { | ||
TODO("프로그램 구현") | ||
BaseballApplication(BaseballView(), BaseballController(BaseballService())).run() | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package step1 | ||
|
||
import camp.nextstep.edu.missionutils.Randoms | ||
|
||
fun announceBaseballGameStartMessage() = println("숫자 야구 게임을 시작합니다.") | ||
|
||
fun announceEnterNumbersMessage() = print("숫자를 입력해주세요 : ") | ||
|
||
fun announceThreeStrike() = println("3개의 숫자를 모두 맞히셨습니다! 게임 종료") | ||
|
||
fun announceBaseballRestartMessage() = println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.") | ||
|
||
fun announceBaseballResult(userInputNumbers: String, randomNumbers: String) = println(calculateBaseballGameResult(userInputNumbers, randomNumbers)) | ||
|
||
fun pickRandomNumbers(): String { | ||
val randomNumbers = mutableListOf<Int>() | ||
while (randomNumbers.size < 3) { | ||
val randomNumber = Randoms.pickNumberInRange(1, 9) | ||
if (!randomNumbers.contains(randomNumber)) { | ||
randomNumbers.add(randomNumber) | ||
} | ||
} | ||
return randomNumbers.joinToString(separator = "") | ||
} | ||
|
||
fun isUserInputValid(userInputNumbers: String): Boolean = userInputNumbers.length == 3 && userInputNumbers.toIntOrNull() != null | ||
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. 사용자가 0을 입력한 경우도 Invalid하다고 판단해줘야 하지 않을까요? |
||
|
||
|
||
private fun calculateBaseballGameResult(userInputNumbers: String, randomNumbers: String): String { | ||
val result = StringBuilder() | ||
var strikeCount = 0 | ||
var ballCount = 0 | ||
|
||
for (i in randomNumbers.indices) { | ||
if (userInputNumbers[i] == randomNumbers[i]) { | ||
strikeCount++ | ||
} else if (userInputNumbers[i] in randomNumbers) { | ||
ballCount++ | ||
} | ||
} | ||
|
||
if (ballCount > 0) { | ||
result.append("${ballCount}볼 ") | ||
} | ||
|
||
if (strikeCount > 0) { | ||
result.append("${strikeCount}스트라이크") | ||
} | ||
|
||
return if (ballCount == 0 && strikeCount == 0) "낫싱" else result.toString() | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package step1 | ||
|
||
import camp.nextstep.edu.missionutils.Console | ||
|
||
fun stepOneRunner() { | ||
announceBaseballGameStartMessage() | ||
var randomNumbers = pickRandomNumbers() | ||
|
||
while (true) { | ||
announceEnterNumbersMessage() | ||
val readLine = Console.readLine() | ||
if (!isUserInputValid(readLine)) { | ||
throw IllegalArgumentException() | ||
} | ||
|
||
announceBaseballResult(readLine, randomNumbers) | ||
if (readLine.isThreeStrike(readLine, randomNumbers)) { | ||
announceThreeStrike() | ||
announceBaseballRestartMessage() | ||
if (Console.readLine() == "2") break | ||
randomNumbers = pickRandomNumbers() | ||
} | ||
} | ||
} | ||
|
||
|
||
fun String.isThreeStrike(numbers: String, randomNumbers: String): Boolean = | ||
numbers[0] == randomNumbers[0] && numbers[1] == randomNumbers[1] && numbers[2] == randomNumbers[2] | ||
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. 이 부분은 간단하게 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package step2.api | ||
|
||
import step2.application.BaseballService | ||
import step2.dto.BaseballResultDto | ||
import step2.view.BaseballView | ||
|
||
class BaseballController( | ||
val baseballService: BaseballService | ||
) { | ||
|
||
fun saveRandomNumbers() { | ||
baseballService.createBaseball() | ||
} | ||
|
||
fun getBaseballGameResult(userInputNumbers: String): BaseballResultDto = | ||
requireNotNull(userInputNumbers.takeIf { it.length == 3 && it.toIntOrNull() != null }) { | ||
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. 이거 몇몇 선배님들께서 상수,Enum로 관리하시던데 그렇게 바꿔보는 것도 좋을 것 같습니다!! (저도 바꿀 예정..헷) 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. 그리고 required 쓰는거 좋은 것 같습니다! |
||
"유효하지 않은 숫자 또는 문자입니다." | ||
}.let { baseballService.compareRandomNumbers(it) } | ||
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. 오 |
||
|
||
} | ||
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. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package step2.application | ||
|
||
import step2.dto.BaseballResultDto | ||
import step2.entity.RandomNumbers | ||
import step2.global.createUniqueRandomNumbers | ||
|
||
class BaseballService { | ||
|
||
fun createBaseball() { | ||
val createUniqueRandomNumbers = createUniqueRandomNumbers(3) | ||
RandomNumbers.changeRandomNumbers(createUniqueRandomNumbers) | ||
} | ||
Comment on lines
+9
to
+12
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. createBaseball() 메서드를 통해 랜덤한 야구 게임 숫자를 생성해준다는 걸 메서드 명으로 더 표현하면 좋을 것 같습니다~ |
||
|
||
fun compareRandomNumbers(userInputNumbers: String): BaseballResultDto = | ||
BaseballResultDto(RandomNumbers.countStrike(userInputNumbers), RandomNumbers.countBall(userInputNumbers)) | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package step2.dto | ||
|
||
data class BaseballResultDto( | ||
val strikeCount: Int, | ||
val ballCount: Int, | ||
) | ||
Comment on lines
+3
to
+6
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. 혹시 포매터 어떤 거 쓰시나요?? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package step2.entity | ||
|
||
object RandomNumbers { | ||
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 var randomNumber: String? = null | ||
|
||
fun changeRandomNumbers(number: String): String { | ||
this.randomNumber = number | ||
return this.randomNumber!! | ||
} | ||
Comment on lines
+6
to
+9
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. 클래스 내부 상태를 바꾸기보단 불변으로 만들고 매번 새로 만드는게 유지보수하기엔 더 좋을 것 같습니다~ 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. randomNumber 을 nullable하게 만드신 이유가 따로 있으신가요?? 만약 nullable을 사용하고 싶다면 not-null 보다는 ?: 을 쓰는게 더 안전할 것 같아요..!! 제가 옛날에 뭣모르고 !! 남발하다가 NPE 많이 터졌어서 괜히 신경쓰게 되네요 ㅎㅎ ㅠㅠ |
||
|
||
fun countStrike(number: String): Int = number.indices.count { i -> number[i] == randomNumber!![i] } | ||
|
||
fun countBall(number: String): Int = number.indices.count { i -> number[i] != randomNumber!![i] && number[i] in randomNumber!! } | ||
} | ||
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. 저는 이거 비교하는 역할을 service나 아니면 baseball controller와 같이 다른 곳에 뒀는데 random numbers클래스 안에 두고 개수를 세는게 더 좋은지 궁금합니다! service에서 간편하게 비교하기 위해서 사용하셨나요?? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package step2.global | ||
|
||
import camp.nextstep.edu.missionutils.Console | ||
import camp.nextstep.edu.missionutils.Randoms | ||
|
||
fun createUniqueRandomNumbers(count: Int): String = | ||
generateSequence { Randoms.pickNumberInRange(1, 9) } | ||
.distinct() | ||
.take(count) | ||
.joinToString("") | ||
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. 오 저는 set으로 사용했는데 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. 우왕... 굳이네요!! 👍 그런데 @stopmin님이 말씀하신 것 처럼 메서드 명은 |
||
|
||
fun getThreeUniqueNumbers(): String = Console.readLine() ?: throw IllegalArgumentException() | ||
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. 함수명은 |
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.
말씀대로 Util 역할을 하는 코틀린 파일에서 최상위 함수로 쓰면 더 좋을 것 같습니다. 지금은
BaseballGame
클래스에 너무 많은 역할이 들어있는 느낌이에용