diff --git a/README.md b/README.md index e1c7c927d..9667cd69b 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# kotlin-blackjack \ No newline at end of file +# kotlin-blackjack + +### 기능 요구사항 +- 블랙잭 게임을 변형한 프로그램을 구현한다. +- 블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다. +- 카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다. +- 게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. +- 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다. + +### 요구 사항 명세 정리 +- [x] 카드 모양은 Spades, Clubs, Hearts, Diamonds 4가지로 이루어져있다 +- [x] 카드는 1부터 10까지로 이루어져 있다 +- [x] 숫자가 아닌 카드는 Jack, Queen, King으로 이루어져있으며 모두 숫자 10을 나타낸다 +- [x] 카드덱에는 모든 카드가 존재해야한다 +- [x] 카드덱에서 한번 꺼낸 카드는 카드덱에 더이상 존재할 수 없다 +- [x] 플레이어는 본인이 원할 때 까지 카드를 계속 뽑을 수 있다 +- [x] 플레이어는 본인이 가진 카드의 합산을 알 수 있다 +- [x] 플레이어가 21을 넘을 경우 카드를 뽑으면 에러가 발생한다 +- [x] 플레이어가 2명이 아닐 경우 에러가 발생한다 +- [x] 블랙잭 게임 시작 시, 플레이어에게 카드 2장씩 배분한다 +- [x] Ace(숫자1)는 1 또는 11로 계산할 수 있다 +- [x] 플레이어에게 카드는 랜덤하게 제공된다 + + +### 프로그래밍 요구 사항 +- 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외 +- indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. +- **모든 엔티티를 작게 유지한다.** +- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다. +- 기능을 구현하기 전에 README.md 파일에 구현할 기능 목록을 정리해 추가한다. +- git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다. diff --git a/build.gradle.kts b/build.gradle.kts index 8366e1cbe..0191fcd94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,6 @@ repositories { } dependencies { - implementation("org.testng:testng:7.1.0") testImplementation("org.junit.jupiter", "junit-jupiter", "5.10.2") testImplementation("org.assertj", "assertj-core", "3.25.3") testImplementation("io.kotest", "kotest-runner-junit5", "5.8.0") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136f..000000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index b82aa23a4..000000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/src/main/kotlin/blackjack/application/Main.kt b/src/main/kotlin/blackjack/application/Main.kt new file mode 100644 index 000000000..c1381e874 --- /dev/null +++ b/src/main/kotlin/blackjack/application/Main.kt @@ -0,0 +1,17 @@ +package blackjack.application + +import blackjack.domain.CardDeck +import blackjack.domain.shuffledDeckGenerator +import blackjack.view.BlackJackController + +fun main() { + val blackJackController = BlackJackController() + + val players = blackJackController.initPlayers() + + val blackJack = blackJackController.initBlackJack(players, CardDeck(shuffledDeckGenerator())) + + blackJackController.addCard(blackJack) + + blackJackController.result(blackJack) +} diff --git a/src/main/kotlin/blackjack/domain/BlackJack.kt b/src/main/kotlin/blackjack/domain/BlackJack.kt new file mode 100644 index 000000000..2abd950e9 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/BlackJack.kt @@ -0,0 +1,11 @@ +package blackjack.domain + +class BlackJack(val players: Players, val cardDeck: CardDeck) { + init { + repeat(INIT_CARD_DRAW_REPEAT) { players.players.forEach { it.addCard(cardDeck.drawCard()) } } + } + + companion object { + const val INIT_CARD_DRAW_REPEAT = 2 + } +} diff --git a/src/main/kotlin/blackjack/domain/Card.kt b/src/main/kotlin/blackjack/domain/Card.kt new file mode 100644 index 000000000..7669dc366 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Card.kt @@ -0,0 +1,3 @@ +package blackjack.domain + +data class Card(val suit: Suit, val rank: Rank) diff --git a/src/main/kotlin/blackjack/domain/CardDeck.kt b/src/main/kotlin/blackjack/domain/CardDeck.kt new file mode 100644 index 000000000..d08732e73 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/CardDeck.kt @@ -0,0 +1,13 @@ +package blackjack.domain + +data class CardDeck(val deck: MutableList) { + init { + val defaultDeck = defaultDeckGenerator() + require(deck.containsAll(defaultDeck)) { "블랙잭 게임을 하기 위해서는 모든 카드가 준비되어야합니다" } + } + + fun drawCard(): Card { + require(deck.isNotEmpty()) { "더이상 카드가 남아있지 않습니다" } + return deck.removeAt(deck.lastIndex) + } +} diff --git a/src/main/kotlin/blackjack/domain/DeckGenerator.kt b/src/main/kotlin/blackjack/domain/DeckGenerator.kt new file mode 100644 index 000000000..ee19152cc --- /dev/null +++ b/src/main/kotlin/blackjack/domain/DeckGenerator.kt @@ -0,0 +1,17 @@ +package blackjack.domain + +fun defaultDeckGenerator(): MutableList { + return createAllCards().toMutableList() +} + +fun shuffledDeckGenerator(): MutableList { + return createAllCards().shuffled().toMutableList() +} + +private fun createAllCards(): List { + return Suit.entries.flatMap { createAllCardsBySuit(it) } +} + +private fun createAllCardsBySuit(suit: Suit): List { + return Rank.entries.map { Card(suit, it) } +} diff --git a/src/main/kotlin/blackjack/domain/MutableCards.kt b/src/main/kotlin/blackjack/domain/MutableCards.kt new file mode 100644 index 000000000..6edfdcfb1 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/MutableCards.kt @@ -0,0 +1,29 @@ +package blackjack.domain + +data class MutableCards(val cards: MutableList) { + fun add(card: Card) { + cards.add(card) + } + + fun cardsToString(): String { + return cards.joinToString(", ") { it.rank.alias + it.suit.alias } + } + + fun sumValues(): Int { + var sum = cards.sumOf { card -> card.rank.getNumber().max() } + var aceCount = cards.count { card -> card.rank == Rank.ACE } + + while (sum > MAX_SUM_CARD_VALUES && aceCount > ACE_MIN_COUNT) { + sum -= Rank.ACE.getNumber().max() + sum += Rank.ACE.value + aceCount-- + } + + return sum + } + + companion object { + const val MAX_SUM_CARD_VALUES = 21 + const val ACE_MIN_COUNT = 0 + } +} diff --git a/src/main/kotlin/blackjack/domain/Player.kt b/src/main/kotlin/blackjack/domain/Player.kt new file mode 100644 index 000000000..2168b188d --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Player.kt @@ -0,0 +1,18 @@ +package blackjack.domain + +data class Player(val playerName: PlayerName, val mutableCards: MutableCards) { + fun addCard(card: Card) { + mutableCards.add(card) + require(sumCardValues() <= MutableCards.MAX_SUM_CARD_VALUES) { + playerName.name + " Bust! / " + mutableCards.cardsToString() + } + } + + fun cardsToString(): String { + return mutableCards.cardsToString() + } + + fun sumCardValues(): Int { + return mutableCards.sumValues() + } +} diff --git a/src/main/kotlin/blackjack/domain/PlayerName.kt b/src/main/kotlin/blackjack/domain/PlayerName.kt new file mode 100644 index 000000000..8ae463300 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/PlayerName.kt @@ -0,0 +1,4 @@ +package blackjack.domain + +@JvmInline +value class PlayerName(val name: String) diff --git a/src/main/kotlin/blackjack/domain/Players.kt b/src/main/kotlin/blackjack/domain/Players.kt new file mode 100644 index 000000000..05db0c20a --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Players.kt @@ -0,0 +1,15 @@ +package blackjack.domain + +data class Players(val players: List) { + init { + require(players.size == PLAYER_COUNT) { "블랙잭 게임에서 플레이어는 2명이어야 합니다" } + } + + fun toPlayerNamesString(): String { + return players.joinToString(", ") { it.playerName.name } + } + + companion object { + const val PLAYER_COUNT = 2 + } +} diff --git a/src/main/kotlin/blackjack/domain/Rank.kt b/src/main/kotlin/blackjack/domain/Rank.kt new file mode 100644 index 000000000..1a0b2fc26 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Rank.kt @@ -0,0 +1,26 @@ +package blackjack.domain + +enum class Rank(val value: Int, val alias: String) { + ACE(1, "A"), + TWO(2, "2"), + THREE(3, "3"), + FOUR(4, "4"), + FIVE(5, "5"), + SIX(6, "6"), + SEVEN(7, "7"), + EIGHT(8, "8"), + NINE(9, "9"), + TEN(10, "10"), + JACK(10, "J"), + QUEEN(10, "Q"), + KING(10, "K"), + ; + + fun getNumber(): List { + return if (this == ACE) { + listOf(value, 11) + } else { + listOf(value) + } + } +} diff --git a/src/main/kotlin/blackjack/domain/Suit.kt b/src/main/kotlin/blackjack/domain/Suit.kt new file mode 100644 index 000000000..a87fb91e8 --- /dev/null +++ b/src/main/kotlin/blackjack/domain/Suit.kt @@ -0,0 +1,8 @@ +package blackjack.domain + +enum class Suit(val alias: String) { + SPADES("스페이드"), + HEARTS("하트"), + DIAMONDS("다이아몬드"), + CLUBS("클로버"), +} diff --git a/src/main/kotlin/blackjack/view/AddCardView.kt b/src/main/kotlin/blackjack/view/AddCardView.kt new file mode 100644 index 000000000..5fed39e90 --- /dev/null +++ b/src/main/kotlin/blackjack/view/AddCardView.kt @@ -0,0 +1,39 @@ +package blackjack.view + +import blackjack.domain.BlackJack +import blackjack.domain.CardDeck +import blackjack.domain.Player + +fun addCardView(blackJack: BlackJack) { + val players = blackJack.players.players + println() + players.forEach { addCardViewByPlayer(it, blackJack.cardDeck) } +} + +fun addCardViewByPlayer( + player: Player, + cardDeck: CardDeck, +) { + var inputYesOrNo: String? = "y" + while (inputYesOrNo == "y") { + inputYesOrNo = addCardReturnYesOrNo(player, cardDeck) + } +} + +fun addCardReturnYesOrNo( + player: Player, + cardDeck: CardDeck, +): String { + println(player.playerName.name + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)") + + val inputYesOrNo = readlnOrNull() + requireNotNull(inputYesOrNo) { "어떠한 값도 입력하지 않았습니다" } + require(inputYesOrNo == "y" || inputYesOrNo == "n") { "y 또는 n을 올바르게 입력되지 않았습니다" } + + if (inputYesOrNo == "y") { + player.addCard(cardDeck.drawCard()) + println(player.mutableCards.cardsToString()) + } + + return inputYesOrNo +} diff --git a/src/main/kotlin/blackjack/view/BlackJackController.kt b/src/main/kotlin/blackjack/view/BlackJackController.kt new file mode 100644 index 000000000..5acef8c06 --- /dev/null +++ b/src/main/kotlin/blackjack/view/BlackJackController.kt @@ -0,0 +1,38 @@ +package blackjack.view + +import blackjack.domain.BlackJack +import blackjack.domain.CardDeck +import blackjack.domain.MutableCards +import blackjack.domain.Player +import blackjack.domain.PlayerName +import blackjack.domain.Players + +class BlackJackController { + fun initPlayers(): Players { + val players = + Players( + players = + inputPlayerNameView().map { + Player(PlayerName(it), MutableCards(cards = mutableListOf())) + }, + ) + return players + } + + fun initBlackJack( + players: Players, + cardSet: CardDeck, + ): BlackJack { + val blackJack = BlackJack(players, cardSet) + initBlackJackView(blackJack) + return blackJack + } + + fun addCard(blackJack: BlackJack) { + addCardView(blackJack) + } + + fun result(blackJack: BlackJack) { + resultView(blackJack) + } +} diff --git a/src/main/kotlin/blackjack/view/InitBlackJackView.kt b/src/main/kotlin/blackjack/view/InitBlackJackView.kt new file mode 100644 index 000000000..b162549c7 --- /dev/null +++ b/src/main/kotlin/blackjack/view/InitBlackJackView.kt @@ -0,0 +1,8 @@ +package blackjack.view + +import blackjack.domain.BlackJack + +fun initBlackJackView(blackJack: BlackJack) { + println("\n" + blackJack.players.toPlayerNamesString() + "에게 2장의 나누었습니다.") + blackJack.players.players.forEach { println(it.playerName.name + "카드: " + it.cardsToString()) } +} diff --git a/src/main/kotlin/blackjack/view/InputPlayerNameView.kt b/src/main/kotlin/blackjack/view/InputPlayerNameView.kt new file mode 100644 index 000000000..55450efeb --- /dev/null +++ b/src/main/kotlin/blackjack/view/InputPlayerNameView.kt @@ -0,0 +1,13 @@ +package blackjack.view + +fun inputPlayerNameView(): List { + println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)") + + val inputPlayerNames: String? = readlnOrNull() + requireNotNull(inputPlayerNames) { "플레이어 이름들이 입력되지 않았습니다" } + + val playerNames = inputPlayerNames.split(",") + require(playerNames.size == 2) { "플레이어는 최소 2명 이상 입력되어야합니다" } + + return playerNames +} diff --git a/src/main/kotlin/blackjack/view/ResultView.kt b/src/main/kotlin/blackjack/view/ResultView.kt new file mode 100644 index 000000000..d7e3b0c89 --- /dev/null +++ b/src/main/kotlin/blackjack/view/ResultView.kt @@ -0,0 +1,10 @@ +package blackjack.view + +import blackjack.domain.BlackJack + +fun resultView(blackJack: BlackJack) { + println() + blackJack.players.players.forEach { + println(it.playerName.name + "카드: " + it.mutableCards.cardsToString() + " - 결과: " + it.sumCardValues()) + } +} diff --git a/src/main/kotlin/studydsl/HardSkill.kt b/src/main/kotlin/studydsl/HardSkill.kt deleted file mode 100644 index 856490d14..000000000 --- a/src/main/kotlin/studydsl/HardSkill.kt +++ /dev/null @@ -1,3 +0,0 @@ -package studydsl - -data class HardSkill(override val name: String) : Skill(name) diff --git a/src/main/kotlin/studydsl/Skill.kt b/src/main/kotlin/studydsl/Skill.kt index 18f637746..93339f100 100644 --- a/src/main/kotlin/studydsl/Skill.kt +++ b/src/main/kotlin/studydsl/Skill.kt @@ -1,3 +1,9 @@ package studydsl -open class Skill(open val name: String) +sealed class Skill { + abstract val name: String + + data class HardSkill(override val name: String) : Skill() + + data class SoftSkill(override val name: String) : Skill() +} diff --git a/src/main/kotlin/studydsl/SkillsBuilder.kt b/src/main/kotlin/studydsl/SkillsBuilder.kt index 91a1e08b9..baed2b5ff 100644 --- a/src/main/kotlin/studydsl/SkillsBuilder.kt +++ b/src/main/kotlin/studydsl/SkillsBuilder.kt @@ -4,11 +4,11 @@ class SkillsBuilder { private val skills = mutableListOf() fun soft(value: String) { - skills.add(SoftSkill(value)) + skills.add(Skill.SoftSkill(value)) } fun hard(value: String) { - skills.add(HardSkill(value)) + skills.add(Skill.HardSkill(value)) } fun build() = Skills(skills) diff --git a/src/main/kotlin/studydsl/SoftSkill.kt b/src/main/kotlin/studydsl/SoftSkill.kt deleted file mode 100644 index 456e12344..000000000 --- a/src/main/kotlin/studydsl/SoftSkill.kt +++ /dev/null @@ -1,3 +0,0 @@ -package studydsl - -data class SoftSkill(override val name: String) : Skill(name) diff --git a/src/test/kotlin/blackjack/domain/BlackJackTest.kt b/src/test/kotlin/blackjack/domain/BlackJackTest.kt new file mode 100644 index 000000000..e23cb3ab7 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/BlackJackTest.kt @@ -0,0 +1,17 @@ +package blackjack.domain + +import blackjack.util.createPlayers +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test + +class BlackJackTest { + @Test + fun `블랙잭 게임을 시작할 때 플레이어에게 카드 2장씩 주고 시작해야한다`() { + val players = createPlayers("pablo", "musk") + val blackJack = BlackJack(players, CardDeck(defaultDeckGenerator())) + + blackJack.players.players.forEach { + it.mutableCards.cards.size shouldBeEqual 2 + } + } +} diff --git a/src/test/kotlin/blackjack/domain/CardDeckTest.kt b/src/test/kotlin/blackjack/domain/CardDeckTest.kt new file mode 100644 index 000000000..b3f8e6438 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/CardDeckTest.kt @@ -0,0 +1,29 @@ +package blackjack.domain + +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test + +class CardDeckTest { + @Test + fun `CardDeck에 모든 카드가 준비되어 있지 않으면 에러가 발생한다`() { + shouldThrowWithMessage(message = "블랙잭 게임을 하기 위해서는 모든 카드가 준비되어야합니다") { + CardDeck(mutableListOf(Card(Suit.DIAMONDS, Rank.ACE), Card(Suit.HEARTS, Rank.NINE))) + } + } + + @Test + fun `Deck에 더이상 카드가 남아있지 않을 때 카드를 꺼내면 에러가 발생한다`() { + val cardDeck = CardDeck(defaultDeckGenerator()) + shouldThrowWithMessage(message = "더이상 카드가 남아있지 않습니다") { + repeat(53) { cardDeck.drawCard() } + } + } + + @Test + fun `Deck에서 한번 꺼낸 카드는 더이상 Deck에 남아있지 않아야한다`() { + val cardDeck = CardDeck(defaultDeckGenerator()) + val card = cardDeck.drawCard() + cardDeck.deck.contains(card) shouldBeEqual false + } +} diff --git a/src/test/kotlin/blackjack/domain/MutableCardsTest.kt b/src/test/kotlin/blackjack/domain/MutableCardsTest.kt new file mode 100644 index 000000000..617be7fc2 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/MutableCardsTest.kt @@ -0,0 +1,51 @@ +package blackjack.domain + +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class MutableCardsTest { + @Test + fun `카드를 추가할 수 있다`() { + val mutableCards = MutableCards(mutableListOf()) + val card = Card(Suit.SPADES, Rank.NINE) + mutableCards.add(card) + mutableCards.cards.contains(card) shouldBeEqual true + } + + @Test + fun `가지고 있는 카드 alias를 모두 나열 할 수 있다`() { + val mutableCards = MutableCards(mutableListOf()) + mutableCards.add(Card(Suit.DIAMONDS, Rank.NINE)) + mutableCards.add(Card(Suit.HEARTS, Rank.ACE)) + mutableCards.cardsToString() shouldBeEqual "9다이아몬드, A하트" + } + + @MethodSource("카드와 카드 합산 제공") + @ParameterizedTest + fun `가지고 있는 카드를 합산할 수 있다`( + card1: Card, + card2: Card, + card3: Card, + sum: Int, + ) { + val mutableCards = MutableCards(mutableListOf()) + mutableCards.add(card1) + mutableCards.add(card2) + mutableCards.add(card3) + mutableCards.sumValues() shouldBeEqual sum + } + + fun `카드와 카드 합산 제공`(): Stream { + return Stream.of( + Arguments.of(Card(Suit.CLUBS, Rank.ACE), Card(Suit.SPADES, Rank.ACE), Card(Suit.DIAMONDS, Rank.ACE), 13), + Arguments.of(Card(Suit.HEARTS, Rank.JACK), Card(Suit.SPADES, Rank.QUEEN), Card(Suit.DIAMONDS, Rank.ACE), 21), + Arguments.of(Card(Suit.SPADES, Rank.TWO), Card(Suit.DIAMONDS, Rank.TWO), Card(Suit.DIAMONDS, Rank.TWO), 6), + ) + } +} diff --git a/src/test/kotlin/blackjack/domain/PlayerTest.kt b/src/test/kotlin/blackjack/domain/PlayerTest.kt new file mode 100644 index 000000000..0b9dda407 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/PlayerTest.kt @@ -0,0 +1,54 @@ +package blackjack.domain + +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class PlayerTest { + @Test + fun `플레이어가 카드를 추가할 때 21을 넘어서면 즉시 패배한다`() { + val player = Player(PlayerName("pablo"), MutableCards(mutableListOf())) + player.addCard(Card(Suit.SPADES, Rank.TWO)) + player.addCard(Card(Suit.HEARTS, Rank.QUEEN)) + shouldThrowWithMessage(message = "pablo Bust! / 2스페이드, Q하트, Q다이아몬드") { + player.addCard(Card(Suit.DIAMONDS, Rank.QUEEN)) + } + } + + @Test + fun `플레이어가 가진 카드를 문자열로 나열할 수 있다`() { + val player = Player(PlayerName("pablo"), MutableCards(mutableListOf())) + player.addCard(Card(Suit.SPADES, Rank.TWO)) + player.addCard(Card(Suit.HEARTS, Rank.QUEEN)) + player.cardsToString() shouldBeEqual "2스페이드, Q하트" + } + + @MethodSource("카드와 카드 합산 제공") + @ParameterizedTest + fun `플레이어가 가진 카드의 합계를 계산할 수 있다`( + card1: Card, + card2: Card, + card3: Card, + sum: Int, + ) { + val player = Player(PlayerName("pablo"), MutableCards(mutableListOf())) + player.addCard(card1) + player.addCard(card2) + player.addCard(card3) + player.sumCardValues() shouldBeEqual sum + } + + fun `카드와 카드 합산 제공`(): Stream { + return Stream.of( + Arguments.of(Card(Suit.CLUBS, Rank.ACE), Card(Suit.SPADES, Rank.ACE), Card(Suit.DIAMONDS, Rank.ACE), 13), + Arguments.of(Card(Suit.HEARTS, Rank.JACK), Card(Suit.SPADES, Rank.QUEEN), Card(Suit.DIAMONDS, Rank.ACE), 21), + Arguments.of(Card(Suit.SPADES, Rank.TWO), Card(Suit.DIAMONDS, Rank.TWO), Card(Suit.DIAMONDS, Rank.TWO), 6), + ) + } +} diff --git a/src/test/kotlin/blackjack/domain/PlayersTest.kt b/src/test/kotlin/blackjack/domain/PlayersTest.kt new file mode 100644 index 000000000..5a22f9323 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/PlayersTest.kt @@ -0,0 +1,24 @@ +package blackjack.domain + +import blackjack.util.createPlayers +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class PlayersTest { + @Test + fun `플레이어가 2명이 아니면 에러가 발생한다`() { + shouldThrowWithMessage(message = "블랙잭 게임에서 플레이어는 2명이어야 합니다") { + createPlayers("pablo") + } + shouldThrowWithMessage(message = "블랙잭 게임에서 플레이어는 2명이어야 합니다") { + createPlayers("pablo", "musk", "vivi") + } + } + + @Test + fun `플레이어 이름을 나열 할 수 있다`() { + val players = createPlayers("pablo", "musk") + players.toPlayerNamesString() shouldBe "pablo, musk" + } +} diff --git a/src/test/kotlin/blackjack/domain/RankTest.kt b/src/test/kotlin/blackjack/domain/RankTest.kt new file mode 100644 index 000000000..7f0ae07fb --- /dev/null +++ b/src/test/kotlin/blackjack/domain/RankTest.kt @@ -0,0 +1,11 @@ +package blackjack.domain + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class RankTest { + @Test + fun `Ace(숫자1)는 1 또는 11로 계산할 수 있다`() { + Rank.ACE.getNumber() shouldBe listOf(1, 11) + } +} diff --git a/src/test/kotlin/blackjack/util/CreatePlayers.kt b/src/test/kotlin/blackjack/util/CreatePlayers.kt new file mode 100644 index 000000000..5334e65b7 --- /dev/null +++ b/src/test/kotlin/blackjack/util/CreatePlayers.kt @@ -0,0 +1,10 @@ +package blackjack.util + +import blackjack.domain.MutableCards +import blackjack.domain.Player +import blackjack.domain.PlayerName +import blackjack.domain.Players + +fun createPlayers(vararg names: String): Players { + return Players(names.map { Player(PlayerName(it), MutableCards(mutableListOf())) }) +} diff --git a/src/test/kotlin/studydsl/DslTest.kt b/src/test/kotlin/studydsl/DslTest.kt index faf7a9ccd..7ab7d8cec 100644 --- a/src/test/kotlin/studydsl/DslTest.kt +++ b/src/test/kotlin/studydsl/DslTest.kt @@ -2,9 +2,8 @@ import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import studydsl.HardSkill import studydsl.Language -import studydsl.SoftSkill +import studydsl.Skill import studydsl.introduce class DslTest { @@ -40,7 +39,7 @@ class DslTest { } } person.skills.skills.size shouldBe 1 - person.skills.skills[0] shouldBe SoftSkill(name = "A passion for problem solving") + person.skills.skills[0] shouldBe Skill.SoftSkill(name = "A passion for problem solving") } @Test @@ -54,7 +53,7 @@ class DslTest { } } person.skills.skills.size shouldBe 1 - person.skills.skills[0] shouldBe HardSkill(name = "Node.js") + person.skills.skills[0] shouldBe Skill.HardSkill(name = "Node.js") } @Test @@ -70,9 +69,9 @@ class DslTest { } } person.skills.skills.size shouldBe 3 - person.skills.skills[0] shouldBe SoftSkill(name = "A passion for problem solving") - person.skills.skills[1] shouldBe HardSkill(name = "Node.js") - person.skills.skills[2] shouldBe HardSkill(name = "Kotlin") + person.skills.skills[0] shouldBe Skill.SoftSkill(name = "A passion for problem solving") + person.skills.skills[1] shouldBe Skill.HardSkill(name = "Node.js") + person.skills.skills[2] shouldBe Skill.HardSkill(name = "Kotlin") } @Test @@ -96,19 +95,3 @@ class DslTest { person.languages.languages[1] shouldBe Language(name = "English", level = 2) } } - -/* -introduce { - name("박재성") - company("우아한형제들") - skills { - soft("A passion for problem solving") - soft("Good communication skills") - hard("Kotlin") - } - languages { - "Korean" level 5 - "English" level 3 - } -} -*/