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단계 - 블랙잭 게임 실행] 로빈(임수빈) 미션 제출합니다. #1

Open
wants to merge 56 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
89a8f44
docs: 요구사항 분석 및 기능 목록 작성
BurningFalls Mar 5, 2024
db91493
feat: 덱 관리 기능 구현
BurningFalls Mar 5, 2024
178ad20
feat: 카드 점수 계산 기능 구현
BurningFalls Mar 5, 2024
40019ad
refactor: CardValue 를 CardName 으로 변경
BurningFalls Mar 5, 2024
7196074
feat: 보유한 카드 점수 합계 계산 기능 구현
BurningFalls Mar 5, 2024
399fa25
feat: 플레이어 및 딜러 점수 계산 기능 구현
BurningFalls Mar 5, 2024
19cfa4c
fix: 플레이어가 카드를 뽑을 수 없는 경우에도 카드를 뽑을 수 있던 오류 수정
BurningFalls Mar 5, 2024
ab2676b
fix: 딜러가 카드를 뽑을 수 없는 경우에도 카드를 뽑을 수 있던 오류 수정
BurningFalls Mar 5, 2024
f1319fd
refactor: Player 와 Dealer 통합
BurningFalls Mar 5, 2024
8656caf
feat: 플레이어 이름 입력 기능 구현
BurningFalls Mar 5, 2024
9a66483
feat: 카드 받을지 여부 입력 기능 구현
BurningFalls Mar 5, 2024
4adbb3e
feat: 플레이어 및 딜러간 승부 계산 기능 구현
BurningFalls Mar 6, 2024
b2a5a12
refactor: 플레이어 및 딜러간 승부 계산 기능 Gamer 에서 분리
BurningFalls Mar 6, 2024
7106b9c
feat: 게임 결과 출력 기능 구현
BurningFalls Mar 6, 2024
213a3f2
docs: 기능 목록 정리
BurningFalls Mar 6, 2024
77439a2
feat: 플레이어 및 딜러 손패 출력 기능 구현
BurningFalls Mar 6, 2024
453bb19
feat: 게임 승부 결과 출력 기능 구현
BurningFalls Mar 6, 2024
aa2a65e
feat: 전체 게임 진행 기능 구현
BurningFalls Mar 6, 2024
5685701
fix: 게이머가 죽었을 경우 승부가 잘못 판단되는 오류 수정
BurningFalls Mar 6, 2024
c6e7564
feat: Ace 카드 점수 보정 기능 구현
BurningFalls Mar 6, 2024
9f15cc9
docs: TODO 목록 정리
BurningFalls Mar 7, 2024
3b47a6d
fix: Main 메서드에서 플레이어 이름을 입력받지 않는 오류 수정
BurningFalls Mar 7, 2024
a1b7720
docs: 딜러 Ace 카드 점수 보정 기능 추가
BurningFalls Mar 7, 2024
3502c5d
feat: 딜러 Ace 카드 점수 보정 기능 구현
BurningFalls Mar 7, 2024
89e773e
fix: 게임 도중 플레이어의 손패를 출력하지 않는 오류 수정
BurningFalls Mar 7, 2024
c6047ff
fix: 딜러의 카드 한장 숨기도록 수정
BurningFalls Mar 7, 2024
da5c9ce
refactor: TODO 처리
BurningFalls Mar 7, 2024
a6ba73b
refactor: domain 하위 패키지 추가
BurningFalls Mar 7, 2024
f0aae99
refactor: 클래스 및 패키지 접근지정자 조이기
BurningFalls Mar 7, 2024
6322d3d
refactor: 메서드 분리
robinjoon Mar 7, 2024
61eb780
style: 클래스와 제일 위에 위치한 필드(메서드) 사이에 공백 라인 제거
robinjoon Mar 7, 2024
4c5d1a4
refactor: 일부 매직 값을 상수 혹은 의미있는 변수로 추출
robinjoon Mar 7, 2024
1411054
fix: 플레이어 이름을 잘못 출력하는 버그 수정
robinjoon Mar 7, 2024
b7ff262
chore: 람다표현식으로 변경
robinjoon Mar 7, 2024
0adedd5
docs: 1단계 피드백 반영 예정 목록 추가
robinjoon Mar 9, 2024
adecadf
refactor: 드로우가 가능한지 확인하는 책임 컨트롤러에서 Gamer로 이동
robinjoon Mar 9, 2024
74d6688
refactor: 드로우 여부 결정하는 정책과 드로우 방식을 결정하는 정책 분리
robinjoon Mar 10, 2024
15ee815
refactor: Card Enum화
robinjoon Mar 10, 2024
5ef0343
refactor: 테스트 코드에서 사용하는 테스트 객체 생성 역할을 분리
robinjoon Mar 11, 2024
ea7eb45
test: 게이머의 점수가 잘 계산되는지 검증하는 테스트 추가
robinjoon Mar 11, 2024
f667755
refactor: view만을 위한 enum 추가
robinjoon Mar 11, 2024
6f1a623
chore: 필요 없는 TODO 주석 제거
robinjoon Mar 11, 2024
4df7ab4
refactor: Controller 내부 메서드 분리
robinjoon Mar 11, 2024
bc92c76
fix: 플레이어가 딜러의 전략을 사용하는 오류 수정
robinjoon Mar 11, 2024
671e977
refactor: 딜러와 플레이어 분리
robinjoon Mar 11, 2024
b47d4a9
refactor: 딜러의 카드 하나 숨기는 기능 Dealer로 이관
robinjoon Mar 11, 2024
92ec982
refactor: Main, Controller, View 역할 명확하게 분리
robinjoon Mar 12, 2024
839110d
refactor: Dealer 에서 이름 제거, View로 이관
robinjoon Mar 12, 2024
bea1e52
refactor: GamerOutputView를 DealerOutputView 와 PlayerOutputView로 분리
robinjoon Mar 12, 2024
f7d8e73
refactor: BlackjackController 내부 메서드 정리
robinjoon Mar 12, 2024
9e305e2
refactor: Players 일급 컬렉션 추가
robinjoon Mar 12, 2024
0f6df51
refactor: Players 생성자 변경
robinjoon Mar 12, 2024
15543db
chore: 사용하지 않는 메서드 제거
robinjoon Mar 12, 2024
0f008c7
refactor: RandomCardSelectStrategy 싱글톤으로 변경
robinjoon Mar 12, 2024
0b09e12
fix: 출력문구 누락 수정
robinjoon Mar 12, 2024
438015e
refactor: BlackJackGameMachine 내부 메서드 이름 및 접근 지정자 변경
robinjoon Mar 12, 2024
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: 56 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,59 @@
# java-blackjack
## 기능 요구 사항

