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

Step2 - 블랙젝 #672

Merged
merged 54 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
aabf9e4
Refactor: Skills, Language의 builder를 사용하여 가독성 향상
oyj7677 Nov 21, 2023
67bf9ca
Docs: 기능 목록 초기 구성
oyj7677 Nov 23, 2023
58a82f8
Refactor: Skills, language 구현 변경
oyj7677 Nov 23, 2023
15c50de
Feat: 카드 번호, 카드 무늬 유효성 검증 구현
oyj7677 Nov 23, 2023
6b33e03
Feat: 카드 포인트 반환 기능 구현, 카드 무늬 명 반환 기능 구현
oyj7677 Nov 23, 2023
b88d964
Feat: 카드 클래스 생성 및 카드 구성 데이터 캐싱
oyj7677 Nov 25, 2023
0d06426
Feat: 카드팩 클래스 생성 및 캐싱 구현
oyj7677 Nov 25, 2023
c1a5504
Docs: 블랙젝 게임 기능 추가 (카드팩 기능 이동), 플레이어 기능 목록 변경
oyj7677 Nov 25, 2023
257482f
Docs: 블랙젝 게임 기능 목록 추가.
oyj7677 Nov 25, 2023
e384c31
Feat: 블랙젝 게임 클래스 생성, 카드팩 검증 로직 구현(52장, 중복X)
oyj7677 Nov 25, 2023
683ccfd
Docs: 카드인텍스 기능 목록 추가.
oyj7677 Nov 25, 2023
d261000
Docs: 카드 인텍스 검증 기능 목록 추가
oyj7677 Nov 25, 2023
8aca69f
Feat: 카드 배포 구현
oyj7677 Nov 25, 2023
e897c27
Feat: 플레이어 상태 추가, 플레이어 상태 추가 및 변경 구현
oyj7677 Nov 25, 2023
18317d6
Feat: 플레이어 카드 저장 기능 구현
oyj7677 Nov 25, 2023
88e3b66
Refactor: CardNumber 명칭 추가, class PlayingCard @override toString(), 카…
oyj7677 Nov 25, 2023
c5b5adf
Refactor: 블랙젝 게임 디폴트 파라미터 추가 - playerList: List<Player>
oyj7677 Nov 25, 2023
aae5ec2
Docs: 블랙젝 게임 기능 추가, 블랙젝 계산기 추가.
oyj7677 Nov 26, 2023
84b7ea9
Feat: 카드 초기 세팅 기능 추가(게임 시작시 카드 2장 받음)
oyj7677 Nov 26, 2023
f4fef00
Refactor: CardIndex -> GameIndex로 역할 범위 확장. Index 값 생성자 파라미터 -> Backi…
oyj7677 Nov 27, 2023
231ba04
Refactor: 참여 가능 플레이어 조건 변경, 카드팩 검증 로직 역할 변경(BlackjackGame -> CardPack…
oyj7677 Nov 27, 2023
07f695a
Chore: 프로덕트 클래스, 테스트 클래스 패키지 구조 동기화
oyj7677 Nov 27, 2023
5b83654
Feat: 블랙젝 계산기 추가(승리에 유리한 계산 결과 반환)
oyj7677 Nov 27, 2023
00d42dd
Refactor: CardNumber파라미터 접근 제한 변경 private -> publid
oyj7677 Nov 27, 2023
18c0aea
Docs: 기능 목록 체크
oyj7677 Nov 27, 2023
eccd3a8
Refactor: GameIndex의 index 변수 명 변경 -> cardIndex
oyj7677 Nov 27, 2023
05dbca5
Feat: 게임 인덱스, 플레이어 인덱스 추가 및 증가 기능 구현
oyj7677 Nov 27, 2023
9280506
Feat: 플레이어 카드 저장 함수 추가
oyj7677 Nov 27, 2023
3cf1551
 Feat: 플레이어 상태 업데이트 기능 구현
oyj7677 Nov 27, 2023
d056703
Feat: PlayerGroup 일급 컬렉션 추가,
oyj7677 Nov 27, 2023
70a6c84
Refactor: 카드 반환 기능 CardPack으로 이동
oyj7677 Nov 27, 2023
a8acb07
Refactor: 카드 배포 역할 변경(BlackjackGame -> CardPack), 게임 진행 로직 변경
oyj7677 Nov 27, 2023
9c0d5e9
Refactor: 불필요한 코드 제거 및 수정
oyj7677 Nov 29, 2023
cfe4fde
Refactor
oyj7677 Nov 29, 2023
63171c3
Feat: CardDeck생성(카드 캐싱)
oyj7677 Nov 29, 2023
23fd469
Refactor:
oyj7677 Nov 29, 2023
5854bb5
Refactor:
oyj7677 Nov 29, 2023
335541a
Feat: 플레이어 카드 점수 계산 기능 추가.
oyj7677 Nov 30, 2023
a041fe2
Refactor:
oyj7677 Nov 30, 2023
2b1857d
chore
oyj7677 Nov 30, 2023
ac1c262
Refactor: 플레이어 상태 업데이트 로직 변경
oyj7677 Nov 30, 2023
c70c516
chore: GameDeckTest 주석 추가.
oyj7677 Nov 30, 2023
30d7837
Feat: Input, Output View 구현
oyj7677 Dec 2, 2023
01d4259
Feat: InputData to PlayerList 를 위한 플래이어 팩토리 구현
oyj7677 Dec 2, 2023
e8c4212
Docs: README.md 변경
oyj7677 Dec 2, 2023
9dd1499
Refactor: 게임 덱 셔플 기능 추가, 생성자 public으로 변경, 플레이어 덱 override toString()
oyj7677 Dec 2, 2023
07ed6eb
Refactor: 블랙잭 게임 로직 재구현
oyj7677 Dec 2, 2023
3bd337a
Refactor: 플레이어 관련 불필요한 함수 제거 및 매직 넘버 제거
oyj7677 Dec 2, 2023
fa7ef73
Feat: 메인 함수 구현
oyj7677 Dec 2, 2023
31afda1
style: 코드 컨벤션 정리 (feat: Gradle)
oyj7677 Dec 2, 2023
1c2fd96
Refactor: CardDeck interface 삭제, 플레이어 생성자 추가, 카드팩 재사용, 게임덱 리셋 기능 구현 등…
oyj7677 Dec 6, 2023
4396f52
Chore: 클래스 명 변경 GameDeck -> CardDeck
oyj7677 Dec 6, 2023
aacff6c
Refactor: ViewInterfacd생성 및 BlackjackGame 생성자 추가.
oyj7677 Dec 6, 2023
ff53d99
BlackjackGame 생성자로 ViewInterFace 추가.
oyj7677 Dec 6, 2023
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
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,55 @@
# kotlin-blackjack
# kotlin-blackjack

## 기능 요구 사항

블랙잭 게임을 변형한 프로그램을 구현한다. 블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다.

- 카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다.
- 게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다.

## 기능 목록

### 플레이어

- [O] 플레이어의 초기 상태는 START이다.
- [O] 플레이어가 카드 받는 것을 끝내면 상태는 STAND가 된다.
- [O] 플레이어는 받은 카드를 저장한다.
- [O] 플레이어는 상태를 업데이트 한다.
- [O] 카드의 합이 20 이하 라면 PLAYING
- [O] 카드의 합이 21을 이상 이라면 BUST
- [O] 카드를 받지 않는다 하면 STAND
- [O] 첫 2장의 카드 합이 21이라면 BLACK_JACK

### 플레이어 그룹

- [O] 플레이어는 최소 2명 이상 26명 이하여야 한다.

### 플레이어 펙토리
- [O] 문자열을 받아서 플레이어 리스트 생성.
- [O] 공백은 플레어어로 생성하지 않는다.

### 트럼프 카드(플레잉 카드)

- [O] 카드의 포인트를 반환한다.
- [O] 카드의 무늬 명을 반환한다.
- [O] 카드의 번호를 반환한다.

### 게임 덱
- [O] 카드를 순차적으로 반환한다.
- [O] 카드덱을 추가할 수 있다.

### 플레이어 덱
- [O] 카드를 추가할 수 있다.
- [O] 점수를 반환한다.
- [O] A는 블랙잭에 유리하게 점수를 반영한다.

### inputView

- [O] 플레이어를 입력받는다.
- [O] 플레이어가 입력되지 않으면 예외를 던진다.

### output

- [O] 게임 시작 시 초기 카드 출력
- [O] 플레이어가 가지고 있는 카드를 출력
- [O] 플레이어 카드 계산값을 출력
55 changes: 55 additions & 0 deletions src/main/kotlin/BlackjackGame.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import card.deck.GameDeck
import player.Player
import player.PlayerGroup
import player.Status
import view.InputView
import view.OutputView

class BlackjackGame(private val cardDeck: GameDeck, val playerGroup: PlayerGroup) {

init {
for (player in playerGroup.playerList) {
settingCard(player)
}
}

fun start() {
for (player in playerGroup.playerList) {
gamePlay(player)
}
}

private fun gamePlay(player: Player) {
while (player.status == Status.PLAYING) {
val response = InputView.askForHit(player.name)
handleForResponse(response, player)
OutputView.showPlayingCard(player)
Copy link
Member

Choose a reason for hiding this comment

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

BlackjackGame.kt에서 View와 비지니스 로직이 함께 있습니다. 이번 미션의 경우 지속적으로 input과 output이 있는 경우 클래스나 함수의 구성을 어떤 식으로 해야 테스트 코드와 함께 진행될 수 있나요?

View에 대한 interface를 만들어서, console에 대한 구현체를 주입 받아 사용해볼 수 있겠어요 :)

Copy link
Author

@oyj7677 oyj7677 Dec 6, 2023

Choose a reason for hiding this comment

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

InputViewInterface, OutputViewInterface View interface, 생성 하여 BlackjackGame에 생성자로 전달하여 사용해봤습니다.

class BlackjackGame(
private val cardDeck: CardDeck,
val playerGroup: PlayerGroup,
private val inputView: InputViewInterface,
private val outputView: OutputViewInterface,
) 

Copy link
Author

Choose a reason for hiding this comment

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

InputViewInterface에선
fun askForHit(playerName: String): String

OutputViewInterface에선
fun showPlayingCard(player: Player)

}
}

private fun handleForResponse(response: String, player: Player) {
when (response.uppercase()) {
Comment on lines +35 to +36
Copy link
Member

Choose a reason for hiding this comment

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

response가 String으로 들어오는 것은 Console View의 의존성이 여전히 묻어나보여요.
입력 뷰가 조금 바뀌어서 y, n가 아닌, YES, NO 혹은 예,아니오로 변경된다면, 이 모든 String에서 검증해주어야할까요?

view에서는 예 혹은 아니오에 대한 도메인 객체를 반환하도록 만들어보는 건 어떨까요?

TEXT_ANSWER_YES -> {
player.saveCard(cardDeck.getCardWithIncrease())
}
TEXT_ANSWER_NO -> {
player.playDone()
}
else -> {
println(TEXT_RETRY_INPUT)
}
Comment on lines +43 to +45
Copy link
Member

Choose a reason for hiding this comment

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

이 부분도 여전히 Console View의 의존관계를 가지고있습니다 :)
output View에 대한 추상화를 만드셨으니 이쪽으로 옮겨주세요!

}
}

private fun settingCard(player: Player) {
repeat(2) {
player.saveCard(cardDeck.getCardWithIncrease())
}
}

companion object {
private const val TEXT_RETRY_INPUT = "Y 혹은 N만 입력 가능합니다."
private const val TEXT_ANSWER_YES = "Y"
private const val TEXT_ANSWER_NO = "N"
}
}
21 changes: 21 additions & 0 deletions src/main/kotlin/BlackjackMain.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import card.CardPack
import card.deck.GameDeck
import player.PlayerFactory
import player.PlayerGroup
import view.InputView
import view.OutputView

fun main() {

val playerNames = InputView.inputPlayerName()
val playerGroup = PlayerGroup(PlayerFactory.createPlayerList(playerNames))
val gameDeck = GameDeck(CardPack.cards.toMutableList())

val game = BlackjackGame(cardDeck = gameDeck, playerGroup = playerGroup)

OutputView.showGameStart(game.playerGroup)

game.start()

OutputView.showGameEnd(game.playerGroup)
}
9 changes: 9 additions & 0 deletions src/main/kotlin/card/CardPack.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package card

object CardPack {
val cards: List<PlayingCard> = CardRank.values().flatMap { rank ->
Suit.values().map { suit ->
PlayingCard(suit = suit, cardRank = rank)
}
}
}
27 changes: 27 additions & 0 deletions src/main/kotlin/card/CardRank.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package card

enum class CardRank(val point: Int, val symbol: String) {
ACE(1, "A"),
TWO(2, "2"),
TREE(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");

companion object {

private val cardNumberList = listOf(
ACE, TWO, TREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING,
)

fun getCardNumberList() = cardNumberList
Copy link
Member

Choose a reason for hiding this comment

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

#672 (comment)

이 피드백을 참고해볼 수 있겠네요 :)

Copy link
Author

@oyj7677 oyj7677 Dec 6, 2023

Choose a reason for hiding this comment

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

해당 리뷰 수정하였습니다. 사용하지 않는 함수 제거하였습니다.

init {
        for (suit in Suit.values()) {
            for (cardRank in CardRank.values()) {
                CARDS[toKey(suit, cardRank)] = PlayingCard(suit, cardRank)
            }
        }
    }

}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/card/PlayingCard.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package card

data class PlayingCard(private val suit: Suit, private val cardRank: CardRank) {
Copy link
Member

Choose a reason for hiding this comment

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

#672 (comment)
여전히 유효한 피드백입니다 :)

Copy link
Author

@oyj7677 oyj7677 Dec 6, 2023

Choose a reason for hiding this comment

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

생성자의 내부로 들어가야하는 값은 메세지를 보내서 받고 직접 접근하는 건 접근제한자를 제거했습니다.

data class PlayingCard(val suit: Suit, val cardRank: CardRank) {
    fun getPoint(): Int {
        return cardRank.point
    }

    fun getSuitName(): String {
        return suit.koName
    }
.....
}

윤혁님만의 직접 접근과 메시지를 통한 접근에 대한 기준점을 알려주시면 감사드리겠습니다.

Copy link
Member

Choose a reason for hiding this comment

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

여러 팩의 카드를 현실세계에서 사용한다면, 스페이드 ACE라는 카드는 팩의 수 만큼 존재하겠지요 :)
컴퓨터의 세계에서도 동일할까요?
여러 팩의 카드를 쓰더라도, 동일한 인스턴스를 가리킨다면, 스페이드 ACE라는 카드(인스턴스)는 메모리 상에 단 한 장만 존재해도 됩니다.

하지만 현재 스페이드 ACE 라는 카드는 생성자를 통해 얼마든지 만들어낼 수 있는 구조이지요 :)
그렇기에 생성자를 private으로 변경하고, 팩터리 메서드를 통해 캐싱된 카드를 반환하도록 만들어보라는 의미었습니다.

자바에서는 Integer라는 class에서 자주 사용하는 숫자를 캐싱해두고 사용해요.
이 부분의 구현을 참고해보셔도 좋겠어요 :)

fun getPoint(): Int {
return cardRank.point
}

fun getSuitName(): String {
return suit.koName
}

fun getCardRank(): CardRank {
return cardRank
}
Copy link
Member

Choose a reason for hiding this comment

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

#672 (comment)

코틀린 프로퍼티에 아직 익숙하지 않으신 것 같네요!
의식적인 연습을 하시면 충분히 익숙해지실 거라 생각해요 :)

