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

[부나] 1단계 블랙잭 제출합니다. #29

Merged
merged 86 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
6d56055
chore: .gitkeep 파일 제거
tmdgh1592 Feb 28, 2023
62534e6
study: DSL 스터디
tmdgh1592 Feb 28, 2023
0ef6f34
docs: 기능 목록 요구사항 작성
tmdgh1592 Feb 28, 2023
574a268
refactor: DslTest.kt 패키지 이동
tmdgh1592 Mar 1, 2023
732ffb2
feat: 스페이드, 다이아몬드, 하트, 클로버를 가지는 카드 모양 클래스 구현
tmdgh1592 Mar 1, 2023
17dd825
feat: 카드 숫자의 범위가 1부터 13인지 검증하는 기능 구현
tmdgh1592 Mar 1, 2023
e485c71
feat: 카드 숫자를 문자로 반환하는 기능 구현
tmdgh1592 Mar 1, 2023
12c2936
refactor: 카드 모양 클래스 요소를 한글명으로 변경
tmdgh1592 Mar 1, 2023
4ecb57d
feat: 카드는 각 모양별로 2부터 10, A, J, Q, K가 존재하도록 구현
tmdgh1592 Mar 1, 2023
665cd3f
feat: 카드 목록에 카드를 추가하는 기능 구현
tmdgh1592 Mar 1, 2023
ebb267e
feat: 카드 숫자를 정수형으로 반환하는 기능 구현
tmdgh1592 Mar 1, 2023
873652f
feat: 총 점수를 반환하는 기능 구현
tmdgh1592 Mar 1, 2023
c34208b
refactor: 카드 목록 클래스명 변경
tmdgh1592 Mar 1, 2023
c000e8a
feat: 카드 하나를 뽑는 기능 구현
tmdgh1592 Mar 1, 2023
164a338
feat: 이름을 갖는 플레이어 클래스 구현
tmdgh1592 Mar 1, 2023
f07fa50
feat: 플레이어가 가진 카드 목록에 카드를 추가하는 기능 구현
tmdgh1592 Mar 2, 2023
462fe5b
feat: 카드의 합이 21을 초과하지 않는지 확인하는 기능 구현
tmdgh1592 Mar 2, 2023
6f81c4d
feat: 플레이어 자신의 점수를 반환하는 기능 구현
tmdgh1592 Mar 2, 2023
4e25946
refactor: 플레이어의 카드 목록 블랙잭 상수 캡슐화
tmdgh1592 Mar 2, 2023
dc551ca
feat: 플레이어가 자신이 가진 카드를 반환하는 기능 구현
tmdgh1592 Mar 2, 2023
b8593a6
feat: 모든 플레이어의 카드를 2장씩 뽑는 기능 구현
tmdgh1592 Mar 2, 2023
6cc7c41
feat: 딜러가 스테이인지 확인하는 기능 구현
tmdgh1592 Mar 2, 2023
d81e48a
feat: 플레이어의 승패를 결정하는 기능 구현
tmdgh1592 Mar 2, 2023
2642d6f
feat: 모든 플레이어의 승패 결과를 반환하는 기능 구현
tmdgh1592 Mar 2, 2023
f9ea704
feat: 사용자의 입력을 받는 기능 구현
no1msh Mar 3, 2023
8758b12
feat: 게임 참여자의 초기 카드 세팅을 출력하는 기능 구현
no1msh Mar 3, 2023
8136214
feat: 딜러가 카드를 한 장 더 받는 메세지를 출력하는 기능 구현
no1msh Mar 3, 2023
97827b6
refactor: 게임 참여자들이 가지고 있는 정보 DTO 리팩터링
tmdgh1592 Mar 3, 2023
7f13916
feat: 스코어 보드 출력하는 기능 구현
tmdgh1592 Mar 3, 2023
36f007c
refactor: 게임 참여자의 초기 카드 세팅을 출력하는 기능 리팩터링
tmdgh1592 Mar 3, 2023
b9370d2
refactor: 최종 결과를 출력하는 기능 구현
tmdgh1592 Mar 3, 2023
4554fca
feat: 블랙잭 초기 설정 구현
tmdgh1592 Mar 3, 2023
a422885
feat: 플레이어에게 카드 뽑을지 물어보는 기능 구현
tmdgh1592 Mar 3, 2023
2a7727c
feat: 딜러 차례에 카드를 추가로 뽑는 기능 구현
tmdgh1592 Mar 3, 2023
d484e96
feat: 스코어 보드 출력 기능 컨트롤러와 연결
tmdgh1592 Mar 3, 2023
ab844ca
feat: 최종 승패 출력 기능 컨트롤러와 연결
tmdgh1592 Mar 3, 2023
505e1eb
feat: 명령어 검증 기능 구현
tmdgh1592 Mar 3, 2023
3d245ae
test: 딜러는 자신이 보유한 첫번째 카드를 반환하는 기능 테스트 추가
tmdgh1592 Mar 3, 2023
9538695
refactor: 코드 라인 및 depth 줄임
tmdgh1592 Mar 3, 2023
6ac1cdd
refactor: 카드 모양 네이밍 변경
tmdgh1592 Mar 6, 2023
01f139f
refactor: 카드 숫자를 enum 클래스로 변경
tmdgh1592 Mar 6, 2023
e464505
refactor: 카드덱 Generator 제거
tmdgh1592 Mar 6, 2023
9832ec0
refactor: 카드 모양 열거 순서 변경
tmdgh1592 Mar 6, 2023
584e709
refactor: 카드 클래스 생성 방식 변경
tmdgh1592 Mar 6, 2023
d5772ca
refactor: 점수 계산 로직 수정
tmdgh1592 Mar 6, 2023
25916d4
refactor: 입출력 상수 리팩터링
tmdgh1592 Mar 6, 2023
b1a5d65
feat: 플레이어 수를 제한하는 기능 구현
tmdgh1592 Mar 6, 2023
319818b
refactor: 카드 뽑기 명령어 검증을 View에서 처리하도록 변경
tmdgh1592 Mar 6, 2023
cfc3417
refactor: 블랙잭 객체를 컨트롤러의 시작 함수 내에서 초기화하도록 변경
tmdgh1592 Mar 6, 2023
0858ccf
refactor: 딜러와 플레이러가 참여자 클래스를 상속받도록 변경
tmdgh1592 Mar 6, 2023
4790920
refactor: 딜러가 승부 결과를 반환하도록 변경
tmdgh1592 Mar 7, 2023
1bff0ae
refactor: 참여자가 처음 카드를 공개하는 로직을 추상화
tmdgh1592 Mar 7, 2023
a990b7c
refactor: 이름과 보유한 카드 목록을 반환하는 기능 리팩터링
tmdgh1592 Mar 7, 2023
08c3ab7
refactor: 플레이어가 보유한 카드를 처음 오픈하는 기능에서 DTO 제거
tmdgh1592 Mar 7, 2023
4d3b86a
refactor: 게임 참여자의 점수를 반환하는 기능에서 DTO 제거
tmdgh1592 Mar 7, 2023
ffd6f14
refactor: 카드를 디스플레이 하는 기능을 도메인 로직에서 UI 로직으로 이동
tmdgh1592 Mar 7, 2023
d6fe092
refactor: 도메인에서 DSL 제거
tmdgh1592 Mar 7, 2023
837a6fe
refactor: 카드 목록에서 첫 번째 카드를 가져오는 함수의 반환 타입 변경
tmdgh1592 Mar 8, 2023
5ab0252
fix: 플레이어가 카드를 뽑을 수 있는지 여부를 반환하는 조건 수정
tmdgh1592 Mar 8, 2023
ab2b1d8
refactor: 참여자끼리 승패를 반환하는 기능을 참여자 클래스로 이동
tmdgh1592 Mar 8, 2023
22bb2a4
feat: 참여자의 스테이 상태를 반환하는 기능 구현
tmdgh1592 Mar 8, 2023
2a3853d
refactor: 딜러와 플레이어들을 참여자들을 관리하는 클래스로 이동
tmdgh1592 Mar 8, 2023
08ccdc3
refactor: 참여자들이 카드를 뽑는 과정을 함수형으로 변경
tmdgh1592 Mar 8, 2023
1052618
refactor: 게임 결과를 합쳐서 블랙잭 클래스에서 반환하도록 변경
tmdgh1592 Mar 8, 2023
1a52be5
refactor: 게임 결과를 합쳐서 블랙잭 클래스에서 반환하도록 변경
tmdgh1592 Mar 8, 2023
bb1bebd
refactor: 카드의 총 점수를 계산하는 기능에서 블랙잭 점수를 클래스 내에서 참조하도록 변경
tmdgh1592 Mar 9, 2023
3844089
refactor: 카드 목록에 카드를 가변 인자로 추가할 수 있도록 변경
tmdgh1592 Mar 9, 2023
2fd6f72
Merge branch 'step1' of https://github.com/tmdgh1592/kotlin-blackjack…
tmdgh1592 Mar 9, 2023
f7fafc1
refactor: 패키지, 클래스, 메서드명에서 BlackJack을 Blackjack으로 변경
tmdgh1592 Mar 9, 2023
b856fda
refactor: 카드덱에 가변인자를 전달받는 부생성자 추가
tmdgh1592 Mar 9, 2023
e98eb4d
refactor: 카드목록의 초기화 블록의 코드 위치 변경
tmdgh1592 Mar 9, 2023
fea1fe5
test(카드 목록): 카드 목록 테스트 코드 추가
tmdgh1592 Mar 9, 2023
b5d1be7
test(카드): 카드 테스트 코드에서 각 테스트 케이스별로 테스트명을 출력하도록 변경
tmdgh1592 Mar 9, 2023
cf4acd2
fix: 딜러가 카드를 뽑을 수 있는지 판단하는 메서드 버그 수정
tmdgh1592 Mar 9, 2023
9c69293
test(딜러): 딜러와 플레이어의 중복 테스트 코드 제거
tmdgh1592 Mar 9, 2023
99e833a
refactor: 사용하지 않는 클래스 제거
tmdgh1592 Mar 9, 2023
2ca1467
test(카드 모양): 카드 모양 테스트 코드에서 인자 변경
tmdgh1592 Mar 9, 2023
800dee5
refactor: 플레이어가 카드를 뽑을 것인지 판단하는 콜백의 기본값 설정
tmdgh1592 Mar 9, 2023
24518fa
refactor: 참여자들의 인원 제한 변경
tmdgh1592 Mar 9, 2023
94fbd5a
refactor: 매 차례뼐로 카드를 뽑는 메서드 분리
tmdgh1592 Mar 9, 2023
bd49760
refactor: 참여자가 보유한 카드 점수가 21점이 넘는지 판단하는 메서드 변경
tmdgh1592 Mar 9, 2023
0fa56ff
test(플레이어): 카드를 뽑을 수 있는지 여부를 반환하는 테스트 코드 결과 수정
tmdgh1592 Mar 9, 2023
6d09998
refactor: 참여자들 카드를 뽑는 순서를 플레이어와 딜러순으로 분리
tmdgh1592 Mar 9, 2023
c6d0c08
test(참여자들): 참여자들 테스트 코드 추가
tmdgh1592 Mar 9, 2023
eb4d450
refactor: 카드 결과 출력시 한 칸씩 띄도록 변경
tmdgh1592 Mar 9, 2023
52b79d8
refactor: 블랙잭 컨트롤러에서 게임 시작 람다 함수를 리플렉션으로 축약
tmdgh1592 Mar 9, 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
60 changes: 60 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 기능 요구 사항
- 카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다.
- 게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다.
- 딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다.
- 게임을 완료한 후 각 플레이어별로 승패를 출력한다.

