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

[디디] 블랙잭 2단계 미션 제출합니다. #66

Merged
merged 18 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
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
35 changes: 22 additions & 13 deletions src/main/java/controller/BlackJackGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import view.InputView;
import view.OutputView;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

public class BlackJackGame {
public static final String COMMA = ",";
public static final int ADDITIONAL_DRAW_COUNT = 1;
public static final int INITIAL_DRAW_COUNT = 2;
public static final int HIT_BOUNDARY = 16;
Expand All @@ -13,18 +18,22 @@ public class BlackJackGame {
public static void play() {
Deck deck = new Deck(CardFactory.createCardList());
PlayerNames playerNames = new PlayerNames(InputView.inputPlayerNames());
Players players = new Players(playerNames, deck, INITIAL_DRAW_COUNT);
Dealer dealer = new Dealer(deck, INITIAL_DRAW_COUNT);

OutputView.printInitialCards(players, dealer);
OutputView.printUsersCard(players, dealer);
PlayersData playersData = new PlayersData(makePlayersData(playerNames));
Players players = new Players(playersData, deck);
Dealer dealer = new Dealer(deck);
OutputView.printInitialState(players, dealer);
drawCardToPlayers(players, deck);
hitOrStayForDealer(dealer, deck);
OutputView.printFinalCardHandResult(players, dealer);

GameResult gameResult = new GameResult(players, dealer);
gameResult.calculateResults();
OutputView.printResult(gameResult);
OutputView.printResult(gameResult, players, dealer);
}

private static Map<String, Bet> makePlayersData(PlayerNames playerNames) {
Map<String, Bet> playerData = new LinkedHashMap<>();
for (String name : playerNames) {
playerData.put(name, new Bet(InputView.inputBet(name)));
}
return Collections.unmodifiableMap(playerData);
}

private static void drawCardToPlayers(final Players players, final Deck deck) {
Expand All @@ -34,20 +43,20 @@ private static void drawCardToPlayers(final Players players, final Deck deck) {
}

private static void drawCardEachPlayer(Deck deck, Player player) {
while (!player.isBust()) {
while (!player.isMoreThanBlackJack()) {
Answer answer = Answer.getYesOrNoByValue(InputView.inputYesOrNo(player));
if (!answer.getTrueOrFalse()) {
if (!answer.isYes()) {
break;
}
player.drawCard(deck, ADDITIONAL_DRAW_COUNT);
player.additionalDraw(deck);
OutputView.printPlayerCard(player);
}
}

private static void hitOrStayForDealer(Dealer dealer, Deck deck) {
if (dealer.isHitBound()) {
OutputView.printDealerDraw(dealer);
dealer.drawCard(deck, ADDITIONAL_DRAW_COUNT);
dealer.additionalDraw(deck);
}
}
}
7 changes: 7 additions & 0 deletions src/main/java/exception/BetFormatException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package exception;

public class BetFormatException extends RuntimeException {
public BetFormatException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/exception/BetRangeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package exception;

public class BetRangeException extends RuntimeException {
public BetRangeException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/exception/IllegalDrawException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package exception;

public class IllegalDrawException extends RuntimeException {
public IllegalDrawException(String message) {
super(message);
}
}
29 changes: 11 additions & 18 deletions src/main/java/model/Answer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,29 @@
import java.util.Arrays;

public enum Answer {
YES("y", true),
NO("n", false);
YES("y"),
NO("n");

private String yesOrNo;
private boolean trueOrFalse;
private final String answer;

Answer(String yesOrNo, boolean trueOrFalse) {
this.yesOrNo = yesOrNo;
this.trueOrFalse = trueOrFalse;
Answer(String answer) {
this.answer = answer;
}

public static Answer getYesOrNoByValue(String input) {
validate(input);
StringUtils.validateString(input);
return Arrays.stream(Answer.values())
.filter(answer -> answer.isSameYesOrNo(input))
.filter(answer -> answer.isSameAnswer(input))
.findAny()
.orElseThrow(() -> new IllegalYesOrNoInputException(String.format("%s는 올바르지 않은 값입니다.", input)));
}

private boolean isSameYesOrNo(final String input) {
return yesOrNo.equalsIgnoreCase(input);
private boolean isSameAnswer(final String input) {
return answer.equalsIgnoreCase(input);
}

private static void validate(String input) {
StringUtils.validateNull(input);
StringUtils.validateEmpty(input);
}

public boolean getTrueOrFalse() {
return trueOrFalse;
public boolean isYes() {
return this == YES;
}
}

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

import exception.BetFormatException;
import exception.BetRangeException;
import utils.StringUtils;

public class Bet {
Copy link

Choose a reason for hiding this comment

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

값객체로 활용하신다면 당장 쓰이진 않더라도 equals, hashCode를 구현하는걸 습관화 하면 좋을 것 같습니다. :)

public static final double LOWER_BET_BOUND = 100;

private final double bet;

public Bet(String input) {
validate(input);
this.bet = Double.parseDouble(input);
}

public Bet(double input) {
this.bet = input;
}
Copy link

Choose a reason for hiding this comment

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

double로 생성할 경우에 대해서도 validate가 필요하지 않을까요??


private void validate(String input) {
StringUtils.validateString(input);
validateFormat(input);
validateRange(input);
}

private void validateFormat(String input) {
try {
Double.parseDouble(input);
} catch (NumberFormatException e) {
throw new BetFormatException("베팅금액은 실수만 입력 가능합니다.");
}
}

private void validateRange(String input) {
if (Double.parseDouble(input) < LOWER_BET_BOUND) {
throw new BetRangeException("베팅금액은 100원 이상부터 입력 가능합니다.");
}
}

public Bet MultiplyBet(double ratio) {
Copy link

Choose a reason for hiding this comment

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

메서드 네이밍 컨벤션 지켜주세요. :)

return new Bet(bet * ratio);
}

public double getBet() {
Copy link

Choose a reason for hiding this comment

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

bet.getBet()은 조금 부자연스럽지 않을까요?

return bet;
}
}
26 changes: 13 additions & 13 deletions src/main/java/model/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.Objects;

public class Card {
public final class Card {
private final Symbol symbol;
private final Type type;

Expand All @@ -15,13 +15,13 @@ public boolean isAce() {
return symbol == Symbol.ACE;
}

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

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Card card = (Card) o;
return symbol == card.symbol &&
type == card.type;
public String toString() {
return symbol.toString() + type.toString();
}

@Override
Expand All @@ -30,11 +30,11 @@ public int hashCode() {
}

@Override
public String toString() {
return symbol.toString() + type.toString();
}

public int calculateScore() {
return symbol.getScore();
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Card card = (Card) o;
return symbol == card.symbol &&
type == card.type;
}
}
18 changes: 10 additions & 8 deletions src/main/java/model/CardFactory.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package model;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CardFactory {

public static List<Card> createCardList() {
List<Card> cards = new ArrayList<>();
for (Symbol symbol : Symbol.values()) {
createByType(cards, symbol);
}
List<Card> cards = Arrays
.stream(Type.values())
.flatMap(CardFactory::mapToCard)
.collect(Collectors.toList());
return Collections.unmodifiableList(cards);
}

private static void createByType(List<Card> cards, Symbol symbol) {
for (Type type : Type.values()) {
cards.add(new Card(symbol, type));
}
private static Stream<Card> mapToCard(Type type) {
return Arrays
.stream(Symbol.values())
.map(symbol -> new Card(symbol, type));
}
}
34 changes: 26 additions & 8 deletions src/main/java/model/CardHand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,59 @@
import java.util.Iterator;
import java.util.List;

import static controller.BlackJackGame.BLACK_JACK_COUNT;
import static controller.BlackJackGame.INITIAL_DRAW_COUNT;

public class CardHand implements Iterable<Card> {
public static final int ADDITIONAL_ACE_SCORE = 10;
public static final int BLACK_JACK_SCORE = 21;
private static final int ADDITIONAL_ACE_SCORE = 10;

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

public void addCard(Card card) {
cards.add(card);
}

public int calculateScore() {
if (isAce()) {
public int getScore() {
if (hasAce()) {
return calculateScoreWithAce();
}
return calculateScoreWithNoAce();
}

public boolean isEmpty() {
return cards.size() == 0;
}

public int calculateScoreWithAce() {
int score = calculateScoreWithNoAce();
if (score + ADDITIONAL_ACE_SCORE > BLACK_JACK_SCORE) {
if (score + ADDITIONAL_ACE_SCORE > BLACK_JACK_COUNT) {
return score;
}
return score + ADDITIONAL_ACE_SCORE;
}

public int calculateScoreWithNoAce() {
return cards.stream()
.mapToInt(Card::calculateScore)
.mapToInt(Card::getScore)
.sum();
}

public boolean isAce() {
public boolean hasAce() {
return cards.stream().anyMatch(Card::isAce);
}

public boolean isBust() {
return getScore() > BLACK_JACK_COUNT;
}

public boolean isBlackJack() {
return (getScore() == BLACK_JACK_COUNT) && (cards.size() == INITIAL_DRAW_COUNT);
}

public boolean isMoreThanBlackJack() {
return getScore() >= BLACK_JACK_COUNT;
}

public List<Card> getCards() {
return Collections.unmodifiableList(cards);
}
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/model/Dealer.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package model;

import java.util.List;

import static controller.BlackJackGame.HIT_BOUNDARY;

public class Dealer extends User {
public static final int ZERO = 0;
private static final int FIRST = 0;
public static final String DEALER_NAME = "딜러";

public Dealer(Deck deck, int initialDrawCount) {
super(DEALER_NAME, deck, initialDrawCount);
public Dealer(Deck deck) {
super(DEALER_NAME, deck);
}

public Dealer(List<Card> cards) {
super(DEALER_NAME, cards);
}

public String toStringCardHandFirst() {
return cardHand.getCards().get(ZERO).toString();
return cardHand.getCards().get(FIRST).toString();
}

public boolean isHitBound() {
Copy link

Choose a reason for hiding this comment

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

지금 보니 해당 메서드를 Player의 isMoreThanBlackJack이랑 묶어서 더 카드를 뽑을수 있는지, 없는지를 판단하는 메서드로 추상화 할 수 있을 것 같네요. :)
Dealer, Player가 각자의 룰에 맞춰서 오버라이드 해보면 어떨까요?

Expand Down
Loading