-
Notifications
You must be signed in to change notification settings - Fork 313
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
[Step4] 4단계 - 블랙잭(베팅) #697
base: bong6981
Are you sure you want to change the base?
Changes from 15 commits
ed22ad5
ea2d901
d095226
b1ebc8a
158af44
c8eca31
3d30c05
5181cef
fc1d9ae
a4db3db
780067a
d95162a
00f52f0
8bbefe0
f96543d
ebae7ee
c66f8bf
02e8ce0
25c8735
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
package blackjack.controller | ||
|
||
import blackjack.domain.Action | ||
import blackjack.domain.batting.Amount | ||
import blackjack.domain.player.Player | ||
import blackjack.domain.player.PlayerNames | ||
|
||
interface InputProcessor { | ||
fun playerNames(): PlayerNames | ||
|
||
fun playerBet(player: Player): Amount | ||
|
||
fun playerAction(player: Player): Action | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,20 @@ | ||
package blackjack.controller | ||
|
||
import blackjack.domain.result.Result | ||
import blackjack.domain.result.distribution.DealEndResult | ||
import blackjack.domain.result.distribution.DealInitialCardResult | ||
import blackjack.domain.result.distribution.DealToDealerResult | ||
import blackjack.domain.result.distribution.DealToPlayerResult | ||
import blackjack.domain.result.game.GameResult | ||
import blackjack.domain.result.game.GameEndResult | ||
|
||
class ResultProcessor { | ||
fun handle(result: Result) { | ||
when (result) { | ||
is DealInitialCardResult -> ViewResultProcessor.drawInitialDistribution(result) | ||
is DealToPlayerResult -> { | ||
if (result.isSystemStand) return | ||
ViewResultProcessor.drawPlayerState(result) | ||
} | ||
is DealToPlayerResult -> ViewResultProcessor.drawPlayerState(result) | ||
is DealEndResult -> {} | ||
is DealToDealerResult -> ViewResultProcessor.drawDealerState(result) | ||
is GameResult -> ViewResultProcessor.drawGameResult(result) | ||
is GameEndResult -> ViewResultProcessor.drawGameResult(result) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package blackjack.controller | ||
|
||
import blackjack.domain.Action | ||
import blackjack.domain.batting.Amount | ||
import blackjack.domain.player.Player | ||
import blackjack.domain.player.PlayerNames | ||
import blackjack.view.dto.PlayerNameDto | ||
|
@@ -10,11 +11,17 @@ class ViewInputProcessor : InputProcessor { | |
override fun playerNames(): PlayerNames = | ||
InputView.playerNames().let(PlayerNames::from) | ||
|
||
override fun playerBet(player: Player): Amount = | ||
InputView.playerBet(player.nameDto()) | ||
.let { Amount.betAmount(it.toInt()) } | ||
|
||
override fun playerAction(player: Player): Action { | ||
val action = InputView.playerAction(player.let(PlayerNameDto::from)) | ||
val action = InputView.playerAction(player.nameDto()) | ||
return toPlayerAction(action) | ||
} | ||
|
||
private fun Player.nameDto(): PlayerNameDto = this.let(PlayerNameDto::from) | ||
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. let에 생성자 제가 조금 설명을 러프하게 드렸었는데요. 생성자를 사용해도 되는 것에 대해서 굳이 let을 사용하지 않는게 좋을 것 같다라는 것이 제 의견이었습니다. this.let(PlayerNameDto::from)
PlayerNameDto.from(this) 에서 읽히는 과정을 본다면 let은 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. 음.. 제가 아직 명확하게 이해하지 못한 것 같습니다.
만약, 아래 예시에서는
return when {
ranks.hasAce().not() -> score
score + ACE_BONUS_SCORE > MAX_SCORE -> score
else -> score + ACE_BONUS_SCORE
}.let(::HandScore) 이런 케이스에서도 HandScore 을 생성하다는 로직 보다는 어떻게 점수 계산이 되는지 when { } 안의 로직이 먼저 읽혀야 한다고 생각해서 여기는 let 사용이 낫지 않나 라는 생각이 듭니다! 그러나 위 2 케이스 모두 리뷰어님이 말씀주신 큰 복잡한 로직 없이 생성하는 로직인 것 같습니다. 이에 대해서도 같은 생각이신지 궁금합니다! |
||
|
||
private fun toPlayerAction(action: String): Action = when (action) { | ||
"y" -> Action.HIT | ||
"n" -> Action.STAND | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,11 +3,13 @@ package blackjack.controller | |||||||||||||||||
import blackjack.domain.result.distribution.DealInitialCardResult | ||||||||||||||||||
import blackjack.domain.result.distribution.DealToDealerResult | ||||||||||||||||||
import blackjack.domain.result.distribution.DealToPlayerResult | ||||||||||||||||||
import blackjack.domain.result.game.GameResult | ||||||||||||||||||
import blackjack.domain.result.game.GameEndResult | ||||||||||||||||||
import blackjack.view.dto.DealerCardsResultDto | ||||||||||||||||||
import blackjack.view.dto.DealerHitDto | ||||||||||||||||||
import blackjack.view.dto.FinalDealerStateDto | ||||||||||||||||||
import blackjack.view.dto.FinalPlayerStateDto | ||||||||||||||||||
import blackjack.view.dto.DealerProfitDto | ||||||||||||||||||
import blackjack.view.dto.PlayerCardsResultDto | ||||||||||||||||||
import blackjack.view.dto.PlayerDto | ||||||||||||||||||
import blackjack.view.dto.PlayerProfitDto | ||||||||||||||||||
import blackjack.view.output.OutputView | ||||||||||||||||||
|
||||||||||||||||||
object ViewResultProcessor { | ||||||||||||||||||
|
@@ -18,6 +20,7 @@ object ViewResultProcessor { | |||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fun drawPlayerState(result: DealToPlayerResult) { | ||||||||||||||||||
if (result.isSystemStand) return | ||||||||||||||||||
val dto = result.player.let { PlayerDto(it.name.value, it.hand.cards) } | ||||||||||||||||||
OutputView.drawPlayerCurrentState(dto) | ||||||||||||||||||
} | ||||||||||||||||||
|
@@ -26,15 +29,26 @@ object ViewResultProcessor { | |||||||||||||||||
OutputView.drawDealerHitStatus(DealerHitDto(result.isHit)) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fun drawGameResult(result: GameResult) { | ||||||||||||||||||
fun drawGameResult(result: GameEndResult) { | ||||||||||||||||||
drawCardResult(result) | ||||||||||||||||||
drawProfitResult(result) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
private fun drawCardResult(result: GameEndResult) { | ||||||||||||||||||
val dealerDto = | ||||||||||||||||||
DealerCardsResultDto(result.dealerHand.cards, result.dealerScore.value) | ||||||||||||||||||
val playersDto = result.playerResults.map { | ||||||||||||||||||
PlayerCardsResultDto(it.name.value, it.hand.cards, it.score.value) | ||||||||||||||||||
} | ||||||||||||||||||
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.
Suggested change
사소한 의견이지만, 개인적으로 이렇게 처리하는 것이 가독성이 더 좋을 것 같네요. 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. 이를 반영했습니다! |
||||||||||||||||||
OutputView.drawCardsResults(dealerDto, playersDto) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
private fun drawProfitResult(result: GameEndResult) { | ||||||||||||||||||
val dealerDto = | ||||||||||||||||||
result.dealerResults.let { | ||||||||||||||||||
FinalDealerStateDto(it.dealer.hand.cards, it.dealer.score.cardScore, it.status) | ||||||||||||||||||
} | ||||||||||||||||||
val playersDto = | ||||||||||||||||||
result.playersResult.map { | ||||||||||||||||||
FinalPlayerStateDto(it.player.name.value, it.player.hand.cards, it.player.score.cardScore, it.status) | ||||||||||||||||||
} | ||||||||||||||||||
OutputView.drawFinalResults(dealerDto, playersDto) | ||||||||||||||||||
DealerProfitDto(result.dealerProfit.value.toString()) | ||||||||||||||||||
val playersDto = result.playerResults.map { | ||||||||||||||||||
PlayerProfitDto(it.name.value, it.profit.value.toString()) | ||||||||||||||||||
} | ||||||||||||||||||
OutputView.drawProfitResults(dealerDto, playersDto) | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package blackjack.domain | ||
|
||
import blackjack.domain.player.CardPlayer | ||
import blackjack.domain.player.Player | ||
import blackjack.domain.result.game.VictoryStatus | ||
|
||
object BlackJackJudge { | ||
private const val BUST_SCORE = 0 | ||
private const val BLACK_JACK_CARD_COUNT = 2 | ||
private const val BLACK_JACK_SCORE = 21 | ||
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. 21이라는 비즈니스 상수값이 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. 제가 도메인에 대한 지식이 부족해서 발생한 코드 같습니다
|
||
|
||
fun judgeVictory(player: Player, dealer: Dealer): VictoryStatus = | ||
when { | ||
player.isBust() -> VictoryStatus.LOSS | ||
player.gameScore() > dealer.gameScore() -> VictoryStatus.WIN | ||
player.gameScore() == dealer.gameScore() -> VictoryStatus.PUSH | ||
else -> VictoryStatus.LOSS | ||
} | ||
|
||
fun isBlackJack(player: Player): Boolean = | ||
(player isSameCardCount BLACK_JACK_CARD_COUNT) && (player isSameScore BLACK_JACK_SCORE) | ||
|
||
private fun CardPlayer.gameScore(): Int = | ||
if (this.isBust()) BUST_SCORE | ||
else this.score.value | ||
|
||
private fun CardPlayer.isBust() = score.value > BLACK_JACK_SCORE | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package blackjack.domain.batting | ||
|
||
import java.math.BigDecimal | ||
|
||
data class Amount( | ||
val value: BigDecimal, | ||
) : Comparable<Amount> { | ||
|
||
operator fun plus(other: Amount): Amount = Amount(value.plus(other.value)) | ||
operator fun times(count: Int): Amount = Amount(value.times(count.toBigDecimal())) | ||
|
||
operator fun times(count: BigDecimal): Amount = | ||
Amount(value * count) | ||
override fun compareTo(other: Amount): Int = | ||
this.value.compareTo(other.value) | ||
|
||
companion object { | ||
val ZERO = Amount(BigDecimal.ZERO) | ||
fun betAmount(amount: Int): Amount { | ||
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.
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. BetAmount(val value: Amount) 로 분리하지 않은 이유는 단순 생성시에서 값 체크만 BetAmount 로서의 기능을 한다고 생각해서 정적 팩토리 메서드로 검증을 하도록 했습니다! 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. BetAmount 로 이를 분리했습니다! |
||
require(amount > 0) { "베팅 금액은 0보다 커야 합니다" } | ||
return Amount(amount.toBigDecimal()) | ||
} | ||
} | ||
} |
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.
문서화 👍