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

Dazzle 블랙잭 2단계 #14

Open
wants to merge 38 commits into
base: woo-chang
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
095f92f
[1단계 - 블랙잭 게임 실행] 다즐(최우창) 미션 제출합니다. (#443)
woo-chang Mar 6, 2023
72d2d7f
docs: 요구사항 명세서 작성
woo-chang Mar 7, 2023
30252f1
refactor: dto 변환 책임은 dto가 가지도록 수정
woo-chang Mar 7, 2023
b9fc77d
chore: 우테코 컨벤션으로 수정
woo-chang Mar 7, 2023
705379f
chore: 개행 수정
woo-chang Mar 7, 2023
004c830
refactor: 사용하지 않는 생성자 제거
woo-chang Mar 8, 2023
fcf4974
refactor: 상수에 의미를 부여하도록 수정
woo-chang Mar 8, 2023
1da866c
feat: 마지막 카드를 숨긴 카드 목록을 반환하는 기능 구현
woo-chang Mar 8, 2023
c4712a7
feat: 베팅 금액 입력 기능 구현
woo-chang Mar 8, 2023
e3e8f60
feat: 수익이 1.5배가 되는 기능 구현
woo-chang Mar 8, 2023
0d7034c
feat: 수익이 반전되는 기능 구현
woo-chang Mar 8, 2023
9e2ae57
feat: 플레이어가 블랙잭 보너스를 획득하는 기능 구현
woo-chang Mar 8, 2023
7681194
feat: 플레이어가 베팅에 실패하는 기능 구현
woo-chang Mar 8, 2023
38dcf8c
feat: 딜러의 수익을 확인하는 기능 구현
woo-chang Mar 8, 2023
fd50b64
refactor: 베팅 도메인 리팩토링
woo-chang Mar 8, 2023
be602fd
refactor: 딜러, 참가자 도메인 리팩토링
woo-chang Mar 8, 2023
3b0c9d4
refactor: 수익 도메인 리팩토링
woo-chang Mar 8, 2023
4fd9dea
feat: 블랙잭 게임 도메인 구현
woo-chang Mar 8, 2023
2ed62c4
refactor: 퍼센트를 받아 수익에 적용하도록 수정
woo-chang Mar 9, 2023
1b51f1b
feat: 수익이 사라지는 기능 구현
woo-chang Mar 9, 2023
de2820a
feat: 결과에 따라 수익을 재계산하는 기능 구현
woo-chang Mar 9, 2023
69bff94
feat: 결과에 따라 수익을 업데이트하는 기능 구현
woo-chang Mar 9, 2023
0fe6fd4
refactor: Betting -> BettingTable 도메인명 수정
woo-chang Mar 11, 2023
9a5d76b
refactor: 베팅 도메인을 불변으로 수정
woo-chang Mar 11, 2023
a2e97f6
refactor: 블랙잭 게임에게 플레이어 이름을 물어보도록 수정
woo-chang Mar 11, 2023
bafa2c4
test: 블랙잭 게임에게 플레이어 이름을 물어보도록 수정하여 테스트 코드 추가
woo-chang Mar 11, 2023
ff230c0
refactor: Number -> Denomination 도메인명 수정
woo-chang Mar 11, 2023
db5dc6e
refactor: 게임 결과는 블랙잭 게임이 알려주도록 수정
woo-chang Mar 11, 2023
388fd96
refactor: 블랙잭 게임에서 딜러는 뽑을 수 있는 상태일 때 뽑을 수 있도록 수정
woo-chang Mar 11, 2023
5aea768
refactor: 숨겨진 핸드를 만드는 역할을 딜러의 역할로 수정
woo-chang Mar 11, 2023
3d15375
refactor: 의미있는 상수 사용하도록 수정
woo-chang Mar 11, 2023
cbe0e83
fix: 블랙잭인 경우 보너스 수익을 얻도록 수정
woo-chang Mar 11, 2023
e7d6079
docs: 명세서 수정
woo-chang Mar 11, 2023
f29d7b3
test: 리팩토링 과정에서 부족했던 테스트 코드 추가
woo-chang Mar 11, 2023
20bf718
refactor: 블랙잭 승리라는 특수한 승리 결과 추가
woo-chang Mar 12, 2023
34cb8ef
refactor: 핵심 dto가 생성 역할을 가지도록 수정
woo-chang Mar 13, 2023
ecc6b2c
refactor: 테스트 상위 컨텍스트에서 필요한 값을 세팅 및 테스트 가독성 수정
woo-chang Mar 13, 2023
ece6266
refactor: 결과를 생성하는 역할은 Result에서 수행하도록 수정
woo-chang Mar 13, 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
131 changes: 131 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,134 @@
## 우아한테크코스 코드리뷰

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)