# 기능 목록
- 카드 모양
- [x] 카드 모양에는 스페이드, 다이아몬드, 하트, 클로버가 있다.

- 카드 숫자
- [x] 카드 숫자의 범위는 1부터 13이다.
- [x] 카드 숫자를 문자로 반환한다.
- [x] 1, 11, 12, 13은 각각 A, J, Q, K로 반환한다.
- [x] 2 ~ 10은 그대로 반환한다.
- [x] 카드 숫자를 정수형으로 반환한다.

- 카드
- [x] 카드는 각 모양별로 2부터 10, A, J, Q, K가 존재한다.

- 플레이어의 카드 목록
- [x] 카드 목록에 카드를 추가한다.
- [x] 총 점수를 반환한다.
- [x] 단, A는 기존 총 점수에 11점을 더한 값이 21점 이하이면 11점으로 계산하고, 21점을 초과하면 1점으로 계산한다.
- [x] 단, J, Q, K는 모두 10점으로 계산한다.
- [x] 2 ~ 10은 그대로 계산한다.

- 카드덱
- [x] 카드 하나를 뽑는다.
- [x] 카드덱은 아직 뽑히지 않은 카드를 갖는다.
- [x] 뽑은 카드는 아직 뽑히지 않은 카드 중 하나여야 한다.

- 플레이어
- [x] 플레이어는 이름을 갖는다.
- [x] 플레이어는 카드 목록에 카드를 추가한다.
- [x] 플레이어는 자신이 뽑은 카드 목록을 갖는다.
- [x] 플레이어는 카드의 합이 21을 초과하지 않는지 확인한다.
- [x] 자신의 점수를 반환한다.
- [x] 자신이 가진 카드를 반환한다.

- 플레이어들
- [x] 모든 플레이어의 카드를 2장씩 뽑는다.

- 딜러
- [x] 딜러는 스테이인지 확인한다.
- [x] 카드의 합이 17점 이상이면 스테이이다.
- [x] 카드의 합이 16점 이하이면 스테이가 아니다.
- [x] 딜러는 자신이 보유한 첫번째 카드를 반환한다.

- 승부 결과
- [x] 플레이어의 승패를 결정한다.
- [x] 플레이어가 21점을 초과하면 패배한다.
- [x] 딜러만 21점을 초과하면 플레이어가 승리한다.
- [x] 딜러와 플레이어 모두 21점을 초과하지 않고 플레이어가 딜러보다 점수가 높으면 플레이어가 승리한다.
- [x] 딜러와 플레이어 모두 21점을 초과하지 않고 플레이어와 딜러의 점수가 같으면 무승부이다.
- [x] 딜러와 플레이어 모두 21점을 초과하지 않고 딜러가 플레이어보다 점수가 높으면 플레이어가 패배한다.