Copy link
Author

Choose a reason for hiding this comment

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

생성자 프로퍼티가 public이 되면서 삭제하였습니다.


override fun toString(): String {
return "${cardRank.symbol}${suit.koName}"
}
}
7 changes: 7 additions & 0 deletions src/main/kotlin/card/Suit.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package card
enum class Suit(val koName: String) {
SPADE("스페이드"),
HEART("하트"),
DIAMOND("다이아몬드"),
CLUB("클러버");
}
7 changes: 7 additions & 0 deletions src/main/kotlin/card/deck/CardDeck.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package card.deck

import card.PlayingCard

interface CardDeck {
val cardDeck: MutableList<PlayingCard>
}
19 changes: 19 additions & 0 deletions src/main/kotlin/card/deck/GameDeck.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package card.deck

import card.PlayingCard

class GameDeck(override val cardDeck: MutableList<PlayingCard>) : CardDeck {

init {
cardDeck.shuffle()
}
private var index = 0

fun getCardWithIncrease(): PlayingCard {
return cardDeck[index++]
}

fun addCards(cards: List<PlayingCard>) {
this.cardDeck.addAll(cards)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

index가 51을 넘어가면 out of index 예외가 발생할 것으로 우려되는데요,

블랙잭 게임 룰 중에는 한 번에 여러 벌의 카드를 섞어 진행하기도 합니다.
이런 요구사항에 유연하게 대응할 수 있게 구성해보는 건 어떨까요?

Copy link
Author

@oyj7677 oyj7677 Dec 6, 2023

Choose a reason for hiding this comment

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

카드의 인덱스가 카드덱 사이즈와 같아지면 인덱스를 0으로 변경하고 카드 셔플을 진행하도록 변경하였습니다.

fun getCardWithIncrease(): PlayingCard {
    if (isMaxIndexOfCard()) resetCard()
    return cardList[index++]
}

private fun isMaxIndexOfCard(): Boolean {
    return index == cardList.size
}

private fun resetCard() {
    cardList.shuffle()
    index = 0
}

50 changes: 50 additions & 0 deletions src/main/kotlin/card/deck/PlayerDeck.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package card.deck

import card.CardRank
import card.PlayingCard

class PlayerDeck(override val cardDeck: MutableList<PlayingCard> = mutableListOf()) : CardDeck {

Copy link
Member

Choose a reason for hiding this comment

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

deck클래스의 경우 게임 덱(배포 될 카드)과 플레이어 덱(받은 카드) PlayingCard의 컬렉션으로 구성되어 있어서 interface를 만들어 사용했습니다. 이러한 구성이 맞는지 자세히 리뷰 부탁드리겠습니다.

개발에 맞고 틀림은 없다고 생각해요. 관점과 방향이 달라 정답이 없는 분야라고 생각해요 :)

다만, PlayerDeck이라고 표현하기에는, 플레이어가 가지게 될 몇 장 정도의 카드를 "덱" 이라고 부르는 것은 조금 부자연스러워보여요.
#672 (comment)
이전에 남긴 피드백이었던, 카드들을 일급 컬렉션으로 만들어보는 건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

PlayerDeck 대신 Hands로 변경하였습니다.

class Hands(val cardList: MutableList<PlayingCard> = mutableListOf())

해당 일급 컬랩션은 Player가 사용합니다.

fun addCard(playingCard: PlayingCard) {
cardDeck.add(playingCard)
}

fun getResultPoint(): Int {
var point = cardDeck.sumOf { it.getPoint() }

if (isContainAce()) {
point += addAcePoint(point)
}

return point
}

fun cardDeckSize() = cardDeck.size

private fun isContainAce(): Boolean {
return cardDeck.any { it.getCardRank() == CardRank.ACE }
}

private fun addAcePoint(point: Int): Int {
return if (point <= 11) {
ADD_ACE_POINT
} else {
ADD_ACE_POINT_NONE
}
}

companion object {
fun create() = PlayerDeck(mutableListOf())
private const val ADD_ACE_POINT = 10
private const val ADD_ACE_POINT_NONE = 0
}

override fun toString(): String {
val sb = StringBuilder()
for (card in cardDeck) {
sb.append("$card, ")
}
sb.deleteCharAt(sb.lastIndex - 1)
return sb.toString()
}
}
48 changes: 48 additions & 0 deletions src/main/kotlin/player/Player.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package player

import card.PlayingCard
import card.deck.PlayerDeck

class Player(val name: String) {

var status = Status.START
private set

var playerDeck = PlayerDeck()
private set
Copy link
Member

Choose a reason for hiding this comment

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

이 값들을 생성자에서 주입받을 수 있게 구현한다면,
테스트를 작성할 떄 필요한 초기화 내용을 다른 메서드를 호출하지 않고도 넣어 줄 수 있겠어요.

Copy link
Author

@oyj7677 oyj7677 Dec 6, 2023

Choose a reason for hiding this comment

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

객체지향 생활 체조 원칙
7. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

위 원칙을 생성자에도 적용해야되는 줄 알고 아래로 뺐었습니다.
DM으로 질문 드린 구조 적용하였습니다.

class Player(
    val name: String,
    status: Status = Status.START,
    hands: Hands = Hands(),
) {

    var status = status
        private set

    var playerDeck = hands
        private set

Copy link
Member

Choose a reason for hiding this comment

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

3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다 에서는,
필드 즉, 멤버변수가 인스턴스 변수임을 의미해요.

다만, 코틀린 생성자에서는 파라미터와 함께 멤버변수를 동시에 정의할 수 있기에, 파라미터로 들어오는 것 또한 인스턴스 변수라고 헷갈릴 수 있을 것 같아요.

인스턴스 변수가 많다면, 비슷한 책임을 지닌 변수들을 하나의 모델로 묶어서 표현한다면, 2개로 줄여볼 수 있겠네요 :)


fun playDone() {
this.status = Status.STAND
}

fun saveCard(card: PlayingCard) {
playerDeck.addCard(card)
updateStatus()
}

fun updateStatus() {
val totalPoint = playerDeck.getResultPoint()

if (totalPoint > BLACKJACK_NUMBER) {
this.status = Status.BUST
} else if (isBlackJack()) {
this.status = Status.BLACK_JACK
} else {
this.status = Status.PLAYING
}
}

fun getResultPoint(): Int {
return playerDeck.getResultPoint()
}

private fun isBlackJack(): Boolean {
val totalPoint = playerDeck.getResultPoint()
return playerDeck.cardDeckSize() == BLACKJACK_CARD_COUNT && totalPoint == BLACKJACK_NUMBER
}

companion object {
private const val BLACKJACK_CARD_COUNT = 2
private const val BLACKJACK_NUMBER = 21
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/player/PlayerFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package player

object PlayerFactory {

private const val DELIMITERS = ','

fun createPlayerList(playerNames: String): List<Player> {
val playerNameList = splitInputData(playerNames)
val playerList = mutableListOf<Player>()
playerNameList.forEach { name ->
playerList.add(Player(name))
}
return playerList
}

private fun splitInputData(inputData: String): List<String> {
return inputData.split(DELIMITERS).map { it.trim() }.filter { it.isNotBlank() }
}
}
17 changes: 17 additions & 0 deletions src/main/kotlin/player/PlayerGroup.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package player

class PlayerGroup(val playerList: List<Player>) {

init {
validatePlayer()
}

private fun validatePlayer() {
require(playerList.size in MIN_PLAYER_CNT..MAM_PLAYER_CNT) { "참여 가능한 플레이어의 범위를 넘어섰습니다." }
}

companion object {
private const val MIN_PLAYER_CNT = 2
private const val MAM_PLAYER_CNT = 26
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/player/Status.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package player

enum class Status {
START, PLAYING, STAND, BLACK_JACK, BUST
}
Loading