From f92da97fa35ea80b80b2627e1ce57d6b7146e1c8 Mon Sep 17 00:00:00 2001 From: kimihiqq Date: Wed, 11 Dec 2024 11:08:17 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=B2=A0=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++ src/main/kotlin/blackjack/app/Main.kt | 12 +++++-- src/main/kotlin/blackjack/domain/Game.kt | 35 +++++++++++++++++-- .../kotlin/blackjack/domain/Participant.kt | 9 +++++ src/main/kotlin/blackjack/domain/Player.kt | 9 ++++- src/main/kotlin/blackjack/view/InputView.kt | 5 +++ src/main/kotlin/blackjack/view/ResultView.kt | 23 +++++------- .../domain/GameResultCalculatorTest.kt | 8 ++--- src/test/kotlin/blackjack/domain/GameTest.kt | 28 +++++++-------- .../kotlin/blackjack/domain/PlayerTest.kt | 8 ++--- .../kotlin/blackjack/domain/PlayersTest.kt | 6 ++-- 11 files changed, 98 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index f1794d675..90f464581 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,6 @@ ## Step3 - [x] 딜러 카드 관리 - [x] 게임 진행 로직(딜러) + +## Step4 +- [x] 게임 진행 로직(베팅) diff --git a/src/main/kotlin/blackjack/app/Main.kt b/src/main/kotlin/blackjack/app/Main.kt index 353c822f8..e7dbe5b1c 100644 --- a/src/main/kotlin/blackjack/app/Main.kt +++ b/src/main/kotlin/blackjack/app/Main.kt @@ -11,7 +11,13 @@ import blackjack.view.ResultView fun main() { val playerNames = InputView.getPlayerNames() - val players = Players(playerNames.map { Player(it) }) + val players = + Players( + playerNames.map { name -> + val bettingAmount = InputView.getBettingAmount(name) + Player(name, bettingAmount) + }, + ) val dealer = Dealer() val participants = GameParticipants(dealer, players) val deck = Deck() @@ -31,6 +37,6 @@ fun main() { game.dealerPlayTurn() ResultView.showDealerCards(dealer.getCards()) - val gameResult = game.calculateResults() - ResultView.showFinalResults(gameResult) + val profits = game.calculateFinalResults() + ResultView.showFinalProfits(profits) } diff --git a/src/main/kotlin/blackjack/domain/Game.kt b/src/main/kotlin/blackjack/domain/Game.kt index 070796b0e..cc3aad2c2 100644 --- a/src/main/kotlin/blackjack/domain/Game.kt +++ b/src/main/kotlin/blackjack/domain/Game.kt @@ -4,6 +4,11 @@ class Game( private val deck: Deck, private val participants: GameParticipants, ) { + companion object { + private const val BUST_THRESHOLD = 21 + private const val BLACKJACK_MULTIPLIER = 1.5 + } + fun start() { participants.distributeInitialCards(deck) } @@ -16,7 +21,33 @@ class Game( participants.dealer.playTurn(deck) } - fun calculateResults(): GameResult { - return GameResultCalculator.calculate(participants.dealer, participants.players) + fun calculateFinalResults(): Map { + val dealerBlackjack = participants.dealer.isBlackjack() + val dealerScore = participants.dealer.getTotalValue() + + val playerResults = + participants.players.getPlayers() + .associate { player -> + player.name to calculatePlayerResult(player, dealerScore, dealerBlackjack) + } + + val dealerProfit = playerResults.values.sum() * -1 + return playerResults + ("Dealer" to dealerProfit) + } + + private fun calculatePlayerResult( + player: Player, + dealerScore: Int, + dealerBlackjack: Boolean, + ): Int { + val playerBlackjack = player.isBlackjack() + return when { + player.getTotalValue() > BUST_THRESHOLD -> -player.getBettingAmount() + dealerScore > BUST_THRESHOLD -> player.getBettingAmount() + dealerBlackjack && playerBlackjack -> 0 + playerBlackjack -> (player.getBettingAmount() * BLACKJACK_MULTIPLIER).toInt() + player.getTotalValue() > dealerScore -> player.getBettingAmount() + else -> -player.getBettingAmount() + } } } diff --git a/src/main/kotlin/blackjack/domain/Participant.kt b/src/main/kotlin/blackjack/domain/Participant.kt index ca86076ef..a7bd71ce2 100644 --- a/src/main/kotlin/blackjack/domain/Participant.kt +++ b/src/main/kotlin/blackjack/domain/Participant.kt @@ -14,4 +14,13 @@ open class Participant { fun getCards(): List { return cards.asList() } + + fun isBlackjack(): Boolean { + return getCards().size == INITIAL_DRAW_COUNT && getTotalValue() == BLACKJACK + } + + companion object { + private const val BLACKJACK = 21 + private const val INITIAL_DRAW_COUNT = 2 + } } diff --git a/src/main/kotlin/blackjack/domain/Player.kt b/src/main/kotlin/blackjack/domain/Player.kt index 5bb92ac5f..49321cb33 100644 --- a/src/main/kotlin/blackjack/domain/Player.kt +++ b/src/main/kotlin/blackjack/domain/Player.kt @@ -1,3 +1,10 @@ package blackjack.domain -class Player(val name: String) : Participant() +class Player( + val name: String, + private var bettingAmount: Int, +) : Participant() { + fun getBettingAmount(): Int { + return bettingAmount + } +} diff --git a/src/main/kotlin/blackjack/view/InputView.kt b/src/main/kotlin/blackjack/view/InputView.kt index 9b90723d9..86027f295 100644 --- a/src/main/kotlin/blackjack/view/InputView.kt +++ b/src/main/kotlin/blackjack/view/InputView.kt @@ -6,6 +6,11 @@ object InputView { return readlnOrNull()?.split(",")?.map { it.trim() } ?: emptyList() } + fun getBettingAmount(playerName: String): Int { + println("$playerName 의 배팅 금액은?") + return readlnOrNull()?.toIntOrNull() ?: 0 + } + fun askToHit(playerName: String): Boolean { println("$playerName 은 한 장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)") return readlnOrNull()?.lowercase() == "y" diff --git a/src/main/kotlin/blackjack/view/ResultView.kt b/src/main/kotlin/blackjack/view/ResultView.kt index dbfee3c4b..5ac36cd95 100644 --- a/src/main/kotlin/blackjack/view/ResultView.kt +++ b/src/main/kotlin/blackjack/view/ResultView.kt @@ -1,7 +1,6 @@ package blackjack.view import blackjack.domain.Card -import blackjack.domain.GameResult import blackjack.domain.PlayerResultDTO object ResultView { @@ -12,28 +11,22 @@ object ResultView { } } - fun showDealerInitialCard(firstCard: Card) { - println("딜러: ${firstCard.rank}${firstCard.suit}") + fun showDealerInitialCard(card: Card) { + println("딜러: ${card.rank}${card.suit}") } fun showPlayerCards(playerResult: PlayerResultDTO) { println("${playerResult.name}카드: ${playerResult.cards}") } - fun showDealerCards(dealerCards: List) { - val cardDetails = dealerCards.joinToString { "${it.rank}${it.suit}" } - println("딜러 카드: $cardDetails") + fun showDealerCards(cards: List) { + println("딜러 카드: ${cards.joinToString { "${it.rank}${it.suit}" }}") } - fun showFinalResults(gameResult: GameResult) { - println("\n## 최종 승패") - - val (wins, losses) = gameResult.getDealerWinLoss() - println("딜러: ${wins}승 ${losses}패") - - gameResult.playerResults.forEach { (playerName, result) -> - val outcome = if (result == GameResult.Result.WIN) "승" else "패" - println("$playerName: $outcome") + fun showFinalProfits(profits: Map) { + println("\n## 최종 수익") + profits.forEach { (name, profit) -> + println("$name: $profit") } } } diff --git a/src/test/kotlin/blackjack/domain/GameResultCalculatorTest.kt b/src/test/kotlin/blackjack/domain/GameResultCalculatorTest.kt index f3ce9093d..d89cef016 100644 --- a/src/test/kotlin/blackjack/domain/GameResultCalculatorTest.kt +++ b/src/test/kotlin/blackjack/domain/GameResultCalculatorTest.kt @@ -15,11 +15,11 @@ class GameResultCalculatorTest : StringSpec({ val players = Players( listOf( - Player("pobi").apply { + Player("pobi", 1000).apply { addCard(Card(Rank.FIVE, Suit.CLUB)) addCard(Card(Rank.SIX, Suit.SPADE)) }, - Player("jason").apply { + Player("jason", 1000).apply { addCard(Card(Rank.SEVEN, Suit.DIAMOND)) addCard(Card(Rank.FOUR, Suit.CLUB)) }, @@ -44,11 +44,11 @@ class GameResultCalculatorTest : StringSpec({ val players = Players( listOf( - Player("pobi").apply { + Player("pobi", 1000).apply { addCard(Card(Rank.NINE, Suit.CLUB)) addCard(Card(Rank.SEVEN, Suit.SPADE)) }, - Player("jason").apply { + Player("jason", 1000).apply { addCard(Card(Rank.EIGHT, Suit.DIAMOND)) addCard(Card(Rank.SIX, Suit.CLUB)) }, diff --git a/src/test/kotlin/blackjack/domain/GameTest.kt b/src/test/kotlin/blackjack/domain/GameTest.kt index 1bb3c375e..f55f282dc 100644 --- a/src/test/kotlin/blackjack/domain/GameTest.kt +++ b/src/test/kotlin/blackjack/domain/GameTest.kt @@ -1,13 +1,13 @@ package blackjack.domain import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.shouldBe class GameTest : StringSpec({ + "Game should distribute initial cards to dealer and players" { val dealer = Dealer() - val players = Players(listOf(Player("pobi"), Player("jason"))) + val players = Players(listOf(Player("pobi", 10000), Player("jason", 20000))) val participants = GameParticipants(dealer, players) val deck = Deck() val game = Game(deck, participants) @@ -30,7 +30,7 @@ class GameTest : StringSpec({ val players = Players( listOf( - Player("pobi").apply { + Player("pobi", 10000).apply { addCard(Card(Rank.FIVE, Suit.SPADE)) addCard(Card(Rank.THREE, Suit.HEART)) }, @@ -40,12 +40,10 @@ class GameTest : StringSpec({ val deck = Deck() val game = Game(deck, participants) - val result = game.calculateResults() + val results = game.calculateFinalResults() - result.dealerScore shouldBe dealer.getTotalValue() - result.playerResults.shouldContainExactly( - GameResult.PlayerGameResult("pobi", GameResult.Result.WIN), - ) + results["pobi"] shouldBe 10000 + results["Dealer"] shouldBe -10000 } "Game should handle player wins and losses" { @@ -57,11 +55,11 @@ class GameTest : StringSpec({ val players = Players( listOf( - Player("pobi").apply { + Player("pobi", 15000).apply { addCard(Card(Rank.TEN, Suit.SPADE)) addCard(Card(Rank.SEVEN, Suit.HEART)) }, - Player("jason").apply { + Player("jason", 20000).apply { addCard(Card(Rank.EIGHT, Suit.DIAMOND)) addCard(Card(Rank.FOUR, Suit.HEART)) }, @@ -71,12 +69,10 @@ class GameTest : StringSpec({ val deck = Deck() val game = Game(deck, participants) - val result = game.calculateResults() + val results = game.calculateFinalResults() - result.dealerScore shouldBe dealer.getTotalValue() - result.playerResults.shouldContainExactly( - GameResult.PlayerGameResult("pobi", GameResult.Result.WIN), - GameResult.PlayerGameResult("jason", GameResult.Result.LOSE), - ) + results["pobi"] shouldBe 15000 + results["jason"] shouldBe -20000 + results["Dealer"] shouldBe 5000 } }) diff --git a/src/test/kotlin/blackjack/domain/PlayerTest.kt b/src/test/kotlin/blackjack/domain/PlayerTest.kt index d29b25886..817f90f27 100644 --- a/src/test/kotlin/blackjack/domain/PlayerTest.kt +++ b/src/test/kotlin/blackjack/domain/PlayerTest.kt @@ -5,13 +5,13 @@ import io.kotest.matchers.shouldBe class PlayerTest : StringSpec({ "Player should have a name and manage cards through Cards" { - val player = Player("pobi") + val player = Player("pobi", 1000) player.name shouldBe "pobi" player.getCards().isEmpty() shouldBe true } "Player should add cards to their collection" { - val player = Player("pobi") + val player = Player("pobi", 1000) val card = Card(Rank.ACE, Suit.HEART) player.addCard(card) @@ -20,7 +20,7 @@ class PlayerTest : StringSpec({ } "Player should calculate the total value of their cards correctly" { - val player = Player("pobi") + val player = Player("pobi", 1000) player.addCard(Card(Rank.ACE, Suit.HEART)) player.addCard(Card(Rank.KING, Suit.CLUB)) @@ -28,7 +28,7 @@ class PlayerTest : StringSpec({ } "Player should consider Ace as 1 if 11 causes the total to exceed 21" { - val player = Player("pobi") + val player = Player("pobi", 1000) player.addCard(Card(Rank.ACE, Suit.HEART)) player.addCard(Card(Rank.KING, Suit.CLUB)) player.addCard(Card(Rank.TWO, Suit.DIAMOND)) diff --git a/src/test/kotlin/blackjack/domain/PlayersTest.kt b/src/test/kotlin/blackjack/domain/PlayersTest.kt index 9c85333e9..008acee03 100644 --- a/src/test/kotlin/blackjack/domain/PlayersTest.kt +++ b/src/test/kotlin/blackjack/domain/PlayersTest.kt @@ -6,7 +6,7 @@ import io.kotest.matchers.shouldBe class PlayersTest : StringSpec({ "Players should distribute two cards to each player" { - val players = Players(listOf(Player("pobi"), Player("jason"))) + val players = Players(listOf(Player("pobi", 1000), Player("jason", 1000))) val deck = Deck() players.distributeInitialCards(deck) @@ -17,7 +17,7 @@ class PlayersTest : StringSpec({ } "Players should allow a specific player to draw a card" { - val players = Players(listOf(Player("pobi"), Player("jason"))) + val players = Players(listOf(Player("pobi", 1000), Player("jason", 1000))) val deck = Deck() players.distributeInitialCards(deck) @@ -28,7 +28,7 @@ class PlayersTest : StringSpec({ } "Players should throw exception if a non-existent player tries to hit" { - val players = Players(listOf(Player("pobi"), Player("jason"))) + val players = Players(listOf(Player("pobi", 1000), Player("jason", 1000))) val deck = Deck() shouldThrow {