- 명령어
- [x] 명령어는 y 또는 n이다.
- [x] 단, 대소문자를 구분하지 않는다.
Empty file removed src/main/kotlin/.gitkeep
Empty file.
7 changes: 7 additions & 0 deletions src/main/kotlin/blackjack/Application.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package blackjack

import blackjack.controller.BlackjackController

fun main() {
BlackjackController().start()
}
36 changes: 36 additions & 0 deletions src/main/kotlin/blackjack/controller/BlackjackController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package blackjack.controller

import blackjack.domain.Blackjack
import blackjack.domain.CardDeck
import blackjack.domain.Player
import blackjack.view.InputView
import blackjack.view.OutputView

class BlackjackController {
fun start() {
with(initBlackjack()) {
setUpCard(this)

val result = start(onDrawn = OutputView::printDrawn)
OutputView.printBlackjackResult(result)
}
}

private fun initBlackjack(): Blackjack = Blackjack(CardDeck(), enrollPlayers())

private fun enrollPlayers(): List<Player> = InputView.inputNames().map { name ->
Player(name, needToDraw = {
InputView.inputDrawCommand(name)
})
}

private fun setUpCard(blackJack: Blackjack) {
drawInitialCards(blackJack)
OutputView.printFirstOpenCards(blackJack.getFirstOpenCards())
OutputView.printInterval()
}

private fun drawInitialCards(blackJack: Blackjack) {
blackJack.readyToStart()
}
Comment on lines +33 to +35
Copy link

Choose a reason for hiding this comment

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

함수를 분리하지 않아도? 괜찮아 보여요!
setupCard()와 drawInitialCards()가 어떤 차이인지 헷갈림!

Copy link
Member Author

Choose a reason for hiding this comment

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

앗 그렇군요..!
어차피 한 줄이고 굳이 나누지 않는 것이 가독성이 좋아보입니다!

}
21 changes: 21 additions & 0 deletions src/main/kotlin/blackjack/domain/Blackjack.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package blackjack.domain

