-
Notifications
You must be signed in to change notification settings - Fork 313
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
Step2: 블랙잭 구현 #667
base: baek0318
Are you sure you want to change the base?
Step2: 블랙잭 구현 #667
Changes from all commits
fd3513d
7c30e8f
96a8a5a
548b223
0530d68
d776058
18cd2e0
d2d6a5c
3dcf331
d76b686
f583371
c145171
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
# kotlin-blackjack | ||
# kotlin-blackjack | ||
|
||
## 요구사항 | ||
- 카드의 숫자 계산은 카드 숫자를 기본으로 하며 | ||
- Ace는 1 또는 11로 계산할 수 있으며 | ||
- King, Queen, Jack은 각각 10으로 계산한다. | ||
- 게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며 | ||
- 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. | ||
- 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package blackjack | ||
|
||
enum class Card( | ||
val score: Int | ||
) { | ||
ACE(1), | ||
TWO(2), | ||
THREE(3), | ||
FOUR(4), | ||
FIVE(5), | ||
SIX(6), | ||
SEVEN(7), | ||
EIGHT(8), | ||
NINE(9), | ||
TEN(10), | ||
JACK(10), | ||
QUEEN(10), | ||
KING(10); | ||
} | ||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package blackjack | ||
|
||
interface CardDeck { | ||
fun drawCard(): Card | ||
|
||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package blackjack | ||
|
||
fun oneMoreCardInput(): Boolean { | ||
val input = readlnOrNull() ?: throw IllegalArgumentException("올바른 입력을 해주세요") | ||
return when (input) { | ||
"y" -> true | ||
"n" -> false | ||
else -> throw IllegalArgumentException("올바른 입력을 해주세요") | ||
} | ||
Comment on lines
+5
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3; view의 영역이라도 적절한 객체로 관리하면 어떨까요? |
||
} | ||
|
||
fun namesInput(): List<String> { | ||
return readlnOrNull()?.split(",") ?: throw IllegalArgumentException("이름을 입력해주세요.") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package blackjack | ||
|
||
class ListCardDeck( | ||
private val cards: MutableList<Card> | ||
): CardDeck { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3; 클래스 정렬이 되어 있지 않은 거 같아요. |
||
|
||
override fun drawCard(): Card { | ||
checkCardCount() | ||
return cards.removeAt(cards.size - 1) | ||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
private fun checkCardCount() { | ||
if (cards.size == 0) { | ||
throw IllegalStateException("카드가 없습니다.") | ||
} | ||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package blackjack | ||
|
||
fun main() { | ||
startOutput() | ||
val names = namesInput() | ||
val players = names.map { Player(it) } | ||
val deck = RandomCardDeck() | ||
|
||
giveCardsOutput(players.joinToString(separator = ",") { it.name }) | ||
initPlayer(players, deck) | ||
|
||
playGame(players, deck) | ||
|
||
resultOutput(players) | ||
} | ||
|
||
fun initPlayer(players: List<Player>, deck: CardDeck) { | ||
players.forEach { | ||
it.go(deck.drawCard()) | ||
it.go(deck.drawCard()) | ||
whatCardsOutput(it.name, it.cards.joinToString(separator = ",") { card -> card.name }) | ||
} | ||
} | ||
|
||
fun playGame(players: List<Player>, deck: CardDeck) { | ||
players.forEach { | ||
playerGoOrStop(it, deck) | ||
} | ||
} | ||
|
||
private fun playerGoOrStop(player: Player, deck: CardDeck) { | ||
while (true) { | ||
if (isGo(player, deck)) break | ||
} | ||
} | ||
|
||
private fun isGo(player: Player, deck: CardDeck): Boolean { | ||
oneMoreCardOutput(player.name) | ||
val isGo = oneMoreCardInput() | ||
if (isGo) { | ||
player.go(deck.drawCard()) | ||
drawResultOutput(player.name, player.cards.joinToString(separator = ",") { card -> card.name }) | ||
} else { | ||
return true | ||
} | ||
return false | ||
} | ||
Comment on lines
+3
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p1; 메인에 작성해 주신 내용들은 비즈니스 로직 성격이 짙은 거 같아요. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package blackjack | ||
|
||
fun startOutput() { | ||
println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)") | ||
} | ||
|
||
fun giveCardsOutput(name: String) { | ||
println("${name}에게 카드를 2장 나누었습니다.") | ||
} | ||
|
||
fun whatCardsOutput(name: String, cardsName: String) { | ||
println("${name}카드: $cardsName") | ||
} | ||
|
||
fun drawResultOutput(name: String, cardsName: String) { | ||
println("${name}카드: $cardsName") | ||
} | ||
|
||
fun resultOutput(players: List<Player>) { | ||
players.forEach { | ||
println("${it.name}카드: ${it.cards.joinToString(separator = ",") { card -> card.name }}-결과: ${it.stop()}") | ||
} | ||
} | ||
|
||
fun oneMoreCardOutput(name: String) { | ||
println("${name}는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package blackjack | ||
|
||
class Player( | ||
val name: String, | ||
) { | ||
private val _cards: MutableList<Card> = mutableListOf() | ||
|
||
val cards: List<Card> | ||
get() = _cards.toList() | ||
|
||
fun go(card: Card) { | ||
_cards.add(card) | ||
} | ||
|
||
fun stop(): Int { | ||
return ScoreCalculator.calc(cards) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p2; stop이라는 메서드에서 계산까지 해주는 형태네요. 플레이어가 ScoreCalculator를 알아야 할지 고민해 보면 좋을 거 같아요. |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package blackjack | ||
|
||
class RandomCardDeck: CardDeck { | ||
override fun drawCard(): Card { | ||
return Card.values().random() | ||
} | ||
} | ||
Comment on lines
+3
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p1; 카드덱은 정해져 있고, 그 과정에서 랜덤하게 나와야 할 거 같은데 이 구조라면 A(다이아), A(다이아), A(다이아)... 처럼 동일한 카드와 형태를 받을 수도 있을 거 같아요. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package blackjack | ||
|
||
object ScoreCalculator { | ||
|
||
fun calc(cards: List<Card>): Int { | ||
return cards.map { it.score }.reduce { acc, i -> acc + i } | ||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package dsl | ||
|
||
@DslMarker | ||
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) | ||
annotation class Dsl() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,82 @@ | ||
package dsl | ||
|
||
class Resume( | ||
var name: String = "", | ||
var company: String = "", | ||
var skills: Skill = Skill(), | ||
var languages: Language = Language() | ||
data class Resume( | ||
val name: String, | ||
val company: String, | ||
val skills: Skills, | ||
val languages: Languages | ||
) { | ||
|
||
fun name(name: String) { | ||
this.name = name | ||
} | ||
|
||
fun company(companyName: String) { | ||
this.company = companyName | ||
} | ||
|
||
fun skills(block: Skill.() -> Unit) { | ||
skills.block() | ||
} | ||
|
||
fun languages(block: Language.() -> Unit) { | ||
languages.block() | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
|
||
other as Resume | ||
|
||
if (name != other.name) return false | ||
if (company != other.company) return false | ||
if (skills != other.skills) return false | ||
if (languages != other.languages) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = name.hashCode() | ||
result = 31 * result + company.hashCode() | ||
result = 31 * result + skills.hashCode() | ||
result = 31 * result + languages.hashCode() | ||
return result | ||
class Builder( | ||
private var name: String = "", | ||
private var company: String = "", | ||
private var skills: Skills.Builder = Skills.Builder(), | ||
private var languages: Languages.Builder = Languages.Builder() | ||
) { | ||
|
||
fun name(name: String) { | ||
this.name = name | ||
} | ||
|
||
fun company(companyName: String) { | ||
this.company = companyName | ||
} | ||
|
||
fun skills(block: (@Dsl Skills.Builder).() -> Unit) { | ||
skills.block() | ||
} | ||
|
||
fun languages(block: (@Dsl Languages.Builder).() -> Unit) { | ||
languages.block() | ||
} | ||
|
||
internal fun build(): Resume { | ||
return Resume(name, company, skills.build(), languages.build()) | ||
} | ||
baek0318 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
|
||
} | ||
|
||
class Skill( | ||
val softSkills: MutableList<String> = mutableListOf(), | ||
val hardSkills: MutableList<String> = mutableListOf() | ||
data class Skills( | ||
val softSkills: List<String>, | ||
val hardSkills: List<String> | ||
) { | ||
|
||
fun soft(skill: String) { | ||
softSkills.add(skill) | ||
} | ||
|
||
fun hard(skill: String) { | ||
hardSkills.add(skill) | ||
class Builder( | ||
private val softSkills: MutableList<String> = mutableListOf(), | ||
private val hardSkills: MutableList<String> = mutableListOf() | ||
) { | ||
|
||
fun soft(skill: String) { | ||
softSkills.add(skill) | ||
} | ||
|
||
fun hard(skill: String) { | ||
hardSkills.add(skill) | ||
} | ||
|
||
internal fun build(): Skills { | ||
return Skills(softSkills, hardSkills) | ||
} | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
|
||
other as Skill | ||
|
||
if (softSkills != other.softSkills) return false | ||
if (hardSkills != other.hardSkills) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = softSkills.hashCode() | ||
result = 31 * result + hardSkills.hashCode() | ||
return result | ||
} | ||
|
||
|
||
} | ||
|
||
class Language( | ||
val languages: MutableMap<String, Int> = mutableMapOf() | ||
data class Languages( | ||
val languages: Map<String, Int> | ||
) { | ||
class Builder( | ||
private val languages: MutableMap<String, Int> = mutableMapOf() | ||
) { | ||
|
||
infix fun String.level(level: Int) { | ||
languages[this] = level | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
infix fun String.level(level: Int) { | ||
languages[this] = level | ||
} | ||
|
||
other as Language | ||
|
||
return languages == other.languages | ||
internal fun build(): Languages { | ||
return Languages(languages) | ||
} | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return languages.hashCode() | ||
} | ||
|
||
|
||
} | ||
|
||
|
||
fun introduce(block: Resume.() -> Unit): Resume { | ||
val resume = Resume() | ||
resume.block() | ||
return resume | ||
fun introduce(block: (@Dsl Resume.Builder).() -> Unit): Resume { | ||
val builder = Resume.Builder() | ||
builder.block() | ||
return builder.build() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package blackjack | ||
|
||
import io.kotest.core.spec.style.StringSpec | ||
import io.kotest.matchers.shouldBe | ||
import java.util.* | ||
import kotlin.collections.ArrayList | ||
|
||
class CardDeckTest: StringSpec({ | ||
|
||
"카드를 뽑을 수 있다" { | ||
val cardDeck = ListCardDeck(mutableListOf(Card.TWO, Card.THREE)) | ||
val card = cardDeck.drawCard() | ||
card shouldBe Card.THREE | ||
} | ||
|
||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p1; 프로그래밍 요구사항이 몇 가지 지켜지지 않은 부분들이 있습니다.
다음 요구사항을 확인하고, 다시 PR 요청 부탁드리겠습니다. 💪🏽