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

[블랙잭 1단계] 디랙 미션 제출합니다. #126

Open
wants to merge 72 commits into
base: doabletuple
Choose a base branch
from

Conversation

doabletuple
Copy link

셀프 체크리스트

  • 프로그램이 정상적으로 작동하는가?
  • 모든 테스트가 통과하는가?
  • 이전에 받은 피드백을 모두 반영하였는가?
  • 코딩 스타일 가이드를 준수하였는가?
    • IDE 코드 자동 정렬을 적용하였는가?
    • 린트 검사를 통과하였는가?
  • 프로그래밍 요구 사항을 준수하였는가?
  • README.md에 기능 목록을 정리하고 명확히 기술하였는가?

어떤 부분에 집중하여 리뷰해야 할까요?

안녕하세요, 제이든! 7기 안드로이드 크루 디랙입니다.

블랙잭 미션 잘 부탁드립니다. 감사합니다! 😊

승/패/무 상태를 관리하기 위해 enum class Verdict를 만들고, 각 엔트리가 "승", "패" 또는 "무" 문자열을 갖도록 했습니다.

생각해보니 해당 문자열들은 출력을 위해서만 사용되고 있는만큼, 엔트리를 문자열로 표현하는 것은 View의 책임에 더 가까운 것이 아닐지 헷갈리는 부분이 생겼습니다.

반면 이 책임을 View로 옮긴다면 ViewVerdict별로 어떤 문자열을 사용할지 판단해야 할 것 같은데, View가 이러한 로직을 가져도 되는지에 대해서도 확신이 서지 않았습니다.

두 방법 중 어느 쪽이 MVC 패턴에 더 가깝다고 생각하시는지 궁금합니다.

donghyun81 and others added 30 commits March 4, 2025 15:53
@KwonDae KwonDae self-requested a review March 7, 2025 14:49
Copy link

@KwonDae KwonDae left a comment

Choose a reason for hiding this comment

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

안녕하세요 디랙!
이번 블랙잭 미션 함께할 제이든입니다.
블랙잭 미션 구현 잘 진행해주셨고, 최대한 객체간 분리하려 고민하신 흔적이 보였어요.
함께 고민해볼 부분에 코멘트를 남겼으며 어려운 부분이 있다면 편하게 DM주세요!

Comment on lines 8 to 12
fun readPlayerNames(): List<String> {
outputView.requestPlayerNames()
val input: String = readln()
return input.split(PLAYER_NAMES_DELIMITER).map { name: String -> name.trim() }
}
Copy link

Choose a reason for hiding this comment

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

image

입력에 대해 검증이 필요해 보여요!

import blackjack.domain.model.Player

class InputView {
private val outputView = OutputView()
Copy link

Choose a reason for hiding this comment

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

InputView에서 OutputView로만 출력이 가능할까요?
바로 print로 출력하면 안되는걸까요? 🧐

Comment on lines 14 to 18
fun readPlayerAction(player: Player): String {
outputView.requestPlayerAction(player)
val input: String = readln()
return input
}
Copy link

Choose a reason for hiding this comment

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

단순 String 대신 Hit or Stand를 명시적으로 반환하는 방법에는 무엇이 있을까요?

@@ -0,0 +1,35 @@
package blackjack.domain.model

open class Player(val name: String, initCards: List<Card> = listOf()) {
Copy link

Choose a reason for hiding this comment

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

open class를 활용하신 배경에는 어떤게 있었을까요?

  • open class
  • abstract class
  • interface

세가지는 어떤 차이점이 있을까요?

Comment on lines 14 to 28
fun getScore(): Int {
val score = this.cards.sumOf { it.rank.score }
return score + getBonusScore(totalScore = score)
}

private fun getBonusScore(totalScore: Int): Int {
if (totalScore <= MAX_BONUS_SCORE && hasAce()) return BONUS_SCORE
return 0
}

private fun hasAce(): Boolean = this.cards.any { it.rank == Rank.ACE }

fun isBust(): Boolean {
return getScore() > BUST_THRESHOLD
}
Copy link

Choose a reason for hiding this comment

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

현재 Player가 다소 많은 역할을 갖고 있는거 같습니다.
게임 참가자, 딜러 모두 카드를 들고있는데
또 다른 객체로 분리해볼 수 있을까요?

Comment on lines 3 to 4
class Participants(val players: List<Player>) {
constructor(dealer: Dealer, playersName: List<String>) : this(listOf(dealer) + playersName.map(::Player))
Copy link

Choose a reason for hiding this comment

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

궁금한게 있습니다!
현재 Controller에서는 두가지 생성자를 혼용하고 있는데,

Participants는 "참가자의 집합" 이라는 객체로
하나의 게임에 하나의 인스턴스가 존재하는게 아닌걸까요?

Comment on lines 3 to 18
class Choice(private val value: String) {
init {
require(value == CHOICE_YES || value == CHOICE_NO) { ERROR_INVALID_CHOICE }
}

fun isHit(): Boolean {
return value == CHOICE_YES
}

companion object {
private const val CHOICE_YES = "y"
private const val CHOICE_NO = "n"

private const val ERROR_INVALID_CHOICE = "y 또는 n을 입력해주세요."
}
}
Copy link

Choose a reason for hiding this comment

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

Hit or Stand의 역할을 하는 객체로 이해했습니다.
도메인으로 관리되어야 할 주체일까요?
도메인 패키지에 존재하지만 내부는 View에 관련된 로직으로 보이네요 🥲

Comment on lines 4 to 7
WIN("승"),
LOSE("패"),
DRAW("무"),
;
Copy link

Choose a reason for hiding this comment

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

승, 패, 무 는 View에서 사용되는 로직으로 보여요!
혹시 디자인 요구사항이 기호로 바뀌었다면 도메인 로직이 수정되어야 할겁니다

Comment on lines 18 to 29
fun determine(
standardPlayer: Dealer,
comparePlayer: Player,
): Verdict {
return when {
standardPlayer.isBust() && comparePlayer.isBust() -> LOSE
standardPlayer.isBust() -> WIN
standardPlayer.getScore() > comparePlayer.getScore() || comparePlayer.isBust() -> LOSE
standardPlayer.getScore() < comparePlayer.getScore() && !comparePlayer.isBust() -> WIN
else -> DRAW
}
}
Copy link

Choose a reason for hiding this comment

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

이부분에 대해 같이 이야기 해보고 싶어요.
현재 Verdict라는 별도의 객체를 두어 승/패를 계산하고 있습니다.

현실세계에서 생각해본다면, 참가자와 딜러 스스로가 본인의 카드뭉치와 상대방의 카드 뭉치를 비교해서 각자의 승패 여부를 알거에요.
별도의 장치를 두어 계산하지 않습니다.
그렇다면 참가자 스스로가 판단할 수 있도록 해볼 수 있을까요?

Comment on lines 63 to 66
while (dealer.getScore() <= Dealer.DEALER_DRAW_THRESHOLD) {
outputView.printDealerHitsState()
dealer.accept(deck.draw())
}
Copy link

Choose a reason for hiding this comment

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

현재 딜러의 상태를 판단해 히트 가능한 여부를 Controller에서 진행하고 있습니다.
딜러든 참가자든 스스로 본인이 Hitable 한지 알 수 있을겁니다.
지금 구조에서 구현해주신 것 처럼,

// in Participant
abstract fun canDraw()

식으로 상속을 이용해 구현해볼 수 있을까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants