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

[Lev1][미션3] 블랙잭 1단계 누누 #4

Open
wants to merge 97 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
3e14a55
docs: 기능 목록 작성
be-student Feb 28, 2023
34967de
test: Name 객체 유효성 테스트 및 도메인 생성
be-student Feb 28, 2023
3229c65
feat: Shape 도메인 생성
be-student Feb 28, 2023
ca9d522
test: Card 테스트
be-student Feb 28, 2023
712e585
feat: Card 도메인 생성
be-student Feb 28, 2023
0568cd9
feat: shuffle 객체 추가
be-student Feb 28, 2023
ce6262d
feat: deck을 생성할 때 factory 형태로 생성하는 기능 추가
be-student Feb 28, 2023
4caf176
feat: cardPocket 점수 계산 기능 추가
zillionme Mar 2, 2023
50d04d4
feat: Participant 도메인 생성
zillionme Mar 2, 2023
8d1eb0c
feat: dealer 카드 DRAW여부 확인 기능 추가 및 테스트
zillionme Mar 2, 2023
ce1da35
feat: blackjack 상수 추가
zillionme Mar 2, 2023
1bb7e5c
feat: participant 카드 getter 기능 추가
zillionme Mar 2, 2023
7ab51e7
refactor: 테스트에서 사용되는 fixture 메서드로 분리
zillionme Mar 2, 2023
7a32bdd
feat: Player 기능 추가
zillionme Mar 2, 2023
1988ae4
feat: Players 기능 및 테스트 추가
zillionme Mar 2, 2023
56cc008
refactor: 빈 CardPocket 생성 기능 추가
zillionme Mar 2, 2023
14a6b65
feat: 결과를 저장하는 객체를 추가
zillionme Mar 2, 2023
b3a5c0a
feat: dealer 에서 결과 계산 기능 추가
zillionme Mar 2, 2023
f7bb0df
docs: readme 작성
be-student Mar 3, 2023
5fe1153
feat: 출력 기능 작성
be-student Mar 3, 2023
88d03cb
feat: 입력 기능 추가
be-student Mar 3, 2023
ec2321a
fix: 딜러 점수 계산 방식 오류 수정
be-student Mar 3, 2023
021977d
feat: hasName 메서드로 검색 가능하도록 추가
be-student Mar 3, 2023
471b570
feat: 출력을 위한 메서드들 추가
be-student Mar 3, 2023
b395c23
feat: 게임 객체 추가
be-student Mar 3, 2023
5f69d94
feat: controller 작성
be-student Mar 3, 2023
79ca7fb
docs: 클래스 주석 작성
be-student Mar 3, 2023
d1538e2
docs: 사용하지 않는 주석 제거
be-student Mar 3, 2023
c0524c2
refactor: remove blackjackGame to controller
be-student Mar 3, 2023
190e64d
refactor: Optional 안 사용하도록 변경
be-student Mar 3, 2023
6fe316c
refactor: 메서드 분리만
be-student Mar 3, 2023
f1e962e
refactor: controller indent 2 메서드 분리
be-student Mar 3, 2023
5756fe4
refactor: factory 내부 indent 2 제거
be-student Mar 3, 2023
efbd27b
chore: 사용하지 않는 메서드 제거
be-student Mar 3, 2023
8bab4ba
chore: 매개변수 타입 명칭 변경
be-student Mar 3, 2023
d59c109
style: reformat
be-student Mar 3, 2023
7ea7726
refactor: 한번에 결과를 반환하도록 변경
be-student Mar 3, 2023
83422e7
style : 자바 컨벤션 수정
zillionme Mar 3, 2023
fc63956
docs: 사용하지 않는 주석 제거
be-student Mar 3, 2023
b4c7d49
feat: 줄바꿈 변경
be-student Mar 3, 2023
6c0d203
refactor: 접근 제어자 더 좁은 방향으로 변경
be-student Mar 3, 2023
2655498
feat: util 클래스 생성 방지를 위한 private 생성자 추가
be-student Mar 3, 2023
35df4c6
feat: participant 쪽에 공통으로 draw 하는 메서드 추가
be-student Mar 5, 2023
76257bd
refactor: 안 쓰이는 equals, hashcode 제거
be-student Mar 5, 2023
51446dd
refactor: isAce 메서드와, score 메서드를 통해 결합도를 낮춤
be-student Mar 5, 2023
f46b378
test: isAce 메서드와, 점수 계산 테스트 추가
be-student Mar 5, 2023
941cfb0
test: ace 가 현재 점수에 따라 다르게 계산되는 것 검증 추가
be-student Mar 5, 2023
5504da4
refactor: 메서드 네이밍 변경
be-student Mar 5, 2023
909b264
test: 52장 제거 테스트 추가
be-student Mar 5, 2023
f8adcb0
refactor: for문을 flatMap 형태로 stream 으로 변경
be-student Mar 5, 2023
186197e
refactor: set 형태 대신, distinct 로 중복 검사 변경
be-student Mar 5, 2023
f4b57fe
feat: initialCardResponseDto 추가
be-student Mar 5, 2023
4764a15
feat: CardsScoreResponse 작성
be-student Mar 5, 2023
2ac0fa0
feat: enum 의 이름을 기준으로 가져올 수 있도록 변경
be-student Mar 5, 2023
5bb124d
fix: getter로 꺼내오는 메서드 제거
be-student Mar 5, 2023
a9220a3
feat: 결과를 변환하는 전략 추가
be-student Mar 5, 2023
044ec19
feat: resultTypeResponse 추가
be-student Mar 6, 2023
c9a0d41
refactor: InitialCardResponse 적용
be-student Mar 6, 2023
41503ae
feat: PlayerCardsResponse 적용
be-student Mar 6, 2023
72130a7
feat: playersCardsResponse 추가
be-student Mar 6, 2023
1594d05
refactor: FinalResultResponse 를 사용하도록 변경
be-student Mar 6, 2023
2fe6d38
chore: 안 쓰이는 dto 제거
be-student Mar 6, 2023
eff7295
chore: 안 쓰이는 변환 제거
be-student Mar 6, 2023
6c2a105
refactor: String format 대신 MessageFormat 사용
be-student Mar 6, 2023
0cd0732
refactor: 바로 도메인 객체를 받아서 변환하도록 변경
be-student Mar 6, 2023
ad763ee
refactor: util 로 이동
be-student Mar 6, 2023
6243a34
refactor: 상수를 각각의 클래스로 옮김
be-student Mar 6, 2023
cf67ed5
chore: 클래스 네이밍 변경
be-student Mar 6, 2023
a3f6ac2
feat: 컨트롤러에서 사용하는 로직을 game 객체로 이동
be-student Mar 6, 2023
be6dfaa
refactor: dto 로 변환하는 작업을 game 쪽으로 이동
be-student Mar 6, 2023
8982d6b
chore: 안 쓰이는 메서드 제거
be-student Mar 6, 2023
8323c9c
refactor: blackjack game 안쪽에서 Players 를 생성하도록 변경
be-student Mar 6, 2023
a1ee961
refactor: getter를 비즈니스 로직에서 덜 사용하도록 변경
be-student Mar 6, 2023
3da8a8d
feat: blackjack Rule 객체 추가
be-student Mar 6, 2023
bdb25bf
feat: dealer 에서 계산 로직 제거
be-student Mar 6, 2023
6cbc719
feat: 결과를 계산하는 로직을 담당하는 객체 추가
be-student Mar 6, 2023
cf77fdf
style: 메시지 줄바꿈 추가
be-student Mar 6, 2023
4e903c7
feat: innerClass 로 particiPantResult 이동
be-student Mar 6, 2023
52b23ca
refactor: 패키지 이동
be-student Mar 6, 2023
a9bfb31
feat: 계속 반복되는 CustomException 으로 분리
be-student Mar 6, 2023
2a2c35e
style: 줄바꿈 변경
be-student Mar 6, 2023
9b7182e
chore: 카드 포켓 에러 메시지 변경
be-student Mar 6, 2023
ea05169
chore: 메서드명 변경
be-student Mar 6, 2023
8021c0a
chore: 에러 메시지 변경
be-student Mar 6, 2023
420321d
refactor: deck, deckFactory 패키지 변경
be-student Mar 7, 2023
60f5105
chore: 주석 제거
be-student Mar 7, 2023
6528777
refactor: blackjackGame 패키지 변경
be-student Mar 7, 2023
9907bc6
refactor: 메서드 인라인
be-student Mar 7, 2023
c68cb0d
refactor: response 에 있던 정적 팩토리 제거
be-student Mar 7, 2023
c56db90
feat: blackJackRule 인터페이스로 분리
be-student Mar 7, 2023
9dbe90f
fix: 테스트 깨진 것 제거
be-student Mar 7, 2023
c769a1e
feat: 점수 저장 기능 BlackJackGame 으로 이동
be-student Mar 7, 2023
11c1db1
fix: 제거된 클래스 관련 메서드 제거
be-student Mar 7, 2023
23c3493
chore: 메서드명 popCard 로 변경
be-student Mar 7, 2023
62326fc
fix: 안 지워진 파일 제거
be-student Mar 8, 2023
dfba760
refactor: 도메인 객체에 이름을 주는 방식으로 view에 strategy 제거
be-student Mar 9, 2023
d1f62ef
refactor: response 객체 대신 Collection 을 넘기는 것으로 수정
be-student 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
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,79 @@
## 우아한테크코스 코드리뷰

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

