-
Notifications
You must be signed in to change notification settings - Fork 0
[1단계 - 블랙잭 게임 실행] 커찬(이충안) 미션 제출합니다. #8
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
base: main
Are you sure you want to change the base?
Changes from 44 commits
870ad1a
a0a1235
2b505f1
f774cc7
3e83ed2
99baedb
de19b03
1da0e57
ed6c932
e11dee2
877680b
d7e7685
bcf2305
4b8ca83
3a71ec4
717e0cb
940a3a7
2079c7a
541e6c2
c5aab02
3bc66d8
da419b2
fd9106d
aea2457
0fdf520
a6af44f
1d288f1
fcef46a
f35da09
7cbb8ca
f3968ad
7c07079
dddca7c
785590d
bf63670
c23e7d2
116a613
0d2c7d5
7d5b4e4
10bb3a8
1fa7850
4f2994a
b2c1c91
4c5d051
efc2b15
d7c7f64
4465e8e
cf3878f
f3a92c0
a1ca324
cfe591e
ba33f16
cf5c481
6bccbbb
770c1a9
72369a7
be2535a
79068a6
f255e57
4d88fee
b9feef4
c0f458b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package blackjack; | ||
|
|
||
| public class BlackJackApplication { | ||
| public static void main(String[] args) { | ||
| BlackJackGame blackJackGame = new BlackJackGame(); | ||
| blackJackGame.run(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package blackjack; | ||
|
|
||
| import blackjack.domain.Deck; | ||
| import blackjack.domain.participant.Dealer; | ||
| import blackjack.domain.participant.Player; | ||
| import blackjack.domain.participant.Players; | ||
| import blackjack.view.InputView; | ||
| import blackjack.view.OutputView; | ||
| import java.util.List; | ||
|
|
||
| public class BlackJackGame { | ||
|
|
||
| private final InputView inputView = new InputView(); | ||
| private final OutputView outputView = new OutputView(); | ||
|
|
||
| public void run() { | ||
| Deck deck = Deck.createShuffledDeck(); | ||
| Dealer dealer = new Dealer(); | ||
| Players players = createPlayers(); | ||
| drawStartCards(dealer, players, deck); | ||
| play(players, dealer, deck); | ||
| printResult(dealer, players); | ||
| } | ||
|
|
||
| private Players createPlayers() { | ||
| List<String> names = inputView.inputPlayerNames(); | ||
| return Players.from(names); | ||
| } | ||
|
|
||
| private void drawStartCards(Dealer dealer, Players players, Deck deck) { | ||
| dealer.drawStartCards(deck); | ||
| players.drawStartCards(deck); | ||
| outputView.printStartCards(dealer, players); | ||
| } | ||
|
|
||
| private void play(Players players, Dealer dealer, Deck deck) { | ||
| players.play(this::playTurn, deck); | ||
| while (dealer.isDrawable()) { | ||
| outputView.printDealerDraw(); | ||
| dealer.add(deck.draw()); | ||
| } | ||
|
Comment on lines
+36
to
+41
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아이디어가 번뜩이시는군요 👍 뷰로직과 엉켜있는 플레이어 덱 완성 로직을 컨트롤러의 메서드 레퍼런스로 해결하셨군요
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 정말 이 방법이 좋은 방법인지 고민되긴 해요... 제가 받았던 리뷰에는 이런 내용도 있었어요!
|
||
| } | ||
|
|
||
| private void playTurn(Player player, Deck deck) { | ||
| while (player.isDrawable() && inputView.isPlayerWantDraw(player.getName())) { | ||
| player.add(deck.draw()); | ||
| outputView.printPlayerCards(player); | ||
| } | ||
| } | ||
|
|
||
| private void printResult(Dealer dealer, Players players) { | ||
| outputView.printResultCardAndScore(dealer, players); | ||
| outputView.printDealerMatchResult(dealer.match(players)); | ||
| for (Player player : players.getPlayers()) { | ||
| outputView.printPlayerMatchResult(player.getName(), player.isWin(dealer)); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package blackjack.domain; | ||
|
|
||
| import static java.util.stream.Collectors.toList; | ||
|
|
||
| import blackjack.domain.card.Card; | ||
| import blackjack.domain.card.Shape; | ||
| import blackjack.domain.card.Value; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Queue; | ||
|
|
||
| public class Deck { | ||
|
|
||
| private final Queue<Card> cards; | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| Deck(List<Card> cards) { | ||
| this.cards = new LinkedList<>(cards); | ||
| } | ||
|
|
||
| public static Deck createShuffledDeck() { | ||
| List<Card> cards = Arrays.stream(Shape.values()) | ||
| .map(Deck::makeCards) | ||
| .flatMap(List::stream) | ||
| .collect(toList()); | ||
| Collections.shuffle(cards); | ||
| return new Deck(cards); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩토리 메서드를 사용한 커찬의 이유가 궁금해요 💭
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "52장을 랜덤으로 구성하는 부분"과 "카드를 생성하는 부분"을 분리하고 싶었습니다. |
||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 복잡한 생성 로직을 정적 팩토리 메서드로 추상화 해주셨네요 👍 |
||
| private static List<Card> makeCards(Shape shape) { | ||
| return Arrays.stream(Value.values()) | ||
| .map(value -> new Card(value, shape)) | ||
| .toList(); | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분은 모든 모양과 모든 숫자에 대해 카드를 생성하는 로직 같은데요! 예쁜 코드를 작성하는 것이 모두의 공통 목표라고 생각해요. 코드를 읽는 것은 같은 개발자이고, 중첩 반복문을 모르는 개발자는 없겠죠 👀
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 java8에 익숙한 개발자가 읽는다면, 위와 같은 시선에서 본다면, |
||
| public Card draw() { | ||
| if (cards.isEmpty()) { | ||
| throw new IllegalStateException("카드를 더 이상 뽑을 수 없습니다."); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 깔끔하네요 👍 |
||
| } | ||
| return cards.poll(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package blackjack.domain.card; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class Card { | ||
|
|
||
| private final Value value; | ||
| private final Shape shape; | ||
|
|
||
| public Card(Value value, Shape shape) { | ||
| this.value = Objects.requireNonNull(value); | ||
| this.shape = Objects.requireNonNull(shape); | ||
|
Comment on lines
+11
to
+12
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. null 검증 👍 |
||
| } | ||
|
|
||
| public int getMinScore() { | ||
| return value.getMinScore(); | ||
| } | ||
|
|
||
| public int getMaxScore() { | ||
| return value.getMaxScore(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object object) { | ||
| if (this == object) { | ||
| return true; | ||
| } | ||
| if (object == null || getClass() != object.getClass()) { | ||
| return false; | ||
| } | ||
| Card card = (Card) object; | ||
| return value == card.value && shape == card.shape; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(value, shape); | ||
| } | ||
|
|
||
| public Value getValue() { | ||
| return value; | ||
| } | ||
|
|
||
| public Shape getShape() { | ||
| return shape; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package blackjack.domain.card; | ||
|
|
||
| public enum Shape { | ||
| SPADE, DIAMOND, HEART, CLOVER | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package blackjack.domain.card; | ||
|
|
||
| public enum Value { | ||
| 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); | ||
|
|
||
| private final int minScore; | ||
|
|
||
| Value(int minScore) { | ||
| this.minScore = minScore; | ||
| } | ||
|
|
||
| public int getMinScore() { | ||
| return minScore; | ||
| } | ||
|
|
||
| public int getMaxScore() { | ||
| if (this == ACE) { | ||
| return minScore + 10; | ||
| } | ||
| return minScore; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package blackjack.domain.participant; | ||
|
|
||
| import blackjack.domain.card.Card; | ||
| import blackjack.dto.MatchResultDto; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class Dealer extends Participant { | ||
|
|
||
|
Comment on lines
+6
to
+8
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상속에 대한 커찬의 생각 궁금합니다. 개인적으로는 상속에 여러 단점을 높게 평가하는 편인데요 한번 읽어보셔도 좋을 만한 참고글 첨부합니다 👍
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
상속의 단점들을 보완하기 위해. 자체적인 규칙들을 도입해봤어요~
|
||
| private static final int DRAWABLE_MAX_SCORE = 16; | ||
|
|
||
| public Dealer() { | ||
| super(Collections.emptyList()); | ||
| } | ||
|
|
||
| Dealer(List<Card> cards) { | ||
| super(cards); | ||
| } | ||
|
|
||
| public boolean isWin(Player player) { | ||
| if (player.isBusted()) { | ||
| return true; | ||
| } | ||
| if (this.isBusted()) { | ||
| return false; | ||
| } | ||
| return this.calculateScore() >= player.calculateScore(); | ||
| } | ||
|
|
||
| private boolean isLose(Player player) { | ||
| return !isWin(player); | ||
| } | ||
|
|
||
| public MatchResultDto match(Players players) { | ||
| int winCount = (int) players.getPlayers().stream() | ||
| .filter(this::isWin) | ||
| .count(); | ||
| int loseCount = (int) players.getPlayers().stream() | ||
| .filter(this::isLose) | ||
| .count(); | ||
| return new MatchResultDto(winCount, loseCount); | ||
| } | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만약 비긴 횟수도 관리해달라는 요구사항이 생기면 현재의 코드에서 Dealer를 찾아와야 합니다. 승패를 말아주는 새로운 도메인에 책임을 위임하는 것이 개인적으로는 좋아보이네요 😃
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지금은 |
||
| @Override | ||
| protected int getMaxDrawableScore() { | ||
| return DRAWABLE_MAX_SCORE; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package blackjack.domain.participant; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class Name { | ||
|
|
||
| private final String name; | ||
|
|
||
| public Name(String name) { | ||
| validate(name); | ||
| this.name = name.strip(); | ||
| } | ||
|
|
||
| private void validate(String name) { | ||
| if (name == null || name.isBlank()) { | ||
| throw new IllegalArgumentException("이름은 적어도 한 글자 이상을 포함해야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object object) { | ||
| if (this == object) { | ||
| return true; | ||
| } | ||
| if (object == null || getClass() != object.getClass()) { | ||
| return false; | ||
| } | ||
| Name name1 = (Name) object; | ||
| return Objects.equals(name, name1.name); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(name); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package blackjack.domain.participant; | ||
|
|
||
| import blackjack.domain.Deck; | ||
| import blackjack.domain.card.Card; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public abstract class Participant { | ||
|
|
||
| protected static final int BLACKJACK_SCORE = 21; | ||
| private static final int START_CARDS_SIZE = 2; | ||
|
|
||
| private final List<Card> cards; | ||
|
|
||
| protected Participant(List<Card> cards) { | ||
| this.cards = new ArrayList<>(cards); | ||
| } | ||
|
|
||
| public final int calculateScore() { | ||
| int score = getMaxScore(); | ||
| int cardIndex = 0; | ||
| while (score > BLACKJACK_SCORE && cardIndex < cards.size()) { | ||
| Card card = cards.get(cardIndex); | ||
| score = score + card.getMinScore() - card.getMaxScore(); | ||
| cardIndex++; | ||
| } | ||
| return score; | ||
| } | ||
|
|
||
| private int getMaxScore() { | ||
| return cards.stream() | ||
| .mapToInt(Card::getMaxScore) | ||
| .sum(); | ||
| } | ||
|
|
||
| public final boolean isDrawable() { | ||
| return calculateScore() <= getMaxDrawableScore(); | ||
| } | ||
|
|
||
| public final boolean isBusted() { | ||
| return calculateScore() > BLACKJACK_SCORE; | ||
| } | ||
|
|
||
| public void drawStartCards(Deck deck) { | ||
| if (!cards.isEmpty()) { | ||
| throw new IllegalStateException("이미 시작 카드를 뽑았습니다."); | ||
| } | ||
| for (int i = 0; i < START_CARDS_SIZE; i++) { | ||
| add(deck.draw()); | ||
| } | ||
| } | ||
|
|
||
| public final void add(Card card) { | ||
| if (!isDrawable()) { | ||
| throw new IllegalStateException("더 이상 카드를 추가할 수 없습니다."); | ||
| } | ||
| cards.add(card); | ||
| } | ||
|
|
||
| public final List<Card> getCards() { | ||
| return Collections.unmodifiableList(cards); | ||
| } | ||
|
|
||
| protected abstract int getMaxDrawableScore(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도메인 로직과 뷰 로직이 엉켜있는 미션이었는데 깔끔하게 처리하셨네요 👍