블랙잭 미션 저장소
### 플레이어 이름 입력

## 우아한테크코스 코드리뷰
1. 플레이어의 이름은 ","을 기준으로 구분한다.
2. 플레이어의 이름은 길이가 1 이상이어야 한다.
3. 플레이어의 이름은 알파벳 대소문자와 숫자로만 구성되어야 한다.
4. 플레이어의 이름은 중복되면 안된다.

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
### 플레이어 및 딜러 점수 계산

1. 플레이어가 소유한 카드의 점수의 합이 플레이어의 점수다.
2. 카드의 점수는 카드의 숫자로 계산한다.
3. Ace 카드는 1 혹은 11 중 카드의 소유자가 더 유리한 것으로 계산한다.
4. King, Queen, Jack은 각각 10으로 계산한다.

### 게임 진행 규칙

1. 모든 플레이어와 딜러는 카드를 2장씩 가지고 시작한다.
2. 플레이어는 서로 돌아가면서 자기 턴을 가진다.
3. 플레이어는 자신의 턴에 자신이 카드를 더 받을지 말지 선택할 수 있다. 단, 자신의 점수가 21 이상인 경우 카드를 더 받을 수 없다.
4. 플레이어는 한 번 카드를 받지 않기로 결정한 경우, 앞으로의 턴에서 카드를 더 받을 수 없다.
5. 모든 플레이어가 카드를 더 받을 수 없는 경우, 딜러의 턴으로 넘어간다.
6. 딜러의 턴에서 딜러는 딜러의 점수가 16점 이하인 경우 카드를 더 받는다. 17점 이상인 경우 카드를 더 받지 않는다.
7. 딜러의 턴이 끝나면, 최종 점수 계산 및 게임의 승패를 가린다.
8. 최종 점수가 21점에 가장 가까우면서 21점을 넘기지 않는 사람이 승리한다. 동점인 플레이어(딜러 포함)이 나온 경우, 무승부로 판단한다.
Copy link
Member

Choose a reason for hiding this comment

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

