-
Notifications
You must be signed in to change notification settings - Fork 82
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
base: doabletuple
Are you sure you want to change the base?
Conversation
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.
안녕하세요 디랙!
이번 블랙잭 미션 함께할 제이든입니다.
블랙잭 미션 구현 잘 진행해주셨고, 최대한 객체간 분리하려 고민하신 흔적이 보였어요.
함께 고민해볼 부분에 코멘트를 남겼으며 어려운 부분이 있다면 편하게 DM주세요!
fun readPlayerNames(): List<String> { | ||
outputView.requestPlayerNames() | ||
val input: String = readln() | ||
return input.split(PLAYER_NAMES_DELIMITER).map { name: String -> name.trim() } | ||
} |
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.
import blackjack.domain.model.Player | ||
|
||
class InputView { | ||
private val outputView = OutputView() |
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.
InputView에서 OutputView로만 출력이 가능할까요?
바로 print로 출력하면 안되는걸까요? 🧐
fun readPlayerAction(player: Player): String { | ||
outputView.requestPlayerAction(player) | ||
val input: String = readln() | ||
return input | ||
} |
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.
단순 String 대신 Hit or Stand를 명시적으로 반환하는 방법에는 무엇이 있을까요?
@@ -0,0 +1,35 @@ | |||
package blackjack.domain.model | |||
|
|||
open class Player(val name: String, initCards: List<Card> = listOf()) { |
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.
open class를 활용하신 배경에는 어떤게 있었을까요?
- open class
- abstract class
- interface
세가지는 어떤 차이점이 있을까요?
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 | ||
} |
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.
현재 Player가 다소 많은 역할을 갖고 있는거 같습니다.
게임 참가자, 딜러 모두 카드를 들고있는데
또 다른 객체로 분리해볼 수 있을까요?
class Participants(val players: List<Player>) { | ||
constructor(dealer: Dealer, playersName: List<String>) : this(listOf(dealer) + playersName.map(::Player)) |
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.
궁금한게 있습니다!
현재 Controller에서는 두가지 생성자를 혼용하고 있는데,
Participants는 "참가자의 집합" 이라는 객체로
하나의 게임에 하나의 인스턴스가 존재하는게 아닌걸까요?
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을 입력해주세요." | ||
} | ||
} |
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.
Hit or Stand의 역할을 하는 객체로 이해했습니다.
도메인으로 관리되어야 할 주체일까요?
도메인 패키지에 존재하지만 내부는 View에 관련된 로직으로 보이네요 🥲
WIN("승"), | ||
LOSE("패"), | ||
DRAW("무"), | ||
; |
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.
승, 패, 무 는 View에서 사용되는 로직으로 보여요!
혹시 디자인 요구사항이 기호로 바뀌었다면 도메인 로직이 수정되어야 할겁니다
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 | ||
} | ||
} |
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.
이부분에 대해 같이 이야기 해보고 싶어요.
현재 Verdict라는 별도의 객체를 두어 승/패를 계산하고 있습니다.
현실세계에서 생각해본다면, 참가자와 딜러 스스로가 본인의 카드뭉치와 상대방의 카드 뭉치를 비교해서 각자의 승패 여부를 알거에요.
별도의 장치를 두어 계산하지 않습니다.
그렇다면 참가자 스스로가 판단할 수 있도록 해볼 수 있을까요?
while (dealer.getScore() <= Dealer.DEALER_DRAW_THRESHOLD) { | ||
outputView.printDealerHitsState() | ||
dealer.accept(deck.draw()) | ||
} |
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.
현재 딜러의 상태를 판단해 히트 가능한 여부를 Controller에서 진행하고 있습니다.
딜러든 참가자든 스스로 본인이 Hitable 한지 알 수 있을겁니다.
지금 구조에서 구현해주신 것 처럼,
// in Participant
abstract fun canDraw()
식으로 상속을 이용해 구현해볼 수 있을까요?
셀프 체크리스트
README.md
에 기능 목록을 정리하고 명확히 기술하였는가?어떤 부분에 집중하여 리뷰해야 할까요?
안녕하세요, 제이든! 7기 안드로이드 크루 디랙입니다.
블랙잭 미션 잘 부탁드립니다. 감사합니다! 😊
승/패/무 상태를 관리하기 위해
enum class Verdict
를 만들고, 각 엔트리가"승"
,"패"
또는"무"
문자열을 갖도록 했습니다.생각해보니 해당 문자열들은 출력을 위해서만 사용되고 있는만큼, 엔트리를 문자열로 표현하는 것은
View
의 책임에 더 가까운 것이 아닐지 헷갈리는 부분이 생겼습니다.반면 이 책임을
View
로 옮긴다면View
가Verdict
별로 어떤 문자열을 사용할지 판단해야 할 것 같은데,View
가 이러한 로직을 가져도 되는지에 대해서도 확신이 서지 않았습니다.두 방법 중 어느 쪽이 MVC 패턴에 더 가깝다고 생각하시는지 궁금합니다.