class Blackjack(private val deck: CardDeck, private val participants: Participants) {
constructor(deck: CardDeck, players: List<Player>) : this(deck, Participants(listOf(Dealer()) + players))

fun readyToStart() {
participants.drawFirst(deck)
}

fun start(onDrawn: (Participant) -> Unit): BlackjackResult {
participants.takePlayerTurns(deck, onDrawn)
participants.takeDealerTurns(deck, onDrawn)

return BlackjackResult(
participants.getCardResults(),
participants.getMatchResults(),
)
}

fun getFirstOpenCards(): Map<String, List<Card>> = participants.getFirstOpenCards()
Comment on lines +6 to +20
Copy link

Choose a reason for hiding this comment

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

좋습니다.
조금 더 나아가 본다면, start() 함수 하나에서 처음 뽑을 카드와 이어서 뽑는 카드들을 같이 묶을 수 있을 것 같네요!

fun start(onDrawn: (Participant) -> Unit): Result {
   participants.drawFirst(deck, onDrawn)
   participants.draw(deck, onDrawn)

   return ...
}

}
6 changes: 6 additions & 0 deletions src/main/kotlin/blackjack/domain/BlackjackResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package blackjack.domain

data class BlackjackResult(
val cardResults: List<CardResult>,
val matchResults: List<MatchResult>,
Comment on lines +4 to +5
Copy link

Choose a reason for hiding this comment

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

CardResult랑 MatchResult를 나눌 필요가 있을까요?
플레이어의 입장에서도 승, 패, 무를 비교한다면 1승 0무 0패 처럼 나타낼 수 있지 않을까요?

)
17 changes: 17 additions & 0 deletions src/main/kotlin/blackjack/domain/Card.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package blackjack.domain

data class Card(val number: CardNumber, val suit: Suit) {
fun getScore(): Int = number.score

fun isAce(): Boolean = number == CardNumber.ACE

companion object {
private val CARDS = Suit.values().flatMap { suit ->
CardNumber.values().map { cardNumber ->
Card(cardNumber, suit)
}
}

fun all(): List<Card> = CARDS.toList()
}
}
9 changes: 9 additions & 0 deletions src/main/kotlin/blackjack/domain/CardDeck.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package blackjack.domain

class CardDeck(deck: List<Card> = Card.all().shuffled()) {
constructor(vararg cards: Card) : this(cards.toList())

private val deck: MutableList<Card> = deck.toMutableList()

fun draw(): Card = deck.removeFirst()
}
17 changes: 17 additions & 0 deletions src/main/kotlin/blackjack/domain/CardNumber.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package blackjack.domain

enum class CardNumber(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);
}
7 changes: 7 additions & 0 deletions src/main/kotlin/blackjack/domain/CardResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package blackjack.domain

data class CardResult(
val participant: Participant,
val cards: List<Card>,
val scoreSum: Int,
)
39 changes: 39 additions & 0 deletions src/main/kotlin/blackjack/domain/Cards.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package blackjack.domain

