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

[라테] 블랙잭 미션 제출합니다. #3

Open
wants to merge 17 commits into
base: tdd-minuyim
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 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
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# java-blackjack
블랙잭 게임 미션 저장소

## 우아한테크코스 코드리뷰
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
## 기능 구현
- 플레이어 이름을 입력받는다
- 영문자 이외의 값이 입력되면 안된다.(대소문자 구별 안한다)
- 첫턴에는 딜러와 등록된 플레이어에게 2장의 카드를 나눠준다.
- 딜러는 한장의 카드만 출력한다.
- 플레이어 들은 모든 카드를 출력한다.
- 모든 플레이어들은 원하는 만큼 카드를 입력받는다.
- 21이 넘어갈경우 더이상 카드를 받지 못하고 버스트, 다음 플레이어로 넘어간다.
- 딜러는 정해진 규칙에 따라 카드를 추가 지급 받는다.
- 16이하일 경우 한장의 카드를 추가 지급 받는다.
- 21초과할 경우 딜러는 버스트한다.
- 17이상일 경우 더이상 지급받지 않는다.
- 각 플레이어별 점수를 계산한다.
- ACE는 1또는 11로 계산한다.
- 11로 계산했을때 21이 초과하지 않으면 11로 계산한다.
- 21이 초과하면 1로 계산한다.
- 승패를 정한다.
- 플레이어가 버스트 될경우 무조건 플레이어가 패배한다.
- 플레이어가 버스트 되지 않고 딜러가 버스트 되면 플레이어 승리한다.
- 둘다 아닐 경우 점수를 계산하여 승패를 정한다.
- 플레이어에게 배팅할 금액을 입력받는다.
- 숫자 이외의 값을 읽으면 예외처리
- 음수를 입력받을 경우 예외처리
- 플레이어 배팅액을 참고하여 게임 승패에 따른 수익을 보여준다.
- 블랙잭으로 이길 경우 배팅액의 1.5배, 정상적으로 이길 경우 1배, 비길 경우 0배, 질 경우 -1배를 출력한다.
- 딜러는 플레이어의 수익 결과를 합한 값의 - 값을 출력한다.
13 changes: 13 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import java.util.Scanner;

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

public class Application {
public static void main(String[] args) {
BlackJackController blackJackController = new BlackJackController(new InputView(new Scanner(System.in)),
new OutputView());
blackJackController.run();
}
}
76 changes: 76 additions & 0 deletions src/main/java/controller/BlackJackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package controller;

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

import java.util.List;

import domain.card.deck.Deck;
import domain.card.deck.DeckFactory;
import domain.card.deck.RandomShuffledDeckFactory;
import domain.gamer.Dealer;
import domain.gamer.Player;
import domain.gamer.Players;
import dto.GamerDto;
import dto.GamerEarningDto;
import dto.GamerWithScoreDto;
import dto.PlayerInfo;
import view.InputView;
import view.OutputView;

public class BlackJackController {
private final InputView inputView;
private final OutputView outputView;

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

public void run() {
Deck deck = getDeck();
Players players = getPlayers(deck);
Dealer dealer = Dealer.of(deck);
playBlackJack(deck, players, dealer);
printResult(players, dealer);
}

private void playBlackJack(Deck deck, Players players, Dealer dealer) {
outputView.printGamersCards(GamerDto.listOf(dealer, players.getPlayers()));
for (Player player : players.getPlayers()) {
decideHitOrStay(deck, player);
}
decideDealerHit(deck, dealer);
}

private void decideDealerHit(Deck deck, Dealer dealer) {
while (dealer.canHit()) {
outputView.printDealerHit();
dealer.hit(deck);
}
}

private void decideHitOrStay(Deck deck, Player player) {
while (player.canHit()) {
YesOrNo yesOrNo = YesOrNo.findByShortName(inputView.inputYesOrNo(player.getName()));
yesOrNo.execute(player, deck);
outputView.printGamerCards(GamerDto.of(player));
}
}

private Players getPlayers(Deck deck) {
List<PlayerInfo> playerInfos = inputView.inputPlayerInfos();
return playerInfos.stream()
.map(playerInfo -> Player.of(playerInfo.getName(), deck, playerInfo.getBattingMoney()))
.collect(collectingAndThen(toList(), Players::new));
}

private Deck getDeck() {
DeckFactory randomShuffledDeckFactory = new RandomShuffledDeckFactory();
return randomShuffledDeckFactory.create();
}

private void printResult(Players players, Dealer dealer) {
outputView.printGamersCardsWithScore(GamerWithScoreDto.listOf(dealer, players.getPlayers()));
outputView.printEarning(GamerEarningDto.listOf(dealer, players));
}
}
31 changes: 31 additions & 0 deletions src/main/java/controller/YesOrNo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package controller;

import java.util.Arrays;
import java.util.function.BiConsumer;

import domain.card.deck.Deck;
import domain.gamer.Player;

