From 4d8a92cd98abd3830a4bafea8afb145d45a76fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Wed, 15 Nov 2023 22:18:22 +0900 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20step1=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dto -> domain 패키지 변경 - 빌더 패턴 fix --- .../kotlin/study/builder/LangaugeBuilder.kt | 2 +- .../kotlin/study/builder/PersonBuilder.kt | 14 ++++++------- .../kotlin/study/builder/SkillsBuilder.kt | 2 +- .../kotlin/study/{dto => domain}/Language.kt | 2 +- .../kotlin/study/{dto => domain}/Person.kt | 2 +- .../kotlin/study/{dto => domain}/Skill.kt | 2 +- src/main/kotlin/study/dsl/Person.kt | 6 +++--- src/test/kotlin/study/DslTest.kt | 21 +++++++++++++++++++ 8 files changed, 36 insertions(+), 15 deletions(-) rename src/main/kotlin/study/{dto => domain}/Language.kt (72%) rename src/main/kotlin/study/{dto => domain}/Person.kt (84%) rename src/main/kotlin/study/{dto => domain}/Skill.kt (67%) diff --git a/src/main/kotlin/study/builder/LangaugeBuilder.kt b/src/main/kotlin/study/builder/LangaugeBuilder.kt index de31c6a614..4af95888bd 100644 --- a/src/main/kotlin/study/builder/LangaugeBuilder.kt +++ b/src/main/kotlin/study/builder/LangaugeBuilder.kt @@ -1,6 +1,6 @@ package study.builder -import study.dto.Language +import study.domain.Language class LangaugeBuilder { private var languages: List = emptyList() diff --git a/src/main/kotlin/study/builder/PersonBuilder.kt b/src/main/kotlin/study/builder/PersonBuilder.kt index 9e91c6d38a..c8b9541917 100644 --- a/src/main/kotlin/study/builder/PersonBuilder.kt +++ b/src/main/kotlin/study/builder/PersonBuilder.kt @@ -1,14 +1,14 @@ package study.builder -import study.dto.Language -import study.dto.Person -import study.dto.Skill +import study.domain.Language +import study.domain.Person +import study.domain.Skill class PersonBuilder { - private lateinit var name: String - private lateinit var company: String - private lateinit var skills: List - private lateinit var languages: List + private var name: String = "홍길동" + private var company: String = "미정" + private var skills: List = emptyList() + private var languages: List = emptyList() fun name(value: String) { name = value diff --git a/src/main/kotlin/study/builder/SkillsBuilder.kt b/src/main/kotlin/study/builder/SkillsBuilder.kt index 29dc790e26..8e01d9c764 100644 --- a/src/main/kotlin/study/builder/SkillsBuilder.kt +++ b/src/main/kotlin/study/builder/SkillsBuilder.kt @@ -1,6 +1,6 @@ package study.builder -import study.dto.Skill +import study.domain.Skill class SkillsBuilder { private var skills: List = emptyList() diff --git a/src/main/kotlin/study/dto/Language.kt b/src/main/kotlin/study/domain/Language.kt similarity index 72% rename from src/main/kotlin/study/dto/Language.kt rename to src/main/kotlin/study/domain/Language.kt index fc895d3e47..ff1f571ecc 100644 --- a/src/main/kotlin/study/dto/Language.kt +++ b/src/main/kotlin/study/domain/Language.kt @@ -1,3 +1,3 @@ -package study.dto +package study.domain data class Language(val name: String, val level: Int) diff --git a/src/main/kotlin/study/dto/Person.kt b/src/main/kotlin/study/domain/Person.kt similarity index 84% rename from src/main/kotlin/study/dto/Person.kt rename to src/main/kotlin/study/domain/Person.kt index f0c3e62f51..caab2c25f9 100644 --- a/src/main/kotlin/study/dto/Person.kt +++ b/src/main/kotlin/study/domain/Person.kt @@ -1,3 +1,3 @@ -package study.dto +package study.domain data class Person(val name: String, val company: String, val skills: List, val languages: List) diff --git a/src/main/kotlin/study/dto/Skill.kt b/src/main/kotlin/study/domain/Skill.kt similarity index 67% rename from src/main/kotlin/study/dto/Skill.kt rename to src/main/kotlin/study/domain/Skill.kt index efacd5dcd9..723ba6c7ea 100644 --- a/src/main/kotlin/study/dto/Skill.kt +++ b/src/main/kotlin/study/domain/Skill.kt @@ -1,3 +1,3 @@ -package study.dto +package study.domain data class Skill(val description: String) diff --git a/src/main/kotlin/study/dsl/Person.kt b/src/main/kotlin/study/dsl/Person.kt index c2df507322..987ed559cd 100644 --- a/src/main/kotlin/study/dsl/Person.kt +++ b/src/main/kotlin/study/dsl/Person.kt @@ -3,9 +3,9 @@ package study.dsl import study.builder.LangaugeBuilder import study.builder.PersonBuilder import study.builder.SkillsBuilder -import study.dto.Language -import study.dto.Person -import study.dto.Skill +import study.domain.Language +import study.domain.Person +import study.domain.Skill fun introduce(block: PersonBuilder.() -> Unit): Person { return PersonBuilder().apply(block).build() diff --git a/src/test/kotlin/study/DslTest.kt b/src/test/kotlin/study/DslTest.kt index c49c9dc5be..3ca9f8b3e1 100644 --- a/src/test/kotlin/study/DslTest.kt +++ b/src/test/kotlin/study/DslTest.kt @@ -18,6 +18,27 @@ class DslTest { skills[0].description shouldBe "A passion for problem solving" } + @Test + fun name() { + val person = introduce {} + person.name shouldBe "홍길동" + } + + @Test + fun skills() { + val person = introduce { + name("홍길동") + company("활빈당") + skills { + soft("A passion for problem solving") + soft("Good communication skills") + hard("Kotlin") + } + } + person.skills[0].description shouldBe "A passion for problem solving" + person.skills.size shouldBe 3 + } + @Test fun languageTest() { val person = introduce { From 8cc87289ed74534a547c146fdc2218feccdfb352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Mon, 20 Nov 2023 17:40:35 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=201=EC=B0=A8=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e1c7c927d8..1d5942db27 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ -# kotlin-blackjack \ No newline at end of file +# kotlin-blackjack + +## step2 - 블랙잭 + +기능 요구사항 +- 딜러 + - [ ] : 게임 시작 시에, Player 에게 카드를 2장씩 나눠준다. + - [ ] : Player 에게 추가로 카드를 줄지 말지를 물어본다. + - [ ] : Player 의 답변을 듣는다. + - [ ] : Player 에게 카드를 나눠준다. + - [ ] : Player 의 턴을 종료한다. + - [ ] : Player 가 Bust 가 되었는지 물어본다. +- 플레이어 + - [ ] : 게임 시작시에, 받은 2장의 카드를 보여준다. + - [ ] : 딜러에게 Stay 하겠다고 한다. + - [ ] : 딜러에게 Hit 하겠다고 한다. + - [ ] : 받은 카드의 총합을 계산한다. +- 테이블 + - [ ] : N 명의 플레이어가 play 할 수 있다. \ No newline at end of file From cc9a256ab337f65600650351f7fbef6b37afe6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:22:23 +0900 Subject: [PATCH 03/11] =?UTF-8?q?chore:=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index e78e729567..46d50fa69d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,8 @@ repositories { dependencies { testImplementation("org.junit.jupiter", "junit-jupiter", "5.8.2") testImplementation("org.assertj", "assertj-core", "3.22.0") - testImplementation("io.kotest", "kotest-runner-junit5", "5.2.3") + testImplementation("io.kotest", "kotest-runner-junit5", "5.7.2") + testImplementation("io.kotest", "kotest-assertions-core-jvm", "5.7.2") } tasks { From 77f999a771433d23d89e581d5adfad072e6b4954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:25:28 +0900 Subject: [PATCH 04/11] =?UTF-8?q?chore:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=8F=20=EC=9A=A9=EC=96=B4=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1d5942db27..d7a8ea8847 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,17 @@ 기능 요구사항 - 딜러 - - [ ] : 게임 시작 시에, Player 에게 카드를 2장씩 나눠준다. - - [ ] : Player 에게 추가로 카드를 줄지 말지를 물어본다. - - [ ] : Player 의 답변을 듣는다. - - [ ] : Player 에게 카드를 나눠준다. - - [ ] : Player 의 턴을 종료한다. - - [ ] : Player 가 Bust 가 되었는지 물어본다. -- 플레이어 - - [ ] : 게임 시작시에, 받은 2장의 카드를 보여준다. - - [ ] : 딜러에게 Stay 하겠다고 한다. - - [ ] : 딜러에게 Hit 하겠다고 한다. - - [ ] : 받은 카드의 총합을 계산한다. -- 테이블 - - [ ] : N 명의 플레이어가 play 할 수 있다. \ No newline at end of file + - [x] : 게임 시작 시에, Player 에게 카드를 2장씩 나눠준다. + - [x] : Player 에게 카드를 나눠준다. + - [x] : Player 에게 카드를 나눠줄 수 있는지 확인한다. +- 플레이어 + - [x] : 딜러에게 카드를 달라고 한다. + - [x] : 받은 카드의 총합을 계산한다. +- 게임 + - [x] : N 명의 플레이어가 play 할 수 있다. + +## 용어 정리 +- Hand : 플레이어가 들고 있는 패 +- Card : 카드 (단수) +- Rank : 무늬별로 A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K의 13 가지 끗수(rank) +- Suit : 스페이드, 하트, 다이아몬드, 클럽의 4 가지 무늬(suit) \ No newline at end of file From 3efda6a3f7082314c46dbdb08c98185de3f8b13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:27:46 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20Player=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/model/Player.kt | 22 ++++++++ .../kotlin/blackjack/domain/PlayerSpec.kt | 55 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/main/kotlin/blackJack/model/Player.kt create mode 100644 src/test/kotlin/blackjack/domain/PlayerSpec.kt diff --git a/src/main/kotlin/blackJack/model/Player.kt b/src/main/kotlin/blackJack/model/Player.kt new file mode 100644 index 0000000000..c3a3cbd5b2 --- /dev/null +++ b/src/main/kotlin/blackJack/model/Player.kt @@ -0,0 +1,22 @@ +package blackJack.model + +class Player( + val name: String, + var hand: List = listOf() +) { + fun addCard(card: Card) { + hand += card + } + + fun calculateScore(): Int { + return hand.sumOf { it.rank.score } + } + + fun askMoreCard(dealer: Dealer) { + if (dealer.isDrawCardAllowedFor(this).not()) { + return + } + + addCard(dealer.drawCard()) + } +} diff --git a/src/test/kotlin/blackjack/domain/PlayerSpec.kt b/src/test/kotlin/blackjack/domain/PlayerSpec.kt new file mode 100644 index 0000000000..abd6f25bc3 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/PlayerSpec.kt @@ -0,0 +1,55 @@ +package blackjack.domain + +import blackJack.model.Card +import blackJack.model.Dealer +import blackJack.model.Player +import blackJack.model.enums.Rank +import blackJack.model.enums.Suit +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe + +class PlayerSpec : BehaviorSpec({ + + given("플레이어가 2장의 카드를 받았을 때") { + val player = Player("플레이어") + val dealer = Dealer("딜러") + player.addCard(Card(Suit.SPADES, Rank.ACE)) + player.addCard(Card(Suit.CLUBS, Rank.EIGHT)) + + `when`("플레이어가 가진 카드의 합을 구하면") { + val score = player.calculateScore() + + then("플레이어의 카드 합은 9이다.") { + score shouldBe 9 + } + } + + `when`("bust 상태가 아닌 플레이어가 딜러에게 카드를 더 달라고 요구하면") { + val currentCardCount = player.hand.size + player.askMoreCard(dealer) + val newCardCount = player.hand.size + + then("플레이어는 카드를 한장 더 받는다.") { + currentCardCount shouldBe newCardCount - 1 + } + } + } + + given("bust 상태인 플레이어가") { + val player = Player("플레이어") + val dealer = Dealer("딜러") + player.addCard(Card(Suit.SPADES, Rank.JACK)) + player.addCard(Card(Suit.SPADES, Rank.QUEEN)) + player.addCard(Card(Suit.CLUBS, Rank.EIGHT)) + + `when`("딜러에게 카드를 더 달라고 요구하면") { + val currentCardCount = player.hand.size + player.askMoreCard(dealer) + val newCardCount = player.hand.size + + then("플레이어는 카드를 받지 않는다.") { + newCardCount shouldBe currentCardCount + } + } + } +}) From 562450ae7534d608927b7fda4843f860cc11f8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:27:52 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20Dealer=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/model/Dealer.kt | 38 +++++++++++++++ .../kotlin/blackjack/domain/DealerSpec.kt | 48 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/main/kotlin/blackJack/model/Dealer.kt create mode 100644 src/test/kotlin/blackjack/domain/DealerSpec.kt diff --git a/src/main/kotlin/blackJack/model/Dealer.kt b/src/main/kotlin/blackJack/model/Dealer.kt new file mode 100644 index 0000000000..6f5b981cd7 --- /dev/null +++ b/src/main/kotlin/blackJack/model/Dealer.kt @@ -0,0 +1,38 @@ +package blackJack.model + +class Dealer(val name: String) { + private var cardDeck = CardDeck.of() + + fun startGame(players: List): List { + return initializePlayerHands(players) + } + + private fun initializePlayerHands(players: List): List { + players.forEach { player -> + player.addCard(drawCard()) + player.addCard(drawCard()) + } + + return players + } + + fun drawCard(): Card { + val currentCard = cardDeck.cards + .shuffled() + .first() + + cardDeck = cardDeck.cards + .filter { it != currentCard } + .let(::CardDeck) + + return currentCard + } + + fun isDrawCardAllowedFor(player: Player): Boolean { + return player.calculateScore() < 21 + } + + fun countCard(): Int { + return cardDeck.cards.size + } +} diff --git a/src/test/kotlin/blackjack/domain/DealerSpec.kt b/src/test/kotlin/blackjack/domain/DealerSpec.kt new file mode 100644 index 0000000000..6efb615800 --- /dev/null +++ b/src/test/kotlin/blackjack/domain/DealerSpec.kt @@ -0,0 +1,48 @@ +package blackjack.domain + +import blackJack.model.Dealer +import blackJack.model.Player +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe + +class DealerSpec : BehaviorSpec({ + given("딜러와 플레이어 2명이 있을떄") { + val dealer = Dealer("dealer") + val player1 = Player("player1") + val player2 = Player("player2") + val players = listOf(player1, player2) + + `when`("게임을 시작했을때") { + dealer.startGame(players) + + then("플레이어는 딜러가 나눠준 카드를 두장씩 갖고 있다.") { + players[0].hand.size shouldBe 2 + players[1].hand.size shouldBe 2 + } + } + } + + given("딜러에게 카드덱이 주어지고") { + val dealer = Dealer("dealer") + + `when`("딜러가 게임을 시작했을때") { + val players = listOf(Player("player1"), Player("player2")) + dealer.startGame(players) + + then("플레이어는 딜러가 나눠준 카드를 두장씩 갖고 있다.") { + players[0].hand.size shouldBe 2 + players[1].hand.size shouldBe 2 + } + } + + `when`("딜러에게 카드를 한장 나눠줬을때") { + val prevCount = dealer.countCard() + dealer.drawCard() + val currentCount = dealer.countCard() + + then("카드덱에는 한장의 카드가 사라졌다.") { + currentCount shouldBe prevCount - 1 + } + } + } +}) From 6f4931154c3b1867fd9d8f8cb65a6c43be2c7227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:28:02 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20enum=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/model/enums/Rank.kt | 21 +++++++++++++++++++ src/main/kotlin/blackJack/model/enums/Suit.kt | 8 +++++++ 2 files changed, 29 insertions(+) create mode 100644 src/main/kotlin/blackJack/model/enums/Rank.kt create mode 100644 src/main/kotlin/blackJack/model/enums/Suit.kt diff --git a/src/main/kotlin/blackJack/model/enums/Rank.kt b/src/main/kotlin/blackJack/model/enums/Rank.kt new file mode 100644 index 0000000000..b538499735 --- /dev/null +++ b/src/main/kotlin/blackJack/model/enums/Rank.kt @@ -0,0 +1,21 @@ +package blackJack.model.enums + +enum class Rank( + val symbol: String, + val score: Int, + val isAce: Boolean = false +) { + ACE("A", 1, true), + 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("J", 10), + QUEEN("Q", 10), + KING("K", 10), +} diff --git a/src/main/kotlin/blackJack/model/enums/Suit.kt b/src/main/kotlin/blackJack/model/enums/Suit.kt new file mode 100644 index 0000000000..2f07838ac4 --- /dev/null +++ b/src/main/kotlin/blackJack/model/enums/Suit.kt @@ -0,0 +1,8 @@ +package blackJack.model.enums + +enum class Suit(val symbol: String) { + CLUBS("클로버"), + DIAMONDS("다이아몬드"), + HEARTS("하트"), + SPADES("스페이드") +} From e241a39c7de3c4f368d288fa455d4f8dbe880d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:28:17 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/model/Card.kt | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/kotlin/blackJack/model/Card.kt diff --git a/src/main/kotlin/blackJack/model/Card.kt b/src/main/kotlin/blackJack/model/Card.kt new file mode 100644 index 0000000000..ee7cb783fe --- /dev/null +++ b/src/main/kotlin/blackJack/model/Card.kt @@ -0,0 +1,30 @@ +package blackJack.model + +import blackJack.model.enums.Rank +import blackJack.model.enums.Suit + +data class Card( + val suit: Suit, + val rank: Rank +) + +class CardDeck(val cards: List) { + companion object { + fun of(): CardDeck { + val cards = generateAllCards() + return CardDeck(cards) + } + + private fun generateAllCards(): List { + return Suit.values().flatMap { suit -> + generateCardsForSuit(suit) + } + } + + private fun generateCardsForSuit(suit: Suit): List { + return Rank.values().map { rank -> + Card(suit, rank) + } + } + } +} From 118996ee35b0e6154702bf4c700760b08f58f98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:28:27 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EB=B7=B0=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/view/InputView.kt | 22 +++++++++++++++ src/main/kotlin/blackJack/view/OutputView.kt | 28 ++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/main/kotlin/blackJack/view/InputView.kt create mode 100644 src/main/kotlin/blackJack/view/OutputView.kt diff --git a/src/main/kotlin/blackJack/view/InputView.kt b/src/main/kotlin/blackJack/view/InputView.kt new file mode 100644 index 0000000000..f58f356a9c --- /dev/null +++ b/src/main/kotlin/blackJack/view/InputView.kt @@ -0,0 +1,22 @@ +package blackJack.view + +object InputView { + private const val PLAYER_QUERY_FORMAT = "%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)" + + fun getNames(): List { + println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)") + val input = readlnOrNull() ?: throw IllegalArgumentException("콘솔 입력을 확인해 주세요.") + + return input.replace(" ", "") + .split(",") + } + + fun getPlayerInput(playerName: String): String { + println(PLAYER_QUERY_FORMAT.format(playerName)) + + val input = readlnOrNull() ?: throw IllegalArgumentException("콘솔 입력을 확인해 주세요.") + require(input == "y" || input == "n") ?: throw IllegalArgumentException("y 또는 n을 입력해 주세요.") + + return input + } +} \ No newline at end of file diff --git a/src/main/kotlin/blackJack/view/OutputView.kt b/src/main/kotlin/blackJack/view/OutputView.kt new file mode 100644 index 0000000000..28f4d595b2 --- /dev/null +++ b/src/main/kotlin/blackJack/view/OutputView.kt @@ -0,0 +1,28 @@ +package blackJack.view + +import blackJack.model.Player + +object OutputView { + private const val PLAYER_STATE_FORMAT = "%s카드 : %s" + private const val PLAYER__FINAL_STATE_FORMAT = "%s카드 : %s - 결과: %s" + + fun printPlayersState(players: List) { + players.forEach { printPlayerState(it) } + } + + fun printFinalState(players: List) { + players.forEach { printPlayerFinalState(it) } + } + + fun printPlayerState(player: Player) { + player.hand + .joinToString { it.rank.symbol + it.suit.symbol } + .let { println(PLAYER_STATE_FORMAT.format(player.name, it)) } + } + + private fun printPlayerFinalState(player: Player) { + player.hand + .joinToString { it.rank.symbol + it.suit.symbol } + .let { println(PLAYER__FINAL_STATE_FORMAT.format(player.name, it, player.calculateScore())) } + } +} From 0a5687d250b37f8bbdeb7277bf1f09bdb84257ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:28:36 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # step2 --- src/main/kotlin/blackJack/BlackJackRunner.kt | 9 +++++ .../controller/BlackJackController.kt | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/main/kotlin/blackJack/BlackJackRunner.kt create mode 100644 src/main/kotlin/blackJack/controller/BlackJackController.kt diff --git a/src/main/kotlin/blackJack/BlackJackRunner.kt b/src/main/kotlin/blackJack/BlackJackRunner.kt new file mode 100644 index 0000000000..ac4f83d1f4 --- /dev/null +++ b/src/main/kotlin/blackJack/BlackJackRunner.kt @@ -0,0 +1,9 @@ +package blackJack + +import blackJack.controller.BlackJackController + +class BlackJackRunner + +fun main() { + BlackJackController().play() +} diff --git a/src/main/kotlin/blackJack/controller/BlackJackController.kt b/src/main/kotlin/blackJack/controller/BlackJackController.kt new file mode 100644 index 0000000000..cf85d9f572 --- /dev/null +++ b/src/main/kotlin/blackJack/controller/BlackJackController.kt @@ -0,0 +1,39 @@ +package blackJack.controller + +import blackJack.model.Dealer +import blackJack.model.Player +import blackJack.view.InputView +import blackJack.view.OutputView + +class BlackJackController { + fun play() { + val req = InputView.getNames() + + val candidates = req.map { Player(it) } + val dealer = Dealer("dealer") + + val players = dealer.startGame(candidates) + OutputView.printPlayersState(players) + + players.forEach { player -> + shouldContinue(player, dealer) + } + + OutputView.printFinalState(players) + } + + private fun shouldContinue(player: Player, dealer: Dealer) { + while (true) { + val req = InputView.getPlayerInput(player.name) + if (req == "n") { + break + } + player.askMoreCard(dealer) + + if (dealer.isDrawCardAllowedFor(player).not()) { + break + } + OutputView.printPlayerState(player) + } + } +} From 5f843a9aacf9e838fc021ac5952aa6d8583423f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moses=2Elee=28=EC=9D=B4=EC=83=81=ED=9B=84=29/kakao?= Date: Tue, 21 Nov 2023 21:56:36 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 가독성 증진 - unused file 정리 # step2 --- .../controller/BlackJackController.kt | 6 ++-- src/main/kotlin/blackJack/model/Card.kt | 21 ------------- src/main/kotlin/blackJack/model/CardDeck.kt | 25 +++++++++++++++ src/main/kotlin/blackJack/model/Dealer.kt | 31 ++++++++++--------- src/main/kotlin/blackJack/model/Player.kt | 18 +++++------ .../kotlin/blackjack/domain/PlayerSpec.kt | 16 +++++----- 6 files changed, 62 insertions(+), 55 deletions(-) create mode 100644 src/main/kotlin/blackJack/model/CardDeck.kt diff --git a/src/main/kotlin/blackJack/controller/BlackJackController.kt b/src/main/kotlin/blackJack/controller/BlackJackController.kt index cf85d9f572..9c5e1dab9d 100644 --- a/src/main/kotlin/blackJack/controller/BlackJackController.kt +++ b/src/main/kotlin/blackJack/controller/BlackJackController.kt @@ -2,6 +2,8 @@ package blackJack.controller import blackJack.model.Dealer import blackJack.model.Player +import blackJack.model.askMoreCard +import blackJack.model.checkDrawCardIsAllowedFor import blackJack.view.InputView import blackJack.view.OutputView @@ -28,9 +30,9 @@ class BlackJackController { if (req == "n") { break } - player.askMoreCard(dealer) + player askMoreCard dealer - if (dealer.isDrawCardAllowedFor(player).not()) { + if ((dealer checkDrawCardIsAllowedFor player).not()) { break } OutputView.printPlayerState(player) diff --git a/src/main/kotlin/blackJack/model/Card.kt b/src/main/kotlin/blackJack/model/Card.kt index ee7cb783fe..f457d73136 100644 --- a/src/main/kotlin/blackJack/model/Card.kt +++ b/src/main/kotlin/blackJack/model/Card.kt @@ -7,24 +7,3 @@ data class Card( val suit: Suit, val rank: Rank ) - -class CardDeck(val cards: List) { - companion object { - fun of(): CardDeck { - val cards = generateAllCards() - return CardDeck(cards) - } - - private fun generateAllCards(): List { - return Suit.values().flatMap { suit -> - generateCardsForSuit(suit) - } - } - - private fun generateCardsForSuit(suit: Suit): List { - return Rank.values().map { rank -> - Card(suit, rank) - } - } - } -} diff --git a/src/main/kotlin/blackJack/model/CardDeck.kt b/src/main/kotlin/blackJack/model/CardDeck.kt new file mode 100644 index 0000000000..6543781e15 --- /dev/null +++ b/src/main/kotlin/blackJack/model/CardDeck.kt @@ -0,0 +1,25 @@ +package blackJack.model + +import blackJack.model.enums.Rank +import blackJack.model.enums.Suit + +class CardDeck(val cards: List) { + companion object { + fun of(): CardDeck { + val cards = generateAllCards() + return CardDeck(cards) + } + + private fun generateAllCards(): List { + return Suit.values().flatMap { suit -> + generateCardsForSuit(suit) + } + } + + private fun generateCardsForSuit(suit: Suit): List { + return Rank.values().map { rank -> + Card(suit, rank) + } + } + } +} diff --git a/src/main/kotlin/blackJack/model/Dealer.kt b/src/main/kotlin/blackJack/model/Dealer.kt index 6f5b981cd7..7ef62379b4 100644 --- a/src/main/kotlin/blackJack/model/Dealer.kt +++ b/src/main/kotlin/blackJack/model/Dealer.kt @@ -2,18 +2,10 @@ package blackJack.model class Dealer(val name: String) { private var cardDeck = CardDeck.of() + val MAXIMUM_SCORE = 21 - fun startGame(players: List): List { - return initializePlayerHands(players) - } - - private fun initializePlayerHands(players: List): List { - players.forEach { player -> - player.addCard(drawCard()) - player.addCard(drawCard()) - } - - return players + fun countCard(): Int { + return cardDeck.cards.size } fun drawCard(): Card { @@ -28,11 +20,20 @@ class Dealer(val name: String) { return currentCard } - fun isDrawCardAllowedFor(player: Player): Boolean { - return player.calculateScore() < 21 + fun startGame(players: List): List { + return initializePlayerHands(players) } - fun countCard(): Int { - return cardDeck.cards.size + private fun initializePlayerHands(players: List): List { + players.forEach { player -> + player requestCardToDealer drawCard() + player requestCardToDealer drawCard() + } + + return players } } + +infix fun Dealer.checkDrawCardIsAllowedFor(player: Player): Boolean { + return player.calculateScore() < MAXIMUM_SCORE +} diff --git a/src/main/kotlin/blackJack/model/Player.kt b/src/main/kotlin/blackJack/model/Player.kt index c3a3cbd5b2..237b964d5e 100644 --- a/src/main/kotlin/blackJack/model/Player.kt +++ b/src/main/kotlin/blackJack/model/Player.kt @@ -4,19 +4,17 @@ class Player( val name: String, var hand: List = listOf() ) { - fun addCard(card: Card) { - hand += card - } - fun calculateScore(): Int { return hand.sumOf { it.rank.score } } +} - fun askMoreCard(dealer: Dealer) { - if (dealer.isDrawCardAllowedFor(this).not()) { - return - } - - addCard(dealer.drawCard()) +infix fun Player.askMoreCard(dealer: Dealer) { + if (dealer checkDrawCardIsAllowedFor this) { + this requestCardToDealer dealer.drawCard() } } + +infix fun Player.requestCardToDealer(card: Card) { + hand += card +} diff --git a/src/test/kotlin/blackjack/domain/PlayerSpec.kt b/src/test/kotlin/blackjack/domain/PlayerSpec.kt index abd6f25bc3..d29f7d8f35 100644 --- a/src/test/kotlin/blackjack/domain/PlayerSpec.kt +++ b/src/test/kotlin/blackjack/domain/PlayerSpec.kt @@ -3,8 +3,10 @@ package blackjack.domain import blackJack.model.Card import blackJack.model.Dealer import blackJack.model.Player +import blackJack.model.askMoreCard import blackJack.model.enums.Rank import blackJack.model.enums.Suit +import blackJack.model.requestCardToDealer import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe @@ -13,8 +15,8 @@ class PlayerSpec : BehaviorSpec({ given("플레이어가 2장의 카드를 받았을 때") { val player = Player("플레이어") val dealer = Dealer("딜러") - player.addCard(Card(Suit.SPADES, Rank.ACE)) - player.addCard(Card(Suit.CLUBS, Rank.EIGHT)) + player requestCardToDealer Card(Suit.SPADES, Rank.ACE) + player requestCardToDealer Card(Suit.CLUBS, Rank.EIGHT) `when`("플레이어가 가진 카드의 합을 구하면") { val score = player.calculateScore() @@ -26,7 +28,7 @@ class PlayerSpec : BehaviorSpec({ `when`("bust 상태가 아닌 플레이어가 딜러에게 카드를 더 달라고 요구하면") { val currentCardCount = player.hand.size - player.askMoreCard(dealer) + player askMoreCard dealer val newCardCount = player.hand.size then("플레이어는 카드를 한장 더 받는다.") { @@ -38,13 +40,13 @@ class PlayerSpec : BehaviorSpec({ given("bust 상태인 플레이어가") { val player = Player("플레이어") val dealer = Dealer("딜러") - player.addCard(Card(Suit.SPADES, Rank.JACK)) - player.addCard(Card(Suit.SPADES, Rank.QUEEN)) - player.addCard(Card(Suit.CLUBS, Rank.EIGHT)) + player requestCardToDealer Card(Suit.SPADES, Rank.JACK) + player requestCardToDealer Card(Suit.SPADES, Rank.QUEEN) + player requestCardToDealer Card(Suit.CLUBS, Rank.EIGHT) `when`("딜러에게 카드를 더 달라고 요구하면") { val currentCardCount = player.hand.size - player.askMoreCard(dealer) + player askMoreCard dealer val newCardCount = player.hand.size then("플레이어는 카드를 받지 않는다.") {