## 블랙잭 개요

- 블랙잭 게임은 딜러와 플레이어가 진행한다.
- 카드의 합이 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다.
- 숫자 계산은 카드의 숫자를 기본으로 하되,
- Ace: 1 or 11
- King, Queen, Jack: 10
- 게임을 시작하면, 플레이어는 베팅 금액을 정한다.
- 딜러와 플레이어는 두 장의 카드를 받는다.
- 처음 두 장의 카드 합이 21일 경우 블랙잭으로 베팅 금액의 1.5배를 딜러에게 받는다.
- 동시에 블랙잭이라면 플레이어는 베팅한 금액을 딜러에게 받는다.
- 플레이어는 카드 숫자의 합이 21 미만이라면 카드를 계속 뽑을 수 있다.
- 카드를 추가로 뽑아 21을 초과하면 베팅 금액을 모두 잃는다.
- 딜러는 카드 숫자의 합이 16 이하인 경우에만 1장의 카드를 추가로 받아야 한다.
- 딜러는 최대 3장의 카드만 받을 수 있다.
- 게임이 완료되면, 각 플레이어의 승패를 출력한다.

## 블랙잭 규칙

- `승`, `무`, `패`는 플레이어에 결과를 나타낸다.
- 플레이어 점수가 21점 초과일 때
- 딜러 점수 상관없이 `패`
- 플레이어 점수가 21점 이하일 때
- 딜러 점수가 21점 초과일 때
- 플레이어 `승`
- 딜러 점수가 21점 이하일 때
- 플레이어 점수가 높으면 `승`
- 플레이어 점수가 낮으면 `패`
- 플레어어 점수와 같으면 `무`

- 수익은 아래와 같이 계산된다.
- 플레이어가 블랙잭일 때
- 게임에서 승리했다면, 수익은 베팅 금액의 1.5배가 된다.
- 게임에서 비겼다면, 수익은 없다.
- 플레이어가 블랙잭이 아닐 때
- 게임에서 승리했다면, 수익은 베팅 금액의 1배가 된다.
- 게임에서 비겼다면, 수익은 없다.
- 게임에서 졌다면, 베팅 금액만큼 지출이 발생한다.

## 도메인 다이어그램

```mermaid
graph TD
BlackJackController --> InputView
BlackJackController --> OutputView
BlackJackController --> BlackJackGame
InputView --> Parser
BlackJackGame --> Participants
BlackJackGame --> Deck
BlackJackGame --> BettingTable
Participants --> Participant
BettingTable --> Betting
Participant --> Player
Participant --> Dealer
Participant --> Hand
Player --> PlayerName
Hand --> Card
Card --> Suit
Card --> Denomination
```

## 기능 구현 목록

### 참가자

- [x] 카드를 받는다.
- [x] 블랙잭 여부를 확인한다.
- [x] 점수를 확인한다.
- [x] 딜러인지를 확인한다.
- [x] 카드 추가 여부를 확인한다.
- [x] 여러 명일 수 있다.
- [x] 딜러는 포함되어야 한다.
- [x] 중복되는 이름은 가질 수 없다.
- [x] 최대 6명이다.

### 딜러

- [x] `딜러`라는 이름을 가진다.
- [x] 블랙잭 게임 결과를 보여준다.
- [x] 카드 패를 숨긴 채로 드러낸다.
- [x] 카드를 뽑을 수 있는 점수를 확인한다.
- [x] 카드를 추가적으로 뽑았는지 확인한다.

### 플레이어

- [x] 이름을 가진다.
- [x] 최소 1자, 최대 10자까지 가능하다.
- [x] 중간 공백은 허용한다.
- [x] `딜러`라는 이름은 가질 수 없다.

### 덱

- [x] 카드 목록을 가진다.
- [x] 트럼프를 이용해 덱을 생성한다.
- [x] 카드를 뽑는다.
- [x] 카드가 없으면 뽑을 수 없다.

### 카드

- [x] 문양을 가진다.
- [x] 숫자를 가진다.
- [x] 에이스인지 확인한다.

### 핸드

- [x] 카드를 추가한다.
- [x] 점수를 계산한다.
- [x] 카드 개수를 확인한다.

### 베팅 테이블

- [x] 플레이어의 베팅을 확인한다.

### 베팅

