From 49a7f70bcbb54a13bf903a36bc0e9bf16f67ca60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?yoonnyeong=28=EC=B5=9C=EC=9C=A4=EB=85=95=29?= Date: Mon, 4 Dec 2023 23:21:29 +0900 Subject: [PATCH] =?UTF-8?q?step4:=20=EB=B8=94=EB=9E=99=EC=9E=AD(=EB=B2=A0?= =?UTF-8?q?=ED=8C=85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++ src/main/kotlin/blackjack/BlackJackMain.kt | 9 +-- .../blackjack/domain/BlackjackParticipant.kt | 9 +-- src/main/kotlin/blackjack/domain/Dealer.kt | 11 ++- .../kotlin/blackjack/domain/GameResult.kt | 17 ++++- .../kotlin/blackjack/domain/MatchResult.kt | 9 +-- src/main/kotlin/blackjack/domain/Player.kt | 5 +- src/main/kotlin/blackjack/domain/Players.kt | 3 +- src/main/kotlin/blackjack/domain/Score.kt | 8 +++ src/main/kotlin/blackjack/view/InputView.kt | 6 ++ src/main/kotlin/blackjack/view/ResultView.kt | 26 +++---- .../kotlin/blackjack/domain/DealerTest.kt | 16 ++--- .../kotlin/blackjack/domain/GameResultTest.kt | 72 +++++++++++++++++++ .../kotlin/blackjack/domain/PlayerTest.kt | 7 ++ 14 files changed, 158 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 35bb358bb..ca570987f 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,10 @@ - [X] 딜러와 player의 점수를 각자 비교해서 21에 더 가까운 사람이 승, 나머지 사람은 패이다. - [X] 플레이어는 승, 패, 무 셋 중 한가지 값을 가진다 +# 4단계 - 블랙잭(베팅) +- [X] 게임을 시작할 때 베팅금액을 정한다. +- [X] 플레이어는 베팅 금액을 가지고 있다. +- [X] 플레이어가 21점 초과(버스트 상태)가 되면 베팅 금액을 전부 잃는다. +- [X] 딜러가 21 이상이 되면 플레이어는 베팅 금액을 그대로 돌려받는다. +- [X] 처음 받은 두장의 카드의 총합이 21이면 베팅 금액의 1.5배를 돌려받는다. +- [X] 최종 승패를 가지고 수익을 계산해서 최종 수익을 출력한다. diff --git a/src/main/kotlin/blackjack/BlackJackMain.kt b/src/main/kotlin/blackjack/BlackJackMain.kt index 05a311fa8..0a1a5e73a 100644 --- a/src/main/kotlin/blackjack/BlackJackMain.kt +++ b/src/main/kotlin/blackjack/BlackJackMain.kt @@ -2,7 +2,6 @@ package blackjack import blackjack.domain.Dealer import blackjack.domain.Deck -import blackjack.domain.GameResult import blackjack.domain.Players import blackjack.view.InputView import blackjack.view.ResultView @@ -10,6 +9,9 @@ import blackjack.view.ResultView fun main() { val deck = Deck.init() val players = InputView.getPlayers() + for (player in players) { + InputView.getPlayersBettingAmount(player) + } val dealer = Dealer() val playersObject = Players(players) @@ -18,17 +20,16 @@ fun main() { dealer.getFirstDealCards(deck.firstDraw()) ResultView.showPlayerCards(dealer) - playersObject.getFirstTwoCards(deck.firstDraw()) { player -> + playersObject.getFirstTwoCards(deck) { player -> ResultView.showPlayerCards(player) } for (player in players) { - while (InputView.askPlayer(player.name) && !player.isBusted) { + while (!player.isBusted && InputView.askPlayer(player.name)) { player.hit(deck.draw()) ResultView.showPlayerCards(player) } } ResultView.showPlayerResult(dealer.getCard(deck), dealer, players) - ResultView.displayGameResult(GameResult(dealer, players)) } diff --git a/src/main/kotlin/blackjack/domain/BlackjackParticipant.kt b/src/main/kotlin/blackjack/domain/BlackjackParticipant.kt index 7fae5dc87..d8cdb952a 100644 --- a/src/main/kotlin/blackjack/domain/BlackjackParticipant.kt +++ b/src/main/kotlin/blackjack/domain/BlackjackParticipant.kt @@ -1,10 +1,10 @@ package blackjack.domain -abstract class BlackjackParticipant(val name: String) { +abstract class BlackjackParticipant(val name: String, var bettingAmount: Int = 0) { private var _cards = Cards(mutableListOf()) - + var profit = 0.0 val isBusted get() = getScore() > Score.BLACKJACK - + val isBlackjack get() = this.getScore() == Score.BLACKJACK val cards: Cards get() = _cards @@ -13,7 +13,8 @@ abstract class BlackjackParticipant(val name: String) { } fun getFirstDealCards(twoCards: List) { - twoCards.forEach { cards.addCard(it) } + twoCards.forEach { _cards.addCard(it) } + } fun hit(card: Card) { diff --git a/src/main/kotlin/blackjack/domain/Dealer.kt b/src/main/kotlin/blackjack/domain/Dealer.kt index 91a66cc00..49d73c813 100644 --- a/src/main/kotlin/blackjack/domain/Dealer.kt +++ b/src/main/kotlin/blackjack/domain/Dealer.kt @@ -10,10 +10,17 @@ class Dealer() : BlackjackParticipant(DEALER_NAME) { return count } + fun calculateProfit(playerProfit: Int) { + profit -= playerProfit + } + override val canHit: Boolean - get() = getScore() < DEALER_TARGET_SCORE + get() = getScore() < DEALER_MIN_SCORE && !isBusted fun compare(player: Player): MatchResult { + if (player.isBlackjack && player.cards.cards.size == 2) { + return MatchResult.BLACKJACK_WIN + } if (this.isBusted) return MatchResult.WIN if (player.isBusted) return MatchResult.LOSS val playerScore = player.getScore() @@ -26,6 +33,6 @@ class Dealer() : BlackjackParticipant(DEALER_NAME) { companion object { private const val DEALER_NAME = "딜러" - private const val DEALER_TARGET_SCORE = 17 + private const val DEALER_MIN_SCORE = 17 } } diff --git a/src/main/kotlin/blackjack/domain/GameResult.kt b/src/main/kotlin/blackjack/domain/GameResult.kt index ad19f9bb4..e0162b5c3 100644 --- a/src/main/kotlin/blackjack/domain/GameResult.kt +++ b/src/main/kotlin/blackjack/domain/GameResult.kt @@ -1,9 +1,6 @@ package blackjack.domain class GameResult(private val dealer: Dealer, private val players: List) { - fun getMatchCount(resultMap: List>): List> = - resultMap.map { playerMap -> playerMap.values.groupingBy { it }.eachCount() } - fun getResultMap(): List> { var resultMap: MutableList> = mutableListOf() for (player in players) { @@ -12,4 +9,18 @@ class GameResult(private val dealer: Dealer, private val players: List) } return resultMap } + + fun setProfit(): List { + val resultMapList = getResultMap() + + for (resultMap in resultMapList) { + for ((player, matchResult) in resultMap) { + val profit = matchResult.rate * player.bettingAmount + player.profit = profit + dealer.calculateProfit(profit.toInt()) + } + } + + return players + } } diff --git a/src/main/kotlin/blackjack/domain/MatchResult.kt b/src/main/kotlin/blackjack/domain/MatchResult.kt index fb7c38b67..96dd5d90f 100644 --- a/src/main/kotlin/blackjack/domain/MatchResult.kt +++ b/src/main/kotlin/blackjack/domain/MatchResult.kt @@ -1,7 +1,8 @@ package blackjack.domain -enum class MatchResult(val text: String) { - WIN("승"), - LOSS("패"), - TIE("무") +enum class MatchResult(val text: String, val rate: Double) { + BLACKJACK_WIN("승", 1.5), + WIN("승", 1.0), + LOSS("패", -1.0), + TIE("무", 1.0) } diff --git a/src/main/kotlin/blackjack/domain/Player.kt b/src/main/kotlin/blackjack/domain/Player.kt index 3c53a3d48..21bc7d034 100644 --- a/src/main/kotlin/blackjack/domain/Player.kt +++ b/src/main/kotlin/blackjack/domain/Player.kt @@ -1,6 +1,7 @@ package blackjack.domain -class Player(name: String) : BlackjackParticipant(name) { +class Player(name: String, bettingAmount: Int) : BlackjackParticipant(name, bettingAmount) { + constructor(name: String) : this(name, bettingAmount = 0) - override val canHit: Boolean = (getScore() < Score.BLACKJACK) + override val canHit: Boolean = (getScore() < Score.BLACKJACK && !isBusted) } diff --git a/src/main/kotlin/blackjack/domain/Players.kt b/src/main/kotlin/blackjack/domain/Players.kt index 725c388b1..1005deb4b 100644 --- a/src/main/kotlin/blackjack/domain/Players.kt +++ b/src/main/kotlin/blackjack/domain/Players.kt @@ -2,8 +2,9 @@ package blackjack.domain class Players(private val players: List) { - fun getFirstTwoCards(cards: List, callback: (Player) -> Unit) { + fun getFirstTwoCards(cardDeck: Deck, callback: (Player) -> Unit) { for (player in players) { + val cards = cardDeck.firstDraw() player.getFirstDealCards(cards) callback(player) } diff --git a/src/main/kotlin/blackjack/domain/Score.kt b/src/main/kotlin/blackjack/domain/Score.kt index 7d98903ff..6ca7c65da 100644 --- a/src/main/kotlin/blackjack/domain/Score.kt +++ b/src/main/kotlin/blackjack/domain/Score.kt @@ -6,6 +6,10 @@ class Score(private val denominations: List) { var score = denominations.sumOf { it.score } var numOfAce = denominations.count { it == Denomination.ACE } + if (denominations.size == 2 && numOfAce == 1 && denominations.containsScoreTen()) { + return BLACKJACK + } + while (numOfAce > 0 && score > BLACKJACK) { score -= Denomination.ACE.let { it.score - it.optionScore } numOfAce -= 1 @@ -13,6 +17,10 @@ class Score(private val denominations: List) { return score } + private fun List.containsScoreTen(): Boolean { + return any { it.score == 10 } + } + companion object { const val BLACKJACK = 21 } diff --git a/src/main/kotlin/blackjack/view/InputView.kt b/src/main/kotlin/blackjack/view/InputView.kt index 81e7e38ca..e6b64b8ff 100644 --- a/src/main/kotlin/blackjack/view/InputView.kt +++ b/src/main/kotlin/blackjack/view/InputView.kt @@ -8,6 +8,12 @@ object InputView { return readln().replace(" ", "").split(",").map { Player(it) } } + fun getPlayersBettingAmount(player: Player) { + println("${player.name} 의 배팅 금액은?") + val amount = readln().toInt() + player.bettingAmount = amount + } + fun askPlayer(playerName: String): Boolean { println("\n${playerName}는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)") val answer = readln().trim() diff --git a/src/main/kotlin/blackjack/view/ResultView.kt b/src/main/kotlin/blackjack/view/ResultView.kt index 9e42761fe..3070fc8d4 100644 --- a/src/main/kotlin/blackjack/view/ResultView.kt +++ b/src/main/kotlin/blackjack/view/ResultView.kt @@ -3,7 +3,6 @@ package blackjack.view import blackjack.domain.BlackjackParticipant import blackjack.domain.Dealer import blackjack.domain.GameResult -import blackjack.domain.MatchResult import blackjack.domain.Player object ResultView { @@ -21,27 +20,24 @@ object ResultView { for (player in players) { println("${player.name}카드: ${player.cards.cards} - 결과: ${player.getScore()}") } + displayGameProfit(GameResult(dealer, players), dealer) } - fun displayGameResult(gameResult: GameResult) { - println("\n## 최종 승패") - val resultMap = gameResult.getResultMap() - displayDealerResult(gameResult.getMatchCount(resultMap)) - for (resultMapEntry in resultMap) { - println("${resultMapEntry.keys.first().name}: ${resultMapEntry.values.first().text}") + private fun displayGameProfit(gameResult: GameResult, dealer: Dealer) { + println("\n## 최종 수익") + val players = gameResult.setProfit() + showProfit(dealer) + for (player in players) { + println("${player.name} : ${player.profit.toInt()}") } } + private fun showProfit(blackjackParticipant: BlackjackParticipant) { + println("${blackjackParticipant.name}: ${blackjackParticipant.profit.toInt()}") + } + private fun showDealerDrawCount(count: Int) { if (count == 0) return println("딜러는 16점이하라 ${count}장의 카드를 더 받았습니다.\n") } - - private fun displayDealerResult(matches: List>) { - val loss = matches.sumOf { it.getOrDefault(MatchResult.WIN, 0) } - val win = matches.sumOf { it.getOrDefault(MatchResult.LOSS, 0) } - val tie = matches.sumOf { it.getOrDefault(MatchResult.TIE, 0) } - - println("딜러: ${win}승 ${loss}패 ${tie}무") - } } diff --git a/src/test/kotlin/blackjack/domain/DealerTest.kt b/src/test/kotlin/blackjack/domain/DealerTest.kt index 8fa408541..63758ab19 100644 --- a/src/test/kotlin/blackjack/domain/DealerTest.kt +++ b/src/test/kotlin/blackjack/domain/DealerTest.kt @@ -7,34 +7,26 @@ class DealerTest { @Test fun `딜러는 16점 이하이면 카드를 받아야한다`() { val dealer = Dealer() - val cards = Cards( + dealer.getFirstDealCards( mutableListOf( Card(Denomination.TWO, Suit.CLUBS), Card(Denomination.JACK, Suit.HEARTS), ) ) - for (card in cards.cards) { - dealer.hit(card) - } - dealer.canHit shouldBe true } @Test fun `딜러는 17점 이상이면 카드를 받을 수 없다`() { val dealer = Dealer() - val cards = Cards( - mutableListOf( + dealer.getFirstDealCards( + listOf( Card(Denomination.JACK, Suit.CLUBS), - Card(Denomination.JACK, Suit.HEARTS), + Card(Denomination.JACK, Suit.HEARTS) ) ) - for (card in cards.cards) { - dealer.hit(card) - } - dealer.canHit shouldBe false } } diff --git a/src/test/kotlin/blackjack/domain/GameResultTest.kt b/src/test/kotlin/blackjack/domain/GameResultTest.kt index e683cb6cc..201fd48dc 100644 --- a/src/test/kotlin/blackjack/domain/GameResultTest.kt +++ b/src/test/kotlin/blackjack/domain/GameResultTest.kt @@ -44,4 +44,76 @@ class GameResultTest { resultMap.first()[player1] shouldBe MatchResult.WIN } + + @Test + fun `플레이어가 버스트 상태가 되면 가진 돈을 전부 잃는다`() { + val dealer = Dealer() + val player1 = Player("player1", 10000) + dealer.getFirstDealCards( + mutableListOf( + Card(Denomination.SEVEN, Suit.CLUBS), + Card(Denomination.JACK, Suit.CLUBS), + ) + ) + player1.getFirstDealCards( + mutableListOf( + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS) + ) + ) + + val gameResult = GameResult(dealer, listOf(player1)) + gameResult.setProfit() + + player1.profit shouldBe -10000 + } + + @Test + fun `딜러가 버스트 상태가 되면 플레이어의 점수와 상관없이 베팅 금액을 돌려받는다`() { + val dealer = Dealer() + val player1 = Player("player1", 10000) + dealer.getFirstDealCards( + mutableListOf( + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS) + ) + ) + player1.getFirstDealCards( + mutableListOf( + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.KING, Suit.CLUBS) + ) + ) + + val gameResult = GameResult(dealer, listOf(player1)) + gameResult.setProfit() + + player1.profit shouldBe 10000 + } + + @Test + fun `처음받은 카드 2장의 합이 21이면 베팅 금액의 1,5배를 돌려받는다`() { + val dealer = Dealer() + val player1 = Player("player1", 10000) + dealer.getFirstDealCards( + mutableListOf( + Card(Denomination.TWO, Suit.CLUBS), + Card(Denomination.THREE, Suit.CLUBS) + ) + ) + player1.getFirstDealCards( + mutableListOf( + Card(Denomination.KING, Suit.CLUBS), + Card(Denomination.ACE, Suit.CLUBS) + ) + ) + + val gameResult = GameResult(dealer, listOf(player1)) + val players = gameResult.setProfit() + + players.get(0).profit.toInt() shouldBe 15000 + } } diff --git a/src/test/kotlin/blackjack/domain/PlayerTest.kt b/src/test/kotlin/blackjack/domain/PlayerTest.kt index 75c8a38e4..0e7838be2 100644 --- a/src/test/kotlin/blackjack/domain/PlayerTest.kt +++ b/src/test/kotlin/blackjack/domain/PlayerTest.kt @@ -49,4 +49,11 @@ class PlayerTest { player.getScore() shouldBe 17 } + + @Test + fun `player 베팅금액을 정할 수 있다`() { + val player = Player("test", 10000) + + player.bettingAmount shouldBe 10000 + } }