모든 플레이어가 버스트가 된 경우 딜러는 카드를 뽑지 않아도 승리하기 때문에 딜러가 승이라고 생각합니다!

image


### 게임 진행 상황 출력

1. 게임이 시작 되자마자, 딜러와 플레이어가 받은 카드를 출력한다.
2. 단, 딜러는 카드를 한장만 출력한다.
3. 이 후 플레이어의 차례마다 플레이어가 소유한 카드를 출력한다.

### 게임 결과 출력

1. 게임을 완료한 후 각 플레이어(딜러 포함)가 보유한 카드 및 점수를 출력한다.
2. 게임을 완료한 후 각 플레이어별로 승패를 출력한다.
- 딜러는 다른 모든 플레이어에 대한 승패가 출력된다.
- 딜러가 아닌 플레이어는 딜러에 대한 승패가 출력된다.

### 게임 진행 가이드 출력

- 게임의 원활한 진행을 위해 가이드 문구를 출력한다.

## 기능 목록

- [x] 플레이어 이름 입력 기능
- [x] 카드 점수 계산 기능
- [x] Ace 카드 점수 보정 기능
- [x] 플레이어 및 딜러 점수 계산 기능
- [x] 플레이어 및 딜러간 승부 계산 기능
- [x] 플레이어 및 딜러 손패 출력 기능
- [x] 게임 결과 출력 기능
- [x] 게임 승부 결과 출력 기능
- [x] 덱 관리 기능
- [x] 보유한 카드 점수 합계 계산 기능
- [x] 카드 받을지 여부 입력 기능
- [x] 전체 게임 진행 기능
- [x] 딜러 Ace 카드 점수 보정 기능
19 changes: 19 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import controller.BlackjackController;
import domain.blackjack.Gamer;
import domain.blackjack.HoldingCards;
import domain.card.Deck;
import java.util.List;
import view.NameInputView;
import view.OutputView;
Copy link

Choose a reason for hiding this comment

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

패키지 구조를
src/main/java 아래

  • controller
  • domain
  • view
    등이 바로 있는데 이런경우에 이렇게
    import 중간에 java.util.List 가 끼게 됩니다.
    하나의 패키지로 더 묶으면 좋을 것 같습니다.


public class Main {
public static void main(String[] args) {
Gamer dealer = new Gamer("딜러", HoldingCards.of());
OutputView.print("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)");
List<Gamer> players = NameInputView.getNames().stream()
.map(name -> new Gamer(name, HoldingCards.of()))
.toList();
BlackjackController blackjackController = new BlackjackController(dealer, players);
blackjackController.startBlackjackGame(Deck.fullDeck());
}
}
Copy link

Choose a reason for hiding this comment

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

로빈이 생각한 Main 클래스의 역할은 무엇인가요? 💭

140 changes: 140 additions & 0 deletions src/main/java/controller/BlackjackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package controller;

import domain.blackjack.DealerRandomCardDrawStrategy;
import domain.blackjack.GameResult;
import domain.blackjack.GameResultCalculator;
import domain.blackjack.Gamer;
import domain.blackjack.PlayerRandomCardDrawStrategy;
import domain.blackjack.SummationCardPoint;
import domain.card.Card;
import domain.card.Deck;
import dto.DealerGameResultDTO;
import dto.GamerDTO;
import dto.PlayerGameResultDTO;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import view.GameResultOutputView;
import view.GamerOutputView;
import view.OutputView;
import view.YesOrNoInputView;