- [x] 베팅 금액은 100원 이상, 100만 원 이하까지 가능하다.

### 입력

- [x] 플레이어의 이름을 입력한다.
- [x] 앞, 뒤 공백은 제거한다.
- [x] 카드를 받을 여부를 입력한다.
- [x] 베팅 금액을 입력한다.

### 출력

- [x] 딜러와 플레이어의 카드 현황을 출력한다.
- [x] 딜러 카드 추가 여부를 출력한다.
- [x] 최종 결과를 출력한다.
- [x] 최종 승패를 출력한다.
16 changes: 16 additions & 0 deletions src/main/java/blackjack/BlackJackApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package blackjack;

import blackjack.controller.BlackJackController;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackJackApplication {

public static void main(String[] args) {
final InputView inputView = new InputView();
final OutputView outputView = new OutputView();

final BlackJackController blackJackController = new BlackJackController(inputView, outputView);
blackJackController.run();
}
}
95 changes: 95 additions & 0 deletions src/main/java/blackjack/controller/BlackJackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package blackjack.controller;

import blackjack.controller.dto.DealerStateResponse;
import blackjack.controller.dto.ParticipantResponse;
import blackjack.controller.dto.ParticipantResultResponse;
import blackjack.domain.BlackJackGame;
import blackjack.domain.betting.Betting;
import blackjack.domain.betting.BettingTable;
import blackjack.domain.participant.Dealer;
import blackjack.domain.participant.Participants;
import blackjack.domain.participant.Player;
import blackjack.domain.participant.PlayerName;
import blackjack.view.InputView;
import blackjack.view.OutputView;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BlackJackController {

private final InputView inputView;
private final OutputView outputView;

public BlackJackController(final InputView inputView, final OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void run() {
final BlackJackGame blackJackGame = createBlackJackGame();
initialGame(blackJackGame);

drawCardsForPlayers(blackJackGame);
drawCardForDealer(blackJackGame);

printResult(blackJackGame);
Comment on lines +31 to +37
Copy link
Member

Choose a reason for hiding this comment

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

추상화 기준이 깔끔해서 구조를 이해하기 쉬웠어 👍

Choose a reason for hiding this comment

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

허브 의견에 동의 합니다 굿굿

}

private BlackJackGame createBlackJackGame() {
final Participants participants = new Participants(new Dealer(), gatherPlayers());

Choose a reason for hiding this comment

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

Participants 생성자에 dealer와 player를 따로 넣어주는 방식 좋네요!!

Choose a reason for hiding this comment

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

근데 제가 못 찾은 것일수도 있는데 Participants안의 validate에서 예외를 던져주는데 해당 예외들에 대한 핸들링이 이루어지지 않고 있는것 같네요..?!

Copy link
Author

Choose a reason for hiding this comment

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

이번 미션에서는 예외가 발생했을 때 올바르지 않은 상황으로 판단하여 예외 처리를 하지 않았습니다 :)

final BettingTable bettingTable = createBettingTable(participants.getPlayerNames());
return new BlackJackGame(participants, bettingTable);
}

private List<Player> gatherPlayers() {
return inputView.readPlayerNames()
.stream()
.map(Player::new)
.collect(Collectors.toList());
}

private BettingTable createBettingTable(final List<PlayerName> playerNames) {
final Map<PlayerName, Betting> bettingTable = new HashMap<>();
playerNames.forEach(
playerName -> bettingTable.put(playerName, new Betting(inputView.readBetting(playerName.getValue()))));
return new BettingTable(bettingTable);
}

private void initialGame(final BlackJackGame blackJackGame) {
blackJackGame.initialDraw();
final ParticipantResponse dealer = ParticipantResponse.ofDealerWithHidden(blackJackGame);
final List<ParticipantResponse> players = ParticipantResponse.listOfPlayer(blackJackGame);
outputView.printDealCards(dealer, players, blackJackGame.getInitialDrawCount());
}

private void drawCardsForPlayers(final BlackJackGame blackJackGame) {
final List<PlayerName> playerNames = blackJackGame.getPlayerNames();
playerNames.forEach(playerName -> drawCard(playerName, blackJackGame));
}

private void drawCard(final PlayerName playerName, final BlackJackGame blackJackGame) {
while (blackJackGame.isDrawablePlayer(playerName) && inputView.readMoreDraw(playerName.getValue())) {
blackJackGame.dealCardForPlayer(playerName);
outputView.printCardsWithoutScore(ParticipantResponse.ofPlayer(playerName, blackJackGame));
}
}

public void drawCardForDealer(final BlackJackGame blackJackGame) {
blackJackGame.dealCardForDealer();
outputView.printDealerDrawn(
DealerStateResponse.of(
blackJackGame.isDealerAdditionalDrawn(),
blackJackGame.getDealerAdditionalDrawScore()
)
);
}

private void printResult(final BlackJackGame blackJackGame) {
final ParticipantResponse dealer = ParticipantResponse.ofDealer(blackJackGame);
final List<ParticipantResponse> players = ParticipantResponse.listOfPlayer(blackJackGame);
outputView.printCardsWithScore(dealer, players);
outputView.printFinalResult(ParticipantResultResponse.listOfParticipants(blackJackGame));
}
}
35 changes: 35 additions & 0 deletions src/main/java/blackjack/controller/dto/CardsResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package blackjack.controller.dto;

