-
Notifications
You must be signed in to change notification settings - Fork 317
3단계 - 블랙잭(딜러) #566
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
base: jonghoonok
Are you sure you want to change the base?
3단계 - 블랙잭(딜러) #566
Changes from 2 commits
287bbff
826b9e8
c9c6bde
f0cc8cf
521e560
5c9b3c5
3e4aa37
7547274
c8d1741
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,6 +1,7 @@ | ||||||||||||||||
| package blackjack | ||||||||||||||||
|
|
||||||||||||||||
| import blackjack.domain.Dealer | ||||||||||||||||
| import blackjack.domain.Distributor | ||||||||||||||||
| import blackjack.domain.Player | ||||||||||||||||
| import blackjack.domain.Players | ||||||||||||||||
| import blackjack.domain.card.CardDeck | ||||||||||||||||
|
|
@@ -14,30 +15,44 @@ class BlackJackGame { | |||||||||||||||
| val players = Players(names) | ||||||||||||||||
| DisplayView.dealOutCards(players) | ||||||||||||||||
|
|
||||||||||||||||
| val dealer = Dealer(CardDeck()) | ||||||||||||||||
| dealer.dealOutCards(players) | ||||||||||||||||
| DisplayView.cardsOfPlayers(players) | ||||||||||||||||
| val distributor = Distributor(CardDeck()) | ||||||||||||||||
| val dealer = Dealer() | ||||||||||||||||
|
|
||||||||||||||||
| dealOutAdditionalCards(dealer, players) | ||||||||||||||||
| DisplayView.result(players) | ||||||||||||||||
| distributor.dealOutCards(dealer, players) | ||||||||||||||||
| DisplayView.cardsOfPlayers(dealer, players) | ||||||||||||||||
|
|
||||||||||||||||
| dealOutAdditionalCards(distributor, players) | ||||||||||||||||
| dealOutAdditionalCard(distributor, dealer) | ||||||||||||||||
| DisplayView.finalScore(dealer, players) | ||||||||||||||||
|
|
||||||||||||||||
| GameResultCalculator.getResult(dealer, players) | ||||||||||||||||
| DisplayView.result(dealer, players) | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private fun dealOutAdditionalCards(dealer: Dealer, players: Players) { | ||||||||||||||||
| private fun dealOutAdditionalCards(distributor: Distributor, players: Players) { | ||||||||||||||||
| players.players.forEach { | ||||||||||||||||
| dealOutAdditionalCard(dealer, it) | ||||||||||||||||
| dealOutAdditionalCard(distributor, it) | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private fun dealOutAdditionalCard(dealer: Dealer, player: Player) { | ||||||||||||||||
| private fun dealOutAdditionalCard(distributor: Distributor, player: Player) { | ||||||||||||||||
| DisplayView.dealOutAdditionalCard(player) | ||||||||||||||||
| if (InputView.inputAdditionalCard() == "y") { | ||||||||||||||||
| dealer.dealOutCard(player) | ||||||||||||||||
| takeAnotherCard(dealer, player) | ||||||||||||||||
| distributor.dealOutCard(player) | ||||||||||||||||
| takeAnotherCard(distributor, player) | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private fun dealOutAdditionalCard(distributor: Distributor, dealer: Dealer) { | ||||||||||||||||
| val receiveNewCard = dealer.getScore() < Dealer.LIMIT_SCORE | ||||||||||||||||
| if (receiveNewCard) { | ||||||||||||||||
| distributor.dealOutCard(dealer) | ||||||||||||||||
| } | ||||||||||||||||
|
||||||||||||||||
| val receiveNewCard = dealer.getScore() < Dealer.LIMIT_SCORE | |
| if (receiveNewCard) { | |
| distributor.dealOutCard(dealer) | |
| } | |
| if (dealer.isReceiveNewCard) { | |
| distributor.dealOutCard(dealer) | |
| } |
Outdated
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.
여기도 위에 남긴 코멘트와 동일한 의견입니다. 점수를 꺼내 비교하기보단 해당 행위 자체가 메서드로 추출되면 가독성 측면 등 여러 이점이 있을 것 같아요.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package blackjack | ||
|
|
||
| enum class GameResult(val description: String) { | ||
| WIN("승"), | ||
| LOSE("패") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package blackjack | ||
|
|
||
| import blackjack.domain.Dealer | ||
| import blackjack.domain.Players | ||
|
|
||
| object GameResultCalculator { | ||
| // 딜러와 각 플레이어의 점수를 비교해서 승패를 판별하고 기록함 | ||
| // 딜러가 21을 초과하면 그 시점까지 남아 있던 플레이어들은 가지고 있는 패에 상관 없이 승리한다 | ||
| fun getResult(dealer: Dealer, players: Players) { | ||
|
||
| val scoreOfDealer = dealer.getScore() | ||
| val isDealerLose = scoreOfDealer > BlackJackGame.MAX_SCORE | ||
| players.players.forEach { | ||
| val scoreOfPlayer = it.getScore() | ||
| it.getGameResult(isDealerLose || scoreOfPlayer > scoreOfDealer) | ||
| dealer.getGameResult(!isDealerLose && scoreOfDealer > scoreOfPlayer) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,34 @@ | ||
| package blackjack.domain | ||
|
|
||
| import blackjack.GameResult | ||
| import blackjack.domain.card.Card | ||
| import blackjack.domain.card.CardDeck | ||
| import kotlin.random.Random | ||
| import blackjack.domain.card.Cards | ||
|
|
||
| class Dealer( | ||
| private val cardDeck: CardDeck | ||
| ) { | ||
| class Dealer(name: String, cards: Cards = Cards()) : Player(name, cards) { | ||
| var isFinished = false | ||
| val gameResults = mutableListOf<GameResult>() | ||
|
|
||
| /** | ||
| * 플레이어들에게 2장씩 카드를 분배함 | ||
| */ | ||
| fun dealOutCards(players: Players) { | ||
| repeat(DEAL_OUT_CARD_AMOUNT){ | ||
| players.players.forEach{ dealOutCard(it) } | ||
| constructor(cards: Cards = Cards()) : this(DEALER_DISPLAY_NAME, cards) | ||
|
|
||
| // 17점이 넘으면 호출되어도 더 이상 카드를 추가하지 않는다 | ||
| override fun addCard(card: Card) { | ||
| if (isAddable()) { | ||
| super.addCard(card) | ||
| } else { | ||
| isFinished = true | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 플레이어들에게 1장씩 카드를 분배함 | ||
| */ | ||
| fun dealOutCard(player: Player) { | ||
| player.cards.addCard(peekCard()) | ||
| override fun getGameResult(win: Boolean) { | ||
| gameResults.add(if (win) GameResult.WIN else GameResult.LOSE) | ||
| } | ||
|
||
|
|
||
| /** | ||
| * 카드덱에서 랜덤한 카드를 1장 꺼냄 | ||
| */ | ||
| private fun peekCard(): Card { | ||
| val random = Random.Default | ||
| val randomIndex = random.nextInt(cardDeck.cards.size) | ||
| return cardDeck.peekCard(randomIndex) | ||
| private fun isAddable(): Boolean { | ||
| return !isFinished && getScore() < LIMIT_SCORE | ||
| } | ||
|
|
||
| companion object { | ||
| const val DEAL_OUT_CARD_AMOUNT = 2 | ||
| private const val DEALER_DISPLAY_NAME = "딜러" | ||
| const val LIMIT_SCORE = 17 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package blackjack.domain | ||
|
|
||
| import blackjack.domain.card.Card | ||
| import blackjack.domain.card.CardDeck | ||
| import kotlin.random.Random | ||
|
|
||
| class Distributor( | ||
|
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. CardDeck에 테스트를 작성해주시긴 했지만 이 클래스를 호출한 뒤 dealer나 players에 카드가 정상적으로 분배 되었는지 등을 테스트해볼 수 있을 것 같습니다. |
||
| private val cardDeck: CardDeck | ||
| ) { | ||
|
|
||
| /** | ||
| * 딜러와 플레이어들에게 2장씩 카드를 분배함 | ||
| */ | ||
| fun dealOutCards(dealer: Dealer, players: Players) { | ||
| repeat(DEAL_OUT_CARD_AMOUNT) { | ||
| dealOutCard(dealer) | ||
| players.players.forEach { dealOutCard(it) } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 플레이어들에게 1장씩 카드를 분배함 | ||
| */ | ||
| fun dealOutCard(player: Player) { | ||
| player.addCard(peekCard()) | ||
| } | ||
|
|
||
| /** | ||
| * 카드덱에서 랜덤한 카드를 1장 꺼냄 | ||
| */ | ||
| private fun peekCard(): Card { | ||
| val random = Random.Default | ||
| val randomIndex = random.nextInt(cardDeck.cards.size) | ||
| return cardDeck.peekCard(randomIndex) | ||
| } | ||
|
|
||
| companion object { | ||
| const val DEAL_OUT_CARD_AMOUNT = 2 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,28 @@ | ||
| package blackjack.domain | ||
|
|
||
| import blackjack.GameResult | ||
| import blackjack.domain.card.Card | ||
| import blackjack.domain.card.Cards | ||
|
|
||
| data class Player( | ||
| open class Player( | ||
| val name: String, | ||
| val cards: Cards = Cards() | ||
| ) { | ||
| lateinit var gameResult: GameResult | ||
|
|
||
| override fun toString(): String { | ||
| return name | ||
| } | ||
|
|
||
| open fun addCard(card: Card) { | ||
| cards.addCard(card) | ||
| } | ||
|
|
||
| fun getScore(): Int { | ||
| return cards.getScore() | ||
| } | ||
|
|
||
| open fun getGameResult(win: Boolean) { | ||
| gameResult = if (win) GameResult.WIN else GameResult.LOSE | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package blackjack.domain | ||
|
|
||
| import blackjack.domain.card.Card | ||
| import blackjack.domain.card.CardNumber | ||
| import blackjack.domain.card.CardSymbol | ||
| import blackjack.domain.card.Cards | ||
| import io.kotest.core.spec.style.StringSpec | ||
| import io.kotest.matchers.ints.shouldBeGreaterThan | ||
| import io.kotest.matchers.shouldBe | ||
|
|
||
| class DealerTest : StringSpec({ | ||
| "17점이상의 카드를 가진 딜러는 카드를 받지 않는다" { | ||
| val cardsUnder17 = Cards(mutableListOf(Card(CardNumber.SIX, CardSymbol.DIAMOND), Card(CardNumber.JACK, CardSymbol.DIAMOND))) | ||
| val cardsScore17 = Cards(mutableListOf(Card(CardNumber.SEVEN, CardSymbol.HEART), Card(CardNumber.JACK, CardSymbol.HEART))) | ||
| val cardsOver17 = Cards(mutableListOf(Card(CardNumber.EIGHT, CardSymbol.SPADE), Card(CardNumber.JACK, CardSymbol.SPADE))) | ||
|
|
||
| val firstDealer = Dealer("cardsUnder17", cardsUnder17) | ||
| val scoreOfFirstDealer = firstDealer.getScore() | ||
|
|
||
| val secondDealer = Dealer("cardsScore17", cardsScore17) | ||
| val scoreOfSecondDealer = secondDealer.getScore() | ||
|
|
||
| val thirdDealer = Dealer("cardsOver17", cardsOver17) | ||
| val scoreOfThirdDealer = thirdDealer.getScore() | ||
|
|
||
| val additionalCard = Card(CardNumber.ACE, CardSymbol.CLOVER) | ||
|
|
||
| // when | ||
| firstDealer.addCard(additionalCard) | ||
| secondDealer.addCard(additionalCard) | ||
| thirdDealer.addCard(additionalCard) | ||
|
|
||
| // then | ||
| firstDealer.getScore() shouldBeGreaterThan scoreOfFirstDealer | ||
| secondDealer.getScore() shouldBe scoreOfSecondDealer | ||
| thirdDealer.getScore() shouldBe scoreOfThirdDealer | ||
| } | ||
| }) |
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.
일급 컬렉션 형태로 묶었을 때
players. players와 같이 사용되는 부분이 조금 어색하실텐데요.불변 컬렉션을 사용한다면 Kotlin delegation을 적용하거나, 메서드를 추출하고 컬렉션 인터페이스의 메서드(forEach)를 숨기는 형태로 변경해보시면 좋겠습니다.
아마 지금은 dealOutAdditionalCard 같은 부분에 입출력 로직이 포함되어 있으니 delegation을 적용하시는 편이 조금 더 나을 수 있겠네요.