public class BlackjackController {
private final Gamer dealer;
private final List<Gamer> players;
Copy link

Choose a reason for hiding this comment

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

controller의 필드에 두 도메인이 있는 객체를 선언한 이유가 궁금합니다.
이렇게 했을때 장점이 무엇인가요?

Copy link

Choose a reason for hiding this comment

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

Deck은 단순히 요구사항 때문에 인자로 안넣으신건지 궁금합니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

controller의 필드에 두 도메인이 있는 객체를 선언한 이유가 궁금합니다. 이렇게 했을때 장점이 무엇인가요?

장점이 있다기 보다는 딱히 별로 중요한 부분이라 생각하지 않았습니다. 어차피 컨트롤러 내부 private 메서드 이곳 저곳에서 도메인을 사용하기 때문에, 필드로 두든, 메서드를 통해 넘겨주든 실질적인 차이가 있다고 생각하지 않습니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

Deck은 단순히 요구사항 때문에 인자로 안넣으신건지 궁금합니다.

네. 맞습니다.


public BlackjackController(Gamer dealer, List<Gamer> players) {
this.dealer = dealer;
this.players = players;
}

public void startBlackjackGame(Deck deck) {
initDealerAndPlayers(deck);
printDealerAndPlayers();

playersTryDraw(deck);
dealerTryDraw(deck);

printDealerAndPlayersWithPoint();
printDealerAndPlayersGameResult();
}

private void initDealerAndPlayers(Deck deck) {
dealerDraw(deck);
dealerDraw(deck);
players.forEach(player -> playerDraw(deck, player));
players.forEach(player -> playerDraw(deck, player));
String namesOutput = players.stream().map(Gamer::getRawName).collect(Collectors.joining(", "));
OutputView.print("딜러와 %s에게 2장을 나누었습니다.".formatted(namesOutput));
Copy link

Choose a reason for hiding this comment

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

👍 좋은 메서드 배워갑니다!

}

private void dealerDraw(Deck deck) {
dealer.draw(deck, new DealerRandomCardDrawStrategy(dealer));
}

private void playerDraw(Deck deck, Gamer player) {
player.draw(deck, new PlayerRandomCardDrawStrategy(player));
}
Copy link

Choose a reason for hiding this comment

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

엇.. draw가 호출될 때마다 전략 인스턴스가 생성되네요. 괜찮을까요?

Copy link

Choose a reason for hiding this comment

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

전략 인스턴스를 실질적으로 사용하는 곳이 Deck.class 인 것 같아요.
depth가 꽤 깊어지는 것 같은데, 전략 생성에 대한 책임을 controller가 맡는 것에 대한 근거가 있을까요?
고민하신 내용이 궁금해요 💭 로빈의 생각을 공유해주시면 감사하겠습니다~


private void printDealerAndPlayers() {
printDealer(dealer);
players.forEach(BlackjackController::printPlayer);
}

private static void printDealer(Gamer dealer) {
List<Card> rawHoldingCards = new ArrayList<>(dealer.getRawHoldingCards());
rawHoldingCards.remove(0);
GamerDTO gamerDTO = new GamerDTO(dealer.getRawName(), rawHoldingCards,
dealer.getRawSummationCardPoint());
Copy link

Choose a reason for hiding this comment

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

이 부분 개행에 대한 로빈의 생각이 궁금해요 💭
참고로 저.. 이런 개행 좋아해요 😀

GamerOutputView.printWithoutSummationCardPoint(gamerDTO);
}
Copy link

Choose a reason for hiding this comment

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

단 한 번 실행되긴 하지만, remove의 성능에 대해 생각해 보시면 좋을 것 같아요!


private static void printPlayer(Gamer player) {
GamerDTO gamerDTO = new GamerDTO(player.getRawName(), player.getRawHoldingCards(),
player.getRawSummationCardPoint());
GamerOutputView.printWithoutSummationCardPoint(gamerDTO);
}

private void playersTryDraw(Deck deck) {
players.forEach(player -> playerTryDraw(deck, player));
}

private void playerTryDraw(Deck deck, Gamer player) {
boolean needToDraw = true;
while (needToDraw && canDraw(player, new SummationCardPoint(21))) {
needToDraw = playerTryDrawOnce(deck, player);
}
}

private boolean playerTryDrawOnce(Deck deck, Gamer player) {
boolean needToDraw;
OutputView.print("%s은(는) 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)".formatted(player.getRawName()));
needToDraw = YesOrNoInputView.getYNAsBoolean();
if (needToDraw) {
playerDraw(deck, player);
}
printPlayer(player);
return needToDraw;
}

private boolean canDraw(Gamer player, SummationCardPoint threshold) {
return !player.getSummationCardPoint().isBiggerThan(threshold);
}

private void dealerTryDraw(Deck deck) {
try {
dealerDraw(deck);
OutputView.print("딜러는 16이하라 한장의 카드를 더 받았습니다.\n");
} catch (IllegalStateException ignored) {

}
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
Member Author

Choose a reason for hiding this comment

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

예외를 무시하지 말고 어떤 예외가 발생하였는지 메시지를 던져보는건 어떤가요?

이 부분은 애초에 예외를 여기서 처리하는게 아니라 도메인 내부에서 잡아야 할 것 같아서 리팩토링중입니다.. ㅠㅠ

}

private void printDealerAndPlayersWithPoint() {
GamerDTO dealerDTO = new GamerDTO(dealer.getRawName(), dealer.getRawHoldingCards(),
dealer.getRawSummationCardPoint());
GamerOutputView.print(dealerDTO);

for (Gamer player : players) {
GamerDTO playerDTO = new GamerDTO(player.getRawName(), player.getRawHoldingCards(),
player.getRawSummationCardPoint());
GamerOutputView.print(playerDTO);
}
}

private void printDealerAndPlayersGameResult() {
Map<GameResult, Integer> dealerGameResultCounts = players.stream()
.collect(Collectors.groupingBy(player -> GameResultCalculator.calculate(dealer, player),
Collectors.summingInt(value -> 1)));
DealerGameResultDTO dealerGameResultDTO = new DealerGameResultDTO(dealerGameResultCounts);

List<PlayerGameResultDTO> playerGameResultDTOS = players.stream()
.map(player -> new PlayerGameResultDTO(player.getRawName(),
GameResultCalculator.calculate(player, dealer)))
.toList();

GameResultOutputView.print(dealerGameResultDTO);
playerGameResultDTOS.forEach(GameResultOutputView::print);
}
}
24 changes: 24 additions & 0 deletions src/main/java/domain/blackjack/AbstractRandomCardDrawStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package domain.blackjack;

