diff --git a/Readme.md b/Readme.md index e78fb2f0cf..eea457de8a 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +2,18 @@ ## 플레이어 * 플레이어는 이름을 가지고 있다 + * 블랙잭 시작 시 각 플레이어는 카드 2장을 받는다 + * 발급 받은 카드를 항상 공개한다 + * 21이 넘지 않을 때 까지 카드를 받을 수 있다 + +## 딜러 + * 처음 받은 2장이 16이하면 17이상이 될 때까지 카드를 받는다 + * 발급 받은 카드 중 한장만 공개한다 + * 마지막에 카드를 모두 공개한다 + +## 블랙잭 딜러 승패 계산 + * 딜러가 21이 넘으면 플레이어는 모두 승리한다 + * 딜러가 21이 넘지 않으면 21에 가까운 플레이어가 승리한다 ## 블랙잭 카드 * 숫자(1 ~ 10, Jack, Queen, King)와 문양(클로버, 스페이드, 하트, 다이아)으로 구성 @@ -9,7 +21,3 @@ ## 블랙잭 카드 계산 * Ace는 1 또는 11로 계산한다 * King, Queen, Jack은 각각 10으로 계산한다 - -## 블랙잭 드로우 룰 - * 블랙잭 시작 시 각 플레이어는 카드 2장을 받는다 - * 21이 넘지 않을 때 까지 카드를 받을 수 있다 diff --git a/src/main/kotlin/blackjack/Main.kt b/src/main/kotlin/blackjack/Main.kt index 1d0ff97615..fe525902e6 100644 --- a/src/main/kotlin/blackjack/Main.kt +++ b/src/main/kotlin/blackjack/Main.kt @@ -1,26 +1,41 @@ package blackjack +import blackjack.domain.BlackJack import blackjack.domain.ShuffledCardDeck -import blackjack.domain.Player import blackjack.view.InputView import blackjack.view.OutputView fun main() { - val names = InputView.inputNames() - val players = names.map { Player(it, ShuffledCardDeck()) } + val cardDeck = ShuffledCardDeck() + val playerNames = InputView.inputNames() + val blackjack = BlackJack(cardDeck, *playerNames.toTypedArray()) - OutputView.printPlayersCards(players) - players.forEach { obtainCard(it) } - OutputView.printPlayerResult(players) + OutputView.printParticipantOpenedCards(blackjack.openCardsOfParticipant()) + obtainCards(playerNames, blackjack) + OutputView.printCompareResults(blackjack.compareResults()) } -private fun obtainCard(player: Player) { - while (isObtainCard(player)) { - player.obtain() - OutputView.printPlayerCards(player) +private fun obtainCards(playerNames: List, blackjack: BlackJack) { + obtainCardsForPlayers(playerNames, blackjack) + obtainCardsForDealer(blackjack) + OutputView.printParticipantHands(blackjack.participants()) +} + +private fun obtainCardsForDealer(blackjack: BlackJack) { + while (blackjack.isDealerObtainable()) { + blackjack.obtainDealerCard() + OutputView.printObtainDealerCard() } } -private fun isObtainCard(player: Player): Boolean { - return player.isObtainable() && InputView.inputIsObtainCard(player.name) +private fun obtainCardsForPlayers(playerNames: List, blackjack: BlackJack) { + playerNames.forEach { obtainCardsForPlayer(it, blackjack) } +} + +private fun obtainCardsForPlayer(name: String, blackjack: BlackJack) { + val wantToTake = { InputView.inputIsObtainCard(name) } + while (blackjack.isPlayerObtainable(name, wantToTake)) { + val cards = blackjack.obtainPlayerCard(name) + OutputView.printParticipantCards(name, cards) + } } diff --git a/src/main/kotlin/blackjack/domain/BlackJack.kt b/src/main/kotlin/blackjack/domain/BlackJack.kt new file mode 100644 index 0000000000..c796052f85 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/BlackJack.kt @@ -0,0 +1,43 @@ +package blackjack.domain + +import java.util.function.Supplier + +class BlackJack( + private val cardDeck: CardDeck, + vararg names: String +) { + private val dealer = Dealer(cardDeck.next(), cardDeck.next()) + private val players = names.map { Player(it, cardDeck.next(), cardDeck.next()) } + + fun openCardsOfParticipant(): Map> { + return participants().associate { it.name to it.openCards() } + } + + fun isDealerObtainable(): Boolean { + return dealer.isObtainable() + } + + fun obtainDealerCard(): List { + dealer.obtain(cardDeck.next()) + return dealer.hands + } + + fun isPlayerObtainable(name: String, wantToTake: Supplier): Boolean { + val player = players.first { it.name == name } + return player.isObtainable() && wantToTake.get() + } + + fun obtainPlayerCard(name: String): List { + val player = players.first { it.name == name } + player.obtain(cardDeck.next()) + return player.hands + } + + fun compareResults(): Map { + return dealer.compareWith(*players.toTypedArray()) + } + + fun participants(): List { + return players + listOf(dealer) + } +} diff --git a/src/main/kotlin/blackjack/domain/Cards.kt b/src/main/kotlin/blackjack/domain/Cards.kt index cf43faccda..f8631e8d1c 100644 --- a/src/main/kotlin/blackjack/domain/Cards.kt +++ b/src/main/kotlin/blackjack/domain/Cards.kt @@ -1,5 +1,7 @@ package blackjack.domain +const val BLACKJACK_SCORE = 21 + class Cards ( cards: List, ) { @@ -10,7 +12,7 @@ class Cards ( constructor(vararg cards: Card): this(cards.toList()) fun sum(): Int { - if (BLACKJACK < sumOfMaximum()) { + if (BLACKJACK_SCORE < sumOfMaximum()) { return sumOfMinimum() } return sumOfMaximum() @@ -32,12 +34,4 @@ class Cards ( fun add(card: Card) { cards.add(card) } - - fun isLessThanBlackjack(): Boolean { - return sum() < BLACKJACK - } - - companion object { - private const val BLACKJACK = 21 - } } diff --git a/src/main/kotlin/blackjack/domain/CompareResult.kt b/src/main/kotlin/blackjack/domain/CompareResult.kt new file mode 100644 index 0000000000..1a14dc60d0 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/CompareResult.kt @@ -0,0 +1,9 @@ +package blackjack.domain + +enum class CompareResult { + DEALER_LOSE, + DRAW, + DEALER_WIN + ; + +} diff --git a/src/main/kotlin/blackjack/domain/Dealer.kt b/src/main/kotlin/blackjack/domain/Dealer.kt new file mode 100644 index 0000000000..9b42cface7 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Dealer.kt @@ -0,0 +1,36 @@ +package blackjack.domain + +class Dealer(card1: Card, card2: Card): Participant("딜러", card1, card2) { + + override fun isObtainable(): Boolean { + return sumOfCards() < 17 + } + + override fun openCards(): List { + return listOf(hands.first()) + } + + fun compareWith(vararg players: Player): Map { + return players.associate { it.name to compareWith(it) } + } + + private fun compareWith(player: Player): CompareResult { + if (isMoreThanBlackjack()) { + return CompareResult.DEALER_LOSE + } + if (player.isMoreThanBlackjack()) { + return CompareResult.DEALER_WIN + } + return compareBySumOfCards(player) + } + + private fun compareBySumOfCards(player: Player): CompareResult { + if (sumOfCards() == player.sumOfCards()) { + return CompareResult.DRAW + } + if (sumOfCards() < player.sumOfCards()) { + return CompareResult.DEALER_LOSE + } + return CompareResult.DEALER_WIN + } +} diff --git a/src/main/kotlin/blackjack/domain/Participant.kt b/src/main/kotlin/blackjack/domain/Participant.kt new file mode 100644 index 0000000000..84bd4525c0 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Participant.kt @@ -0,0 +1,26 @@ +package blackjack.domain + +abstract class Participant( + val name: String, card1: Card, card2: Card, +) { + private val cards = Cards(card1, card2) + + val hands + get() = cards.values + + fun obtain(card: Card) { + require(isObtainable()) { "카드를 획득할 수 없습니다." } + cards.add(card) + } + + fun sumOfCards(): Int { + return cards.sum() + } + + fun isMoreThanBlackjack(): Boolean { + return sumOfCards() > BLACKJACK_SCORE + } + + abstract fun isObtainable(): Boolean + abstract fun openCards(): List +} diff --git a/src/main/kotlin/blackjack/domain/Player.kt b/src/main/kotlin/blackjack/domain/Player.kt index 5e271dd386..e8077bd13d 100644 --- a/src/main/kotlin/blackjack/domain/Player.kt +++ b/src/main/kotlin/blackjack/domain/Player.kt @@ -1,23 +1,16 @@ package blackjack.domain class Player( - val name: String, - private val cardDeck: CardDeck, -) { - private val cards = Cards(cardDeck.next(), cardDeck.next()) - val hands - get() = cards.values + name: String, + card1: Card, + card2: Card, +) : Participant(name, card1, card2) { - fun obtain() { - require(isObtainable()) { "카드를 획득할 수 없습니다." } - cards.add(cardDeck.next()) + override fun isObtainable(): Boolean { + return sumOfCards() < BLACKJACK_SCORE } - fun sumOfCards(): Int { - return cards.sum() - } - - fun isObtainable(): Boolean { - return cards.isLessThanBlackjack() + override fun openCards(): List { + return hands.subList(0, 2) } } diff --git a/src/main/kotlin/blackjack/domain/ShuffledCardDeck.kt b/src/main/kotlin/blackjack/domain/ShuffledCardDeck.kt index 37799618e9..59d31ec6ec 100644 --- a/src/main/kotlin/blackjack/domain/ShuffledCardDeck.kt +++ b/src/main/kotlin/blackjack/domain/ShuffledCardDeck.kt @@ -11,8 +11,7 @@ class ShuffledCardDeck: CardDeck { } private fun deck(): Iterator { - return (0 until 4) - .flatMap { cards() } + return cards() .shuffled() .iterator() } diff --git a/src/main/kotlin/blackjack/view/OutputView.kt b/src/main/kotlin/blackjack/view/OutputView.kt index 08abeb5f78..5706ede258 100644 --- a/src/main/kotlin/blackjack/view/OutputView.kt +++ b/src/main/kotlin/blackjack/view/OutputView.kt @@ -1,21 +1,24 @@ package blackjack.view import blackjack.domain.Card +import blackjack.domain.CompareResult import blackjack.domain.Number -import blackjack.domain.Player +import blackjack.domain.Participant import blackjack.domain.Shape object OutputView { - fun printPlayersCards(players: List) { - val names = players.joinToString(separator = ", ") { it.name } + fun printParticipantOpenedCards(openCards: Map>) { + val names = openCards.keys.joinToString(separator = ", ") println("${names}에게 2장의 카드를 나누었습니다") - players.forEach { printPlayerCards(it) } + openCards.entries.forEach { + printParticipantCards(it.key, it.value) + } } - fun printPlayerCards(player: Player) { - val hands = player.hands.joinToString(", ") { cardText(it) } - println("${player.name} 카드 : $hands") + fun printParticipantCards(name: String, cards: List) { + val cardsText = cards.joinToString(", ") { cardText(it) } + println("${name} 카드 : $cardsText") } private fun cardText(card: Card): String { @@ -41,10 +44,41 @@ object OutputView { } } - fun printPlayerResult(players: List) { - for (player in players) { - val hands = player.hands.joinToString(", ") { cardText(it) } - println("${player.name} 카드 : $hands - 결과: ${player.sumOfCards()}") + fun printObtainDealerCard() { + println("딜러는 16이하라 한장의 카드를 더 받았습니다.") + } + + fun printParticipantHands(participants: List) { + for (participant in participants) { + val hands = participant.hands.joinToString(", ") { cardText(it) } + println("${participant.name} 카드 : $hands - 결과: ${participant.sumOfCards()}") + } + } + + fun printCompareResults(compareResults: Map) { + println("## 최종 승패") + printDealerResult(compareResults) + printPlayerResult(compareResults) + } + + private fun printDealerResult(compareResults: Map) { + val dealerWinCount = compareResults.values.count { it == CompareResult.DEALER_WIN } + val dealerDrawCount = compareResults.values.count { it == CompareResult.DRAW } + val dealerLoseCount = compareResults.values.count { it == CompareResult.DEALER_LOSE } + println("딜러 : ${dealerWinCount}승 ${dealerDrawCount}무 ${dealerLoseCount}패") + } + + private fun printPlayerResult(compareResults: Map) { + compareResults.forEach { (name, result) -> + println("${name} ${playerResultText(result)}") + } + } + + private fun playerResultText(result: CompareResult): String { + return when(result) { + CompareResult.DEALER_LOSE -> "승" + CompareResult.DRAW -> "무" + CompareResult.DEALER_WIN -> "패" } } } diff --git a/src/test/kotlin/blackjack/domain/BlackjackTest.kt b/src/test/kotlin/blackjack/domain/BlackjackTest.kt new file mode 100644 index 0000000000..ff79aadd04 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/BlackjackTest.kt @@ -0,0 +1,138 @@ +package blackjack.domain + +import io.kotest.assertions.fail +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource + +class BlackjackTest { + + @Test + fun `블랙잭 오픈 카드 공개`() { + val dealerInitCards = listOf(Card.diamond(Number.NINE), Card.diamond(Number.JACK)) + val jasonInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val pobiInitCards = listOf(Card.heart(Number.ACE), Card.heart(Number.QUEEN)) + val cardDeck = cardDeck(dealerInitCards + jasonInitCards + pobiInitCards) + val blackjack = BlackJack(cardDeck, "jason", "pobi") + + val actual = blackjack.openCardsOfParticipant() + + assertThat(actual) + .containsEntry("딜러", listOf(Card.diamond(Number.NINE))) + .containsEntry("jason", listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN))) + .containsEntry("pobi", listOf(Card.heart(Number.ACE), Card.heart(Number.QUEEN))) + } + + @Test + fun `딜러 카드 얻기`() { + val dealerInitCards = listOf(Card.diamond(Number.FIVE), Card.diamond(Number.JACK)) + val jasonInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val dealerAdditionCards = listOf(Card.diamond(Number.TWO)) + val cardDeck = cardDeck( + dealerInitCards + jasonInitCards + dealerAdditionCards + ) + val blackjack = BlackJack(cardDeck, "jason") + + val actual = blackjack.obtainDealerCard() + + assertThat(actual) + .isEqualTo(listOf(Card.diamond(Number.FIVE), Card.diamond(Number.JACK), Card.diamond(Number.TWO))) + } + + @ParameterizedTest + @MethodSource("dealerInitCardsForCheckObtainable") + fun `딜러 카드 획득 여부 확인`(dealerInitCards: List, expected: Boolean) { + val jasonInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val cardDeck = cardDeck( + dealerInitCards + jasonInitCards + ) + val blackjack = BlackJack(cardDeck, "jason") + + val actual = blackjack.isDealerObtainable() + + assertThat(actual).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("playerInitCardsForCheckObtainable") + fun `플레이어 카드 획득 여부 확인`(playerInitCards: List, expected: Boolean) { + val dealerInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val cardDeck = cardDeck( + dealerInitCards + playerInitCards + ) + val blackjack = BlackJack(cardDeck, "jason") + + val actual = blackjack.isPlayerObtainable("jason") { true } + + assertThat(actual).isEqualTo(expected) + } + + @Test + fun `플레이어가 카드를 획득할 수 없으면 획득 여부도 묻지 않는다`() { + val dealerInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val playerInitCards = listOf(Card.diamond(Number.ACE), Card.diamond(Number.JACK)) + val cardDeck = cardDeck( + dealerInitCards + playerInitCards + ) + val blackjack = BlackJack(cardDeck, "jason") + + blackjack.isPlayerObtainable("jason") { fail("획득 여부를 묻지 않아야 합니다.") } + } + + @Test + fun `플레이어 카드 얻기`() { + val dealerInitCards = listOf(Card.diamond(Number.NINE), Card.diamond(Number.JACK)) + val jasonInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val jasonAdditionCards = listOf(Card.clover(Number.TWO)) + val cardDeck = cardDeck( + dealerInitCards + jasonInitCards + jasonAdditionCards + ) + val blackjack = BlackJack(cardDeck, "jason") + + val actual = blackjack.obtainPlayerCard("jason") + + assertThat(actual) + .isEqualTo(listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN), Card.clover(Number.TWO))) + } + + @Test + fun `블랙잭 결과 확인`() { + val dealerInitCards = listOf(Card.diamond(Number.NINE), Card.diamond(Number.JACK)) + val jasonInitCards = listOf(Card.clover(Number.EIGHT), Card.clover(Number.TEN)) + val pobiInitCards = listOf(Card.heart(Number.ACE), Card.heart(Number.QUEEN)) + val cardDeck = cardDeck(dealerInitCards + jasonInitCards + pobiInitCards) + val blackjack = BlackJack(cardDeck, "jason", "pobi") + + val actual = blackjack.compareResults() + + assertThat(actual) + .containsEntry("jason", CompareResult.DEALER_WIN) + .containsEntry("pobi", CompareResult.DEALER_LOSE) + } + + + private fun cardDeck(cards: List): CardDeck { + val iterator = cards.iterator() + return CardDeck { iterator.next() } + } + + companion object { + @JvmStatic + fun dealerInitCardsForCheckObtainable(): List { + return listOf( + Arguments.of(listOf(Card.diamond(Number.SIX), Card.diamond(Number.JACK)), true), + Arguments.of(listOf(Card.diamond(Number.SEVEN), Card.diamond(Number.JACK)), false) + ) + } + + @JvmStatic + fun playerInitCardsForCheckObtainable(): List { + return listOf( + Arguments.of(listOf(Card.diamond(Number.QUEEN), Card.diamond(Number.JACK)), true), + Arguments.of(listOf(Card.diamond(Number.ACE), Card.diamond(Number.JACK)), false) + ) + } + } +} diff --git a/src/test/kotlin/blackjack/domain/DealerTest.kt b/src/test/kotlin/blackjack/domain/DealerTest.kt new file mode 100644 index 0000000000..9c61bf62e3 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/DealerTest.kt @@ -0,0 +1,146 @@ +package blackjack.domain + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + +class DealerTest { + + @Test + fun `딜러는 발급 받은 첫 카드만 공개한다`() { + val dealer = Dealer(Card.diamond(Number.TEN), Card.heart(Number.FIVE)) + + val actual = dealer.openCards() + + assertThat(actual).containsExactly(Card.diamond(Number.TEN)) + } + + @Test + fun `딜러는 16점 이하인 경우 카드를 발급 받을 수 있다`() { + val dealer = Dealer(Card.diamond(Number.TEN), Card.heart(Number.SIX)) + + dealer.obtain(Card.spade(Number.ACE)) + + assertThat(dealer.openCards()).containsExactly(Card.diamond(Number.TEN)) + assertThat(dealer.hands).containsExactlyInAnyOrder( + Card.diamond(Number.TEN), Card.heart(Number.SIX), Card.spade(Number.ACE) + ) + } + + @Test + fun `딜러는 17점 이상인 경우 카드를 발급 받을 수 없다`() { + val dealer = Dealer(Card.diamond(Number.TEN), Card.heart(Number.SEVEN)) + + assertThrows { dealer.obtain(Card.spade(Number.ACE)) } + assertThat(dealer.hands).containsExactlyInAnyOrder( + Card.diamond(Number.TEN), Card.heart(Number.SEVEN) + ) + } + + @ParameterizedTest + @CsvSource(value = ["TEN, SIX, true", "TEN, SEVEN, false"]) + fun `딜러는 카드 발급 여부를 확인할 수 있다`(num1: Number, num2: Number, expect: Boolean) { + val dealer = Dealer(Card.diamond(num1), Card.heart(num2)) + + assertThat(dealer.isObtainable()).isEqualTo(expect) + } + + @ParameterizedTest + @CsvSource(value = ["TEN, JACK, TWO", "ACE, FIVE, FIVE", "ACE, FOUR, FIVE"]) + fun `딜러가 21이 넘으면 플레이어는 항상 승리한다`(num1: Number, num2: Number, num3: Number) { + // arrange + val dealer = Dealer( + Card.diamond(Number.TEN), Card.heart(Number.SIX) + ).apply { obtain(Card.spade(Number.SIX)) } + val player = Player( + "player", + Card.spade(num1), Card.clover(num2) + ).apply { obtain(Card.heart(num3)) } + + // act + val actual = dealer.compareWith(player) + + // assert + assertThat(actual) + .isEqualTo(mapOf("player" to CompareResult.DEALER_LOSE)) + } + + @ParameterizedTest + @CsvSource(value = ["TEN, TEN, DRAW", "TEN, ACE, DEALER_LOSE", "TEN, NINE, DEALER_WIN"]) + fun `딜러와 플레이어가 21이하면 21에 더 가까운 플레이어가 승리한다`(num1: Number, num2: Number, expect: CompareResult) { + // arrange + val dealer = Dealer( + Card.diamond(Number.TEN), Card.heart(Number.TEN) + ) + val player = Player( + "player", + Card.spade(num1), Card.clover(num2) + ) + + // act + val actual = dealer.compareWith(player) + + // assert + assertThat(actual) + .isEqualTo(mapOf("player" to expect)) + } + + @Test + fun `딜러는 21이하이고 플레이어가 21을 넘으면 딜러가 승리한다`() { + // arrange + val dealer = Dealer( + Card.diamond(Number.TEN), Card.heart(Number.ACE) + ) + val player = Player( + "player", + Card.spade(Number.TEN), Card.clover(Number.JACK) + ).apply { obtain(Card.heart(Number.TWO)) } + + // act + val actual = dealer.compareWith(player) + + // assert + assertThat(actual) + .isEqualTo(mapOf("player" to CompareResult.DEALER_WIN)) + } + + @Test + fun `딜러는 여러 플레이어의 승패 결과를 수집하여 반환한다`() { + // arrange + val dealer = Dealer( + Card.diamond(Number.TEN), Card.diamond(Number.JACK) + ) + val player1 = Player( + "player1", + Card.spade(Number.TEN), Card.spade(Number.ACE) + ) + val player2 = Player( + "player2", + Card.clover(Number.TEN), Card.clover(Number.NINE) + ) + val player3 = Player( + "player3", + Card.heart(Number.TEN), Card.heart(Number.JACK) + ) + + // act + val actual = dealer.compareWith(player1, player2, player3) + + // assert + assertThat(actual) + .isEqualTo( + mapOf( + "player1" to CompareResult.DEALER_LOSE, + "player2" to CompareResult.DEALER_WIN, + "player3" to CompareResult.DRAW, + ) + ) + } + + private fun cardDeck(vararg cards: Card): CardDeck { + val iterator = cards.iterator() + return CardDeck { iterator.next() } + } +} diff --git a/src/test/kotlin/blackjack/domain/PlayerTest.kt b/src/test/kotlin/blackjack/domain/PlayerTest.kt index 3856e2a2b6..793f189ab2 100644 --- a/src/test/kotlin/blackjack/domain/PlayerTest.kt +++ b/src/test/kotlin/blackjack/domain/PlayerTest.kt @@ -10,43 +10,58 @@ class PlayerTest { @Test fun `플레이어는 이름과 2장의 카드를 처음에 가진다`() { val player = Player( - "pobi", cardDeck(Card.diamond(Number.EIGHT), Card.heart(Number.TEN)) + "pobi", Card.diamond(Number.EIGHT), Card.heart(Number.TEN) ) assertThat(player.name).isEqualTo("pobi") - assertThat(player.sumOfCards()).isEqualTo(18) + assertThat(player.openCards()).containsExactlyInAnyOrder( + Card.diamond(Number.EIGHT), Card.heart(Number.TEN) + ) + assertThat(player.hands).containsExactlyInAnyOrder( + Card.diamond(Number.EIGHT), Card.heart(Number.TEN) + ) } @Test - fun `플레이어 카드를 획득할 수 있다`() { + fun `21 미만이면 플레이어는 카드를 획득할 수 있다`() { val player = Player( - "pobi", cardDeck(Card.diamond(Number.TWO), Card.heart(Number.THREE), Card.spade(Number.ACE)) + "pobi", Card.diamond(Number.QUEEN), Card.heart(Number.JACK) ) - player.obtain() + player.obtain(Card.spade(Number.ACE)) - assertThat(player.sumOfCards()).isEqualTo(16) + assertThat(player.openCards()).containsExactlyInAnyOrder( + Card.diamond(Number.QUEEN), Card.heart(Number.JACK) + ) + assertThat(player.hands).containsExactlyInAnyOrder( + Card.diamond(Number.QUEEN), Card.heart(Number.JACK), Card.spade(Number.ACE) + ) } @Test fun `21 이상이면 플레이어는 카드를 획득할 수 없다`() { val player = Player( - "pobi", cardDeck(Card.diamond(Number.ACE), Card.heart(Number.JACK), Card.spade(Number.ACE)) + "pobi", Card.diamond(Number.ACE), Card.heart(Number.JACK) ) + assertThat(player.isObtainable()).isFalse assertThrows { - player.obtain() + player.obtain(Card.spade(Number.ACE)) } - assertThat(player.isObtainable()).isFalse + assertThat(player.hands).containsExactlyInAnyOrder( + Card.diamond(Number.ACE), Card.heart(Number.JACK) + ) } @Test - fun `21 미만이면 플레이어는 카드를 획득할 수 있다`() { + fun `플레이어는 발급 받은 카드의 총합을 계산한다`() { val player = Player( - "pobi", cardDeck(Card.diamond(Number.QUEEN), Card.heart(Number.JACK)) + "pobi", Card.diamond(Number.EIGHT), Card.heart(Number.TEN) ) - assertThat(player.isObtainable()).isTrue() + val actual = player.sumOfCards() + + assertThat(actual).isEqualTo(18) } private fun cardDeck(vararg cards: Card): CardDeck {