-
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 - 블랙잭 미션 #815
base: goodbyeyo
Are you sure you want to change the base?
Step2 - 블랙잭 미션 #815
Changes from all commits
fefa3de
bd1e7be
768e53d
fa0faeb
784bc4d
a8bd02e
bfb1ce2
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 |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package blackjack | ||
|
||
import blackjack.domain.BlackJackGame | ||
import blackjack.domain.GameCards | ||
import blackjack.view.InputView | ||
import blackjack.view.OutputView | ||
|
||
fun main() { | ||
val players = InputView.enterParticipatingPlayers() | ||
val gameCards = GameCards.create() | ||
val blackJackGame = BlackJackGame(players, gameCards) | ||
blackJackGame.startGame() | ||
OutputView.printFirstAllPlayersCards(players) | ||
players.forEach { player -> | ||
blackJackGame.handlePlayerDraw(player, gameCards) | ||
} | ||
OutputView.printFinalResults(players) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package blackjack | ||
|
||
import blackjack.domain.Card | ||
import blackjack.domain.Ranks | ||
|
||
class UserCards(private val cards: MutableList<Card>) : Collection<Card> by cards { | ||
fun calculatePoints(): Int { | ||
val basePoints = cards.sumOf { it.rank.points[0] } | ||
val hasAce = cards.any { it.rank == Ranks.ACE } | ||
if (hasAce && basePoints + 10 <= 21) { | ||
return basePoints + 10 | ||
} | ||
return basePoints | ||
} | ||
|
||
fun addCard(card: Card) { | ||
cards.add(card) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package blackjack.domain | ||
|
||
import blackjack.view.InputView | ||
import blackjack.view.OutputView | ||
|
||
class BlackJackGame( | ||
private val players: Players, | ||
private val gameCards: GameCards, | ||
) { | ||
fun startGame() { | ||
repeat(FIRST_ROUND_HAND_SIZE) { | ||
giveOutCards() | ||
} | ||
} | ||
|
||
private fun giveOutCards() { | ||
players.forEach { players -> | ||
players.receiveCard(gameCards.drawCard()) | ||
} | ||
} | ||
|
||
fun handlePlayerDraw( | ||
player: Player, | ||
gameCards: GameCards, | ||
) { | ||
val previousCardCount = player.cardSize() | ||
InputView.enterIsContinueDrawCard(player) | ||
if (player.isDrawContinue) { | ||
player.receiveCard(gameCards.drawCard()) | ||
OutputView.printPlayerCard(player) | ||
handlePlayerDraw(player, gameCards) // 재귀 호출 | ||
} | ||
|
||
if (!player.isDrawContinue && player.cardSize() == previousCardCount) { | ||
OutputView.printPlayerCard(player) | ||
} | ||
} | ||
Comment on lines
+22
to
+37
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.
View에서 입력을 받는 부분을 람다로 처리해서 외부에서 주입받는 형태로 구성해보는 건 어떨까요? |
||
|
||
companion object { | ||
private const val FIRST_ROUND_HAND_SIZE = 2 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package blackjack.domain | ||
|
||
data class Card(val rank: Ranks, val suits: Suits) | ||
Comment on lines
+2
to
+3
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. 카드의 종류는 총 몇가지가 존재할 수 있을까요? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package blackjack.domain | ||
|
||
import java.util.LinkedList | ||
import java.util.Queue | ||
|
||
class GameCards private constructor(private val deck: Queue<Card>) { | ||
fun drawCard(): Card { | ||
return deck.poll() | ||
} | ||
|
||
fun size(): Int { | ||
return deck.size | ||
} | ||
|
||
companion object { | ||
fun create(): GameCards { | ||
val allCards = | ||
Suits.entries.flatMap { suit -> | ||
Ranks.entries.map { rank -> Card(rank, suit) } | ||
} | ||
return GameCards(LinkedList(allCards.shuffled())) | ||
Comment on lines
+15
to
+21
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. 랜덤 요소 때문에 테스트가 어려워보여요. |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package blackjack.domain | ||
|
||
import blackjack.UserCards | ||
|
||
class Player(val name: String, var isDrawContinue: Boolean = true) { | ||
Comment on lines
+4
to
+5
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. isDrawContinue 변수를 외부에서도 변경 가능한 형태예요. |
||
private var userCards = UserCards(mutableListOf()) | ||
|
||
fun receiveCard(card: Card) { | ||
require(isDrawContinue) { "카드를 받을 수 없습니다" } | ||
userCards.addCard(card) | ||
} | ||
|
||
fun cardSize(): Int { | ||
return userCards.size | ||
} | ||
|
||
fun calculateCardPoints(): Int { | ||
return userCards.calculatePoints() | ||
} | ||
|
||
fun stopCardDraw() { | ||
isDrawContinue = false | ||
} | ||
|
||
fun continueCardDraw() { | ||
isDrawContinue = true | ||
} | ||
|
||
fun findAllCardsNames(): List<String> { | ||
return userCards.map { card -> | ||
card.rank.keyword + card.suits.koreanName | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package blackjack.domain | ||
|
||
data class Players(val players: List<Player>) : Collection<Player> by players { | ||
fun getPlayerNames(): List<String> { | ||
return players.map { it.name } | ||
} | ||
|
||
companion object { | ||
private const val DELIMITER = "," | ||
|
||
fun create(playerNames: String): Players { | ||
val players = playerNames.split(DELIMITER).map { playerName -> Player(playerName) } | ||
Comment on lines
+10
to
+12
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. 문자열을 파싱하는 행위는 View의 일이라고 생각해요. |
||
return Players(players) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package blackjack.domain | ||
|
||
enum class Ranks( | ||
val keyword: String, | ||
Comment on lines
+3
to
+4
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. 카드 끝수를 나타내는 이 문자열은 ConsoleView에 종속적인 값이라고 생각해요. |
||
val points: List<Int>, | ||
) { | ||
ACE("A", listOf(1, 11)), | ||
Comment on lines
+6
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. ACE의 기본 점수는 1이고, 특수한 상황에서 10점이 추가되는 것이니, 이것을 로직으로 표현해보는 건 어떨까요? |
||
TWO("2", listOf(2)), | ||
THREE("3", listOf(3)), | ||
FOUR("4", listOf(4)), | ||
FIVE("5", listOf(5)), | ||
SIX("6", listOf(6)), | ||
SEVEN("7", listOf(7)), | ||
EIGHT("8", listOf(8)), | ||
NINE("9", listOf(9)), | ||
TEN("10", listOf(10)), | ||
JACK("J", listOf(10)), | ||
QUEEN("Q", listOf(10)), | ||
KING("K", listOf(10)), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package blackjack.domain | ||
|
||
enum class Suits( | ||
val koreanName: String, | ||
) { | ||
SPADE("스페이드"), | ||
HEART("하트"), | ||
DIAMOND("다이어"), | ||
CLUB("클로버"), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package blackjack.view | ||
|
||
import blackjack.domain.Player | ||
import blackjack.domain.Players | ||
|
||
object InputView { | ||
private const val CONTINUE_OR_STOP_MESSAGE = "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)" | ||
|
||
fun enterParticipatingPlayers(): Players { | ||
println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)") | ||
val playerNames = readln() | ||
return Players.create(playerNames) | ||
} | ||
|
||
fun enterIsContinueDrawCard(player: Player) { | ||
val userInput = getIsContinueDraw(player) | ||
when (userInput.lowercase()) { | ||
"n" -> player.stopCardDraw() | ||
"y" -> player.continueCardDraw() | ||
else -> println("잘못된 입력입니다. 다시 입력해주세요.") | ||
} | ||
Comment on lines
+15
to
+21
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. 플레이어의 게임 진행 자체를 실행하는 로직은 도메인로직이라 생각해요. |
||
} | ||
|
||
fun getIsContinueDraw(player: Player): String { | ||
println() | ||
println(player.name + CONTINUE_OR_STOP_MESSAGE) | ||
return readln() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package blackjack.view | ||
|
||
import blackjack.domain.Player | ||
import blackjack.domain.Players | ||
|
||
object OutputView { | ||
private const val PLAYER_NAME_DELIMITER = ", " | ||
private const val BLANK_PREFIX_MESSAGE = "" | ||
private const val POST_MESSAGE = "에게 2장의 나누었습니다." | ||
private const val RESULT_EXPRESSION = " - 결과: " | ||
private const val NAME_POSTFIX_EXPRESSION = "카드: " | ||
|
||
fun printFirstAllPlayersCards(players: Players) { | ||
println() | ||
val result = | ||
players.getPlayerNames().joinToString( | ||
PLAYER_NAME_DELIMITER, | ||
BLANK_PREFIX_MESSAGE, | ||
POST_MESSAGE, | ||
) | ||
println(result) | ||
players.forEach { player -> | ||
printPlayerAllCards(player) | ||
println() | ||
} | ||
} | ||
|
||
fun printFinalResults(players: Players) { | ||
println() | ||
println() | ||
println("게임 종료!") | ||
players.forEach { player -> | ||
printPlayerAllCards(player) | ||
resultExpression(player) | ||
} | ||
} | ||
|
||
fun printPlayerCard(player: Player) { | ||
printPlayerAllCards(player) | ||
} | ||
|
||
private fun printPlayerAllCards(player: Player) { | ||
print(player.name + NAME_POSTFIX_EXPRESSION) | ||
print(player.findAllCardsNames().joinToString(PLAYER_NAME_DELIMITER)) | ||
} | ||
|
||
private fun resultExpression(player: Player) { | ||
print(RESULT_EXPRESSION) | ||
println(player.calculateCardPoints()) | ||
} | ||
} |
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.
아래 코드를 실행시키면 어떤 일이 발생할 수 있을까요?
방어적 복사와 읽기 전용 List 를 활용해보시면 좋겠어요!