```mermaid
Copy link
Member

Choose a reason for hiding this comment

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

---
title: 의존성 그래프
---

graph TD위에 title 구문을 사용한다면 제목을 붙일 수 있어~

Copy link
Author

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.

의존성 그래프 그리기 신기해요!! 좋은거 배워갑니다 ><

Choose a reason for hiding this comment

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

mermaid 좋은데요?

graph TD
의존성그래프
BlackJackGame --> Players
BlackJackGame --> Deck
BlackJackGame --> Dealer

Players --> Dealer
Dealer --> Player

Participant --> CardPocket
Dealer --> Participant
Player --> Participant

Players --> Player
Player --> Name
CardPocket --> Card

Deck --> Card
Card --> Shape
Card --> Symbol
```

# 기능구현 목록

## UI

1. 입력

- 참여할 사람을 입력한다
- List<String>으로 변환 및 반환한다
-

## 도메인

1. Deck
- [x] 카드를 생성한다
- [x] 총 52장
- [x] Shape마다 13장을 출력
- [x] 카드를 나눠준다

2. BlackJack
- 딜러와 플레이어에게 카드를 2장씩 나눠준다.
-- 카드를 나눠준다
3. Participant
- [x] 21 이상인지 확인하고
- [x] 21 이상이라면,
- [x] 블랙잭인지 확인한다 = 받을 수 없음
- [x] BURST인지 확인한다 = 받을 수 없음4
- [x] 현재 점수를 숫자 형태로 반환한다
- [x] 현재 카드를 반환한다
4. Player
- [x] 21 미만이면, 받을 수 있다는 boolean
Comment on lines +42 to +61
Copy link
Member