import domain.card.Card;
import domain.card.CardDrawStrategy;
import java.util.List;
import java.util.Random;

abstract class AbstractRandomCardDrawStrategy implements CardDrawStrategy {
@Override
public final Card nextCard(List<Card> cards) {
if (canDraw()) {
Copy link

Choose a reason for hiding this comment

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

this.canDraw는 어떻게 생각하시는지 궁금해요 💭
저는 this 키워드를 좋아하는데, 내부 필드 또는 메서드임을 명확하게 표현하고 싶어서에요!
(실제로 해당 라인 읽으면서, 갑자기 canDraw가 등장해서 static import인가 싶었지만 내부 메서드였다는.. 😢 )

return cardSelectStrategy(cards);
}
throw new IllegalStateException("카드를 더이상 뽑을 수 없습니다.");
}

abstract boolean canDraw();
Copy link

Choose a reason for hiding this comment

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

전략 대신에 Gamer나 Dealer에게 물어보는 것은 어떤가요?


private Card cardSelectStrategy(List<Card> cards) {
Random random = new Random();
int idx = random.nextInt(cards.size());
return cards.get(idx);
}
}
5 changes: 5 additions & 0 deletions src/main/java/domain/blackjack/CardPoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package domain.blackjack;

record CardPoint(int point) {

}
17 changes: 17 additions & 0 deletions src/main/java/domain/blackjack/CardPointCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package domain.blackjack;

import static domain.card.CardName.TEN;

import domain.card.Card;
import domain.card.CardName;

class CardPointCalculator {
static CardPoint calculate(Card card) {
CardName cardName = card.name();
int cardNumber = cardName.getCardNumber();
if (cardNumber > TEN.getCardNumber()) {
return new CardPoint(TEN.getCardNumber());
}
return new CardPoint(cardNumber);
}
Copy link
Member

Choose a reason for hiding this comment

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

블랙잭에서 j,q,k 는 10으로 계산한다! 라는 룰이 있어 enum 값 세팅할 때 10으로 해두어도 되지 않았을까요?
이렇게 설계한 로빈의 생각이 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

블랙잭에서 j,q,k 는 10으로 계산한다! 라는 룰이 있어 enum 값 세팅할 때 10으로 해두어도 되지 않았을까요? 이렇게 설계한 로빈의 생각이 궁금합니다!

저는 블랙잭의 규칙은 트럼프 카드 고유의 것이라 생각하지 않았습니다. 블랙잭은 트럼프 카드를 사용하는 여러 게임 중 하나기 때문에 블랙잭의 규칙이 트럼프 카드를 추상화한 클래스 내부에 있으면 안된다고 생각했습니다.

}
16 changes: 16 additions & 0 deletions src/main/java/domain/blackjack/DealerRandomCardDrawStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package domain.blackjack;