class Cards(vararg cards: Card) {
private val _items: MutableList<Card> by lazy { mutableListOf() }
val items: List<Card>
get() = _items.toList()

init {
_items.addAll(cards)
}
Comment on lines +8 to +10
Copy link

Choose a reason for hiding this comment

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

_items 프로퍼티를 만들면서 생성자로 받은 cards를 초기화 할 수 있어요


fun add(card: Card) {
_items.add(card)
}

fun getFirstCard(): Card = _items.first()

fun calculateTotalScore(): Int {
val score = _items.sumOf(Card::getScore)
return calculateAceScore(score)
}

private fun calculateAceScore(score: Int): Int =
if (hasAce() && !isOverBlackjack(score + BONUS_SCORE)) score + BONUS_SCORE else score

fun isOverBlackjack(): Boolean = calculateTotalScore() > BLACKJACK_SCORE

private fun isOverBlackjack(score: Int): Boolean = score > BLACKJACK_SCORE

fun isStay(): Boolean = calculateTotalScore() >= STAY_SCORE

private fun hasAce(): Boolean = _items.any(Card::isAce)

companion object {
private const val BONUS_SCORE = 10
private const val BLACKJACK_SCORE = 21
private const val STAY_SCORE = 17
Copy link

Choose a reason for hiding this comment

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

블랙잭 게임에서 스테이라는 의미는 어떠한 점수를 나타내는 상태가 아닙니다.
카드들의 개념보다는 정확하게는 "딜러"가 카드를 더 뽑기 위한 조건 이라고 보는게 맞을 것 같습니다

21점 미만일 때, 더 뽑는다 -> 히트
21점 미만일 때, 더 뽑지 않는다 -> 스테이
21점 초과일 때 -> 버스트

Copy link
Member Author

@tmdgh1592 tmdgh1592 Mar 10, 2023

Choose a reason for hiding this comment

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

2단계와 피드백을 보면서 깨달았습니다..
아직 Blackjack이라는 도메인 지식이 부족한 것 같습니다.
스테이더 뽑지 않는다 라는 의미이군요.
감사합니다!

}
}
11 changes: 11 additions & 0 deletions src/main/kotlin/blackjack/domain/Dealer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package blackjack.domain