Choose a reason for hiding this comment

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

도메인 하나 하나에 대해 세세하게 README가 잘 작성 되어있네 👍
미션의 크기가 좀 더 커지면 어떻게 될까?

Copy link
Author

Choose a reason for hiding this comment

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

더 열심히 적는다...?

5. Dealer
- [x] 16 이하이면, 받을 수 있따는 boolean
6. CardPocket
- [x] 카드의 Symbol 점수를 계산한다.(ScoreCalculator 역할)
- 카드반환 한다
- [x] 카드 계산 총합 반환
7. Shape
- [x] enum 형태로 하트, 스페이스, 클로버, 다이아를 저장한다
8. Symbol
- [x] a=1 2-9, j,q,k =10
- [x] value는 int 형으로 저장한다
9. Card
- [x] Shape와 Symbol을 저장하는 자료구조

10. Players
- [x] 플레이어 이름 중복
- [x] 플레이어 수 1명이상, 5명 이하
- [x] 플레이어에게 카드 나눠주기
- [x] 플레이어의 draw여부 알기
11. Name
- [x] isBlank 체크
- [x] 100자 이하 체크
14 changes: 14 additions & 0 deletions src/main/java/blackjack/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package blackjack;

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

public class Application {

public static void main(final String[] args) {
final BlackJackController blackJackController = new BlackJackController(new InputView(), new OutputView());
blackJackController.play(new ShuffledDeckFactory());
}
}
124 changes: 124 additions & 0 deletions src/main/java/blackjack/controller/BlackJackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package blackjack.controller;

import static blackjack.controller.Repeater.repeatUntilNoException;

