Skip to content
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

Step3: 블랙잭(딜러) #677

Open
wants to merge 15 commits into
base: wilgur513
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

## 플레이어
* 플레이어는 이름을 가지고 있다
* 블랙잭 시작 시 각 플레이어는 카드 2장을 받는다
* 발급 받은 카드를 항상 공개한다
* 21이 넘지 않을 때 까지 카드를 받을 수 있다

## 딜러
* 처음 받은 2장이 16이하면 17이상이 될 때까지 카드를 받는다
* 발급 받은 카드 중 한장만 공개한다
* 마지막에 카드를 모두 공개한다

## 블랙잭 딜러 승패 계산
* 딜러가 21이 넘으면 플레이어는 모두 승리한다
* 딜러가 21이 넘지 않으면 21에 가까운 플레이어가 승리한다

## 블랙잭 카드
* 숫자(1 ~ 10, Jack, Queen, King)와 문양(클로버, 스페이드, 하트, 다이아)으로 구성

## 블랙잭 카드 계산
* Ace는 1 또는 11로 계산한다
* King, Queen, Jack은 각각 10으로 계산한다

## 블랙잭 드로우 룰
* 블랙잭 시작 시 각 플레이어는 카드 2장을 받는다
* 21이 넘지 않을 때 까지 카드를 받을 수 있다
39 changes: 27 additions & 12 deletions src/main/kotlin/blackjack/Main.kt
Original file line number Diff line number Diff line change
@@ -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() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main 함수가 너무 많은 책임을 가지고 있는것 같습니다.
블랙잭 게임을 진행하기 위한 클래스를 정의해보는건 어떨까요 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blackjack 클래스 추출했습니다.

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<String>, 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<String>, 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)
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/blackjack/domain/BlackJack.kt
Original file line number Diff line number Diff line change
@@ -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<String, List<Card>> {
return participants().associate { it.name to it.openCards() }
}

fun isDealerObtainable(): Boolean {
return dealer.isObtainable()
}

fun obtainDealerCard(): List<Card> {
dealer.obtain(cardDeck.next())
return dealer.hands
}

fun isPlayerObtainable(name: String, wantToTake: Supplier<Boolean>): Boolean {
val player = players.first { it.name == name }
return player.isObtainable() && wantToTake.get()
}

fun obtainPlayerCard(name: String): List<Card> {
val player = players.first { it.name == name }
player.obtain(cardDeck.next())
return player.hands
}

fun compareResults(): Map<String, CompareResult> {
return dealer.compareWith(*players.toTypedArray())
}

fun participants(): List<Participant> {
return players + listOf(dealer)
}
}
12 changes: 3 additions & 9 deletions src/main/kotlin/blackjack/domain/Cards.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package blackjack.domain

const val BLACKJACK_SCORE = 21

class Cards (
cards: List<Card>,
) {
Expand All @@ -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()
Expand All @@ -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
}
}
9 changes: 9 additions & 0 deletions src/main/kotlin/blackjack/domain/CompareResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package blackjack.domain

enum class CompareResult {
DEALER_LOSE,
DRAW,
DEALER_WIN
;

}
36 changes: 36 additions & 0 deletions src/main/kotlin/blackjack/domain/Dealer.kt
Original file line number Diff line number Diff line change
@@ -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<Card> {
return listOf(hands.first())
}

fun compareWith(vararg players: Player): Map<String, CompareResult> {
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
}
}
26 changes: 26 additions & 0 deletions src/main/kotlin/blackjack/domain/Participant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blackjack.domain

abstract class Participant(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Participant 정의 👍

val name: String, card1: Card, card2: Card,
) {
private val cards = Cards(card1, card2)

val hands
get() = cards.values
Comment on lines +8 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hands 추가 👍


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<Card>
}
23 changes: 8 additions & 15 deletions src/main/kotlin/blackjack/domain/Player.kt
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +9 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

플레이어는 더이상 카드를 받지 않지 않는 선언을 할수 있습니다.
input의 값으로 넘기기 보단 플레이어의 상태값을 추가해보는것을 도전해보세요 😄

}

fun sumOfCards(): Int {
return cards.sum()
}

fun isObtainable(): Boolean {
return cards.isLessThanBlackjack()
override fun openCards(): List<Card> {
return hands.subList(0, 2)
}
}
3 changes: 1 addition & 2 deletions src/main/kotlin/blackjack/domain/ShuffledCardDeck.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ class ShuffledCardDeck: CardDeck {
}

private fun deck(): Iterator<Card> {
return (0 until 4)
.flatMap { cards() }
return cards()
.shuffled()
.iterator()
}
Expand Down
56 changes: 45 additions & 11 deletions src/main/kotlin/blackjack/view/OutputView.kt
Original file line number Diff line number Diff line change
@@ -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<Player>) {
val names = players.joinToString(separator = ", ") { it.name }
fun printParticipantOpenedCards(openCards: Map<String, List<Card>>) {
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<Card>) {
val cardsText = cards.joinToString(", ") { cardText(it) }
println("${name} 카드 : $cardsText")
}

private fun cardText(card: Card): String {
Expand All @@ -41,10 +44,41 @@ object OutputView {
}
}

fun printPlayerResult(players: List<Player>) {
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<Participant>) {
for (participant in participants) {
val hands = participant.hands.joinToString(", ") { cardText(it) }
println("${participant.name} 카드 : $hands - 결과: ${participant.sumOfCards()}")
}
}

fun printCompareResults(compareResults: Map<String, CompareResult>) {
println("## 최종 승패")
printDealerResult(compareResults)
printPlayerResult(compareResults)
}

private fun printDealerResult(compareResults: Map<String, CompareResult>) {
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<String, CompareResult>) {
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 -> "패"
}
}
}
Loading