diff --git a/README.md b/README.md index 2d9bc12..5f44b02 100644 --- a/README.md +++ b/README.md @@ -1 +1,195 @@ # java-blackjack + +# 규칙 +Blackjack : 처음 두 장의 카드 합 21 => 승 +Bust : 카드 합 21 초과 => 패 +Push : 플레이어, 딜러 카드 합이 같음 => 무승부 +Hit : 플레이어의 카드 2장의 합이 21을 초과하지 않을 경우, 추가 카드를 요청 +Stay : 플레이어가 추가 카드를 원하지 않음, 딜러는 카드 합 17 이상이면 추가 카드를 얻을 수 없음 + +# 구현해야 할 기능 목록 +- [x] 입력 + - [x] 플레이어 이름 + - [x] 플레이어(딜러 제외) 추가 카드 요청 여부 + +- [x] 출력 + - [x] 각 플레이어(딜러 포함)에게 2장의 카드 지급 알림 + - [x] 각 플레이어(딜러 포함)가 가진 카드 + - [x] 추가 요청 후 플레이어의 카드 + - [x] 추가 카드가 발급되지 않았고 3장 이상일 경우 출력 X + - [x] 딜러의 추가 카드 지급 여부 결과 + - [x] 각 플레이어(딜러 포함)의 총 카드의 합 + - [x] 최종 승패 결과 + +- [x] 상태 (State) + - 기능 + - [x] 추가 카드 발급 + - [x] 추가 카드 발급 거부 + - [x] 모든 카드 합 반환 + - [x] 참여 종료 여부 반환 + - [x] 발급받은 카드 목록 반환 + - [x] 결과 요청 + +- [x] 시작 상태 (Init) + - 기능 + - [x] 발급받은 카드 목록 반환 + - [x] 모든 카드 합 반환 + +- [x] 참여 상태 (Running) + - 기능 + - [x] 참여 종료 여부 거짓으로 반환 + - [x] ERROR : 결과 요청할 경우 + + - [x] 카드 추가 받은 상태 (Hit) + - 기능 + - [x] 추가 카드 발급 + - [x] 카드의 합 21을 초과할 경우 Burst 상태 반환 + - [x] 카드의 합 21 미만일 경우 Hit 상태 반환 + - [x] 카드의 합 21일 경우 Stay 상태 반환 + - [x] Stay 상태 반환 + +- [x] 종료 상태 (Finished) + - 기능 + - [x] 참여 종료 여부 참으로 반환 + - [x] ERROR : 추가 카드 발급 시 + - [x] ERROR : 추가 카드 발급 거부 시 + + - [x] 처음 카드 두 장의 합이 21인 상태 (Blackjack) + - 기능 + - [x] 승리 결과 (1) 반환 + - [x] 모든 카드의 합이 21인 상태 (Burst) + - 기능 + - [x] 패배 결과 (-1) 반환 + + - [x] 카드 발급 거부 후 참여가 종료된 상태 (Stay) + - 기능 + - [x] 결과 반환 + - [x] 승리 결과 (1) 반환 + - [x] 자신의 합이 더 클 경우 + - [x] 인자로 받아온 카드의 합이 21을 초과할 경우 + - [x] 자신의 합이 더 작을 경우 패배 결과 (-1) 반환 + - [x] 자신의 합과 같을 경우 무승부 결과 (0) 반환 + +- [x] 사람 (Person) + - 기능 + - [x] 초기 상태 주입 + - [x] 카드 추가 발급 + - [x] 카드 추가 발급 거부 + - [x] 카드 목록 반환 + - [x] 카드 합 반환 + - [x] 이름 반환 + - [x] 종료 여부 반환 + +- [x] 게임 참여자 (Gamer) + - 기능 + - [x] 카드 추가 발급 거부 + - [x] 카드 목록 반환 + - [x] 카드 합 반환 + - [x] 이름 반환 + - [x] 종료 여부 반환 + +- [x] 플레이어 (Player) + - 속성 + - [x] 이름 + - [x] 카드 목록 + + - 기능 + - [x] 초기 상태 주입 + - [x] 카드 2장의 합 21일 경우 Blackjack 상태 + - [x] 카드 2장의 합 21 미만일 경우 Hit 상태 + - [x] 카드 추가 발급 + - [x] 카드의 합 21 초과할 경우 Burst 상태 반환 + - [x] 카드의 합 21 미만일 경우 Hit 상태 반환 + - [x] 카드의 합 21일 경우 Stay 상태 반환 + +- [x] 딜러 (Dealer) + - 속성 + - [x] 이름 + - [x] 카드 목록 + + - 기능 + - [x] 초기 상태 주입 + - [x] 카드 2장의 합 21일 경우 Blackjack 상태 + - [x] 카드 2장의 합 16 이하일 경우 Hit 상태 + - [x] 카드 2장의 합 16 초과일 경우 Stay 상태 + - [x] 카드 추가 발급 + - [x] 17 이상 21 이하일 경우, Stay 상태로 변경 + - [x] 종료 여부 반환 + - [x] Blackjack이 아니며, 17 이상 21 이하일 경우 참으로 반환 +- [x] 카드 + - 속성 + - [x] 점수 + - [x] 무늬 + + - 기능 + - [x] 카드의 값 반환 + - [x] 카드의 값 이름 반환 + - [x] ACE인지 확인 + +- [x] 점수 enum + - 속성 + - [x] 점수 이름(끗수) + - [x] 점수 + + - 기능 + - [x] 점수 이름 반환 + - [x] 점수 반환 + - [x] ACE인지 확인 + +- [x] 무늬 enum + - 속성 + - [x] 무늬 + + - 기능 + - [x] 무늬 이름 반환 + +- [x] 결과 enum + - 속성 + - [x] 포인트 + + - 기능 + - [x] 포인트 반환 + +- [x] 현재까지 받은 카드 목록 + - 속성 + - [x] 현재까지 받은 카드 목록 + + - 기능 + - [x] Ace 포함하는지 확인 + - [x] 두 장의 카드 합 21인지 확인 + - [x] 총 카드의 합이 21인지 확인 + - [x] 모든 카드 합이 21을 초과하는지 확인 + - [x] 21을 기준으로 Ace 1 또는 11로 설정 + - [x] 카드 목록 반환 + - [x] 인자로 받은 카드 추가 + - [x] 인자로 받은 카드보다 합이 큰 지 확인 + - [x] 인자로 받은 카드보다 합이 작은 지 확인 + - [x] 인자로 받은 값보다 합이 작거나 같은 지 확인 + +- [x] 카드 덱 + - 속성 + - [x] 카드 52장 + + - 기능 + - [x] 52장 카드 생성 + - [x] 처음 2장 카드 반환 + - [x] 추가 카드 반환 + +- [x] 게임 시스템 + - 속성 + - [x] 딜러 + - [x] 플레이어 목록 + + - 기능 + - [x] 플레이어들의 이름 반환 + - [x] 플레이어들의 모든 카드 반환 + - [x] 딜러의 모든 카드 반환 + - [x] 모든 플레이어가 참여 종료했는지 확인 + - [x] 참여 종료 상태가 아닌 플레이어 중 먼저 입력받은 플레이어 이름 반환 + - [x] 입력받은 이름의 플레이어 추가 카드 발급 + - [x] ERROR : y 또는 n이 아닌 응답을 전달받을 경우 + - [x] 딜러 추가 카드 발급 + - [x] 딜러 종료 여부 반환 + - [x] 딜러 점수 반환 + - [x] 플레이어들의 점수 반환 + - [x] 플레이어들의 승패 결과 반환 diff --git a/src/main/java/blackjack/Blackjack.java b/src/main/java/blackjack/Blackjack.java new file mode 100644 index 0000000..9c7b6fd --- /dev/null +++ b/src/main/java/blackjack/Blackjack.java @@ -0,0 +1,14 @@ +package blackjack; + +import blackjack.controller.BlackjackController; +import blackjack.view.InputView; +import blackjack.view.OutputView; + +public class Blackjack { + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + BlackjackController blackjackController = new BlackjackController(inputView, outputView); + blackjackController.run(); + } +} diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java new file mode 100644 index 0000000..965c1a3 --- /dev/null +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -0,0 +1,57 @@ +package blackjack.controller; + +import blackjack.controller.dto.CardsResponse; +import blackjack.controller.dto.DealerAndPlayerCardsResponse; +import blackjack.domain.GameSystem; +import blackjack.view.InputView; +import blackjack.view.OutputView; + +import java.util.List; + +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; + } + + public void run() { + GameSystem gameSystem = setup(inputView.getPlayerNames()); + playerMode(gameSystem); + dealerMode(gameSystem); + printResult(gameSystem); + } + + private GameSystem setup(final List playerNames) { + GameSystem gameSystem = GameSystem.create(playerNames); + outputView.printGameStart(gameSystem.getPlayerNames()); + DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse = new DealerAndPlayerCardsResponse(gameSystem.getDealerCards(), gameSystem.getPlayerCards()); + outputView.printFirstTwoCards(gameSystem.getPlayerNames(), dealerAndPlayerCardsResponse); + return gameSystem; + } + + private void playerMode(final GameSystem gameSystem) { + while (!gameSystem.allPlayersFinished()) { + String currentPlayer = gameSystem.getCurrentPlayer(); + String answer = inputView.getAnswerForAnotherCard(currentPlayer); + gameSystem.hit(answer, currentPlayer); + CardsResponse cardsResponse = new CardsResponse(gameSystem.getCards(currentPlayer)); + outputView.printPlayerCards(currentPlayer, cardsResponse, answer); + } + } + + private void dealerMode(final GameSystem gameSystem) { + while (!gameSystem.isDealerFinished()) { + outputView.printDealerGetAnotherCard(); + gameSystem.hit(); + } + } + + private void printResult(final GameSystem gameSystem) { + DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse = new DealerAndPlayerCardsResponse(gameSystem.getDealerCards(), gameSystem.getPlayerCards()); + outputView.printCardsAndScores(gameSystem.getPlayerNames(), dealerAndPlayerCardsResponse, gameSystem.getDealerScore(), gameSystem.getPlayerScores()); + outputView.printResults(gameSystem.getPlayerNames(), gameSystem.getResults()); + } +} diff --git a/src/main/java/blackjack/controller/dto/CardResponse.java b/src/main/java/blackjack/controller/dto/CardResponse.java new file mode 100644 index 0000000..6463e2c --- /dev/null +++ b/src/main/java/blackjack/controller/dto/CardResponse.java @@ -0,0 +1,19 @@ +package blackjack.controller.dto; + +public class CardResponse { + private final String denomination; + private final String suit; + + public CardResponse(final String denomination, final String suit) { + this.denomination = denomination; + this.suit = suit; + } + + public String getDenomination() { + return denomination; + } + + public String getSuit() { + return suit; + } +} diff --git a/src/main/java/blackjack/controller/dto/CardsResponse.java b/src/main/java/blackjack/controller/dto/CardsResponse.java new file mode 100644 index 0000000..a017f79 --- /dev/null +++ b/src/main/java/blackjack/controller/dto/CardsResponse.java @@ -0,0 +1,20 @@ +package blackjack.controller.dto; + +import blackjack.domain.card.Card; + +import java.util.List; +import java.util.stream.Collectors; + +public class CardsResponse { + private final List cards; + + public CardsResponse(final List cards) { + this.cards = cards; + } + + public List getCards() { + return cards.stream() + .map(card -> new CardResponse(card.getDenomination(), card.getSuit())) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/blackjack/controller/dto/DealerAndPlayerCardsResponse.java b/src/main/java/blackjack/controller/dto/DealerAndPlayerCardsResponse.java new file mode 100644 index 0000000..5da67ba --- /dev/null +++ b/src/main/java/blackjack/controller/dto/DealerAndPlayerCardsResponse.java @@ -0,0 +1,27 @@ +package blackjack.controller.dto; + +import blackjack.domain.card.Card; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class DealerAndPlayerCardsResponse { + private final List dealerCards; + private final List> playerCards; + + public DealerAndPlayerCardsResponse(final List dealerCards, final List> playerCards) { + this.dealerCards = dealerCards; + this.playerCards = new ArrayList<>(playerCards); + } + + public CardsResponse getDealerCards() { + return new CardsResponse(dealerCards); + } + + public List getAllPlayerCards() { + return playerCards.stream() + .map(CardsResponse::new) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/blackjack/domain/GameSystem.java b/src/main/java/blackjack/domain/GameSystem.java new file mode 100644 index 0000000..256d1de --- /dev/null +++ b/src/main/java/blackjack/domain/GameSystem.java @@ -0,0 +1,98 @@ +package blackjack.domain; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Deck; +import blackjack.domain.card.GivenCards; +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Person; +import blackjack.domain.participant.Players; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class GameSystem { + public static final int BLACKJACK = 21; + private static final String DEFAULT_DEALER_NAME = "딜러"; + private static final String ACCEPT_ANSWER = "y"; + private static final String DECLINE_ANSWER = "n"; + + private final Deck deck; + private final Person dealer; + private final Players players; + + protected GameSystem(final Person dealer, final Players players, final Deck deck) { + this.dealer = dealer; + this.players = players; + this.deck = deck; + } + + public static GameSystem create(final List playerNames) { + Deck deck = new Deck(); + return new GameSystem(new Dealer(DEFAULT_DEALER_NAME, deck.getTwoCards()), new Players(playerNames, deck), deck); + } + + public List getPlayerNames() { + return players.getPlayerNames(); + } + + public List getDealerCards() { + return Collections.unmodifiableList(dealer.getCards().list()); + } + + public List> getPlayerCards() { + return Collections.unmodifiableList(players.getPlayerCards().stream() + .map(GivenCards::list) + .collect(Collectors.toList())); + } + + public boolean allPlayersFinished() { + return players.allPlayersFinished(); + } + + public String getCurrentPlayer() { + return players.getCurrentPlayer(); + } + + public void hit(final String answer, final String name) { + validate(answer); + Person player = players.findPlayerBy(name); + + if (answer.equals(DECLINE_ANSWER)) { + player.stay(); + return; + } + + player.hit(deck.getCard()); + } + + private void validate(final String answer) { + if (!answer.equals(ACCEPT_ANSWER) && !answer.equals(DECLINE_ANSWER)) { + throw new IllegalArgumentException("y 또는 n을 입력해주세요."); + } + } + + public void hit() { + dealer.hit(deck.getCard()); + } + + public boolean isDealerFinished() { + return dealer.isFinished(); + } + + public List getCards(final String name) { + return players.getCards(name).list(); + } + + public int getDealerScore() { + return dealer.sum(); + } + + public List getPlayerScores() { + return players.getPlayerScores(); + } + + public List getResults() { + return players.getResults(dealer.getCards()); + } +} diff --git a/src/main/java/blackjack/domain/card/Card.java b/src/main/java/blackjack/domain/card/Card.java new file mode 100644 index 0000000..bbc1f34 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Card.java @@ -0,0 +1,78 @@ +package blackjack.domain.card; + +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Card { + private static final Map CARDS = createCards(); + + private static Map createCards() { + return Arrays.stream(Score.values()) + .flatMap(Card::createCard) + .collect(Collectors.toMap(card -> generateKey(card.score, card.suit), Function.identity())); + } + + private static Stream createCard(final Score cardScore) { + return Arrays.stream(Suit.values()) + .map(cardSuit -> new Card(cardScore, cardSuit)); + } + + private static String generateKey(final Score score, final Suit suit) { + return score.getDenomination() + suit.getSuit(); + } + + private final Score score; + private final Suit suit; + + private Card(final Score score, final Suit suit) { + this.score = score; + this.suit = suit; + } + + public static Card from(final Score score, final Suit suit) { + String key = generateKey(score, suit); + return CARDS.get(key); + } + + public static Collection getDeck() { + return Collections.unmodifiableCollection(CARDS.values()); + } + + public int getScore() { + return score.getScore(); + } + + public String getDenomination() { + return score.getDenomination(); + } + + public String getSuit() { + return suit.getSuit(); + } + + public boolean isAce() { + return score.isAce(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Card card = (Card) o; + return score == card.score && suit == card.suit; + } + + @Override + public int hashCode() { + return Objects.hash(score, suit); + } +} diff --git a/src/main/java/blackjack/domain/card/Deck.java b/src/main/java/blackjack/domain/card/Deck.java new file mode 100644 index 0000000..6bd1179 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Deck.java @@ -0,0 +1,30 @@ +package blackjack.domain.card; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class Deck { + static final int TWO_CARDS = 2; + private final Deque deck; + + public Deck() { + List cards = new ArrayList<>(Card.getDeck()); + Collections.shuffle(cards); + this.deck = new ArrayDeque<>(cards); + } + + public Card getCard() { + return deck.pop(); + } + + public GivenCards getTwoCards() { + return new GivenCards(Collections.unmodifiableList(IntStream.range(0, TWO_CARDS) + .mapToObj(i -> deck.pop()) + .collect(Collectors.toList()))); + } +} diff --git a/src/main/java/blackjack/domain/card/GivenCards.java b/src/main/java/blackjack/domain/card/GivenCards.java new file mode 100644 index 0000000..ad61728 --- /dev/null +++ b/src/main/java/blackjack/domain/card/GivenCards.java @@ -0,0 +1,74 @@ +package blackjack.domain.card; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static blackjack.domain.GameSystem.BLACKJACK; +import static blackjack.domain.card.Deck.TWO_CARDS; +import static blackjack.domain.enums.Score.ACE_BONUS; + +public class GivenCards { + private final List cards; + + public GivenCards(final List cards) { + this.cards = new ArrayList<>(cards); + } + + public int sum() { + int sum = cards.stream() + .mapToInt(Card::getScore) + .sum(); + + if (hasAce() && isLessThanOrEqualToBlackjack(addAceBonus(sum))) { + sum = addAceBonus(sum); + } + + return sum; + } + + private boolean hasAce() { + return cards.stream() + .anyMatch(Card::isAce); + } + + private boolean isLessThanOrEqualToBlackjack(final int sum) { + return BLACKJACK >= sum; + } + + private int addAceBonus(final int sum) { + return sum + ACE_BONUS; + } + + public boolean isBlackjack() { + return (cards.size() == TWO_CARDS) && isMaximumThreshold(); + } + + public boolean isBurst() { + return BLACKJACK < sum(); + } + + public List list() { + return Collections.unmodifiableList(cards); + } + + public void add(final Card card) { + cards.add(card); + } + + public boolean isGreaterThan(final GivenCards otherCards) { + return sum() > otherCards.sum(); + } + + public boolean isLessThan(final GivenCards otherCards) { + return sum() < otherCards.sum(); + } + + public boolean isLessThanEqualTo(final int value) { + return sum() <= value; + } + + public boolean isMaximumThreshold() { + return sum() == BLACKJACK; + } +} diff --git a/src/main/java/blackjack/domain/enums/Result.java b/src/main/java/blackjack/domain/enums/Result.java new file mode 100644 index 0000000..1b3178f --- /dev/null +++ b/src/main/java/blackjack/domain/enums/Result.java @@ -0,0 +1,17 @@ +package blackjack.domain.enums; + +public enum Result { + WIN(1), + LOSE(-1), + DRAW(0); + + private final int point; + + Result(int point) { + this.point = point; + } + + public int getPoint() { + return point; + } +} diff --git a/src/main/java/blackjack/domain/enums/Score.java b/src/main/java/blackjack/domain/enums/Score.java new file mode 100644 index 0000000..e573961 --- /dev/null +++ b/src/main/java/blackjack/domain/enums/Score.java @@ -0,0 +1,39 @@ +package blackjack.domain.enums; + +public enum Score { + A("A", 1), + 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), + J("J", 10), + Q("Q", 10), + K("K", 10); + + public static final int ACE_BONUS = 10; + + private final String denomination; + private final int score; + + Score(final String denomination, final int score) { + this.denomination = denomination; + this.score = score; + } + + public String getDenomination() { + return denomination; + } + + public int getScore() { + return score; + } + + public boolean isAce() { + return this.equals(Score.A); + } +} diff --git a/src/main/java/blackjack/domain/enums/Suit.java b/src/main/java/blackjack/domain/enums/Suit.java new file mode 100644 index 0000000..8b26e86 --- /dev/null +++ b/src/main/java/blackjack/domain/enums/Suit.java @@ -0,0 +1,18 @@ +package blackjack.domain.enums; + +public enum Suit { + SPADE("스페이드"), + DIAMOND("다이아몬드"), + CLUB("클로버"), + HEART("하트"); + + private final String suit; + + Suit(final String suit) { + this.suit = suit; + } + + public String getSuit() { + return suit; + } +} diff --git a/src/main/java/blackjack/domain/participant/Dealer.java b/src/main/java/blackjack/domain/participant/Dealer.java new file mode 100644 index 0000000..e0680a9 --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Dealer.java @@ -0,0 +1,54 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Blackjack; +import blackjack.domain.state.finished.Stay; +import blackjack.domain.state.running.Hit; + +import static blackjack.domain.GameSystem.BLACKJACK; + +public class Dealer extends Gamer { + private static final int HIT_THRESHOLD = 16; + + public Dealer(final String name, final GivenCards givenCards) { + super(name); + state = injectStateBy(givenCards); + } + + @Override + public State injectStateBy(final GivenCards cards) { + if (cards.isBlackjack()) { + return new Blackjack(cards); + } + + if (cards.isLessThanEqualTo(HIT_THRESHOLD)) { + return new Hit(cards); + } + + return new Stay(cards); + } + + @Override + public void hit(final Card card) { + State newState = state.hit(card); + int sum = newState.sum(); + + if (sum > HIT_THRESHOLD && sum <= BLACKJACK) { + state = new Stay(newState.getCards()); + return; + } + + state = newState; + } + + @Override + public boolean isFinished() { + if (!getCards().isBlackjack() && !getCards().isLessThanEqualTo(HIT_THRESHOLD)) { + stay(); + } + + return super.isFinished(); + } +} diff --git a/src/main/java/blackjack/domain/participant/Gamer.java b/src/main/java/blackjack/domain/participant/Gamer.java new file mode 100644 index 0000000..80b0c8a --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Gamer.java @@ -0,0 +1,44 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Stay; + +public abstract class Gamer implements Person { + private final String name; + protected State state; + + protected Gamer(final String name) { + this.name = name; + } + + @Override + public GivenCards getCards() { + return state.getCards(); + } + + @Override + public String getName() { + return name; + } + + @Override + public int sum() { + return state.sum(); + } + + @Override + public void stay() { + state = new Stay(getCards()); + } + + @Override + public boolean isFinished() { + return state.isFinished(); + } + + @Override + public int compare(GivenCards otherCards) { + return state.compare(otherCards); + } +} diff --git a/src/main/java/blackjack/domain/participant/Person.java b/src/main/java/blackjack/domain/participant/Person.java new file mode 100644 index 0000000..17214e0 --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Person.java @@ -0,0 +1,24 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.State; + +public interface Person { + + State injectStateBy(GivenCards cards); + + void hit(Card card); + + GivenCards getCards(); + + String getName(); + + int sum(); + + void stay(); + + boolean isFinished(); + + int compare(GivenCards otherCards); +} diff --git a/src/main/java/blackjack/domain/participant/Player.java b/src/main/java/blackjack/domain/participant/Player.java new file mode 100644 index 0000000..f4cebb3 --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Player.java @@ -0,0 +1,29 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Blackjack; +import blackjack.domain.state.running.Hit; + +public class Player extends Gamer { + + public Player(final String name, final GivenCards cards) { + super(name); + state = injectStateBy(cards); + } + + @Override + public State injectStateBy(final GivenCards cards) { + if (cards.isBlackjack()) { + return new Blackjack(cards); + } + + return new Hit(cards); + } + + @Override + public void hit(final Card card) { + state = state.hit(card); + } +} diff --git a/src/main/java/blackjack/domain/participant/Players.java b/src/main/java/blackjack/domain/participant/Players.java new file mode 100644 index 0000000..56f1847 --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Players.java @@ -0,0 +1,82 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Deck; +import blackjack.domain.card.GivenCards; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Players { + private final Map players = new LinkedHashMap<>(); + + public Players(final List players) { + converToMap(players); + } + + public Players(final List playerNames, final Deck deck) { + this(createPlayers(playerNames, deck)); + } + + private static List createPlayers(final List playerNames, final Deck deck) { + return playerNames.stream() + .map(playerName -> new Player(playerName, deck.getTwoCards())) + .collect(Collectors.toList()); + } + + private void converToMap(List players) { + players.forEach(player -> this.players.put(player.getName(), player)); + } + + public List getPlayerNames() { + return Collections.unmodifiableList(new ArrayList<>(players.keySet())); + } + + public List getPlayerCards() { + return Collections.unmodifiableList(players.values() + .stream() + .map(Person::getCards) + .collect(Collectors.toList())); + } + + public boolean allPlayersFinished() { + return players.values() + .stream() + .allMatch(Person::isFinished); + } + + public String getCurrentPlayer() { + return players.values() + .stream() + .filter(player -> !player.isFinished()) + .map(Person::getName) + .findFirst() + .orElseThrow(IllegalStateException::new); + } + + public Person findPlayerBy(final String name) { + return players.get(name); + } + + public GivenCards getCards(final String name) { + Person player = findPlayerBy(name); + return player.getCards(); + } + + public List getPlayerScores() { + return players.values() + .stream() + .map(Person::sum) + .collect(Collectors.toList()); + } + + public List getResults(GivenCards dealerCards) { + return players.values() + .stream() + .map(player -> player.compare(dealerCards)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/blackjack/domain/state/Init.java b/src/main/java/blackjack/domain/state/Init.java new file mode 100644 index 0000000..858d1c6 --- /dev/null +++ b/src/main/java/blackjack/domain/state/Init.java @@ -0,0 +1,21 @@ +package blackjack.domain.state; + +import blackjack.domain.card.GivenCards; + +public abstract class Init implements State { + protected final GivenCards givenCards; + + protected Init(final GivenCards givenCards) { + this.givenCards = givenCards; + } + + @Override + public GivenCards getCards() { + return givenCards; + } + + @Override + public int sum() { + return givenCards.sum(); + } +} diff --git a/src/main/java/blackjack/domain/state/State.java b/src/main/java/blackjack/domain/state/State.java new file mode 100644 index 0000000..f13f588 --- /dev/null +++ b/src/main/java/blackjack/domain/state/State.java @@ -0,0 +1,19 @@ +package blackjack.domain.state; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; + +public interface State { + + State hit(Card card); + + State stay(); + + int sum(); + + boolean isFinished(); + + GivenCards getCards(); + + int compare(GivenCards givenCards); +} diff --git a/src/main/java/blackjack/domain/state/finished/Blackjack.java b/src/main/java/blackjack/domain/state/finished/Blackjack.java new file mode 100644 index 0000000..0330b14 --- /dev/null +++ b/src/main/java/blackjack/domain/state/finished/Blackjack.java @@ -0,0 +1,16 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Result; + +public class Blackjack extends Finished { + + public Blackjack(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public int compare(final GivenCards competitorCards) { + return Result.WIN.getPoint(); + } +} diff --git a/src/main/java/blackjack/domain/state/finished/Burst.java b/src/main/java/blackjack/domain/state/finished/Burst.java new file mode 100644 index 0000000..762d569 --- /dev/null +++ b/src/main/java/blackjack/domain/state/finished/Burst.java @@ -0,0 +1,16 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Result; + +public class Burst extends Finished { + + public Burst(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public int compare(final GivenCards competitorCards) { + return Result.LOSE.getPoint(); + } +} diff --git a/src/main/java/blackjack/domain/state/finished/Finished.java b/src/main/java/blackjack/domain/state/finished/Finished.java new file mode 100644 index 0000000..e2eb825 --- /dev/null +++ b/src/main/java/blackjack/domain/state/finished/Finished.java @@ -0,0 +1,28 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.Init; +import blackjack.domain.state.State; + +public abstract class Finished extends Init { + + protected Finished(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public State hit(Card card) { + throw new IllegalStateException("참여 종료 후에는 추가 카드 요청을 할 수 없습니다."); + } + + @Override + public State stay() { + throw new IllegalStateException("참여 종료 후에는 추가 카드 요청 거부를 할 수 없습니다."); + } + + @Override + public boolean isFinished() { + return true; + } +} diff --git a/src/main/java/blackjack/domain/state/finished/Stay.java b/src/main/java/blackjack/domain/state/finished/Stay.java new file mode 100644 index 0000000..d222e79 --- /dev/null +++ b/src/main/java/blackjack/domain/state/finished/Stay.java @@ -0,0 +1,24 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Result; + +public class Stay extends Finished { + + public Stay(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public int compare(final GivenCards competitorCards) { + if (competitorCards.isBurst() || givenCards.isGreaterThan(competitorCards)) { + return Result.WIN.getPoint(); + } + + if (givenCards.isLessThan(competitorCards)) { + return Result.LOSE.getPoint(); + } + + return Result.DRAW.getPoint(); + } +} diff --git a/src/main/java/blackjack/domain/state/running/Hit.java b/src/main/java/blackjack/domain/state/running/Hit.java new file mode 100644 index 0000000..29d8eee --- /dev/null +++ b/src/main/java/blackjack/domain/state/running/Hit.java @@ -0,0 +1,34 @@ +package blackjack.domain.state.running; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Burst; +import blackjack.domain.state.finished.Stay; + +public class Hit extends Running { + + public Hit(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public State hit(final Card card) { + givenCards.add(card); + + if (givenCards.isBurst()) { + return new Burst(givenCards); + } + + if (givenCards.isMaximumThreshold()) { + return new Stay(givenCards); + } + + return new Hit(givenCards); + } + + @Override + public State stay() { + return new Stay(getCards()); + } +} diff --git a/src/main/java/blackjack/domain/state/running/Running.java b/src/main/java/blackjack/domain/state/running/Running.java new file mode 100644 index 0000000..52503cc --- /dev/null +++ b/src/main/java/blackjack/domain/state/running/Running.java @@ -0,0 +1,21 @@ +package blackjack.domain.state.running; + +import blackjack.domain.card.GivenCards; +import blackjack.domain.state.Init; + +public abstract class Running extends Init { + + Running(final GivenCards givenCards) { + super(givenCards); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public int compare(GivenCards givenCards) { + throw new IllegalStateException("게임 진행 중에는 결과를 알 수 없습니다."); + } +} diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java new file mode 100644 index 0000000..c77f1f7 --- /dev/null +++ b/src/main/java/blackjack/view/InputView.java @@ -0,0 +1,24 @@ +package blackjack.view; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + private static final Scanner scanner = new Scanner(System.in); + public static final String SEPARATOR = ","; + + public List getPlayerNames() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + String names = scanner.nextLine(); + return Arrays.stream(names.split(SEPARATOR)) + .map(String::trim) + .collect(Collectors.toList()); + } + + public String getAnswerForAnotherCard(String player) { + System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)%n", player); + return scanner.nextLine().trim(); + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java new file mode 100644 index 0000000..3586043 --- /dev/null +++ b/src/main/java/blackjack/view/OutputView.java @@ -0,0 +1,91 @@ +package blackjack.view; + +import blackjack.controller.dto.CardResponse; +import blackjack.controller.dto.CardsResponse; +import blackjack.controller.dto.DealerAndPlayerCardsResponse; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class OutputView { + private static final String SEPARATOR = ", "; + private static final String DECLINE_ANSWER = "n"; + private static final int FIRST_TWO_CARDS = 2; + private static final Map gameResults = new HashMap<>(); + + static { + gameResults.put(1, "승"); + gameResults.put(0, "무"); + gameResults.put(-1, "패"); + } + + public void printGameStart(List playerNames) { + String names = String.join(SEPARATOR, playerNames); + System.out.printf("%n딜러와 %s에게 2장의 카드를 나누었습니다.%n", names); + } + + public void printFirstTwoCards(List playerNames, DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse) { + System.out.printf("딜러: %s%n", combine(dealerAndPlayerCardsResponse.getDealerCards().getCards().get(0))); + + IntStream.range(0, playerNames.size()) + .forEach(i -> System.out.printf("%s카드: %s%n", playerNames.get(i), join(dealerAndPlayerCardsResponse.getAllPlayerCards().get(i)))); + System.out.println(); + } + + private String combine(final CardResponse cardResponse) { + return cardResponse.getDenomination() + cardResponse.getSuit(); + } + + private String join(final CardsResponse cardResponses) { + List fullCardNames = cardResponses.getCards().stream() + .map(this::combine) + .collect(Collectors.toList()); + + return String.join(SEPARATOR, fullCardNames); + } + + public void printPlayerCards(final String playerName, final CardsResponse cardsResponse, String answer) { + if (answer.equals(DECLINE_ANSWER) && cardsResponse.getCards().size() != FIRST_TWO_CARDS) { + return; + } + + System.out.printf("%s카드: %s%n", playerName, join(cardsResponse)); + } + + public void printDealerGetAnotherCard() { + System.out.printf("%n딜러는 16이하라 한장의 카드를 더 받았습니다.%n"); + } + + public void printCardsAndScores(final List playerNames, DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse, int dealerScore, List playerScores) { + System.out.printf("%n딜러 카드: %s - 결과: %d%n", join(dealerAndPlayerCardsResponse.getDealerCards()), dealerScore); + + IntStream.range(0, playerNames.size()) + .forEach(i -> System.out.printf("%s카드: %s - 결과: %d%n", playerNames.get(i), join(dealerAndPlayerCardsResponse.getAllPlayerCards().get(i)), playerScores.get(i))); + System.out.println(); + } + + public void printResults(List playerNames, final List results) { + System.out.println("## 최종 승패"); + String dealerWin = convertToString(results, -1); + String dealerDraw = convertToString(results, 0); + String dealerLose = convertToString(results, 1); + System.out.printf("딜러: %s%n", String.join("", dealerWin, dealerDraw, dealerLose)); + IntStream.range(0, playerNames.size()) + .forEach(i -> System.out.printf("%s: %s%n", playerNames.get(i), gameResults.get(results.get(i)))); + } + + private String convertToString(List results, int result) { + long count = results.stream() + .filter(integer -> integer == result) + .count(); + + if (count == 0) { + return ""; + } + + return String.format("%d%s ", count, gameResults.get(-result)); + } +} diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/java/blackjack/controller/dto/CardResponseTest.java b/src/test/java/blackjack/controller/dto/CardResponseTest.java new file mode 100644 index 0000000..4a8588e --- /dev/null +++ b/src/test/java/blackjack/controller/dto/CardResponseTest.java @@ -0,0 +1,40 @@ +package blackjack.controller.dto; + +import blackjack.domain.card.Card; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CardResponseTest { + + @Test + @DisplayName("카드의 점수 이름(끗수)을 반환한다.") + void getScore() { + //given + Card card = Card.from(Score.A, Suit.CLUB); + CardResponse cardResponse = new CardResponse(card.getDenomination(), card.getSuit()); + + //when + String denomination = cardResponse.getDenomination(); + + //then + assertThat(denomination).isEqualTo(Score.A.getDenomination()); + } + + @Test + @DisplayName("카드의 무늬를 반환한다.") + void getSuit() { + //given + Card card = Card.from(Score.A, Suit.CLUB); + CardResponse cardResponse = new CardResponse(card.getDenomination(), card.getSuit()); + + //when + String suit = cardResponse.getSuit(); + + //then + assertThat(suit).isEqualTo(Suit.CLUB.getSuit()); + } +} diff --git a/src/test/java/blackjack/controller/dto/CardsResponseTest.java b/src/test/java/blackjack/controller/dto/CardsResponseTest.java new file mode 100644 index 0000000..763878b --- /dev/null +++ b/src/test/java/blackjack/controller/dto/CardsResponseTest.java @@ -0,0 +1,38 @@ +package blackjack.controller.dto; + +import blackjack.domain.card.Card; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class CardsResponseTest { + + @Test + @DisplayName("모든 카드를 반환한다.") + void getCards() { + //given + Score ace = Score.A; + Suit club = Suit.CLUB; + Suit diamond = Suit.DIAMOND; + Card card1 = Card.from(ace, club); + Card card2 = Card.from(ace, diamond); + List playerCards = Arrays.asList(card1, card2); + CardsResponse cardsResponse = new CardsResponse(playerCards); + + //when + List cards = cardsResponse.getCards(); + + //then + assertThat(cards).hasSize(2) + .extracting("denomination", "suit") + .containsOnly(tuple(ace.getDenomination(), club.getSuit()), + tuple(ace.getDenomination(), diamond.getSuit())); + } +} diff --git a/src/test/java/blackjack/controller/dto/DealerAndPlayerCardsResponseTest.java b/src/test/java/blackjack/controller/dto/DealerAndPlayerCardsResponseTest.java new file mode 100644 index 0000000..73dfe02 --- /dev/null +++ b/src/test/java/blackjack/controller/dto/DealerAndPlayerCardsResponseTest.java @@ -0,0 +1,65 @@ +package blackjack.controller.dto; + +import blackjack.domain.card.Card; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class DealerAndPlayerCardsResponseTest { + + @Test + @DisplayName("딜러 카드를 반환한다.") + void getDealerCards() { + //given + Score ace = Score.A; + Suit club = Suit.CLUB; + Suit diamond = Suit.DIAMOND; + Card card1 = Card.from(ace, club); + Card card2 = Card.from(ace, diamond); + List dealerCards = Arrays.asList(card1, card2); + DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse = new DealerAndPlayerCardsResponse(dealerCards, Collections.emptyList()); + + //when + CardsResponse dealerCard = dealerAndPlayerCardsResponse.getDealerCards(); + + //then + assertThat(dealerCard.getCards()).hasSize(2) + .extracting("denomination", "suit") + .containsOnly(tuple(ace.getDenomination(), club.getSuit()), + tuple(ace.getDenomination(), diamond.getSuit())); + } + + @Test + @DisplayName("모든 플레이어의 카드를 반환한다.") + void getAllPlayerCards() { + //given + Score ace = Score.A; + Suit club = Suit.CLUB; + Suit diamond = Suit.DIAMOND; + Card card1 = Card.from(ace, club); + Card card2 = Card.from(ace, diamond); + List playerCards = Arrays.asList(card1, card2); + List> allPlayerCards = Arrays.asList(playerCards, playerCards, playerCards); + DealerAndPlayerCardsResponse dealerAndPlayerCardsResponse = new DealerAndPlayerCardsResponse(Collections.emptyList(), allPlayerCards); + + //when + List allPlayerCardsResponse = dealerAndPlayerCardsResponse.getAllPlayerCards(); + + //then + assertThat(allPlayerCardsResponse).hasSize(3); + allPlayerCardsResponse.forEach( + playerCardsResponse -> assertThat(playerCardsResponse.getCards()).hasSize(2) + .extracting("denomination", "suit") + .containsOnly(tuple(ace.getDenomination(), club.getSuit()), + tuple(ace.getDenomination(), diamond.getSuit())) + ); + } +} diff --git a/src/test/java/blackjack/domain/GameSystemTest.java b/src/test/java/blackjack/domain/GameSystemTest.java new file mode 100644 index 0000000..eda1b46 --- /dev/null +++ b/src/test/java/blackjack/domain/GameSystemTest.java @@ -0,0 +1,265 @@ +package blackjack.domain; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Deck; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Person; +import blackjack.domain.participant.Player; +import blackjack.domain.participant.Players; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class GameSystemTest { + + @Test + @DisplayName("플레이어의 이름을 반환한다.") + void getPlayerNames() { + //given + String name1 = "pobi"; + String name2 = "tobi"; + List names = Arrays.asList(name1, name2); + + //when + GameSystem gameSystem = GameSystem.create(names); + + //then + assertThat(gameSystem.getPlayerNames()).hasSize(2) + .contains(name1, name2); + } + + @Test + @DisplayName("딜러의 모든 카드를 반환한다.") + void getDealerCards() { + //give + List playerNames = Arrays.asList("pobi", "dobi"); + GameSystem gameSystem = GameSystem.create(playerNames); + + //when + List dealerCards = gameSystem.getDealerCards(); + + //then + assertThat(dealerCards).hasSize(2); + } + + @Test + @DisplayName("플레이어들의 모든 카드를 반환한다.") + void getPlayerCards() { + //given + String name1 = "pobi"; + String name2 = "tobi"; + List names = Arrays.asList(name1, name2); + GameSystem gameSystem = GameSystem.create(names); + + //when + List> allPlayerCards = gameSystem.getPlayerCards(); + + //then + assertThat(allPlayerCards).hasSize(2); + allPlayerCards.forEach(playerCards -> assertThat(playerCards).hasSize(2)); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, true", "TEN, TEN, false"}) + @DisplayName("모든 플레이어가 종료하였는지 여부를 반환한다.") + void allPlayersFinished(Score score1, Score score2, boolean expected) { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.J, Suit.DIAMOND); + Card card3 = Card.from(score1, Suit.CLUB); + Card card4 = Card.from(score2, Suit.CLUB); + Person player1 = new Player("pobi", new GivenCards(Arrays.asList(card1, card2))); + Person player2 = new Player("tobi", new GivenCards(Arrays.asList(card3, card4))); + Players players = new Players(Arrays.asList(player1, player2)); + Dealer dealer = new Dealer("딜러", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + boolean isFinished = gameSystem.allPlayersFinished(); + + //then + assertThat(isFinished).isEqualTo(expected); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, A, NINE, player3", "TEN, TEN, TEN, TEN, player2"}) + @DisplayName("참여 종료상태가 아닌 플레이어 중 먼저 입력 받았던 플레이어의 이름을 반환한다.") + void getCurrentPlayer(Score score1, Score score2, Score score3, Score score4, String expectedPlayer) { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.J, Suit.DIAMOND); + Card card3 = Card.from(score1, Suit.CLUB); + Card card4 = Card.from(score2, Suit.CLUB); + Card card5 = Card.from(score3, Suit.HEART); + Card card6 = Card.from(score4, Suit.HEART); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + Person player3 = new Player("player3", new GivenCards(Arrays.asList(card5, card6))); + Players players = new Players(Arrays.asList(player1, player2, player3)); + Dealer dealer = new Dealer("dealer", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + String player = gameSystem.getCurrentPlayer(); + + //then + assertThat(player).isEqualTo(expectedPlayer); + } + + @ParameterizedTest + @CsvSource(value = {"y, 3", "n, 2"}) + @DisplayName("카드 추가 의사와 플레이어 이름을 인자로 전달받아 플레이어의 카드를 추가한다.") + void hit(String answer, int expectedSize) { + //given + String name = "pobi"; + Card card1 = Card.from(Score.A, Suit.HEART); + Card card2 = Card.from(Score.A, Suit.CLUB); + Person player = new Player(name, new GivenCards(Arrays.asList(card1, card2))); + Players players = new Players(Collections.singletonList(player)); + Dealer dealer = new Dealer("딜러", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + gameSystem.hit(answer, name); + + //then + assertThat(player.getCards().list()).hasSize(expectedSize); + } + + @ParameterizedTest + @ValueSource(strings = {"Y", "N", "y1", "n1", "yes", "no"}) + @DisplayName("y 또는 n이 아닌 다른 응답을 전달받을 경우, 예외가 발생한다.") + void hit_with_invalid_answer(String answer) { + //given + String name = "pobi"; + Card card1 = Card.from(Score.A, Suit.HEART); + Card card2 = Card.from(Score.A, Suit.CLUB); + Person player = new Player(name, new GivenCards(Arrays.asList(card1, card2))); + Players players = new Players(Collections.singletonList(player)); + Dealer dealer = new Dealer("딜러", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when //then + assertThatThrownBy(() -> gameSystem.hit(answer, name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("y 또는 n을 입력해주세요."); + } + + @Test + @DisplayName("딜러의 카드를 추가한다.") + void hit_for_dealer() { + //given + Card card1 = Card.from(Score.TWO, Suit.CLUB); + Card card2 = Card.from(Score.TWO, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Players players = new Players(Collections.emptyList()); + Dealer dealer = new Dealer("딜러", givenCards); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + gameSystem.hit(); + + //then + assertThat(gameSystem.getDealerCards()).hasSize(3); + } + + @Test + @DisplayName("인자로 받은 플레이어의 카드를 반환한다.") + void getCards() { + //given + String name = "pobi"; + Card card1 = Card.from(Score.A, Suit.HEART); + Card card2 = Card.from(Score.A, Suit.CLUB); + Person player = new Player(name, new GivenCards(Arrays.asList(card1, card2))); + Players players = new Players(Collections.singletonList(player)); + Dealer dealer = new Dealer("딜러", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + List cards = gameSystem.getCards(name); + + //then + assertThat(cards).hasSize(2) + .containsOnly(card1, card2); + } + + @Test + @DisplayName("딜러의 점수 합을 반환한다.") + void getDealerScore() { + //give + Card card1 = Card.from(Score.A, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Dealer dealer = new Dealer("딜러", givenCards); + Players players = new Players(Collections.emptyList()); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + int dealerScore = gameSystem.getDealerScore(); + + //then + assertThat(dealerScore).isEqualTo(21); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, A, NINE, 21, 20", "TEN, TEN, A, A, 20, 12"}) + @DisplayName("플레이어들의 점수를 반환한다.") + void getPlayerScores(Score score1, Score score2, Score score3, Score score4, int expectedSum1, int expectedSum2) { + //given + Card card1 = Card.from(score1, Suit.CLUB); + Card card2 = Card.from(score2, Suit.CLUB); + Card card3 = Card.from(score3, Suit.HEART); + Card card4 = Card.from(score4, Suit.HEART); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + Players players = new Players(Arrays.asList(player1, player2)); + Dealer dealer = new Dealer("딜러", new GivenCards(Collections.emptyList())); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + + //when + List playerScores = gameSystem.getPlayerScores(); + + //then + assertThat(playerScores).hasSize(2) + .containsOnly(expectedSum1, expectedSum2); + } + + @ParameterizedTest + @CsvSource(value = {"TEN, TEN, n, 1, 1", "TEN, EIGHT, n, 1, -1", "A, EIGHT, n, 1, 0"}) + @DisplayName("플레이어의 승패 결과를 반환한다.") + void getResults(Score score1, Score score2, String answer, int expectedResult1, int expectedResult2) { + //given + Card card1 = Card.from(Score.A, Suit.CLUB); + Card card2 = Card.from(Score.J, Suit.CLUB); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Card card3 = Card.from(score1, Suit.HEART); + Card card4 = Card.from(score2, Suit.HEART); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + Card card5 = Card.from(Score.A, Suit.DIAMOND); + Card card6 = Card.from(Score.EIGHT, Suit.DIAMOND); + GivenCards dealerCards = new GivenCards(Arrays.asList(card5, card6)); + Players players = new Players(Arrays.asList(player1, player2)); + Dealer dealer = new Dealer("딜러", dealerCards); + GameSystem gameSystem = new GameSystem(dealer, players, new Deck()); + gameSystem.hit(answer, "player2"); + + //when + List results = gameSystem.getResults(); + + //then + assertThat(results).hasSize(2) + .containsOnly(expectedResult1, expectedResult2); + } +} diff --git a/src/test/java/blackjack/domain/card/CardTest.java b/src/test/java/blackjack/domain/card/CardTest.java new file mode 100644 index 0000000..f70c912 --- /dev/null +++ b/src/test/java/blackjack/domain/card/CardTest.java @@ -0,0 +1,72 @@ +package blackjack.domain.card; + +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CardTest { + + @Test + @DisplayName("점수와 무늬를 인자로 받아 한 장의 카드를 생성한다.") + void create() { + //given + Score ace = Score.A; + Suit diamond = Suit.DIAMOND; + + //when + Card card = Card.from(ace, diamond); + + //then + assertThat(card).isEqualTo(Card.from(ace, diamond)); + } + + @Test + @DisplayName("카드의 점수를 반환한다.") + void getScore() { + //given + Score jack = Score.J; + Suit diamond = Suit.DIAMOND; + Card card = Card.from(jack, diamond); + + //when + int score = card.getScore(); + + //then + assertThat(score).isEqualTo(jack.getScore()); + } + + @Test + @DisplayName("카드의 점수 이름(끗수)를 반환한다.") + void getDenomination() { + //given + Score jack = Score.J; + Suit diamond = Suit.DIAMOND; + Card card = Card.from(jack, diamond); + + //when + String denomination = card.getDenomination(); + + //then + assertThat(denomination).isEqualTo(jack.getDenomination()); + } + + @ParameterizedTest + @CsvSource(value = {"A, true", "TWO, false", "TEN, false", "J, false"}) + @DisplayName("카드가 Ace일 경우 참을 반환한다.") + void isAce(Score score, boolean expected) { + //given + Suit diamond = Suit.DIAMOND; + Card card = Card.from(score, diamond); + + //when + boolean actual = card.isAce(); + + //then + assertThat(actual).isEqualTo(expected); + } +} diff --git a/src/test/java/blackjack/domain/card/DeckTest.java b/src/test/java/blackjack/domain/card/DeckTest.java new file mode 100644 index 0000000..a4f4436 --- /dev/null +++ b/src/test/java/blackjack/domain/card/DeckTest.java @@ -0,0 +1,35 @@ +package blackjack.domain.card; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DeckTest { + + @Test + @DisplayName("카드 한 장을 반환한다.") + void getCard() { + //given + Deck deck = new Deck(); + + //when + Card card = deck.getCard(); + + //then + assertThat(card).isNotNull(); + } + + @Test + @DisplayName("카드 두 장을 반환한다.") + void getTwoCards() { + //given + Deck deck = new Deck(); + + //when + GivenCards cards = deck.getTwoCards(); + + //then + assertThat(cards.list()).hasSize(2); + } +} diff --git a/src/test/java/blackjack/domain/card/GivenCardsTest.java b/src/test/java/blackjack/domain/card/GivenCardsTest.java new file mode 100644 index 0000000..58d7810 --- /dev/null +++ b/src/test/java/blackjack/domain/card/GivenCardsTest.java @@ -0,0 +1,193 @@ +package blackjack.domain.card; + +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GivenCardsTest { + + @Test + @DisplayName("가지고 있는 카드의 합을 반환한다.") + void sum() { + //given + Card card1 = Card.from(Score.EIGHT, Suit.CLUB); + Card card2 = Card.from(Score.TWO, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + int sum = givenCards.sum(); + + //then + assertThat(sum).isEqualTo(10); + } + + @Test + @DisplayName("Ace가 1로 계산된 카드의 합을 반환한다.") + void sum_with_ace_value_1() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.CLUB); + Card card3 = Card.from(Score.A, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2, card3)); + + //when + int sum = givenCards.sum(); + + //then + assertThat(sum).isEqualTo(21); + } + + @Test + @DisplayName("Ace가 11로 계산된 카드의 합을 반환한다.") + void sum_with_ace_value_11() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.A, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + int sum = givenCards.sum(); + + //then + assertThat(sum).isEqualTo(21); + } + + @Test + @DisplayName("카드 2장이 21일 경우, 참을 반환한다.") + void isBlackjack() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.A, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + boolean isBlackjack = givenCards.isBlackjack(); + + //then + assertThat(isBlackjack).isTrue(); + } + + @Test + @DisplayName("카드의 합이 21을 초과할 경우, 참을 반환한다.") + void isBurst() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + Card card3 = Card.from(Score.TWO, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2, card3)); + + //when + boolean isBurst = givenCards.isBurst(); + + //then + assertThat(isBurst).isTrue(); + } + + @Test + @DisplayName("가지고 있는 카드 목록을 반환한다.") + void list() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.A, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + List cards = givenCards.list(); + + //then + assertThat(cards).hasSize(2) + .containsOnly(card1, card2); + } + + @Test + @DisplayName("인자로 받은 카드를 추가한다.") + void add() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Card newCard = Card.from(Score.TWO, Suit.CLUB); + + //when + givenCards.add(newCard); + + //then + assertThat(givenCards.list()).hasSize(3) + .containsOnly(card1, card2, newCard); + } + + @Test + @DisplayName("인자로 받은 카드보다 자신의 카드 합이 더 클 경우, 참을 반환한다.") + void isGreaterThan() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.CLUB); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + Card card3 = Card.from(Score.SEVEN, Suit.CLUB); + GivenCards otherCards = new GivenCards(Arrays.asList(card1, card3)); + + //when + boolean result = myCards.isGreaterThan(otherCards); + + //then + assertThat(result).isTrue(); + } + + @Test + @DisplayName("인자로 받은 카드보다 자신의 카드 합보다 작을 경우, 참을 반환한다.") + void isLessThan() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.CLUB); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + Card card3 = Card.from(Score.TEN, Suit.HEART); + GivenCards otherCards = new GivenCards(Arrays.asList(card1, card3)); + + //when + boolean result = myCards.isLessThan(otherCards); + + //then + assertThat(result).isTrue(); + } + + @ParameterizedTest + @CsvSource(value = {"18, false", "19, true"}) + @DisplayName("인자로 받은 값보다 자신의 카드 합이 작거나 같을 경우, 참을 반환한다.") + void isLessThanEqualTo(int sum, boolean expected) { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.CLUB); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + boolean result = myCards.isLessThanEqualTo(sum); + + //then + assertThat(result).isEqualTo(expected); + } + + @ParameterizedTest + @CsvSource(value = {"TEN, NINE, TWO, true", "TEN, EIGHT, TWO, false"}) + @DisplayName("카드의 합이 21일 경우, 참을 반환한다.") + void isMaximumThreshhold(Score score1, Score score2, Score score3, boolean expected) { + //given + Card card1 = Card.from(score1, Suit.CLUB); + Card card2 = Card.from(score2, Suit.CLUB); + Card card3 = Card.from(score3, Suit.CLUB); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2, card3)); + + //when + boolean result = myCards.isMaximumThreshold(); + + //then + assertThat(result).isEqualTo(expected); + } +} diff --git a/src/test/java/blackjack/domain/enums/ResultTest.java b/src/test/java/blackjack/domain/enums/ResultTest.java new file mode 100644 index 0000000..a7caade --- /dev/null +++ b/src/test/java/blackjack/domain/enums/ResultTest.java @@ -0,0 +1,21 @@ +package blackjack.domain.enums; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class ResultTest { + + @ParameterizedTest + @CsvSource(value = {"WIN, 1", "LOSE, -1", "DRAW, 0"}) + @DisplayName("게임 결과 포인트를 반환한다.") + void getPoint(Result result, int expectedPoint) { + //when + int point = result.getPoint(); + + //then + assertThat(point).isEqualTo(expectedPoint); + } +} diff --git a/src/test/java/blackjack/domain/enums/ScoreTest.java b/src/test/java/blackjack/domain/enums/ScoreTest.java new file mode 100644 index 0000000..869c7b0 --- /dev/null +++ b/src/test/java/blackjack/domain/enums/ScoreTest.java @@ -0,0 +1,43 @@ +package blackjack.domain.enums; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScoreTest { + + @ParameterizedTest + @CsvSource(value = {"A, 1", "TWO, 2", "THREE, 3", "FOUR, 4", "FIVE, 5", "SIX, 6", "SEVEN, 7", "EIGHT, 8", "NINE, 9", "TEN, 10", "J, 10", "Q, 10", "K, 10"}) + @DisplayName("카드의 점수를 반환한다.") + void getScore(Score cardScore, int expectedScore) { + //when + int score = cardScore.getScore(); + + //then + assertThat(score).isEqualTo(expectedScore); + } + + @ParameterizedTest + @CsvSource(value = {"A, A", "TWO, 2", "THREE, 3", "FOUR, 4", "FIVE, 5", "SIX, 6", "SEVEN, 7", "EIGHT, 8", "NINE, 9", "TEN, 10", "J, J", "Q, Q", "K, K"}) + @DisplayName("카드의 점수 이름을 반환한다.") + void getDenomination(Score score, String expectedDenomiantion) { + //when + String denomination = score.getDenomination(); + + //then + assertThat(denomination).isEqualTo(expectedDenomiantion); + } + + @ParameterizedTest + @CsvSource(value = {"A, true", "TWO, false", "TEN, false", "J, false"}) + @DisplayName("카드가 Ace일 경우 참을 반환한다.") + void isAce(Score score, boolean expected) { + //when + boolean actual = score.isAce(); + + //then + assertThat(actual).isEqualTo(expected); + } +} diff --git a/src/test/java/blackjack/domain/enums/SuitTest.java b/src/test/java/blackjack/domain/enums/SuitTest.java new file mode 100644 index 0000000..6f608be --- /dev/null +++ b/src/test/java/blackjack/domain/enums/SuitTest.java @@ -0,0 +1,21 @@ +package blackjack.domain.enums; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SuitTest { + + @ParameterizedTest + @CsvSource(value = {"SPADE, 스페이드", "DIAMOND, 다이아몬드", "CLUB, 클로버", "HEART, 하트"}) + @DisplayName("카드 무늬 이름을 반환한다.") + void getSuit(Suit cardSuit, String expectedSuit) { + //when + String suit = cardSuit.getSuit(); + + //then + assertThat(suit).isEqualTo(expectedSuit); + } +} diff --git a/src/test/java/blackjack/domain/participant/DealerTest.java b/src/test/java/blackjack/domain/participant/DealerTest.java new file mode 100644 index 0000000..ae8ff04 --- /dev/null +++ b/src/test/java/blackjack/domain/participant/DealerTest.java @@ -0,0 +1,144 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.finished.Blackjack; +import blackjack.domain.state.finished.Burst; +import blackjack.domain.state.finished.Stay; +import blackjack.domain.state.running.Hit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DealerTest { + + @Test + @DisplayName("처음 받은 카드 두 장의 합이 21일 경우, Blackjack 상태가 된다.") + void create_state_blackjack() { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.TEN, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + Person dealer = new Dealer("딜러", givenCards); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Blackjack.class); + } + + @Test + @DisplayName("처음 받은 카드 두 장의 합이 16 이하일 경우, Hit 상태가 된다.") + void create_state_hit() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.SIX, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + Person dealer = new Dealer("딜러", givenCards); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Hit.class); + } + + @Test + @DisplayName("처음 받은 카드 두 장의 합이 16을 초과할 경우, Stay 상태가 된다.") + void create_state_stay() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.SEVEN, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + Person dealer = new Dealer("딜러", givenCards); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Stay.class); + } + + @Test + @DisplayName("발급 받은 카드를 더한 합이 21을 초과할 경우, Burst 상태가 된다.") + void hit_become_burst_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.SIX, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person dealer = new Dealer("pobi", givenCards); + Card card3 = Card.from(Score.SIX, Suit.HEART); + + //when + dealer.hit(card3); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Burst.class); + } + + @Test + @DisplayName("발급 받은 카드를 더한 합이 16 이하일 경우, Hit 상태가 된다.") + void hit_remain_hit_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.FOUR, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person dealer = new Dealer("pobi", givenCards); + Card card3 = Card.from(Score.TWO, Suit.HEART); + + //when + dealer.hit(card3); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Hit.class); + } + + @ParameterizedTest + @ValueSource(strings = {"TWO", "SIX"}) + @DisplayName("발급 받은 카드를 더한 합이 17 이상 21 이하일 경우, Stay 상태가 된다.") + void hit_become_stay_state(Score score) { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.FIVE, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person dealer = new Dealer("pobi", givenCards); + Card card3 = Card.from(score, Suit.HEART); + + //when + dealer.hit(card3); + + //then + assertThat(dealer).extracting("state") + .isInstanceOf(Stay.class); + } + + @ParameterizedTest + @CsvSource(value = {"THREE, true", "SEVEN, true", "TWO, false"}) + @DisplayName("블랙잭이 아니고 17 이상 21 이하일 경우 종료 여부를 참으로 반환한다.") + void isFinished(Score score, boolean expected) { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.FOUR, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person dealer = new Dealer("pobi", givenCards); + Card card3 = Card.from(score, Suit.HEART); + dealer.hit(card3); + + //when + boolean finished = dealer.isFinished(); + + //then + assertThat(finished).isEqualTo(expected); + } +} diff --git a/src/test/java/blackjack/domain/participant/GamerTest.java b/src/test/java/blackjack/domain/participant/GamerTest.java new file mode 100644 index 0000000..555a4f1 --- /dev/null +++ b/src/test/java/blackjack/domain/participant/GamerTest.java @@ -0,0 +1,137 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Stay; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +class GamerTest { + + @Test + @DisplayName("추가 카드 발급을 거부할 경우, Stay 상태가 된다.") + void stay() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person gamer = createGamer("pobi", givenCards, false); + + //when + gamer.stay(); + + //then + assertThat(gamer).extracting("state") + .isInstanceOf(Stay.class); + } + + @Test + @DisplayName("발급 받은 카드 목록을 반환한다.") + void getCards() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person gamer = createGamer("pobi", givenCards, false); + + //when + GivenCards cards = gamer.getCards(); + + //then + assertThat(cards).isEqualTo(givenCards); + } + + @Test + @DisplayName("카드의 합을 반환한다.") + void sum() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person gamer = createGamer("pobi", givenCards, false); + + //when + int sum = gamer.sum(); + + //then + assertThat(sum).isEqualTo(19); + } + + @Test + @DisplayName("이름을 반환한다.") + void getName() { + //given + GivenCards givenCards = new GivenCards(Collections.emptyList()); + String playerName = "pobi"; + Person gamer = createGamer("pobi", givenCards, false); + + //when + String name = gamer.getName(); + + //then + assertThat(name).isEqualTo(playerName); + } + + @Test + @DisplayName("종료 여부를 반환한다.") + void isFinished() { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.TEN, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person gamer = createGamer("pobi", givenCards, true); + + //when + boolean finished = gamer.isFinished(); + + //then + assertThat(finished).isTrue(); + } + + private Gamer createGamer(String name, GivenCards givenCards, boolean isFinished) { + return new Gamer(name) { + @Override + public GivenCards getCards() { + return givenCards; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int sum() { + return givenCards.sum(); + } + + @Override + public void stay() { + super.stay(); + } + + @Override + public boolean isFinished() { + return isFinished; + } + + @Override + public State injectStateBy(GivenCards cards) { + return null; + } + + @Override + public void hit(Card card) { + + } + }; + } +} diff --git a/src/test/java/blackjack/domain/participant/PlayerTest.java b/src/test/java/blackjack/domain/participant/PlayerTest.java new file mode 100644 index 0000000..4e500ec --- /dev/null +++ b/src/test/java/blackjack/domain/participant/PlayerTest.java @@ -0,0 +1,105 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.finished.Blackjack; +import blackjack.domain.state.finished.Burst; +import blackjack.domain.state.finished.Stay; +import blackjack.domain.state.running.Hit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PlayerTest { + + @Test + @DisplayName("처음 받은 카드 두 장의 합이 21일 경우, Blackjack 상태가 된다.") + void create_state_blackjack() { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.TEN, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + Person player = new Player("pobi", givenCards); + + //then + assertThat(player).extracting("state") + .isInstanceOf(Blackjack.class); + } + + @Test + @DisplayName("처음 받은 카드 두 장의 합이 21 미만일 경우, Hit 상태가 된다.") + void create_state_hit() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.TEN, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + Person player = new Player("pobi", givenCards); + + //then + assertThat(player).extracting("state") + .isInstanceOf(Hit.class); + } + + @Test + @DisplayName("발급 받은 카드를 더한 합이 21을 초과할 경우, Burst 상태가 된다.") + void hit_become_burst_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.TEN, Suit.CLUB); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person player = new Player("pobi", givenCards); + Card card3 = Card.from(Score.TWO, Suit.HEART); + + //when + player.hit(card3); + + //then + assertThat(player).extracting("state") + .isInstanceOf(Burst.class); + } + + @Test + @DisplayName("발급 받은 카드를 더한 합이 21 미만일 경우, Hit 상태가 된다.") + void hit_remain_hit_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.EIGHT, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person player = new Player("pobi", givenCards); + Card card3 = Card.from(Score.TWO, Suit.HEART); + + //when + player.hit(card3); + + //then + assertThat(player).extracting("state") + .isInstanceOf(Hit.class); + } + + @Test + @DisplayName("발급 받은 카드를 더한 합이 21일 경우, Stay 상태가 된다.") + void hit_become_stay_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.DIAMOND); + Card card2 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + Person player = new Player("pobi", givenCards); + Card card3 = Card.from(Score.TWO, Suit.HEART); + + //when + player.hit(card3); + + //then + assertThat(player).extracting("state") + .isInstanceOf(Stay.class); + } +} diff --git a/src/test/java/blackjack/domain/participant/PlayersTest.java b/src/test/java/blackjack/domain/participant/PlayersTest.java new file mode 100644 index 0000000..547c9eb --- /dev/null +++ b/src/test/java/blackjack/domain/participant/PlayersTest.java @@ -0,0 +1,189 @@ +package blackjack.domain.participant; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Deck; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class PlayersTest { + + @Test + @DisplayName("플레이어의 이름을 반환한다.") + void getPlayerNames() { + //given + Deck deck = new Deck(); + String name1 = "pobi"; + Player player1 = new Player(name1, deck.getTwoCards()); + String name2 = "tobi"; + Player player2 = new Player(name2, deck.getTwoCards()); + Players players = new Players(Arrays.asList(player1, player2)); + + //when + List playerNames = players.getPlayerNames(); + + //then + assertThat(playerNames).hasSize(2) + .containsOnly(name1, name2); + } + + @Test + @DisplayName("플레이어들의 모든 카드를 반환한다.") + void getPlayerCards() { + //given + Deck deck = new Deck(); + String name1 = "pobi"; + Player player1 = new Player(name1, deck.getTwoCards()); + String name2 = "tobi"; + Player player2 = new Player(name2, deck.getTwoCards()); + Players players = new Players(Arrays.asList(player1, player2)); + + //when + List allPlayerCards = players.getPlayerCards(); + + //then + assertThat(allPlayerCards).hasSize(2); + allPlayerCards.forEach(playerCards -> assertThat(playerCards.list()).hasSize(2)); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, true", "TEN, TEN, false"}) + @DisplayName("모든 플레이어가 종료하였는지 여부를 반환한다.") + void allPlayersFinished(Score score1, Score score2, boolean expected) { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.J, Suit.DIAMOND); + Person player1 = new Player("pobi", new GivenCards(Arrays.asList(card1, card2))); + Card card3 = Card.from(score1, Suit.CLUB); + Card card4 = Card.from(score2, Suit.CLUB); + Person player2 = new Player("tobi", new GivenCards(Arrays.asList(card3, card4))); + Players players = new Players(Arrays.asList(player1, player2)); + + //when + boolean isFinished = players.allPlayersFinished(); + + //then + assertThat(isFinished).isEqualTo(expected); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, A, NINE, player3", "TEN, TEN, TEN, TEN, player2"}) + @DisplayName("참여 종료상태가 아닌 플레이어 중 먼저 입력 받았던 플레이어의 이름을 반환한다.") + void getCurrentPlayer(Score score1, Score score2, Score score3, Score score4, String expectedPlayer) { + //given + Card card1 = Card.from(Score.A, Suit.DIAMOND); + Card card2 = Card.from(Score.J, Suit.DIAMOND); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Card card3 = Card.from(score1, Suit.CLUB); + Card card4 = Card.from(score2, Suit.CLUB); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + Card card5 = Card.from(score3, Suit.HEART); + Card card6 = Card.from(score4, Suit.HEART); + Person player3 = new Player("player3", new GivenCards(Arrays.asList(card5, card6))); + Players players = new Players(Arrays.asList(player1, player2, player3)); + + //when + String player = players.getCurrentPlayer(); + + //then + assertThat(player).isEqualTo(expectedPlayer); + } + + @Test + @DisplayName("인자로 받은 플레이어의 카드를 반환한다.") + void getCards() { + //given + String name = "pobi"; + Card card1 = Card.from(Score.A, Suit.HEART); + Card card2 = Card.from(Score.A, Suit.CLUB); + Person player = new Player(name, new GivenCards(Arrays.asList(card1, card2))); + Players players = new Players(Collections.singletonList(player)); + + //when + GivenCards cards = players.getCards(name); + + //then + assertThat(cards.list()).hasSize(2) + .containsOnly(card1, card2); + } + + @ParameterizedTest + @CsvSource(value = {"A, TEN, A, NINE, 21, 20", "TEN, TEN, A, A, 20, 12"}) + @DisplayName("플레이어들의 점수를 반환한다.") + void getPlayerScores(Score score1, Score score2, Score score3, Score score4, int expectedSum1, int expectedSum2) { + //given + Card card1 = Card.from(score1, Suit.CLUB); + Card card2 = Card.from(score2, Suit.CLUB); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Card card3 = Card.from(score3, Suit.HEART); + Card card4 = Card.from(score4, Suit.HEART); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + Players players = new Players(Arrays.asList(player1, player2)); + + //when + List playerScores = players.getPlayerScores(); + + //then + assertThat(playerScores).hasSize(2) + .containsOnly(expectedSum1, expectedSum2); + } + + @ParameterizedTest + @CsvSource(value = {"TEN, FIVE, SIX, 1, 1", "TEN, TEN, TWO, 1, -1"}) + @DisplayName("자신의 카드의 합이 크거나 블랙잭일 경우 1, 작을 경우 -1을 반환한다.") + void getResults_with_win_and_lose(Score score1, Score score2, Score score3, int expectedResult1, int expectedResult2) { + //given + Card card1 = Card.from(Score.A, Suit.CLUB); + Card card2 = Card.from(Score.J, Suit.CLUB); + Person player1 = new Player("player1", new GivenCards(Arrays.asList(card1, card2))); + Card card3 = Card.from(score1, Suit.HEART); + Card card4 = Card.from(score2, Suit.HEART); + Card card5 = Card.from(score3, Suit.HEART); + Person player2 = new Player("player2", new GivenCards(Arrays.asList(card3, card4))); + player2.hit(card5); + Card card6 = Card.from(Score.A, Suit.DIAMOND); + Card card7 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards dealerCards = new GivenCards(Arrays.asList(card6, card7)); + Players players = new Players(Arrays.asList(player1, player2)); + + //when + List results = players.getResults(dealerCards); + + //then + assertThat(results).hasSize(2) + .containsOnly(expectedResult1, expectedResult2); + } + + @Test + @DisplayName("자신의 합과 같을 경우, 0을 반환한다.") + void getResults_with_draw() { + //given + Card card1 = Card.from(Score.A, Suit.CLUB); + Card card2 = Card.from(Score.FIVE, Suit.CLUB); + Card card3 = Card.from(Score.FIVE, Suit.CLUB); + Person player = new Player("player", new GivenCards(Arrays.asList(card1, card2))); + player.hit(card3); + Card card4 = Card.from(Score.A, Suit.DIAMOND); + Card card5 = Card.from(Score.EIGHT, Suit.DIAMOND); + Card card6 = Card.from(Score.TWO, Suit.DIAMOND); + GivenCards dealerCards = new GivenCards(Arrays.asList(card4, card5, card6)); + Players players = new Players(Collections.singletonList(player)); + + //when + List results = players.getResults(dealerCards); + + //then + assertThat(results).hasSize(1) + .containsOnly(0); + } +} diff --git a/src/test/java/blackjack/domain/state/InitTest.java b/src/test/java/blackjack/domain/state/InitTest.java new file mode 100644 index 0000000..138403a --- /dev/null +++ b/src/test/java/blackjack/domain/state/InitTest.java @@ -0,0 +1,71 @@ +package blackjack.domain.state; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class InitTest { + + @Test + @DisplayName("모든 카드 목록을 반환한다.") + void getCards() { + ///given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State init = createInitState(givenCards); + + //when + GivenCards cards = init.getCards(); + + //then + assertThat(cards).isEqualTo(givenCards); + } + + @Test + @DisplayName("게임 진행 중 카드의 합을 요청할 경우, 예외가 발생한다.") + void sum() { + ///given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State init = createInitState(givenCards); + + //when + int sum = init.sum(); + + //then + assertThat(sum).isEqualTo(20); + } + + private Init createInitState(GivenCards givenCards) { + return new Init(givenCards) { + @Override + public int compare(GivenCards givenCards) { + return 0; + } + + @Override + public State hit(Card card) { + return null; + } + + @Override + public State stay() { + return null; + } + + @Override + public boolean isFinished() { + return false; + } + }; + } +} diff --git a/src/test/java/blackjack/domain/state/finished/BlackjackTest.java b/src/test/java/blackjack/domain/state/finished/BlackjackTest.java new file mode 100644 index 0000000..8207670 --- /dev/null +++ b/src/test/java/blackjack/domain/state/finished/BlackjackTest.java @@ -0,0 +1,34 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +class BlackjackTest { + + @Test + @DisplayName("승리를 의미하는 1을 반환한다.") + void result() { + //given + Card card1 = Card.from(Score.EIGHT, Suit.CLUB); + Card card2 = Card.from(Score.EIGHT, Suit.HEART); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + State blackjack = new Blackjack(myCards); + GivenCards otherCards = new GivenCards(Collections.emptyList()); + + //when + int result = blackjack.compare(otherCards); + + //then + assertThat(result).isEqualTo(1); + } +} diff --git a/src/test/java/blackjack/domain/state/finished/BurstTest.java b/src/test/java/blackjack/domain/state/finished/BurstTest.java new file mode 100644 index 0000000..5fc59d6 --- /dev/null +++ b/src/test/java/blackjack/domain/state/finished/BurstTest.java @@ -0,0 +1,34 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +class BurstTest { + + @Test + @DisplayName("패배를 의미하는 -1을 반환한다.") + void result() { + //given + Card card1 = Card.from(Score.EIGHT, Suit.CLUB); + Card card2 = Card.from(Score.EIGHT, Suit.HEART); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + State burst = new Burst(myCards); + GivenCards otherCards = new GivenCards(Collections.emptyList()); + + //when + int result = burst.compare(otherCards); + + //then + assertThat(result).isEqualTo(-1); + } +} diff --git a/src/test/java/blackjack/domain/state/finished/FinishedTest.java b/src/test/java/blackjack/domain/state/finished/FinishedTest.java new file mode 100644 index 0000000..4923e27 --- /dev/null +++ b/src/test/java/blackjack/domain/state/finished/FinishedTest.java @@ -0,0 +1,76 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class FinishedTest { + + @Test + @DisplayName("참여 종료 상태에서 카드 발급 요청을 할 경우 예외가 발생한다.") + void hit() { + //given + State finishedState = createFinishedState(); + Card card = Card.from(Score.A, Suit.CLUB); + + //when //then + assertThatThrownBy(() -> finishedState.hit(card)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("참여 종료 후에는 추가 카드 요청을 할 수 없습니다."); + } + + @Test + @DisplayName("참여 종료 상태에서 카드 발급 거부를 할 경우 예외가 발생한다.") + void stay() { + //given + State finishedState = createFinishedState(); + + //when //then + assertThatThrownBy(finishedState::stay) + .isInstanceOf(IllegalStateException.class) + .hasMessage("참여 종료 후에는 추가 카드 요청 거부를 할 수 없습니다."); + } + + @Test + @DisplayName("참여 종료 상태에서 참여 종료 여부를 물어볼 경우, 참을 반환한다.") + void isFinished() { + //given + State finishedState = createFinishedState(); + + //when + boolean finished = finishedState.isFinished(); + + //then + assertThat(finished).isTrue(); + } + + private State createFinishedState() { + GivenCards givenCards = new GivenCards(Collections.singletonList(Card.from(Score.A, Suit.CLUB))); + + return new Finished(givenCards) { + @Override + public int compare(GivenCards competitorCards) { + return 0; + } + + @Override + public int sum() { + return 0; + } + + @Override + public GivenCards getCards() { + return null; + } + }; + } +} diff --git a/src/test/java/blackjack/domain/state/finished/StayTest.java b/src/test/java/blackjack/domain/state/finished/StayTest.java new file mode 100644 index 0000000..1a8812f --- /dev/null +++ b/src/test/java/blackjack/domain/state/finished/StayTest.java @@ -0,0 +1,74 @@ +package blackjack.domain.state.finished; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class StayTest { + + @ParameterizedTest + @CsvSource(value = {"FIVE, FOUR", "TEN, TWO"}) + @DisplayName("다른 카드의 합보다 크거나 다른 카드의 합이 21을 초과할 경우, 승리를 의미하는 1을 반환한다.") + void result_win(Score score1, Score score2) { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + State stay = new Stay(myCards); + Card card3 = Card.from(Score.TEN, Suit.DIAMOND); + Card card4 = Card.from(score1, Suit.CLUB); + Card card5 = Card.from(score2, Suit.CLUB); + GivenCards otherCards = new GivenCards(Arrays.asList(card3, card4, card5)); + + //when + int result = stay.compare(otherCards); + + //then + assertThat(result).isEqualTo(1); + } + + @Test + @DisplayName("다른 카드의 합보다 작을 경우, 패배를 의미하는 -1을 반환한다.") + void result_lose() { + //given + Card card1 = Card.from(Score.EIGHT, Suit.CLUB); + Card card2 = Card.from(Score.EIGHT, Suit.HEART); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + State stay = new Stay(myCards); + Card card3 = Card.from(Score.NINE, Suit.DIAMOND); + GivenCards otherCards = new GivenCards(Arrays.asList(card1, card3)); + + //when + int result = stay.compare(otherCards); + + //then + assertThat(result).isEqualTo(-1); + } + + @Test + @DisplayName("다른 카드의 합과 같은 경우, 무승부를 의미하는 0을 반환한다.") + void result_draw() { + //given + Card card1 = Card.from(Score.EIGHT, Suit.CLUB); + Card card2 = Card.from(Score.EIGHT, Suit.HEART); + GivenCards myCards = new GivenCards(Arrays.asList(card1, card2)); + State stay = new Stay(myCards); + GivenCards otherCards = new GivenCards(Arrays.asList(card1, card2)); + + //when + int result = stay.compare(otherCards); + + //then + assertThat(result).isZero(); + } +} diff --git a/src/test/java/blackjack/domain/state/running/HitTest.java b/src/test/java/blackjack/domain/state/running/HitTest.java new file mode 100644 index 0000000..6def088 --- /dev/null +++ b/src/test/java/blackjack/domain/state/running/HitTest.java @@ -0,0 +1,85 @@ +package blackjack.domain.state.running; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import blackjack.domain.state.finished.Burst; +import blackjack.domain.state.finished.Stay; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class HitTest { + + @Test + @DisplayName("지급받은 카드 포함 합이 21을 초과할 경우, Burst 상태를 반환한다.") + void hit_return_burst_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State hit = new Hit(givenCards); + Card newCard = Card.from(Score.TWO, Suit.CLUB); + + //when + State state = hit.hit(newCard); + + //then + assertThat(state).isInstanceOf(Burst.class); + } + + @Test + @DisplayName("지급받은 카드 포함 합이 21 미만일 경우, Hit 상태를 반환한다.") + void hit_return_itself() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State hit = new Hit(givenCards); + Card newCard = Card.from(Score.A, Suit.CLUB); + + //when + State state = hit.hit(newCard); + + //then + assertThat(state).isInstanceOf(Hit.class); + } + + @Test + @DisplayName("지급받은 카드 포함 합이 21일 경우, Stay 상태를 반환한다.") + void hit_return_stay_state() { + //given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.NINE, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State hit = new Hit(givenCards); + Card newCard = Card.from(Score.TWO, Suit.CLUB); + + //when + State state = hit.hit(newCard); + + //then + assertThat(state).isInstanceOf(Stay.class); + } + + @Test + @DisplayName("Stay 상태를 반환한다.") + void stay() { + ///given + Card card1 = Card.from(Score.TEN, Suit.CLUB); + Card card2 = Card.from(Score.TEN, Suit.HEART); + GivenCards givenCards = new GivenCards(Arrays.asList(card1, card2)); + State hit = new Hit(givenCards); + + //when + State state = hit.stay(); + + //then + assertThat(state).isInstanceOf(Stay.class); + } +} diff --git a/src/test/java/blackjack/domain/state/running/RunningTest.java b/src/test/java/blackjack/domain/state/running/RunningTest.java new file mode 100644 index 0000000..9a5955f --- /dev/null +++ b/src/test/java/blackjack/domain/state/running/RunningTest.java @@ -0,0 +1,62 @@ +package blackjack.domain.state.running; + +import blackjack.domain.card.Card; +import blackjack.domain.card.GivenCards; +import blackjack.domain.enums.Score; +import blackjack.domain.enums.Suit; +import blackjack.domain.state.State; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class RunningTest { + + @Test + @DisplayName("게임 진행 중 참여 종료 여부를 물어볼 경우, 거짓을 반환한다.") + void isFinished() { + //given + State runningState = createRunningState(); + + //when + boolean finished = runningState.isFinished(); + + //then + assertThat(finished).isFalse(); + } + + @Test + @DisplayName("게임 진행 중 게임 결과를 요청할 경우, 예외가 발생한다.") + void result() { + //given + State runningState = createRunningState(); + + //when //then + assertThatThrownBy(() -> runningState.compare(new GivenCards(Collections.emptyList()))) + .hasMessage("게임 진행 중에는 결과를 알 수 없습니다."); + } + + private State createRunningState() { + GivenCards givenCards = new GivenCards(Collections.singletonList(Card.from(Score.A, Suit.CLUB))); + + return new Running(givenCards) { + @Override + public State hit(Card card) { + return null; + } + + @Override + public State stay() { + return null; + } + + @Override + public GivenCards getCards() { + return null; + } + }; + } +} diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt deleted file mode 100644 index e69de29..0000000