import blackjack.domain.Dealer;
import blackjack.domain.Deck;
import blackjack.domain.DeckFactory;
import blackjack.domain.Players;
import blackjack.dto.CardsScoreDto;
import blackjack.dto.FinalResultDto;
import blackjack.dto.InitialCardDto;
import blackjack.dto.PlayerCardDto;
import blackjack.dto.PlayerCardsScoreDto;
import blackjack.view.DrawCommand;
import blackjack.view.InputView;
import blackjack.view.OutputView;
import java.util.LinkedHashMap;
import java.util.Map;

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;

Choose a reason for hiding this comment

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

inputView와 outputVIew를 controller외부에서 주입시켜주는 이유가 따로 있나요?? (순수한 궁금증)

}

public void play(final DeckFactory deckFactory) {
final Players players = createPlayers();
final Dealer dealer = new Dealer();
final Deck deck = deckFactory.generate();

distributeInitialCard(players, dealer, deck);
printInitialCards(players, dealer);
drawPlayersCards(players, deck);
drawDealerCards(dealer, deck);
players.calculateResult(dealer);
printResult(players, dealer);
}

private Players createPlayers() {
return repeatUntilNoException(
() -> Players.from(inputView.inputPlayerNames()), outputView::printError);
}

private void distributeInitialCard(final Players players, final Dealer dealer, final Deck deck) {
players.distributeInitialCards(deck);
dealer.drawCard(deck.removeCard());
dealer.drawCard(deck.removeCard());
}


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

Choose a reason for hiding this comment

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

앗 그렇네

private void printInitialCards(final Players players, final Dealer dealer) {
final InitialCardDto initialCardDto = new InitialCardDto(
dealer.getCards()
.get(0),

Choose a reason for hiding this comment

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

0을 상수로 빼는건 어떨까요?

players.findPlayerNameToCards());
outputView.printInitialCards(initialCardDto);
}

private void drawPlayersCards(final Players players, final Deck deck) {
for (final String playerName : players.getPlayerNames()) {
drawPlayerCard(playerName, deck, players);
}
}

private void drawPlayerCard(final String playerName, final Deck deck, final Players players) {
DrawCommand playerInput = DrawCommand.DRAW;
while (players.isDrawable(playerName) && playerInput != DrawCommand.STAY) {

Choose a reason for hiding this comment

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

재입력 받는 부분 언제나 고민이 많았는데,
개인적으로 이부분 로직 너무 좋아요.. 배워갑니다..
repeatUntilNoException 요거도!! 굿굿

playerInput = repeatUntilNoException(
() -> inputView.inputCommand(playerName), outputView::printError);
drawCard(playerName, deck, players, playerInput);
printPlayerResult(playerName, players);
}
}

private void drawCard(final String playerName, final Deck deck, final Players players,

Choose a reason for hiding this comment

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

근데 파라미터가 4개인게 조금 걸리네요.. 하나만 줄여볼 수 없을까ㅎㅎㅎ

final DrawCommand playerInput) {
if (playerInput == DrawCommand.DRAW) {
players.draw(playerName, deck);
}
}

private void printPlayerResult(final String playerName, final Players players) {
final PlayerCardDto playerCardDto = new PlayerCardDto(playerName,
players.findCardsByPlayerName(playerName));
outputView.printCardStatusOfPlayer(playerCardDto);
}


private void drawDealerCards(final Dealer dealer, final Deck deck) {
while (dealer.isDrawable()) {
dealer.drawCard(deck.removeCard());
outputView.printDealerCardDrawMessage();
}
}

private void printResult(final Players players, final Dealer dealer) {
printStatusOfGame(dealer, players);
outputView.printFinalResult(new FinalResultDto(dealer.getResult()));
}

private void printStatusOfGame(final Dealer dealer, final Players players) {
outputView.printFinalStatusOfDealer(
new CardsScoreDto(dealer.getCards(), dealer.currentScore()));
outputView.printFinalStatusOfPlayers(createPlayerCardDto(players));
}

private PlayerCardsScoreDto createPlayerCardDto(final Players players) {
final Map<String, CardsScoreDto> playerNameToResult = new LinkedHashMap<>();

for (final String playerName : players.getPlayerNames()) {
final CardsScoreDto playerCardDto = new CardsScoreDto(
players.findCardsByPlayerName(playerName),
players.getPlayerScoreByName(playerName)
);
playerNameToResult.put(playerName, playerCardDto);
}

return new PlayerCardsScoreDto(playerNameToResult);
}
}
29 changes: 29 additions & 0 deletions src/main/java/blackjack/controller/Repeater.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package blackjack.controller;