import blackjack.domain.card.Card;
import blackjack.domain.card.Hand;
import java.util.List;
import java.util.stream.Collectors;

public class CardsResponse {

private final int score;
private final List<String> cardInfos;

private CardsResponse(final int score, final List<String> cardInfos) {
this.score = score;
this.cardInfos = cardInfos;
}

public static CardsResponse of(final int score, final Hand hand) {
return new CardsResponse(score, createCardInfos(hand.getCards()));
}

private static List<String> createCardInfos(final List<Card> cards) {
return cards.stream()
.map(card -> card.getNumberName() + card.getSuitName())
.collect(Collectors.toList());
}

public int getScore() {
return score;
}

public List<String> createCardInfos() {
return cardInfos;
}
}
24 changes: 24 additions & 0 deletions src/main/java/blackjack/controller/dto/DealerStateResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package blackjack.controller.dto;

public class DealerStateResponse {

private final boolean isDrawn;
private final int limit;

private DealerStateResponse(final boolean isDrawn, final int limit) {
this.isDrawn = isDrawn;
this.limit = limit;
}

public static DealerStateResponse of(final boolean isDrawn, final int limit) {
return new DealerStateResponse(isDrawn, limit);
}

public boolean isDrawn() {
return isDrawn;
}

public int getLimit() {
return limit;
}
}
53 changes: 53 additions & 0 deletions src/main/java/blackjack/controller/dto/ParticipantResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package blackjack.controller.dto;

import blackjack.domain.BlackJackGame;
import blackjack.domain.card.Hand;
import blackjack.domain.participant.PlayerName;
import java.util.ArrayList;
import java.util.List;

public class ParticipantResponse {

private static final int HIDDEN_SCORE = -1;

private final String name;
private final CardsResponse cardsResponse;

private ParticipantResponse(final String name, final CardsResponse cardsResponse) {
this.name = name;
this.cardsResponse = cardsResponse;
}

public static ParticipantResponse ofPlayer(final PlayerName playerName, final BlackJackGame blackJackGame) {
final int score = blackJackGame.getPlayerScore(playerName);
final Hand hand = blackJackGame.getPlayerHand(playerName);
return new ParticipantResponse(playerName.getValue(), CardsResponse.of(score, hand));
}

public static ParticipantResponse ofDealer(final BlackJackGame blackJackGame) {
final int score = blackJackGame.getDealerScore();
final Hand hand = blackJackGame.getDealerHand();
return new ParticipantResponse(blackJackGame.getDealerName(), CardsResponse.of(score, hand));
}

public static ParticipantResponse ofDealerWithHidden(final BlackJackGame blackJackGame) {
final Hand hand = blackJackGame.getDealerHiddenHand();
return new ParticipantResponse(blackJackGame.getDealerName(), CardsResponse.of(HIDDEN_SCORE, hand));
}

Choose a reason for hiding this comment

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

dto에 정적팩토리메소드 여러개둔거 인상깊네요!!

Copy link
Author

Choose a reason for hiding this comment

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

dto도 컨트롤러 레이어에 속하므로 컨트롤러에서 변환하는 로직을 dto의 역할로 위임하였습니다!


public static List<ParticipantResponse> listOfPlayer(final BlackJackGame blackJackGame) {
final List<ParticipantResponse> players = new ArrayList<>();
final List<PlayerName> playerNames = blackJackGame.getPlayerNames();

playerNames.forEach(playerName -> players.add(ParticipantResponse.ofPlayer(playerName, blackJackGame)));
return players;
}

public String getName() {
return name;
}

public CardsResponse getCardsResponse() {
return cardsResponse;
}
}
Loading