public enum YesOrNo {
YES("y", Player::hit),
NO("n", ((player, deck) -> player.stay()));

private final String shortName;
private final BiConsumer<Player, Deck> playerBehavior;

YesOrNo(String shortName, BiConsumer<Player, Deck> playerBehavior) {
this.shortName = shortName;
this.playerBehavior = playerBehavior;
}

public static YesOrNo findByShortName(String name) {
return Arrays.stream(values())
.filter(yesOrNo -> yesOrNo.shortName.equalsIgnoreCase(name))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("잘못된 명령어입니다"));
}

public void execute(Player player, Deck deck) {
playerBehavior.accept(player, deck);
}
}
45 changes: 45 additions & 0 deletions src/main/java/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package domain.card;

import java.util.Objects;

public class Card {
private final Rank rank;
private final Suit suit;

public Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}

public boolean isAce() {
return rank == Rank.ACE;
}

public int getScore() {
return rank.getValue();
}

public String getRank() {
return rank.getPattern();
}

public String getSuit() {
return suit.getPattern();
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Card card = (Card)o;
return rank == card.rank &&
suit == card.suit;
}

@Override
public int hashCode() {
return Objects.hash(rank, suit);
}
}
33 changes: 33 additions & 0 deletions src/main/java/domain/card/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package domain.card;

public enum Rank {
ACE(1, "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 value;
private final String pattern;

Rank(int value, String pattern) {
this.value = value;
this.pattern = pattern;
}

public int getValue() {
return value;
}

public String getPattern() {
return pattern;
}
}
18 changes: 18 additions & 0 deletions src/main/java/domain/card/Suit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package domain.card;

public enum Suit {
CLUB("♣"),
DIAMOND("♦"),
HEART("♥"),
SPADE("♠");

private final String pattern;

Suit(String pattern) {
this.pattern = pattern;
}

public String getPattern() {
return pattern;
}
}
30 changes: 30 additions & 0 deletions src/main/java/domain/card/deck/AbstractDeckFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package domain.card.deck;

import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import java.util.stream.Collectors;

import domain.card.Card;
import domain.card.Rank;
import domain.card.Suit;

public abstract class AbstractDeckFactory implements DeckFactory, CardFactory {
@Override
public List<Card> createCards() {
return Arrays.stream(Rank.values())
.flatMap((rank -> Arrays.stream(Suit.values())
.map(suit -> new Card(rank, suit))))
.collect(Collectors.toList());
}

@Override
public Deck create() {
List<Card> cards = handleCards(createCards());
Stack<Card> newCards = new Stack<>();
newCards.addAll(cards);
return new Deck(newCards);
}

public abstract List<Card> handleCards(List<Card> cards);
}
9 changes: 9 additions & 0 deletions src/main/java/domain/card/deck/CardFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package domain.card.deck;

import java.util.List;

import domain.card.Card;

public interface CardFactory {
List<Card> createCards();
}
17 changes: 17 additions & 0 deletions src/main/java/domain/card/deck/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package domain.card.deck;

import java.util.Stack;

import domain.card.Card;

public class Deck {
private final Stack<Card> cards;

public Deck(Stack<Card> cards) {
this.cards = cards;
}

public Card pop() {
return cards.pop();
}
}
5 changes: 5 additions & 0 deletions src/main/java/domain/card/deck/DeckFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package domain.card.deck;

public interface DeckFactory {
Deck create();
}
14 changes: 14 additions & 0 deletions src/main/java/domain/card/deck/RandomShuffledDeckFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package domain.card.deck;

import java.util.Collections;
import java.util.List;

import domain.card.Card;

public class RandomShuffledDeckFactory extends AbstractDeckFactory {
@Override
public List<Card> handleCards(List<Card> cards) {
Collections.shuffle(cards);
return cards;
}
}
20 changes: 20 additions & 0 deletions src/main/java/domain/gamer/BattingMoney.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package domain.gamer;

public class BattingMoney {
private final int money;

public BattingMoney(int money) {
validate(money);
this.money = money;
}

private void validate(int money) {
if (money < 0) {
throw new IllegalArgumentException("음수는 허용되지 않습니다. input : " + money);
}
}

public int getMoney() {
return money;
}
}
33 changes: 33 additions & 0 deletions src/main/java/domain/gamer/Dealer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package domain.gamer;

import java.util.List;

import domain.card.Card;
import domain.card.deck.Deck;
import domain.state.State;
import domain.state.StateFactory;

public class Dealer extends Gamer {
private static final int HIT_THRESHOLD = 17;

private Dealer(State state) {
super(new Name("딜러"), state);
}

public static Dealer of(Deck deck) {
return new Dealer(StateFactory.create(deck));
}

@Override
public boolean canHit() {
return !state.isFinished() && state.calculateScore() < HIT_THRESHOLD;
}

public int calculateEarning(Players players) {
return -1 * players.calculateTotalEarning(this);
}

public List<Card> getOneCards() {
return getState().getCards().subList(0, 1);
}
}
Loading