public class DealerRandomCardDrawStrategy extends AbstractRandomCardDrawStrategy {
Copy link

Choose a reason for hiding this comment

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

개인적인 의견이니 참고만 해주세요!

추상화 depth가 깊다고 생각해요. 꼭 필요한 추상화였을까 🤔 싶어요!
물론 저도 동일한 미션을 진행한 크루로서 도메인 지식이 있는 상태이기에 읽는 데에 무리는 없었지만,
각 클래스가 담당한 역할이 많이 않아서 추상화를 덜 해도 괜찮을 것 같단 생각이 들었습니다~

private final Gamer dealer;
Copy link

Choose a reason for hiding this comment

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

의존성에 대한 의문인데요
현재 코드는 전략Gamer를 알고 있고, Gamer전략을 알고 있는 것 같아요.
서로에게 의존하고 있는데, 결국 클래스 간의 결합도가 다소 높다는 생각이 드네요 🙂


public DealerRandomCardDrawStrategy(Gamer dealer) {
this.dealer = dealer;
}

@Override
boolean canDraw() {
SummationCardPoint summationCardPoint = dealer.getSummationCardPoint();
SummationCardPoint dealerDrawThresholdPoint = new SummationCardPoint(16);
return !summationCardPoint.isBiggerThan(dealerDrawThresholdPoint);
}
}
5 changes: 5 additions & 0 deletions src/main/java/domain/blackjack/GameResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package domain.blackjack;

public enum GameResult {
WIN, LOSE, TIE;
}
36 changes: 36 additions & 0 deletions src/main/java/domain/blackjack/GameResultCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package domain.blackjack;

public class GameResultCalculator {
/**
* baseGamer의 otherGamer 에 대한 승부 결과 반환
*
* @param baseGamer 기준 게이머
* @param otherGamer 상대 게이머
* @return baseGamer의 otherGamer 에 대한 승부 결과
*/
public static GameResult calculate(Gamer baseGamer, Gamer otherGamer) {
if (baseGamer.isDead() && otherGamer.isDead()) {
return GameResult.TIE;
}
if (baseGamer.isDead()) {
return GameResult.LOSE;
}
if (otherGamer.isDead()) {
return GameResult.WIN;
}
return getGameResultWhenNobodyDead(baseGamer, otherGamer);
}

private static GameResult getGameResultWhenNobodyDead(Gamer baseGamer, Gamer otherGamer) {
SummationCardPoint baseGamerSummationCardPoint = baseGamer.getSummationCardPoint();
SummationCardPoint otherGamerSummationCardPoint = otherGamer.getSummationCardPoint();

if (baseGamerSummationCardPoint.isBiggerThan(otherGamerSummationCardPoint)) {
return GameResult.WIN;
}
if (baseGamerSummationCardPoint.equals(otherGamerSummationCardPoint)) {
return GameResult.TIE;
}
return GameResult.LOSE;
}
}
60 changes: 60 additions & 0 deletions src/main/java/domain/blackjack/Gamer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package domain.blackjack;

import static domain.card.CardName.TEN;

import domain.card.Card;
import domain.card.CardDrawStrategy;
import domain.card.Deck;
import java.util.List;

public class Gamer {
private final String name;
private final HoldingCards holdingCards;

public Gamer(String name, HoldingCards holdingCards) {
this.name = name;
this.holdingCards = holdingCards;
}

public void draw(Deck deck, CardDrawStrategy cardDrawStrategy) {
Card draw = deck.draw(cardDrawStrategy);
holdingCards.add(draw);
}

public SummationCardPoint getSummationCardPoint() {
SummationCardPoint summationCardPoint = holdingCards.calculateTotalPoint();
if (hasAceInHoldingCards()) {
int rawPoint = fixPoint(summationCardPoint.summationCardPoint());
return new SummationCardPoint(rawPoint);
}
return summationCardPoint;
}

private int fixPoint(int rawPoint) {
SummationCardPoint fixPoint = new SummationCardPoint(rawPoint + TEN.getCardNumber());
if (!fixPoint.isDeadPoint()) {
return fixPoint.summationCardPoint();
}
return rawPoint;
}

public String getRawName() {
return name;
}

public List<Card> getRawHoldingCards() {
return List.copyOf(holdingCards.getHoldingCards());
}

public int getRawSummationCardPoint() {
return getSummationCardPoint().summationCardPoint();
}

boolean isDead() {
return holdingCards.calculateTotalPoint().isDeadPoint();
}

boolean hasAceInHoldingCards() {
return holdingCards.hasAce();
}
}
Loading