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단계 미션 제출합니다. #37

Merged
merged 19 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# java-blackjack
블랙잭 게임 미션 저장소

## 우아한테크코스 코드리뷰
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
## 도메인 기능 요구사항
- [x] 딜러가 게임 참가자들에게 카드를 2장씩 나눈다.
- [x] 딜러와 플레이어들은 카드를 가질 수 있다.
- [x] 각 플레이어들의 카드 합을 구한다.
- [x] Ace는 1 또는 11로 계산하고, King, Queen, Jack은 10으로 계산한다.
- [x] 플레이어들의 카드 합이 21을 넘는지 확인한다.
- [x] 딜러의 카드 합이 16 이하인 경우 카드를 계속해서 더 받는다.

## 입출력 기능 요구사항
- [x] 게임에 참여할 사람의 이름을 입력받는다.
- [x] (예외) 공백이 입력될 경우
- [x] 딜러와 플레이어의 카드를 출력한다.
- [x] 딜러는 2장 중 1장만 출력한다.
- [x] 플레이어들을 순회하며 카드를 더 받을지 물어본다.
- [x] 딜러와 플레이어들의 카드 목록과 합을 출력한다.
- [x] 최종 승패를 출력한다.
28 changes: 28 additions & 0 deletions src/main/java/blackjack/BlackJackApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package blackjack;

import blackjack.domain.card.CardFactory;
import blackjack.domain.deck.Deck;
import blackjack.domain.gamer.Dealer;
import blackjack.domain.gamer.Players;
import blackjack.dto.GamersResultAssembler;
import blackjack.dto.GamersResultDto;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackJackApplication {

public static void main(String[] args) {
Deck deck = new Deck(CardFactory.generate());
Dealer dealer = new Dealer();
Players players = Players.of(InputView.askPlayerNames().get());

BlackJackController.initializeCard(dealer, players, deck);
OutputView.printInitialCards(dealer, players);

BlackJackController.drawMoreCard(dealer, players, deck);
OutputView.printGamerScore(dealer, players);

GamersResultDto gamersResultDto = GamersResultAssembler.of(dealer, players);
OutputView.printGamersResult(gamersResultDto);
}
}
47 changes: 47 additions & 0 deletions src/main/java/blackjack/BlackJackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package blackjack;

import blackjack.domain.deck.Deck;
import blackjack.domain.gamer.Dealer;
import blackjack.domain.gamer.Player;
import blackjack.domain.gamer.Players;
import blackjack.domain.rule.HandInitializer;
import blackjack.domain.rule.PlayerAnswer;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackJackController {

public static void initializeCard(Dealer dealer, Players players, Deck deck) {
HandInitializer.initialize(dealer, players, deck);
}

public static void drawMoreCard(Dealer dealer, Players players, Deck deck) {
hitOrStandForPlayers(players, deck);
drawCardForDealer(dealer, deck);
}

private static void hitOrStandForPlayers(Players players, Deck deck) {
for (Player player : players) {
hitOrStand(player, deck);
}
}

private static void drawCardForDealer(Dealer dealer, Deck deck) {
while (dealer.canDrawCard()) {
dealer.draw(deck.pick());
OutputView.printDealerDrewCard();
}
}

private static void hitOrStand(Player player, Deck deck) {
while (player.canDrawCard() && wantMoreCard(player)) {
player.draw(deck.pick());
OutputView.printPlayerHand(player);
}
}

private static boolean wantMoreCard(Player player) {
PlayerAnswer answer = PlayerAnswer.of(InputView.askHitOrStand(player));
return answer.isYes();
}
}
29 changes: 29 additions & 0 deletions src/main/java/blackjack/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package blackjack.domain.card;

public class Card {

private CardSymbol cardSymbol;
private CardType cardType;

public Card(CardSymbol cardSymbol, CardType cardType) {
this.cardSymbol = cardSymbol;
this.cardType = cardType;
}

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

public int getCardNumber() {
return cardSymbol.getCardNumber();
}

public CardType getCardType() {
return cardType;
}

@Override
public String toString() {
return cardSymbol.getCardSymbol() + cardType.getKoreanName();
}
}
23 changes: 23 additions & 0 deletions src/main/java/blackjack/domain/card/CardFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package blackjack.domain.card;

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

public class CardFactory {

public static List<Card> generate() {

List<Card> cards = new ArrayList<>();

for (CardSymbol symbol : CardSymbol.values()) {
createByType(cards, symbol);
}
return cards;
}

private static void createByType(List<Card> cards, CardSymbol symbol) {
for (CardType type : CardType.values()) {
cards.add(new Card(symbol, type));
}
}
}
38 changes: 38 additions & 0 deletions src/main/java/blackjack/domain/card/CardSymbol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package blackjack.domain.card;

public enum CardSymbol {

ACE(11, "A"),
TWO(2, "2"),
THREE(3, "3"),
FOUR(4, "4"),
FIVE(5, "5"),
SIX(6, "6"),
SEVEN(7, "7"),
EIGHT(8, "8"),
NINE(9, "9"),
TEN(10, "10"),
JACK(10, "J"),
QUEEN(10, "Q"),
KING(10, "K");

private final int cardNumber;
private final String cardSymbol;

CardSymbol(int cardNumber, String cardSymbol) {
this.cardNumber = cardNumber;
this.cardSymbol = cardSymbol;
}

public boolean isAce() {
return this == ACE;
}

public int getCardNumber() {
return cardNumber;
}

public String getCardSymbol() {
return cardSymbol;
}
}
20 changes: 20 additions & 0 deletions src/main/java/blackjack/domain/card/CardType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package blackjack.domain.card;