import java.util.function.Consumer;
import java.util.function.Supplier;

class Repeater {

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 Repeater() {
}

static <T> T repeatUntilNoException(final Supplier<T> supplier,
final Consumer<Exception> exceptionHandler) {
T result = null;
while (result == null) {
result = createOutputOrNull(supplier, exceptionHandler);
}
return result;
}

private static <T> T createOutputOrNull(final Supplier<T> inputSupplier,
final Consumer<Exception> exceptionHandler) {
try {
return inputSupplier.get();
} catch (final IllegalArgumentException e) {
exceptionHandler.accept(e);
return null;
}
}
}
14 changes: 14 additions & 0 deletions src/main/java/blackjack/domain/BlackJackConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package blackjack.domain;

/**
* 도메인 로직상 여러곳에서 사용되는 상수를 관리하기 위한 책임을 가지고 있습니다
* <p/>
* 많은 클래스가 블랙잭이라는 숫자에 대한 정보를 필요로 하기에 제작되었습니다
*/
class BlackJackConstant {

static final int BLACKJACK = 21;

Choose a reason for hiding this comment

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

package-private의 적절한 사용 👍


private BlackJackConstant() {
}
}
31 changes: 31 additions & 0 deletions src/main/java/blackjack/domain/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package blackjack.domain;

/**
* 하나의 카드에 대한 정보를 가지고 있는 자료구조입니다
*/
public class Card {

private final Shape shape;
private final Symbol symbol;

public Card(final Shape shape, final Symbol symbol) {
this.shape = shape;
this.symbol = symbol;
}

public boolean isAce() {
return symbol.isAce();
}

public int getScore() {
return symbol.getScore();
}

public Symbol getSymbol() {
return symbol;
}

public Shape getShape() {
return shape;
}
}
63 changes: 63 additions & 0 deletions src/main/java/blackjack/domain/CardPocket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package blackjack.domain;

import static blackjack.domain.BlackJackConstant.BLACKJACK;

import java.util.ArrayList;
import java.util.List;

public class CardPocket {

private static final int VALUE_ACE = 10;
private final List<Card> cards;

private CardPocket(final List<Card> cards) {
validateCardPocket(cards);
this.cards = new ArrayList<>(cards);

Choose a reason for hiding this comment

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

복사해서 넣어주는 이유가 있나요??

}

static CardPocket empty() {
return new CardPocket(new ArrayList<>());
}

private void validateCardPocket(final List<Card> cards) {
if (cards == null) {
throw new IllegalArgumentException("카드를 입력하지 않았습니다");

Choose a reason for hiding this comment

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

도메인의 관점에서 입력이라는 용어가 어색해보이는데 다른 괜찮은 메시지가 있을까요🤔

Copy link
Author

Choose a reason for hiding this comment

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

고마워! 그냥 null 하지 말라고 적었어

}
}

void addCard(final Card card) {
Copy link
Member

Choose a reason for hiding this comment

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

package-private 메소드가 많은데 이유가 궁금해요

Copy link
Member

Choose a reason for hiding this comment

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

@be-student 알려주세요 제발

Copy link
Author

Choose a reason for hiding this comment

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

내일 말해주는 걸로 ㅋㅋㅋ

cards.add(card);
}

int calculateScore() {
final int countOfAce = countAce();
int scoreOfCards = calculateMinimumScore();
for (int i = 0; i < countOfAce; i++) {
scoreOfCards = calculateAceScore(scoreOfCards);
}
return scoreOfCards;
}

private int countAce() {
return (int) cards.stream()
.filter(Card::isAce)
.count();
}

private int calculateMinimumScore() {
return cards.stream()
.mapToInt(Card::getScore)
.sum();
}

private int calculateAceScore(final int score) {
if (score + VALUE_ACE > BLACKJACK) {
return score;
}
return score + VALUE_ACE;
}

List<Card> getCards() {
return List.copyOf(cards);

Choose a reason for hiding this comment

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

생성자 부분에서는 new ArrayList(cards)를 사용하고 해당 부분에서는 List.copyOf를 사용했는데 차이를 둔 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

도메인 객체를 넘기면서, 변경되면 안될것 같아서 일부러 저렇게 방어적 복사를 한 느낌?
getter를 통해서 넘기더라도, 내부 데이터가 바뀌면 안되니까
불변 list 여부 차이가 있을 것 같아

}
}
Loading