class Dealer : Participant(DEALER_NAME) {
override fun getFirstOpenCards(): List<Card> = listOf(getFirstCard())

override fun canDraw(): Boolean = !isStay()

companion object {
private const val DEALER_NAME = "딜러"
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/blackjack/domain/GameResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package blackjack.domain

enum class GameResult {
WIN, DRAW, LOSE;
}
8 changes: 8 additions & 0 deletions src/main/kotlin/blackjack/domain/MatchResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package blackjack.domain

data class MatchResult(
val participant: Participant,
val winCount: Int,
val loseCount: Int,
val drawCount: Int
)
32 changes: 32 additions & 0 deletions src/main/kotlin/blackjack/domain/Participant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package blackjack.domain

abstract class Participant(val name: String) {
private val cards = Cards()

abstract fun getFirstOpenCards(): List<Card>

abstract fun canDraw(): Boolean

fun getTotalScore(): Int = cards.calculateTotalScore()

fun isBust(): Boolean = cards.isOverBlackjack()

fun isStay(): Boolean = cards.isStay()

infix fun judge(other: Participant): GameResult = when {
isBust() && other.isBust() -> GameResult.DRAW
Copy link

Choose a reason for hiding this comment

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

블랙잭 규칙에서는 상대의 점수가 무엇이든지 상관없이 자신이 버스트라면 패배입니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

그렇군요..! 제가 규칙을 잘못 이해하고 있었던 것 같습니다!
2단계 미션을 진행하면서 수업시간에 배운 State, Template Method 패턴을 함께 적용하면서 리팩터링해보겠습니다.
만약 Dealer의 상태가 블랙잭이고, Player의 상태가 블랙잭이면 Draw를 반환한다. 와 같이 작성해볼 수 있을 것 같습니다!

isBust() -> GameResult.LOSE
other.isBust() -> GameResult.WIN
getTotalScore() == other.getTotalScore() -> GameResult.DRAW
getTotalScore() > other.getTotalScore() -> GameResult.WIN
Comment on lines +20 to +21
Copy link

Choose a reason for hiding this comment

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

이 함수를 끝내기까지 getTotalScore()가 몇번 호출이될까요?
가독성을 위해 위처럼 작성을 할 수 있겠지만, 불필요한 호출은 줄이면 좋을 것 같아요

else -> GameResult.LOSE
}

fun addCard(card: Card) {
cards.add(card)
}

fun getCards(): List<Card> = cards.items

fun getFirstCard(): Card = cards.getFirstCard()
}
84 changes: 84 additions & 0 deletions src/main/kotlin/blackjack/domain/Participants.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package blackjack.domain

class Participants(private val participants: List<Participant>) {
init {
require(participants.size in MINIMUM_PARTICIPANTS..MAXIMUM_PARTICIPANTS) {
"블랙잭은 딜러를 포함하여 최소 ${MINIMUM_PARTICIPANTS}명에서 최대 ${MAXIMUM_PARTICIPANTS}명의 플레이어가 참여 가능합니다. (현재 플레이어수 : ${participants.size}명)"
}
}

fun drawFirst(deck: CardDeck) {
participants.forEach { participant ->
participant.addCard(deck.draw())
participant.addCard(deck.draw())
}
}

fun takePlayerTurns(deck: CardDeck, onDrawn: (Participant) -> Unit) {
getPlayers().forEach { participant ->
drawUntilCanDraw(participant, deck, onDrawn)
}
}

fun takeDealerTurns(deck: CardDeck, onDrawn: (Participant) -> Unit) {
drawUntilCanDraw(getDealer(), deck, onDrawn)
}

private fun drawUntilCanDraw(
participant: Participant,
deck: CardDeck,
onDrawn: (Participant) -> Unit
) {
while (participant.canDraw()) {
draw(participant, deck)
onDrawn(participant)
}
}

fun getMatchResults(): List<MatchResult> = listOf(getDealerMatchResult()) + getPlayerMatchResults()

private fun getDealerMatchResult(): MatchResult {
var (win, lose, draw) = Triple(0, 0, 0)
getPlayers().forEach { player ->
when (getDealer() judge player) {
GameResult.WIN -> win++
GameResult.LOSE -> lose++
GameResult.DRAW -> draw++
}
}
return MatchResult(getDealer(), win, lose, draw)
}

private fun getPlayerMatchResults(): List<MatchResult> = getPlayers().map { player ->
var (win, lose, draw) = Triple(0, 0, 0)
when (player judge getDealer()) {
GameResult.WIN -> win++
GameResult.LOSE -> lose++
GameResult.DRAW -> draw++
}
MatchResult(player, win, lose, draw)
}

fun getCardResults(): List<CardResult> = participants.map { participant ->
CardResult(
participant,
participant.getCards(),
participant.getTotalScore()
)
}

fun getFirstOpenCards(): Map<String, List<Card>> = participants.associate { it.name to it.getFirstOpenCards() }

private fun getPlayers(): List<Participant> = participants.filterIsInstance<Player>()

private fun getDealer(): Participant = participants.first { it is Dealer }

private fun draw(participant: Participant, deck: CardDeck) {
participant.addCard(deck.draw())
}

companion object {
private const val MINIMUM_PARTICIPANTS = 2
private const val MAXIMUM_PARTICIPANTS = 8
}
}
7 changes: 7 additions & 0 deletions src/main/kotlin/blackjack/domain/Player.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package blackjack.domain

class Player(name: String, private val needToDraw: () -> Boolean = { true }) : Participant(name) {
override fun getFirstOpenCards(): List<Card> = getCards()

override fun canDraw(): Boolean = !isBust() && needToDraw()
}
5 changes: 5 additions & 0 deletions src/main/kotlin/blackjack/domain/Suit.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package blackjack.domain

enum class Suit {
SPADE, HEART, DIAMOND, CLOVER;
}
Loading