public enum CardType {

SPADE("스페이드"),
HEART("하트"),
CLOVER("클로버"),
DIAMOND("다이아몬드");

private final String koreanName;

CardType(String koreanName) {
this.koreanName = koreanName;
}

public String getKoreanName() {
return koreanName;
}

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

import blackjack.domain.rule.Score;

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

public class Hand {

private final List<Card> hand = new ArrayList<>();

public void add(Card card) {
if (Objects.isNull(card)) {
throw new IllegalArgumentException("카드를 추가할 수 없습니다.");
}
hand.add(card);
}

public Score getScore() {
return Score.calculateScore(hand);
}

public List<Card> getCardStatus() {
return hand;
}
}
28 changes: 28 additions & 0 deletions src/main/java/blackjack/domain/deck/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package blackjack.domain.deck;

import blackjack.domain.card.Card;

import java.util.Collections;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Stack;

public class Deck {

private final Stack<Card> cards = new Stack<>();

public Deck(List<Card> cards) {
if (cards.isEmpty() || cards == null) {
throw new IllegalArgumentException("카드 덱을 생성할 수 없습니다.");
}
Collections.shuffle(cards);
this.cards.addAll(cards);
}

public Card pick() {
if (cards.empty()) {
throw new EmptyStackException();
}
return cards.pop();
}
}
26 changes: 26 additions & 0 deletions src/main/java/blackjack/domain/gamer/Dealer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blackjack.domain.gamer;

import blackjack.domain.card.Card;
import static blackjack.domain.rule.Score.SCORES;

public class Dealer extends Gamer {

private static final int DRAW_THRESHOLD = 16;

@Override
public boolean canDrawCard() {
if (handScore().compareTo(SCORES.get(DRAW_THRESHOLD)) > 0) {
return false;
}
return true;
}

@Override
public String getName() {

Choose a reason for hiding this comment

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

getName을 override하지 않고 Gamer의 속성으로 가지고 있으면 어떨까요?

Copy link
Author

@YebinK YebinK Mar 15, 2020

Choose a reason for hiding this comment

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

이 부분은 출력 로직을 위해 override했습니다!
OutputView에서 중복을 줄이려면

private static void printCardStatusAndResult(Gamer gamer) {
        System.out.println(String.format(CARD_STATUS_AND_RESULT_FORMAT, gamer.getName(), makeHandResult(gamer.getCardStatus()), gamer.calculateSum()));
    }

이렇게 파라미터로 gamer를 받아와서

printCardStatusAndResult(dealer);
printCardStatusAndResult(player);

이런 방식으로 호출하고 싶었습니다. 그리고 딜러 역할을 수행하는 자의 이름이 더 이상 '딜러'가 아니게 될 경우, 도메인을 변경해도 된다고 생각했습니다.

이 부분에 대해 후니 님은 어떻게 생각하시는지 궁금합니다! :)

Choose a reason for hiding this comment

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

파라미터로 gamer를 받아도 같은 결과가 나올 것 같아요!
피드백 남긴 부분을 참고해주세요!

return "딜러";
}

public Card getOpenCard() {
return hand.getCardStatus().get(0);
}
}
36 changes: 36 additions & 0 deletions src/main/java/blackjack/domain/gamer/Gamer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package blackjack.domain.gamer;

import blackjack.domain.card.Card;
import blackjack.domain.card.Hand;
import blackjack.domain.rule.Score;

import java.util.List;

public abstract class Gamer {

protected Hand hand = new Hand();

public void draw(Card card) {
hand.add(card);
}

public boolean isBusted() {
return handScore().isBusted();
}

public Score handScore() {
return hand.getScore();
}

public abstract boolean canDrawCard();

public abstract String getName();

Choose a reason for hiding this comment

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

제가 이전에 피드백했던 부분은 Gamer가

private String name;
public String getName() {
   return name;
}

을 가지면 어떨까였습니다!
그렇게 되면 각 구현체에서는 public abstract String getName(); 해당 메서드를 구현할 필요 없어질 것 같아요!


public List<Card> getHand() {
return hand.getCardStatus();
}

public int getHandScore() {
return handScore().getNumber();
}
}
26 changes: 26 additions & 0 deletions src/main/java/blackjack/domain/gamer/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blackjack.domain.gamer;

import blackjack.domain.rule.HandCalculator;

import static blackjack.domain.rule.Score.SCORES;

import java.util.Objects;

public class Player extends Gamer {

private final String name;

public Player(String name) {
this.name = Objects.requireNonNull(name);
}

@Override
public boolean canDrawCard() {
return !handScore().isBusted();
}

@Override
public String getName() {
return name;
}
}
32 changes: 32 additions & 0 deletions src/main/java/blackjack/domain/gamer/Players.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package blackjack.domain.gamer;

import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

public class Players implements Iterable<Player> {

private final List<Player> players;

private Players(List<Player> players) {
this.players = players;
}

public static Players of(List<String> names) {
List<Player> players = names.stream()
.map(Player::new)
.collect(Collectors.toList());
return new Players(players);
}

public List<String> getNames() {
return players.stream()
.map(Player::getName)
.collect(Collectors.toList());
}

@Override
public Iterator<Player> iterator() {
return players.iterator();
}
}
Loading