diff --git a/README.md b/README.md index b4a4e9446..2371134c2 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - 입력 - [x] 게임에 참여할 사람을 입력받는다. - [x] 한장의 카드를 더 받을지 말지 입력받는다. + - [x] 플레이어의 배팅 금액을 입력받는다. - 출력 - [x] 플레이어가 가지고 있는 카드를 출력한다. @@ -37,6 +38,19 @@ - [x] 딜러는 처음에 받은 2장의 합계가 16이하라면 반드시 한장의 카드를 받는다. - [x] 16점 이하면 계속 카드를 뽑는다. - [x] 17점 이상이면 카드를 추가로 받을 수 없다. + - [x] 상태라는 클래스가 있다. + - [x] 히트라는 상태가 있다 + - [x] 히트는 먼저 받은 두 장의 합이 21에 못미치는 경우다. + - [x] 버스트라는 상태가 있다. + - [x] 버스트는 카드 총합이 21을 넘은 경우다. + - [] 카드를 추가로 뽑아 21을 초과하는 경우 배팅 금액을 모두 잃는다. + - [] 딜러가 버스트라면 남아 있는 플레이어들은 베팅 금액을 받는다. + - [x] 스탠드라는 상태가 있다. + - [x] 스탠드는 더 이상 카드를 뽑지 않는 경우다. + - [x] 블랙잭 이라는 생태가 있다. + - [x] 처음 받은 두 장의 카드의 총 합이 21이 되는 경우이다. + - [] 베팅 금액의 1.5배를 딜러에게 받는다. + - [] 딜러와 플레이어 동시에 블랙잭인 경우 플레이어는 베팅한 금액을 돌려받는다. ## 용어 정리 @@ -45,4 +59,8 @@ - 플레이어가 버스트 당하면 패배가 확정된다. - 딜러가 버스트 당하면 그 시점까지 남아있는 모든 플레이어가 승리한다. - 블랙잭(Blackjack) - - A한장과 10, J, Q, L 로 21을 이루는 경우 베팅 금액의 1.5배를 돌려준다. \ No newline at end of file + - A한장과 10, J, Q, L 로 21을 이루는 경우 베팅 금액의 1.5배를 돌려준다. +- 히트(Hit) + - 먼저 받은 두 장의 합이 21에 못미치는 경우 +- 스탠드(Stand) + - 더 이상 카드를 뽑지 않고 넘어간 경우 \ No newline at end of file diff --git a/src/main/kotlin/blackjack/GameManager.kt b/src/main/kotlin/blackjack/GameManager.kt index 3af5e814a..cd081d5f9 100644 --- a/src/main/kotlin/blackjack/GameManager.kt +++ b/src/main/kotlin/blackjack/GameManager.kt @@ -1,6 +1,9 @@ package blackjack import blackjack.card.CardDeck +import blackjack.supoort.GameResultGenerator +import blackjack.supoort.ScoreCalculator +import blackjack.participant.BettingAmount import blackjack.participant.Dealer import blackjack.participant.Name import blackjack.participant.Player @@ -23,27 +26,24 @@ class GameManager( players.forEach { it.drawCard(CardDeck.draw(FIRST_DRAW)) } dealer.drawCard(CardDeck.draw(FIRST_DRAW)) - outputManager.printFirstTurn2(players) + outputManager.printFirstTurn(players) outputManager.printPlayersAndDealerCards(players, dealer) - val result = playBlackJack() + playBlackJack() - players.forEach { - outputManager.printPlayerResultGame(it) - } + val result = GameResultGenerator.generateGameResult(players, dealer) outputManager.printDealerResultGame(dealer) + players.forEach(outputManager::printPlayerResultGame) outputManager.printResult(result) } - private fun playBlackJack(): GameResult { + private fun playBlackJack() { players.forEach { playerDraw(it) } dealerDraw(dealer) - - return GameResult(players, dealer) } private fun playerDraw(player: Player) { @@ -62,7 +62,6 @@ class GameManager( while (dealer.shouldDraw()) { outputManager.printDealerCanDrawMessage() dealer.drawCard(CardDeck.draw(DRAW_CARD)) - outputManager.printDealerCards(dealer) } } @@ -70,7 +69,7 @@ class GameManager( private fun joinPlayers(): List { val playerNames: List = inputManager.inputPlayerNames() - return playerNames.map { Player(Name(it), ScoreCalculator()) } + return playerNames.map { Player(Name(it), BettingAmount(inputManager.inputBettingAmount(it))) } } private fun joinDealer(): Dealer { diff --git a/src/main/kotlin/blackjack/GameResult.kt b/src/main/kotlin/blackjack/GameResult.kt deleted file mode 100644 index 1c17ea49c..000000000 --- a/src/main/kotlin/blackjack/GameResult.kt +++ /dev/null @@ -1,35 +0,0 @@ -package blackjack - -import blackjack.participant.Dealer -import blackjack.participant.Name -import blackjack.participant.Player -import blackjack.participant.Result - -class GameResult( - players: List, - dealer: Dealer -) { - val resultMap: Map - - init { - - val (winCount, loseCount) = when { - dealer.isBust -> players.partition { !it.isBust } - else -> players.partition { it.resultScore() < dealer.resultScore() } - } - - val playerResult = mutableMapOf().apply { - winCount.map { this[it.name] = Result.Win() } - loseCount.map { this[it.name] = Result.Lose() } - } - - resultMap = mapOf( - Name("딜러") to Result.DealerResult(winCount.size, loseCount.size) - ) + playerResult - } - - companion object { - private const val WIN: String = "승" - private const val LOSE: String = "패" - } -} diff --git a/src/main/kotlin/blackjack/participant/BettingAmount.kt b/src/main/kotlin/blackjack/participant/BettingAmount.kt new file mode 100644 index 000000000..6c16cb1d2 --- /dev/null +++ b/src/main/kotlin/blackjack/participant/BettingAmount.kt @@ -0,0 +1,25 @@ +package blackjack.participant + +import kotlin.math.roundToInt + +@JvmInline +value class BettingAmount( + val amount: Int +) { + + fun winToBlackjack(): BettingAmount { + return BettingAmount((amount * 1.5).roundToInt()) + } + + operator fun unaryMinus(): BettingAmount { + return BettingAmount(amount * -1) + } +} + +infix operator fun BettingAmount.plus(bettingAmount: BettingAmount): BettingAmount { + return BettingAmount(amount + bettingAmount.amount) +} + +infix operator fun BettingAmount.minus(bettingAmount: BettingAmount): BettingAmount { + return BettingAmount(amount - bettingAmount.amount) +} diff --git a/src/main/kotlin/blackjack/participant/BlackjackStrategy.kt b/src/main/kotlin/blackjack/participant/BlackjackStrategy.kt index ccfbcc6fb..ceb2ef383 100644 --- a/src/main/kotlin/blackjack/participant/BlackjackStrategy.kt +++ b/src/main/kotlin/blackjack/participant/BlackjackStrategy.kt @@ -1,24 +1,48 @@ package blackjack.participant -import blackjack.ScoreCalculator +import blackjack.supoort.ScoreCalculator import blackjack.card.BlackJackCard +import blackjack.participant.status.Blackjack +import blackjack.participant.status.Bust +import blackjack.participant.status.Hit +import blackjack.participant.status.Stand +import blackjack.participant.status.Status class BlackjackStrategy( private val scoreCalculator: ScoreCalculator, ) { var cards: List = emptyList() + var status: Status = Hit() - val isBust get() = resultScore() > BUST + fun isBust(): Boolean { + return resultScore() > BLACKJACK + } fun drawCard(cards: List) { this.cards += cards + changeStatus(cards) + } + + private fun changeStatus(cards: List) { + when { + !isFirstTurn(cards) && !isBust() -> status = Stand() + !isFirstTurn(cards) && isBust() -> status = Bust() + isFirstTurn(cards) && isBlackjack() -> status = Blackjack() + } } + private fun isFirstTurn(cards: List): Boolean = cards.size == FIRST_TURN_DRAW + fun resultScore(): Int { return scoreCalculator.calculateGameScore(cards) } + private fun isBlackjack(): Boolean { + return resultScore() == BLACKJACK + } + companion object { - private const val BUST: Int = 21 + private const val BLACKJACK: Int = 21 + private const val FIRST_TURN_DRAW: Int = 2 } -} \ No newline at end of file +} diff --git a/src/main/kotlin/blackjack/participant/Dealer.kt b/src/main/kotlin/blackjack/participant/Dealer.kt index 14784b8fa..80a3d268b 100644 --- a/src/main/kotlin/blackjack/participant/Dealer.kt +++ b/src/main/kotlin/blackjack/participant/Dealer.kt @@ -1,16 +1,15 @@ package blackjack.participant -import blackjack.ScoreCalculator import blackjack.card.BlackJackCard +import blackjack.supoort.ScoreCalculator class Dealer( scoreCalculator: ScoreCalculator -) { +) { private val blackjackStrategy: BlackjackStrategy = BlackjackStrategy(scoreCalculator) - + var bettingAmount: BettingAmount = BettingAmount(0) val cards get() = blackjackStrategy.cards - - val isBust get() = blackjackStrategy.isBust + val status get() = blackjackStrategy.status fun drawCard(cards: List) { blackjackStrategy.drawCard(cards) diff --git a/src/main/kotlin/blackjack/participant/Name.kt b/src/main/kotlin/blackjack/participant/Name.kt index 98da8e574..d3020bacc 100644 --- a/src/main/kotlin/blackjack/participant/Name.kt +++ b/src/main/kotlin/blackjack/participant/Name.kt @@ -3,4 +3,12 @@ package blackjack.participant @JvmInline value class Name( val value: String -) \ No newline at end of file +) { + init { + require(value.isNotBlank()) { VALID_MESSAGE } + } + + companion object { + private const val VALID_MESSAGE: String = "빈 값은 이름이 될 수 없습니다." + } +} diff --git a/src/main/kotlin/blackjack/participant/Player.kt b/src/main/kotlin/blackjack/participant/Player.kt index f4a08da4f..0dc6e22d3 100644 --- a/src/main/kotlin/blackjack/participant/Player.kt +++ b/src/main/kotlin/blackjack/participant/Player.kt @@ -1,18 +1,20 @@ package blackjack.participant -import blackjack.ScoreCalculator +import blackjack.supoort.ScoreCalculator import blackjack.card.BlackJackCard class Player( val name: Name, - scoreCalculator: ScoreCalculator + val bettingAmount: BettingAmount = BettingAmount(0), + scoreCalculator: ScoreCalculator = ScoreCalculator() ) { + constructor(name: Name, scoreCalculator: ScoreCalculator) : this(name, BettingAmount(0), scoreCalculator) private val blackjackStrategy: BlackjackStrategy = BlackjackStrategy(scoreCalculator) val cards get() = blackjackStrategy.cards - val isBust get() = blackjackStrategy.isBust + val status get() = blackjackStrategy.status fun drawCard(cards: List) { blackjackStrategy.drawCard(cards) @@ -23,6 +25,6 @@ class Player( } fun shouldDraw(): Boolean { - return !blackjackStrategy.isBust + return !blackjackStrategy.isBust() } } diff --git a/src/main/kotlin/blackjack/participant/Result.kt b/src/main/kotlin/blackjack/participant/Result.kt index 5950390c6..8d6a92261 100644 --- a/src/main/kotlin/blackjack/participant/Result.kt +++ b/src/main/kotlin/blackjack/participant/Result.kt @@ -1,7 +1,6 @@ package blackjack.participant sealed interface Result { - class Win : Result - class Lose : Result - class DealerResult(val win: Int, val lose: Int) : Result + object Win : Result + object Lose : Result } diff --git a/src/main/kotlin/blackjack/participant/status/Blackjack.kt b/src/main/kotlin/blackjack/participant/status/Blackjack.kt new file mode 100644 index 000000000..a2e19e658 --- /dev/null +++ b/src/main/kotlin/blackjack/participant/status/Blackjack.kt @@ -0,0 +1,13 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result + +class Blackjack : Status { + override fun calculateBettingAmount(result: Result, bettingAmount: BettingAmount): BettingAmount { + return when(result) { + is Result.Win -> bettingAmount.winToBlackjack() + is Result.Lose -> BettingAmount(0) + } + } +} diff --git a/src/main/kotlin/blackjack/participant/status/Bust.kt b/src/main/kotlin/blackjack/participant/status/Bust.kt new file mode 100644 index 000000000..f6821e3fc --- /dev/null +++ b/src/main/kotlin/blackjack/participant/status/Bust.kt @@ -0,0 +1,10 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result + +class Bust : Status { + override fun calculateBettingAmount(result: Result, bettingAmount: BettingAmount): BettingAmount { + return -bettingAmount + } +} diff --git a/src/main/kotlin/blackjack/participant/status/Hit.kt b/src/main/kotlin/blackjack/participant/status/Hit.kt new file mode 100644 index 000000000..5490d3005 --- /dev/null +++ b/src/main/kotlin/blackjack/participant/status/Hit.kt @@ -0,0 +1,13 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result + +class Hit : Status { + override fun calculateBettingAmount(result: Result, bettingAmount: BettingAmount): BettingAmount { + return when (result) { + is Result.Win -> bettingAmount + is Result.Lose -> -bettingAmount + } + } +} diff --git a/src/main/kotlin/blackjack/participant/status/Stand.kt b/src/main/kotlin/blackjack/participant/status/Stand.kt new file mode 100644 index 000000000..ef592412e --- /dev/null +++ b/src/main/kotlin/blackjack/participant/status/Stand.kt @@ -0,0 +1,13 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result + +class Stand : Status { + override fun calculateBettingAmount(result: Result, bettingAmount: BettingAmount): BettingAmount { + return when(result) { + is Result.Win -> bettingAmount + is Result.Lose -> -bettingAmount + } + } +} diff --git a/src/main/kotlin/blackjack/participant/status/Status.kt b/src/main/kotlin/blackjack/participant/status/Status.kt new file mode 100644 index 000000000..bd3adf01e --- /dev/null +++ b/src/main/kotlin/blackjack/participant/status/Status.kt @@ -0,0 +1,8 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result + +interface Status { + fun calculateBettingAmount(result: Result, bettingAmount: BettingAmount): BettingAmount +} \ No newline at end of file diff --git a/src/main/kotlin/blackjack/supoort/GameResult.kt b/src/main/kotlin/blackjack/supoort/GameResult.kt new file mode 100644 index 000000000..5f8582231 --- /dev/null +++ b/src/main/kotlin/blackjack/supoort/GameResult.kt @@ -0,0 +1,8 @@ +package blackjack.supoort + +import blackjack.participant.BettingAmount +import blackjack.participant.Name + +data class GameResult( + val resultMap: Map +) diff --git a/src/main/kotlin/blackjack/supoort/GameResultGenerator.kt b/src/main/kotlin/blackjack/supoort/GameResultGenerator.kt new file mode 100644 index 000000000..58aed4a49 --- /dev/null +++ b/src/main/kotlin/blackjack/supoort/GameResultGenerator.kt @@ -0,0 +1,49 @@ +package blackjack.supoort + +import blackjack.participant.Dealer +import blackjack.participant.Name +import blackjack.participant.Player +import blackjack.participant.Result +import blackjack.participant.status.Blackjack +import blackjack.participant.status.Bust + +object GameResultGenerator { + + fun generateGameResult(players: List, dealer: Dealer): GameResult { + val dealerBettingAmount = MatchingScoreCalculator.matchingScoreForDealer(players, dealer) + val resultMap = mapOf(Name("딜러") to dealerBettingAmount) + players.map { player -> + val result = matchingResult(player, dealer) + val bettingAmount = player.status.calculateBettingAmount(result, player.bettingAmount) + player.name to bettingAmount + } + + return GameResult(resultMap) + } + + private fun matchingResult(player: Player, dealer: Dealer): Result { + if (player.status is Blackjack) { + return when (dealer.status) { + is Blackjack -> Result.Lose + else -> { + return Result.Win + } + } + } + + if (player.status is Bust) { + return Result.Lose + } + + if (dealer.status is Bust) { + return Result.Win + } + + return when (dealer.resultScore() > player.resultScore()) { + true -> { + Result.Lose + } + + else -> Result.Win + } + } +} diff --git a/src/main/kotlin/blackjack/supoort/MatchingScoreCalculator.kt b/src/main/kotlin/blackjack/supoort/MatchingScoreCalculator.kt new file mode 100644 index 000000000..cba9afc5f --- /dev/null +++ b/src/main/kotlin/blackjack/supoort/MatchingScoreCalculator.kt @@ -0,0 +1,28 @@ +package blackjack.supoort + +import blackjack.participant.BettingAmount +import blackjack.participant.Dealer +import blackjack.participant.Player +import blackjack.participant.Result +import blackjack.participant.minus +import blackjack.participant.plus +import blackjack.participant.status.Blackjack +import blackjack.participant.status.Bust + +object MatchingScoreCalculator { + + fun matchingScoreForDealer(players: List, dealer: Dealer): BettingAmount { + val bettingAmount = players.fold(BettingAmount(0)) { acc, player -> + val updatedAmount = when { + player.status is Blackjack && dealer.status !is Blackjack -> acc - player.status.calculateBettingAmount(Result.Win, player.bettingAmount) + player.status is Bust -> acc + player.bettingAmount + dealer.status is Bust -> acc - player.bettingAmount + dealer.resultScore() > player.resultScore() -> acc + player.bettingAmount + else -> acc + } + BettingAmount(updatedAmount.amount) + } + + return bettingAmount + } +} diff --git a/src/main/kotlin/blackjack/ScoreCalculator.kt b/src/main/kotlin/blackjack/supoort/ScoreCalculator.kt similarity index 98% rename from src/main/kotlin/blackjack/ScoreCalculator.kt rename to src/main/kotlin/blackjack/supoort/ScoreCalculator.kt index c459aea7b..a223ff936 100644 --- a/src/main/kotlin/blackjack/ScoreCalculator.kt +++ b/src/main/kotlin/blackjack/supoort/ScoreCalculator.kt @@ -1,4 +1,4 @@ -package blackjack +package blackjack.supoort import blackjack.card.AceCard import blackjack.card.BlackJackCard diff --git a/src/main/kotlin/blackjack/ui/InputManager.kt b/src/main/kotlin/blackjack/ui/InputManager.kt index bb17be52a..4aff3c346 100644 --- a/src/main/kotlin/blackjack/ui/InputManager.kt +++ b/src/main/kotlin/blackjack/ui/InputManager.kt @@ -1,13 +1,17 @@ package blackjack.ui -import blackjack.participant.Player - class InputManager { fun inputPlayerNames(): List { println(INPUT_PLAYER_NAMES_MESSAGE) return inputUserValue().replace("\\s".toRegex(), "").split(",") } + fun inputBettingAmount(playerName: String): Int { + println() + println("${playerName}의 베팅 금액은?") + return inputUserValue().toInt() + } + private fun inputUserValue(): String { val input = readln() require(input.isNotBlank()) { INPUT_NOT_NULL_MESSAGE } @@ -16,15 +20,6 @@ class InputManager { fun inputShouldDrawCard(name: String): Int { println("${name}는 $INPUT_SHOULD_DRAW_CARD_MESSAGE") - return when (readln()) { - "Y", "y" -> 1 - "N", "n" -> 0 - else -> 0 - } - } - - fun inputShouldDrawCard(player: Player): Int { - println("${player.name}는 $INPUT_SHOULD_DRAW_CARD_MESSAGE") return when (readln()) { "Y", "y" -> CHOOSE_DRAW "N", "n" -> CHOOSE_NOT_DRAW @@ -34,7 +29,6 @@ class InputManager { companion object { private const val INPUT_NOT_NULL_MESSAGE = "입력값을 입력해주세요." - private const val INPUT_DEALER_MESSAGE = "16이하라 한장의 카드를 더 받았습니다." private const val INPUT_PLAYER_NAMES_MESSAGE: String = "게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)" private const val INPUT_SHOULD_DRAW_CARD_MESSAGE: String = "한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)" private const val CHOOSE_DRAW: Int = 1 diff --git a/src/main/kotlin/blackjack/ui/OutputManager.kt b/src/main/kotlin/blackjack/ui/OutputManager.kt index 46b105b07..7fac65c4f 100644 --- a/src/main/kotlin/blackjack/ui/OutputManager.kt +++ b/src/main/kotlin/blackjack/ui/OutputManager.kt @@ -1,6 +1,6 @@ package blackjack.ui -import blackjack.GameResult +import blackjack.supoort.GameResult import blackjack.card.AceCard import blackjack.card.BlackJackCard import blackjack.card.CardPattern @@ -9,7 +9,6 @@ import blackjack.card.NormalCard import blackjack.card.PictureCard import blackjack.participant.Dealer import blackjack.participant.Player -import blackjack.participant.Result class OutputManager { fun printPlayersAndDealerCards(players: List, dealer: Dealer) { @@ -18,35 +17,28 @@ class OutputManager { players.forEach { println("${it.name.value}: ${parsingCardsToString(it.cards)}") } + + printEnter() } fun printPlayerCards(player: Player) { println("${player.name.value}: ${parsingCardsToString(player.cards)}") } - fun printDealerCards(dealer: Dealer) { - println("딜러: ${parsingCardsToString(dealer.cards)}") - } - fun printPlayerResultGame(player: Player) { println("${player.name.value} 카드: ${parsingCardsToString(player.cards)} - 결과: ${player.resultScore()}") } fun printDealerResultGame(dealer: Dealer) { + printEnter() println("딜러 카드: ${parsingCardsToString(dealer.cards)} - 결과: ${dealer.resultScore()}") } fun printResult(gameResult: GameResult) { + printEnter() + println(RESULT_MESSAGE) gameResult.resultMap.forEach { - println("${it.key.value} : ${parsingGameResult(it.value)}") - } - } - - private fun parsingGameResult(result: Result): String { - return when(result) { - is Result.Win -> WIN - is Result.Lose -> LOSE - is Result.DealerResult -> "${result.win} $WIN ${result.lose} $LOSE" + println("${it.key.value} : ${it.value.amount}") } } @@ -83,19 +75,24 @@ class OutputManager { } } - fun printFirstTurn2(players: List) { + fun printFirstTurn(players: List) { + printEnter() val names: String = players.joinToString(", ") { it.name.value } println("딜러와 ${names}에게 2장의 카드를 나누었습니다.") } fun printDealerCanDrawMessage() { + printEnter() println(DEALER_MESSAGE) } + private fun printEnter() { + println() + } + companion object { - private const val DEALER_MESSAGE = "16이하라 한장의 카드를 더 받았습니다." - private const val WIN = "승" - private const val LOSE = "패" + private const val DEALER_MESSAGE = "딜러는 16이하라 한장의 카드를 더 받았습니다." + private const val RESULT_MESSAGE = "## 최종승패" } } diff --git a/src/test/kotlin/blackjack/ScoreCalculatorTest.kt b/src/test/kotlin/blackjack/ScoreCalculatorTest.kt index 4a5c3f0e6..8e2637945 100644 --- a/src/test/kotlin/blackjack/ScoreCalculatorTest.kt +++ b/src/test/kotlin/blackjack/ScoreCalculatorTest.kt @@ -6,6 +6,7 @@ import blackjack.card.CardPattern import blackjack.card.CardPicture import blackjack.card.NormalCard import blackjack.card.PictureCard +import blackjack.supoort.ScoreCalculator import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest diff --git a/src/test/kotlin/blackjack/domain/DealerTest.kt b/src/test/kotlin/blackjack/domain/DealerTest.kt index a5346e51d..a04ee49bd 100644 --- a/src/test/kotlin/blackjack/domain/DealerTest.kt +++ b/src/test/kotlin/blackjack/domain/DealerTest.kt @@ -1,11 +1,11 @@ package blackjack.domain -import blackjack.ScoreCalculator +import org.junit.jupiter.api.Test +import io.kotest.matchers.shouldBe import blackjack.card.CardPattern import blackjack.card.NormalCard +import blackjack.supoort.ScoreCalculator import blackjack.participant.Dealer -import io.kotest.matchers.shouldBe -import org.junit.jupiter.api.Test class DealerTest { private val scoreCalculator: ScoreCalculator = ScoreCalculator() diff --git a/src/test/kotlin/blackjack/domain/PlayerTest.kt b/src/test/kotlin/blackjack/domain/PlayerTest.kt index ab3617e6b..8fd207074 100644 --- a/src/test/kotlin/blackjack/domain/PlayerTest.kt +++ b/src/test/kotlin/blackjack/domain/PlayerTest.kt @@ -1,6 +1,6 @@ package blackjack.domain -import blackjack.ScoreCalculator +import blackjack.supoort.ScoreCalculator import blackjack.card.CardDeck import blackjack.card.CardPattern import blackjack.card.CardPicture @@ -8,7 +8,9 @@ import blackjack.card.NormalCard import blackjack.card.PictureCard import blackjack.participant.Name import blackjack.participant.Player +import blackjack.participant.status.Bust import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf import org.junit.jupiter.api.Test class PlayerTest { @@ -72,6 +74,6 @@ class PlayerTest { ) ) - player.isBust shouldBe true + player.status.shouldBeInstanceOf() } } diff --git a/src/test/kotlin/blackjack/participant/BettingAmountTest.kt b/src/test/kotlin/blackjack/participant/BettingAmountTest.kt new file mode 100644 index 000000000..fa37a48ff --- /dev/null +++ b/src/test/kotlin/blackjack/participant/BettingAmountTest.kt @@ -0,0 +1,37 @@ +package blackjack.participant + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class BettingAmountTest { + + @Test + fun `베팅 금액은 금액을 가진다`() { + val amount = BettingAmount(1000) + amount.amount shouldBe 1000 + } + + @Test + fun `베팅 금액을 더한다`() { + val amount1 = BettingAmount(1000) + val amount2 = BettingAmount(2000) + val actual = amount1 + amount2 + + actual.amount shouldBe 3000 + } + + @Test + fun `베팅 금액을 뺀다`() { + val amount1 = BettingAmount(1000) + val amount2 = BettingAmount(2000) + val actual = amount1 - amount2 + + actual.amount shouldBe -1000 + } + + @Test + fun `베팅 금액을 음수로 만든다`() { + val amount = BettingAmount(1000) + amount.unaryMinus().amount shouldBe -1000 + } +} diff --git a/src/test/kotlin/blackjack/participant/BlackjackStrategyTest.kt b/src/test/kotlin/blackjack/participant/BlackjackStrategyTest.kt new file mode 100644 index 000000000..f218e8b80 --- /dev/null +++ b/src/test/kotlin/blackjack/participant/BlackjackStrategyTest.kt @@ -0,0 +1,68 @@ +package blackjack.participant + +import blackjack.supoort.ScoreCalculator +import blackjack.card.AceCard +import blackjack.card.CardPattern +import blackjack.card.CardPicture +import blackjack.card.PictureCard +import blackjack.participant.status.Blackjack +import blackjack.participant.status.Bust +import blackjack.participant.status.Hit +import blackjack.participant.status.Stand +import io.kotest.matchers.types.shouldBeInstanceOf +import org.junit.jupiter.api.Test + +class BlackjackStrategyTest { + + @Test + fun `처음 두 장을 드로우 했을 때 합이 21이면 블랙잭상태이다`() { + val blackjackStrategy = BlackjackStrategy(ScoreCalculator()) + blackjackStrategy.drawCard( + listOf( + PictureCard(CardPicture.JACK, CardPattern.SPADE), + AceCard(CardPattern.SPADE), + ) + ) + + blackjackStrategy.status.shouldBeInstanceOf() + } + + @Test + fun `처음 두 장을 드로우 했을 때 합이 21이 아니면 히트 상태이다`() { + val blackjackStrategy = BlackjackStrategy(ScoreCalculator()) + blackjackStrategy.drawCard( + listOf( + PictureCard(CardPicture.JACK, CardPattern.SPADE), + PictureCard(CardPicture.JACK, CardPattern.SPADE) + ) + ) + + blackjackStrategy.status.shouldBeInstanceOf() + } + + @Test + fun `합이 21미만이고 더 이상 카드를 뽑지 않으면 스탠드 상태이다`() { + val blackjackStrategy = BlackjackStrategy(ScoreCalculator()) + blackjackStrategy.drawCard( + listOf( + PictureCard(CardPicture.JACK, CardPattern.SPADE) + ) + ) + + blackjackStrategy.status.shouldBeInstanceOf() + } + + @Test + fun `합이 21이상이면 버스트 상태이다`() { + val blackjackStrategy = BlackjackStrategy(ScoreCalculator()) + blackjackStrategy.drawCard( + listOf( + PictureCard(CardPicture.JACK, CardPattern.SPADE), + PictureCard(CardPicture.JACK, CardPattern.SPADE), + PictureCard(CardPicture.JACK, CardPattern.SPADE) + ) + ) + + blackjackStrategy.status.shouldBeInstanceOf() + } +} diff --git a/src/test/kotlin/blackjack/participant/NameTest.kt b/src/test/kotlin/blackjack/participant/NameTest.kt new file mode 100644 index 000000000..a07e1df94 --- /dev/null +++ b/src/test/kotlin/blackjack/participant/NameTest.kt @@ -0,0 +1,12 @@ +package blackjack.participant + +import io.kotest.assertions.throwables.shouldThrow +import org.junit.jupiter.api.Test + +class NameTest { + + @Test + fun `빈 문자열은 이름이 될 수 없다`() { + shouldThrow { Name("") } + } +} diff --git a/src/test/kotlin/blackjack/participant/status/StatusTest.kt b/src/test/kotlin/blackjack/participant/status/StatusTest.kt new file mode 100644 index 000000000..993f17217 --- /dev/null +++ b/src/test/kotlin/blackjack/participant/status/StatusTest.kt @@ -0,0 +1,37 @@ +package blackjack.participant.status + +import blackjack.participant.BettingAmount +import blackjack.participant.Result +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class StatusTest { + + @Test + fun `HIT 상태에서 이기면 배팅금액을 그대로 받는다`() { + val hit = Hit() + val result = hit.calculateBettingAmount(Result.Win, BettingAmount(1000)) + result.amount shouldBe 1000 + } + + @Test + fun `Stand 상태에서 이기면 배팅금액을 그대로 받는다`() { + val stand = Stand() + val result = stand.calculateBettingAmount(Result.Win, BettingAmount(1000)) + result.amount shouldBe 1000 + } + + @Test + fun `Bust 상태는 배팅 금액을 잃는다`() { + val bust = Bust() + val result = bust.calculateBettingAmount(Result.Win, BettingAmount(1000)) + result.amount shouldBe -1000 + } + + @Test + fun `블랙잭 상태에서 이기면 배팅금액의 1점 5배를 받는다`() { + val blackjack = Blackjack() + val result = blackjack.calculateBettingAmount(Result.Win, BettingAmount(1000)) + result.amount shouldBe 1500 + } +} diff --git a/src/test/kotlin/blackjack/GameResultTest.kt b/src/test/kotlin/blackjack/supoort/GameResultGeneratorTest.kt similarity index 71% rename from src/test/kotlin/blackjack/GameResultTest.kt rename to src/test/kotlin/blackjack/supoort/GameResultGeneratorTest.kt index 3801e2af6..9e20a7e3e 100644 --- a/src/test/kotlin/blackjack/GameResultTest.kt +++ b/src/test/kotlin/blackjack/supoort/GameResultGeneratorTest.kt @@ -1,23 +1,23 @@ -package blackjack +package blackjack.supoort import blackjack.card.CardPattern import blackjack.card.CardPicture import blackjack.card.NormalCard import blackjack.card.PictureCard +import blackjack.participant.BettingAmount import blackjack.participant.Dealer import blackjack.participant.Name import blackjack.participant.Player -import blackjack.participant.Result -import io.kotest.matchers.types.shouldBeInstanceOf +import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -class GameResultTest { +class GameResultGeneratorTest { private val scoreCalculator: ScoreCalculator = ScoreCalculator() @Test - fun `딜러가 버스트면 해당 시점에 살아있는 나머지 사용자는 승리한다`() { + fun `딜러가 버스트면 해당 시점에 살아있는 나머지 사용자는 베팅 금액을 잃지 않는다`() { val name = "홍길동" - val player = Player(Name(name), scoreCalculator) + val player = Player(Name(name), BettingAmount(1000)) player.drawCard( listOf( NormalCard(9, CardPattern.CLOVER), @@ -32,15 +32,15 @@ class GameResultTest { NormalCard(2, CardPattern.CLOVER), ) ) - val result = GameResult(listOf(player), dealer) + val result = GameResultGenerator.generateGameResult(listOf(player), dealer) - result.resultMap[player.name].shouldBeInstanceOf() + result.resultMap[player.name]?.amount shouldBe 1000 } @Test - fun `딜러가 버스트여도 사용자가 버스트이면 사용자는 패배한다`() { + fun `딜러가 버스트여도 사용자가 버스트이면 사용자는 배팅 금액을 잃는다`() { val name = "홍길동" - val player = Player(Name(name), scoreCalculator) + val player = Player(Name(name), BettingAmount(1000)) player.drawCard( listOf( PictureCard(CardPicture.KING, CardPattern.CLOVER), @@ -56,8 +56,8 @@ class GameResultTest { NormalCard(2, CardPattern.CLOVER), ) ) - val result = GameResult(listOf(player), dealer) + val result = GameResultGenerator.generateGameResult(listOf(player), dealer) - result.resultMap[player.name].shouldBeInstanceOf() + result.resultMap[player.name]?.amount shouldBe -1000 } } diff --git a/src/test/kotlin/blackjack/supoort/MatchingScoreCalculatorTest.kt b/src/test/kotlin/blackjack/supoort/MatchingScoreCalculatorTest.kt new file mode 100644 index 000000000..fb9c32b46 --- /dev/null +++ b/src/test/kotlin/blackjack/supoort/MatchingScoreCalculatorTest.kt @@ -0,0 +1,38 @@ +package blackjack.supoort + +import blackjack.card.AceCard +import blackjack.card.CardPattern +import blackjack.card.NormalCard +import blackjack.participant.BettingAmount +import blackjack.participant.Dealer +import blackjack.participant.Name +import blackjack.participant.Player +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class MatchingScoreCalculatorTest { + private val scoreCalculator: ScoreCalculator = ScoreCalculator() + + @Test + fun `플레이어가 블랙잭 상태로 이기면 딜러에게서 배팅금액을 받는다`() { + val dealer = Dealer(scoreCalculator) + dealer.drawCard( + listOf( + NormalCard(5, CardPattern.CLOVER), + NormalCard(10, CardPattern.CLOVER), + ) + ) + + val player = Player(Name("홍길동"), BettingAmount(1000)) + player.drawCard( + listOf( + AceCard(CardPattern.CLOVER), + NormalCard(10, CardPattern.CLOVER), + ) + ) + + val dealerBettingAmount = MatchingScoreCalculator.matchingScoreForDealer(listOf(player), dealer) + + dealerBettingAmount.amount shouldBe -1500 + } +}