From d37008f62c83a95933199b1a2e15d2c47c17184f Mon Sep 17 00:00:00 2001 From: Seokmyung Ham Date: Tue, 12 Mar 2024 11:10:58 +0900 Subject: [PATCH 01/21] =?UTF-8?q?[1=EB=8B=A8=EA=B3=84=20-=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=EC=9E=AD=20=EA=B2=8C=EC=9E=84=20=EC=8B=A4=ED=96=89]?= =?UTF-8?q?=20=EC=9E=AC=EC=A6=88(=ED=95=A8=EC=84=9D=EB=AA=85)=20=EB=AF=B8?= =?UTF-8?q?=EC=85=98=20=EC=A0=9C=EC=B6=9C=ED=95=A9=EB=8B=88=EB=8B=A4.=20(#?= =?UTF-8?q?636)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(README): 기능 요구 사항 작성 Co-authored-by: seokmyungham * feat: 카드 문양과 숫자에 대한 Enum 클래스 생성 Co-authored-by: seokmyungham * feat(Deck): 모든 카드를 가지는 Deck 클래스 및 테스트 구현 Co-authored-by: seokmyungham * style(DeckTest): 중복 코드 제거 Co-authored-by: seokmyungham * feat(BlackJackGamer): 딜러와 플레이어의 공통 추상 클래스 생성 Co-authored-by: seokmyungham * feat(Dealer): BlackJackGamer를 상속받는 딜러 클래스 생성과 메서드 재정의 Co-authored-by: seokmyungham * feat(Player): BlackJackGamer를 상속받는 플레이어 클래스 생성과 메서드 재정의 Co-authored-by: seokmyungham * feat(Name): 문자열 이름을 포장하는 클래스 생성 Co-authored-by: seokmyungham * feat(Players): Player의 일급 컬렉션 생성 Co-authored-by: seokmyungham * refactor: 예외 메시지 추가 및 테스트 수정 Co-authored-by: seokmyungham * test(NameTest): 정상 입력에 대한 테스트 추가 Co-authored-by: seokmyungham * test(PlayersTest): 정상 입력에 대한 테스트 추가 Co-authored-by: seokmyungham * feat(Player): 딜러의 점수를 입력받아 플레이어의 승패 여부를 결정하는 기능 추가 Co-authored-by: seokmyungham * feat(Hand): 참여자의 카드 리스트에 대한 일급 컬렉션 생성 Co-authored-by: seokmyungham * refactor(BlackjackGamer): Hand를 사용하도록 수정 Co-authored-by: seokmyungham * refactor(Dealer, Player): 생성자 및 메서드 수정 Co-authored-by: seokmyungham * feat(GameResult): 승,패를 표현하는 Enum 클래스 생성 Co-authored-by: seokmyungham * feat: DTO 생성 및 각 도메인에 DTO 생성 로직 추가 Co-authored-by: seokmyungham * refactor(Hand): 카드 숫자의 합계를 구하는 메서드 세분화 및 상수 추가 Co-authored-by: seokmyungham * style(Dealer): 상수 추가 및 dto 생성 메서드명 수정 Co-authored-by: seokmyungham * style(Player): 매직 넘버 상수화 Co-authored-by: seokmyungham * feat(Players): 전체 플레이어의 패를 초기화 하는 기능 및 dto 생성 기능 추가 Co-authored-by: seokmyungham * feat(GameResult): 패배인지 확인하는 기능 및 getter 추가 Co-authored-by: seokmyungham * feat(InputView): 입력을 받아들이는 InputView 클래스 생성 Co-authored-by: seokmyungham * feat(OutputView): 출력을 담당하는 OutputView 클래스 생성 Co-authored-by: seokmyungham * feat(BlackjackController): 블랙잭 게임 흐름을 제어하는 컨트롤러 클래스 생성 Co-authored-by: seokmyungham * style: 출력 요구사항에 맞춰 빈 줄 출력 포맷 수정 Co-authored-by: seokmyungham * feat(Application): 컨트롤러를 생성하고 호출하여 게임을 시작하는 클래스 생성 Co-authored-by: seokmyungham * docs(README): 기능 요구 사항 정리 Co-authored-by: seokmyungham * refactor(BlackjackController): 명령어 상수를 별도의 view Enum으로 분리 및 사용 * refactor(Card): 출력에 의존적인 CardNumber, CardShape을 수정하고 view 패키지에 Enum 추가 * refactor(GameResult): 기존 출력에 의존적이던 필드 문자열을 제거 및 view enum으로 분리 * refactor: 기존 도메인 내에 존재하던 Dto 변환 로직을 Dto 내부로 이동 및 리팩토링 * refactor(Deck): 테스트 목적의 List를 파라미터로 받는 생성자 개방 * test(CardTest): eqauls&hashCode 테스트 추가 * refactor(PlayersTest): 가독성 향상을 위해 테스트 코드 리팩토링 * test(PlayersTest): 경계 값 테스트를 위해 테스트케이스 수정 * feat(Command): 사용자 입력 명령어를 별도의 Enum 클래스로 분리 * style(Players): getter 메서드의 위치를 맨 밑으로 이동 --------- Co-authored-by: 이상진 --- README.md | 39 +++++- src/main/java/blackjack/Application.java | 11 ++ .../controller/BlackjackController.java | 111 ++++++++++++++++++ src/main/java/blackjack/domain/card/Card.java | 47 ++++++++ .../blackjack/domain/card/CardNumber.java | 28 +++++ .../java/blackjack/domain/card/CardShape.java | 9 ++ src/main/java/blackjack/domain/card/Deck.java | 36 ++++++ .../domain/gamer/BlackjackGamer.java | 47 ++++++++ .../java/blackjack/domain/gamer/Dealer.java | 16 +++ .../blackjack/domain/gamer/GameResult.java | 11 ++ .../java/blackjack/domain/gamer/Hand.java | 68 +++++++++++ .../java/blackjack/domain/gamer/Name.java | 12 ++ .../java/blackjack/domain/gamer/Player.java | 27 +++++ .../java/blackjack/domain/gamer/Players.java | 60 ++++++++++ src/main/java/blackjack/dto/CardDto.java | 12 ++ .../blackjack/dto/DealerInitialHandDto.java | 14 +++ .../java/blackjack/dto/DealerResultDto.java | 17 +++ src/main/java/blackjack/dto/GamerHandDto.java | 21 ++++ .../java/blackjack/dto/GamersHandDto.java | 15 +++ .../blackjack/dto/PlayerGameResultsDto.java | 19 +++ src/main/java/blackjack/view/InputView.java | 25 ++++ src/main/java/blackjack/view/OutputView.java | 110 +++++++++++++++++ .../view/object/CardNumberOutput.java | 37 ++++++ .../view/object/CardShapeOutput.java | 28 +++++ .../java/blackjack/view/object/Command.java | 26 ++++ .../view/object/GameResultOutput.java | 26 ++++ .../java/blackjack/domain/card/CardTest.java | 19 +++ .../java/blackjack/domain/card/DeckTest.java | 41 +++++++ .../blackjack/domain/gamer/DealerTest.java | 39 ++++++ .../java/blackjack/domain/gamer/HandTest.java | 51 ++++++++ .../java/blackjack/domain/gamer/NameTest.java | 26 ++++ .../blackjack/domain/gamer/PlayerTest.java | 104 ++++++++++++++++ .../blackjack/domain/gamer/PlayersTest.java | 45 +++++++ 33 files changed, 1195 insertions(+), 2 deletions(-) create mode 100644 src/main/java/blackjack/Application.java create mode 100644 src/main/java/blackjack/controller/BlackjackController.java create mode 100644 src/main/java/blackjack/domain/card/Card.java create mode 100644 src/main/java/blackjack/domain/card/CardNumber.java create mode 100644 src/main/java/blackjack/domain/card/CardShape.java create mode 100644 src/main/java/blackjack/domain/card/Deck.java create mode 100644 src/main/java/blackjack/domain/gamer/BlackjackGamer.java create mode 100644 src/main/java/blackjack/domain/gamer/Dealer.java create mode 100644 src/main/java/blackjack/domain/gamer/GameResult.java create mode 100644 src/main/java/blackjack/domain/gamer/Hand.java create mode 100644 src/main/java/blackjack/domain/gamer/Name.java create mode 100644 src/main/java/blackjack/domain/gamer/Player.java create mode 100644 src/main/java/blackjack/domain/gamer/Players.java create mode 100644 src/main/java/blackjack/dto/CardDto.java create mode 100644 src/main/java/blackjack/dto/DealerInitialHandDto.java create mode 100644 src/main/java/blackjack/dto/DealerResultDto.java create mode 100644 src/main/java/blackjack/dto/GamerHandDto.java create mode 100644 src/main/java/blackjack/dto/GamersHandDto.java create mode 100644 src/main/java/blackjack/dto/PlayerGameResultsDto.java create mode 100644 src/main/java/blackjack/view/InputView.java create mode 100644 src/main/java/blackjack/view/OutputView.java create mode 100644 src/main/java/blackjack/view/object/CardNumberOutput.java create mode 100644 src/main/java/blackjack/view/object/CardShapeOutput.java create mode 100644 src/main/java/blackjack/view/object/Command.java create mode 100644 src/main/java/blackjack/view/object/GameResultOutput.java create mode 100644 src/test/java/blackjack/domain/card/CardTest.java create mode 100644 src/test/java/blackjack/domain/card/DeckTest.java create mode 100644 src/test/java/blackjack/domain/gamer/DealerTest.java create mode 100644 src/test/java/blackjack/domain/gamer/HandTest.java create mode 100644 src/test/java/blackjack/domain/gamer/NameTest.java create mode 100644 src/test/java/blackjack/domain/gamer/PlayerTest.java create mode 100644 src/test/java/blackjack/domain/gamer/PlayersTest.java diff --git a/README.md b/README.md index 556099c4de3..e432c782c79 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,41 @@ 블랙잭 미션 저장소 -## 우아한테크코스 코드리뷰 +## 기능 요구 사항 -- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) +### 게임 + +- [x] 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 쪽이 승리한다. +- [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다. + - [x] 이후 플레이어와 딜러의 카드를 출력한다. + - [x] 단, 딜러의 카드는 하나만 출력한다. +- [x] 플레이어는 카드의 숫자 합이 21을 초과하지 않는다면 카드를 원하는 만큼 다시 뽑을 수 있다. + - [x] 새로 받을 때 마다 해당 플레이어의 카드를 출력한다. +- [x] 플레이어가 카드를 다 받으면 딜러의 카드를 확인한다. +- [x] 딜러의 카드 합이 17 이상이 될 때 까지 카드를 받는다. +- [x] 딜러와 플레이어의 카드, 결과와 최종 승패를 출력한다. + +### 카드 + +- [x] 클로버, 스페이드, 하트, 다이아몬드 모양을 가진다. +- [x] 카드는 2부터 10까지의 숫자와 Ace, King, Queen, Jack으로 이루어져 있다. +- [x] King, Queen, Jack은 10으로 계산한다. +- [x] ACE는 1 또는 11로 계산할 수 있다. + +### 딜러, 플레이어 공통 + +- [x] 최소 1글자, 최대 5글자의 이름을 가진다. +- [x] ACE 카드를 가지는 경우, 일단 11로 계산한 뒤, 합이 21을 초과하면 1로 계산한다. +- [x] 현재 가진 카드 숫자의 합을 기준으로 카드를 더 받을 수 있는지 결정한다. + - [x] 딜러는 숫자의 합이 16 이하이면 카드를 더 받을 수 있다. + - [x] 플레이어는 숫자의 합이 21 이하이면 카드를 더 받을 수 있다. + +### 플레이어 + +- [x] 플레이어의 이름은 중복될 수 없다. +- [x] 플레이어는 최소 2명부터 최대 8명까지 가능하다. +- [x] 딜러의 점수를 입력받아 승,패를 결정한다. + - [x] 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다. + - [x] 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우 패배한다. + - [x] 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다. + - [x] 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 크면 승리한다. diff --git a/src/main/java/blackjack/Application.java b/src/main/java/blackjack/Application.java new file mode 100644 index 00000000000..2ddbf1df987 --- /dev/null +++ b/src/main/java/blackjack/Application.java @@ -0,0 +1,11 @@ +package blackjack; + +import blackjack.controller.BlackjackController; + +public class Application { + + public static void main(String[] args) { + BlackjackController blackjackController = new BlackjackController(); + 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 00000000000..feb65f55e8b --- /dev/null +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -0,0 +1,111 @@ +package blackjack.controller; + +import blackjack.domain.card.Deck; +import blackjack.domain.gamer.Dealer; +import blackjack.domain.gamer.GameResult; +import blackjack.domain.gamer.Name; +import blackjack.domain.gamer.Player; +import blackjack.domain.gamer.Players; +import blackjack.dto.DealerInitialHandDto; +import blackjack.dto.DealerResultDto; +import blackjack.dto.GamerHandDto; +import blackjack.dto.GamersHandDto; +import blackjack.dto.PlayerGameResultsDto; +import blackjack.view.InputView; +import blackjack.view.OutputView; +import blackjack.view.object.Command; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class BlackjackController { + + private final InputView inputView; + private final OutputView outputView; + + public BlackjackController() { + this.inputView = new InputView(); + this.outputView = new OutputView(); + } + + public void run() { + Players players = getPlayers(); + Dealer dealer = new Dealer(); + Deck deck = new Deck(); + deck.shuffle(); + + setUpInitialHands(players, deck, dealer); + distributeCardToPlayers(players, deck); + distributeCardToDealer(dealer, deck); + printAllGamerScores(dealer, players); + printResult(dealer, players); + } + + private Players getPlayers() { + List playerNames = inputView.receivePlayerNames(); + + return new Players(playerNames); + } + + private void setUpInitialHands(Players players, Deck deck, Dealer dealer) { + players.initAllPlayersCard(deck); + dealer.initCard(deck); + printInitialHands(players, dealer); + } + + private void printInitialHands(Players players, Dealer dealer) { + DealerInitialHandDto dealerInitialHandDto = DealerInitialHandDto.fromDealer(dealer); + GamersHandDto playersInitialHandDto = GamersHandDto.fromPlayers(players); + + outputView.printInitialHands(dealerInitialHandDto, playersInitialHandDto); + } + + private void distributeCardToPlayers(Players players, Deck deck) { + for (Player player : players.getPlayers()) { + distributeCardToPlayer(deck, player); + } + } + + private void distributeCardToPlayer(Deck deck, Player player) { + while (canDistribute(player)) { + player.addCard(deck.draw()); + outputView.printPlayerHand(GamerHandDto.fromBlackjackGamer(player)); + } + } + + private boolean canDistribute(Player player) { + return player.canReceiveCard() && Command.isHit(getCommand(player)); + } + + private Command getCommand(Player player) { + return inputView.receiveCommand(player.getName().value()); + } + + private void distributeCardToDealer(Dealer dealer, Deck deck) { + while (dealer.canReceiveCard()) { + dealer.addCard(deck.draw()); + outputView.printDealerMessage(dealer.getName().value()); + } + } + + private void printAllGamerScores(Dealer dealer, Players players) { + outputView.printEmptyLine(); + outputView.printScore(GamerHandDto.fromBlackjackGamer(dealer), dealer.getScore()); + printPlayersScores(players); + } + + private void printPlayersScores(Players players) { + for (Player player : players.getPlayers()) { + outputView.printScore(GamerHandDto.fromBlackjackGamer(player), player.getScore()); + } + } + + private void printResult(Dealer dealer, Players players) { + Map playerGameResults = players.collectPlayerGameResults(dealer.getScore()); + PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerGameResults(playerGameResults); + List playerResults = new ArrayList<>(playerGameResultsDto.resultMap().values()); + DealerResultDto dealerResultDto = DealerResultDto.fromPlayerResults(playerResults); + + outputView.printResult(dealerResultDto, playerGameResultsDto); + } +} 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 00000000000..8a649540af7 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Card.java @@ -0,0 +1,47 @@ +package blackjack.domain.card; + +import java.util.Objects; + +public class Card { + + private final CardShape cardShape; + private final CardNumber cardNumber; + + public Card(CardShape cardShape, CardNumber cardNumber) { + this.cardShape = cardShape; + this.cardNumber = cardNumber; + } + + public boolean isAce() { + return cardNumber == CardNumber.ACE; + } + + public int getNumberValue() { + return cardNumber.getValue(); + } + + public CardShape getCardShape() { + return cardShape; + } + + public CardNumber getCardNumber() { + return cardNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Card card = (Card) o; + return cardShape == card.cardShape && cardNumber == card.cardNumber; + } + + @Override + public int hashCode() { + return Objects.hash(cardShape, cardNumber); + } +} diff --git a/src/main/java/blackjack/domain/card/CardNumber.java b/src/main/java/blackjack/domain/card/CardNumber.java new file mode 100644 index 00000000000..044a8bb42f7 --- /dev/null +++ b/src/main/java/blackjack/domain/card/CardNumber.java @@ -0,0 +1,28 @@ +package blackjack.domain.card; + +public enum CardNumber { + + ACE(11), + TWO(2), + THREE( 3), + FOUR(4), + FIVE(5), + SIX(6), + SEVEN(7), + EIGHT(8), + NINE(9), + TEN(10), + JACK(10), + QUEEN(10), + KING(10); + + private final int value; + + CardNumber(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/blackjack/domain/card/CardShape.java b/src/main/java/blackjack/domain/card/CardShape.java new file mode 100644 index 00000000000..35169f3e95b --- /dev/null +++ b/src/main/java/blackjack/domain/card/CardShape.java @@ -0,0 +1,9 @@ +package blackjack.domain.card; + +public enum CardShape { + + HEART, + CLOVER, + SPADE, + DIAMOND +} 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 00000000000..430a9aa9d38 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Deck.java @@ -0,0 +1,36 @@ +package blackjack.domain.card; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public class Deck { + + private final LinkedList cards; + + public Deck() { + this.cards = Arrays.stream(CardShape.values()) + .flatMap(cardShape -> Arrays.stream(CardNumber.values()) + .map(number -> new Card(cardShape, number))) + .collect(Collectors.toCollection(LinkedList::new)); + } + + public Deck(LinkedList cards) { + this.cards = cards; + } + + public void shuffle() { + Collections.shuffle(cards); + } + + public Card draw() { + return cards.poll(); + } + + public List getCards() { + return new ArrayList<>(cards); + } +} diff --git a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java new file mode 100644 index 00000000000..efab58e7fe7 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java @@ -0,0 +1,47 @@ +package blackjack.domain.gamer; + +import java.util.ArrayList; +import java.util.List; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Deck; +import blackjack.dto.CardDto; +import blackjack.dto.GamerHandDto; + +public abstract class BlackjackGamer { + + private final Name name; + private final Hand hand; + + public BlackjackGamer(Name name) { + this.name = name; + this.hand = new Hand(new ArrayList<>()); + } + + public abstract boolean canReceiveCard(); + + public void initCard(Deck deck) { + addCard(deck.draw()); + addCard(deck.draw()); + } + + public void addCard(Card card) { + hand.add(card); + } + + public Card getFirstCard() { + return hand.getFirstCard(); + } + + public int getScore() { + return hand.calculateScore(); + } + + public Name getName() { + return name; + } + + public Hand getHand() { + return hand; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Dealer.java b/src/main/java/blackjack/domain/gamer/Dealer.java new file mode 100644 index 00000000000..a69e0169554 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Dealer.java @@ -0,0 +1,16 @@ +package blackjack.domain.gamer; + +public class Dealer extends BlackjackGamer { + + private static final String DEFAULT_DEALER_NAME = "딜러"; + private static final int DEALER_DRAW_THRESHOLD = 16; + + public Dealer() { + super(new Name(DEFAULT_DEALER_NAME)); + } + + @Override + public boolean canReceiveCard() { + return getScore() <= DEALER_DRAW_THRESHOLD; + } +} diff --git a/src/main/java/blackjack/domain/gamer/GameResult.java b/src/main/java/blackjack/domain/gamer/GameResult.java new file mode 100644 index 00000000000..a7d6d085459 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/GameResult.java @@ -0,0 +1,11 @@ +package blackjack.domain.gamer; + +public enum GameResult { + + WIN, + LOSE; + + public static boolean isLose(GameResult gameResult) { + return LOSE == gameResult; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Hand.java b/src/main/java/blackjack/domain/gamer/Hand.java new file mode 100644 index 00000000000..41280fb21ea --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Hand.java @@ -0,0 +1,68 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Card; +import java.util.List; + +public class Hand { + + private static final int BLACKJACK_MAX_SCORE = 21; + private static final int ACE_VALUE_MODIFIER = 10; + + private final List cards; + + public Hand(List cards) { + this.cards = cards; + } + + public void add(Card card) { + cards.add(card); + } + + public int calculateScore() { + int sum = cards.stream() + .mapToInt(Card::getNumberValue) + .sum(); + + if (hasAce()) { + return adjustSumWithAce(sum); + } + return sum; + } + + private boolean hasAce() { + return cards.stream() + .anyMatch(Card::isAce); + } + + /** + * ACE가 포함된 경우, 21 이하이면서 가장 가능한 큰 값으로 계산한다. + */ + private int adjustSumWithAce(int sum) { + int aceCount = (int) cards.stream() + .filter(Card::isAce) + .count(); + + for (int i = 0; i < aceCount; i++) { + sum = adjust(sum); + } + return sum; + } + + /** + * Ace는 기본적으로 11로 계산되나, 합계가 21을 초과할 경우 1로 계산한다. + */ + private int adjust(int sum) { + if (sum > BLACKJACK_MAX_SCORE) { + sum -= ACE_VALUE_MODIFIER; + } + return sum; + } + + public Card getFirstCard() { + return cards.get(0); + } + + public List getCards() { + return cards; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Name.java b/src/main/java/blackjack/domain/gamer/Name.java new file mode 100644 index 00000000000..2974903b49c --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Name.java @@ -0,0 +1,12 @@ +package blackjack.domain.gamer; + +public record Name(String value) { + + private static final int MAX_NAME_LENGTH = 5; + + public Name { + if (value.isBlank() || value.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException("이름의 길이는 최소 1글자부터 최대 " + MAX_NAME_LENGTH + "글자까지 가능합니다."); + } + } +} diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java new file mode 100644 index 00000000000..4c36a73f221 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -0,0 +1,27 @@ +package blackjack.domain.gamer; + +public class Player extends BlackjackGamer { + + private static final int BLACKJACK_MAX_SCORE = 21; + + public Player(Name name) { + super(name); + } + + @Override + public boolean canReceiveCard() { + return getScore() <= BLACKJACK_MAX_SCORE; + } + + public GameResult isWin(int dealerScore) { + int playerScore = getScore(); + + if (playerScore > BLACKJACK_MAX_SCORE) { + return GameResult.LOSE; + } + if (dealerScore > BLACKJACK_MAX_SCORE || playerScore > dealerScore) { + return GameResult.WIN; + } + return GameResult.LOSE; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Players.java b/src/main/java/blackjack/domain/gamer/Players.java new file mode 100644 index 00000000000..646b54606be --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Players.java @@ -0,0 +1,60 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Deck; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class Players { + + private static final int MIN_PLAYER_COUNT = 2; + private static final int MAX_PLAYER_COUNT = 8; + + private final List players; + + public Players(List names) { + validateNames(names); + + this.players = names.stream() + .map(name -> new Player(new Name(name))) + .toList(); + } + + private void validateNames(List names) { + validateDuplicate(names); + validateCount(names.size()); + } + + private void validateCount(int count) { + if (count < MIN_PLAYER_COUNT || count > MAX_PLAYER_COUNT) { + throw new IllegalArgumentException( + "플레이어는 최소 " + MIN_PLAYER_COUNT + "명에서 최대 " + MAX_PLAYER_COUNT + "명까지 가능합니다" + ); + } + } + + private void validateDuplicate(List names) { + Set nonDuplicateNames = new HashSet<>(names); + + if (names.size() != nonDuplicateNames.size()) { + throw new IllegalArgumentException("이름은 중복될 수 없습니다."); + } + } + + public void initAllPlayersCard(Deck deck) { + players.forEach(player -> player.initCard(deck)); + } + + public Map collectPlayerGameResults(int dealerScore) { + Map playerGameResults = new LinkedHashMap<>(); + players.forEach(player -> playerGameResults.put(player.getName(), player.isWin(dealerScore))); + + return playerGameResults; + } + + public List getPlayers() { + return List.copyOf(players); + } +} diff --git a/src/main/java/blackjack/dto/CardDto.java b/src/main/java/blackjack/dto/CardDto.java new file mode 100644 index 00000000000..274c3a9b632 --- /dev/null +++ b/src/main/java/blackjack/dto/CardDto.java @@ -0,0 +1,12 @@ +package blackjack.dto; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardNumber; +import blackjack.domain.card.CardShape; + +public record CardDto(CardNumber cardNumber, CardShape cardShape) { + + public static CardDto fromCard(Card card) { + return new CardDto(card.getCardNumber(), card.getCardShape()); + } +} diff --git a/src/main/java/blackjack/dto/DealerInitialHandDto.java b/src/main/java/blackjack/dto/DealerInitialHandDto.java new file mode 100644 index 00000000000..37ef322c180 --- /dev/null +++ b/src/main/java/blackjack/dto/DealerInitialHandDto.java @@ -0,0 +1,14 @@ +package blackjack.dto; + +import blackjack.domain.card.Card; +import blackjack.domain.gamer.Dealer; + +public record DealerInitialHandDto(String name, CardDto firstCard) { + + public static DealerInitialHandDto fromDealer(Dealer dealer) { + String dealerName = dealer.getName().value(); + Card first = dealer.getFirstCard(); + + return new DealerInitialHandDto(dealerName, CardDto.fromCard(first)); + } +} diff --git a/src/main/java/blackjack/dto/DealerResultDto.java b/src/main/java/blackjack/dto/DealerResultDto.java new file mode 100644 index 00000000000..bd1a2fff80f --- /dev/null +++ b/src/main/java/blackjack/dto/DealerResultDto.java @@ -0,0 +1,17 @@ +package blackjack.dto; + +import blackjack.domain.gamer.GameResult; +import java.util.List; + +public record DealerResultDto(int winCount, int loseCount) { + + public static DealerResultDto fromPlayerResults(List playerResults) { + int dealerWinCount = (int) playerResults.stream() + .filter(GameResult::isLose) + .count(); + + int dealerLoseCount = playerResults.size() - dealerWinCount; + + return new DealerResultDto(dealerWinCount, dealerLoseCount); + } +} diff --git a/src/main/java/blackjack/dto/GamerHandDto.java b/src/main/java/blackjack/dto/GamerHandDto.java new file mode 100644 index 00000000000..52da8a1956a --- /dev/null +++ b/src/main/java/blackjack/dto/GamerHandDto.java @@ -0,0 +1,21 @@ +package blackjack.dto; + +import blackjack.domain.gamer.BlackjackGamer; +import blackjack.domain.gamer.Hand; +import java.util.List; + +public record GamerHandDto(String name, List gamerHand) { + + public static GamerHandDto fromBlackjackGamer(BlackjackGamer blackjackGamer) { + String playerName = blackjackGamer.getName().value(); + List gamerHand = convertHandToCardDto(blackjackGamer.getHand()); + + return new GamerHandDto(playerName, gamerHand); + } + + public static List convertHandToCardDto(Hand hand) { + return hand.getCards().stream() + .map(CardDto::fromCard) + .toList(); + } +} diff --git a/src/main/java/blackjack/dto/GamersHandDto.java b/src/main/java/blackjack/dto/GamersHandDto.java new file mode 100644 index 00000000000..e63516b98e7 --- /dev/null +++ b/src/main/java/blackjack/dto/GamersHandDto.java @@ -0,0 +1,15 @@ +package blackjack.dto; + +import blackjack.domain.gamer.Players; +import java.util.List; + +public record GamersHandDto(List gamersHandDto) { + + public static GamersHandDto fromPlayers(Players players) { + List gamerHandDtos = players.getPlayers().stream() + .map(GamerHandDto::fromBlackjackGamer) + .toList(); + + return new GamersHandDto(gamerHandDtos); + } +} diff --git a/src/main/java/blackjack/dto/PlayerGameResultsDto.java b/src/main/java/blackjack/dto/PlayerGameResultsDto.java new file mode 100644 index 00000000000..bacf83827e7 --- /dev/null +++ b/src/main/java/blackjack/dto/PlayerGameResultsDto.java @@ -0,0 +1,19 @@ +package blackjack.dto; + +import blackjack.domain.gamer.GameResult; +import blackjack.domain.gamer.Name; +import java.util.LinkedHashMap; +import java.util.Map; + +public record PlayerGameResultsDto(Map resultMap) { + + public static PlayerGameResultsDto fromPlayerGameResults(Map playerGameResults) { + Map gameResult = new LinkedHashMap<>(); + + for (Name playerName : playerGameResults.keySet()) { + gameResult.put(playerName.value(), playerGameResults.get(playerName)); + } + + return new PlayerGameResultsDto(gameResult); + } +} diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java new file mode 100644 index 00000000000..6adb3dcefcc --- /dev/null +++ b/src/main/java/blackjack/view/InputView.java @@ -0,0 +1,25 @@ +package blackjack.view; + +import blackjack.view.object.Command; +import java.util.List; +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner; + + public InputView() { + scanner = new Scanner(System.in); + } + + public List receivePlayerNames() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + String input = scanner.nextLine(); + return List.of(input.split(",")); + } + + public Command receiveCommand(String name) { + System.out.println(name + "는(은) 한장의 카드를 더 받겠습니까?(예는 y, 아니오: n)"); + return Command.convertInputToCommand(scanner.nextLine()); + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java new file mode 100644 index 00000000000..393e4d9edb2 --- /dev/null +++ b/src/main/java/blackjack/view/OutputView.java @@ -0,0 +1,110 @@ +package blackjack.view; + +import blackjack.dto.CardDto; +import blackjack.dto.DealerInitialHandDto; +import blackjack.dto.DealerResultDto; +import blackjack.dto.GamerHandDto; +import blackjack.dto.GamersHandDto; +import blackjack.dto.PlayerGameResultsDto; +import blackjack.view.object.CardNumberOutput; +import blackjack.view.object.CardShapeOutput; +import blackjack.view.object.GameResultOutput; +import java.util.List; + +public class OutputView { + + private static final String DEALER_DEFAULT_NAME = "딜러"; + + public void printInitialHands(DealerInitialHandDto dealerInitialHandDto, GamersHandDto playersInitialHandDto) { + System.out.printf("\n%s와 %s에게 2장을 나누었습니다.\n", dealerInitialHandDto.name(), + joinPlayerNames(playersInitialHandDto)); + + System.out.printf("%s 카드: %s\n", dealerInitialHandDto.name(), formatCardName(dealerInitialHandDto.firstCard())); + printAllPlayerHands(playersInitialHandDto); + } + + private String joinPlayerNames(GamersHandDto playersInitialHandDto) { + return String.join(", ", getPlayerNames(playersInitialHandDto)); + } + + private List getPlayerNames(GamersHandDto playersInitialHandDto) { + return playersInitialHandDto.gamersHandDto().stream().map(GamerHandDto::name).toList(); + } + + private String formatCardName(CardDto cardDto) { + return CardNumberOutput.convertNumberToOutput(cardDto.cardNumber()) + CardShapeOutput.convertShapeToOutput( + cardDto.cardShape()); + } + + private void printAllPlayerHands(GamersHandDto playersInitialHandDto) { + playersInitialHandDto.gamersHandDto().forEach(this::printPlayerHand); + System.out.println(); + } + + public void printPlayerHand(GamerHandDto playerHandDto) { + System.out.println(buildPlayerHand(playerHandDto)); + } + + private StringBuilder buildPlayerHand(GamerHandDto gamerHandDto) { + StringBuilder stringBuilder = new StringBuilder(); + return stringBuilder + .append(gamerHandDto.name()) + .append(" 카드: ") + .append(joinCardNames(gamerHandDto)); + } + + private String joinCardNames(GamerHandDto gamerHandDto) { + return String.join(", ", getCardNames(gamerHandDto)); + } + + private List getCardNames(GamerHandDto gamerHandDto) { + return gamerHandDto.gamerHand().stream().map(this::formatCardName).toList(); + } + + public void printDealerMessage(String dealerName) { + System.out.printf("\n%s는 16이하라 한장의 카드를 더 받았습니다.\n", dealerName); + } + + public void printScore(GamerHandDto gamerHandDto, int score) { + StringBuilder builder = buildPlayerHand(gamerHandDto) + .append(" - ") + .append("결과: ") + .append(score); + System.out.println(builder); + } + + public void printResult(DealerResultDto dealerResultDto, PlayerGameResultsDto playerGameResultsDto) { + System.out.println("\n## 최종 승패"); + printDealerResult(dealerResultDto); + printPlayerResults(playerGameResultsDto); + } + + private void printDealerResult(DealerResultDto dealerResultDto) { + int winCount = dealerResultDto.winCount(); + int loseCount = dealerResultDto.loseCount(); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder + .append(DEALER_DEFAULT_NAME) + .append(": "); + + if (winCount > 0) { + stringBuilder.append(winCount) + .append("승 "); + } + if (loseCount > 0) { + stringBuilder.append(loseCount) + .append("패"); + } + System.out.println(stringBuilder); + } + + private void printPlayerResults(PlayerGameResultsDto playerGameResultsDto) { + playerGameResultsDto.resultMap().forEach((name, result) -> + System.out.println(name + ": " + GameResultOutput.convertGameResultToOutput(result)) + ); + } + + public void printEmptyLine() { + System.out.println(); + } +} diff --git a/src/main/java/blackjack/view/object/CardNumberOutput.java b/src/main/java/blackjack/view/object/CardNumberOutput.java new file mode 100644 index 00000000000..03d4fa840f6 --- /dev/null +++ b/src/main/java/blackjack/view/object/CardNumberOutput.java @@ -0,0 +1,37 @@ +package blackjack.view.object; + +import blackjack.domain.card.CardNumber; +import java.util.Arrays; + +public enum CardNumberOutput { + + ACE(CardNumber.ACE ,"A"), + TWO(CardNumber.TWO, "2"), + THREE(CardNumber.THREE, "3"), + FOUR(CardNumber.FOUR, "4"), + FIVE(CardNumber.FIVE, "5"), + SIX(CardNumber.SIX, "6"), + SEVEN(CardNumber.SEVEN, "7"), + EIGHT(CardNumber.EIGHT, "8"), + NINE(CardNumber.NINE, "9"), + TEN(CardNumber.TEN, "10"), + JACK(CardNumber.JACK, "J"), + QUEEN(CardNumber.QUEEN, "Q"), + KING(CardNumber.KING, "K"); + + private final CardNumber cardNumber; + private final String output; + + CardNumberOutput(CardNumber cardNumber, String output) { + this.cardNumber = cardNumber; + this.output = output; + } + + public static String convertNumberToOutput(CardNumber cardNumber) { + return Arrays.stream(values()) + .filter(cardNumberOutput -> cardNumberOutput.cardNumber == cardNumber) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 카드 숫자입니다.")) + .output; + } +} diff --git a/src/main/java/blackjack/view/object/CardShapeOutput.java b/src/main/java/blackjack/view/object/CardShapeOutput.java new file mode 100644 index 00000000000..38b0374ce34 --- /dev/null +++ b/src/main/java/blackjack/view/object/CardShapeOutput.java @@ -0,0 +1,28 @@ +package blackjack.view.object; + +import blackjack.domain.card.CardShape; +import java.util.Arrays; + +public enum CardShapeOutput { + + HEART_OUTPUT(CardShape.HEART, "하트"), + CLOVER_OUTPUT(CardShape.CLOVER, "클로버"), + SPADE_OUTPUT(CardShape.SPADE, "스페이드"), + DIAMOND_OUTPUT(CardShape.DIAMOND, "다이아몬드"); + + private final CardShape cardShape; + private final String output; + + CardShapeOutput(CardShape cardShape, String output) { + this.cardShape = cardShape; + this.output = output; + } + + public static String convertShapeToOutput(CardShape cardShape) { + return Arrays.stream(values()) + .filter(cardShapeOutput -> cardShapeOutput.cardShape == cardShape) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 카드 문양입니다.")) + .output; + } +} diff --git a/src/main/java/blackjack/view/object/Command.java b/src/main/java/blackjack/view/object/Command.java new file mode 100644 index 00000000000..670cdbccf70 --- /dev/null +++ b/src/main/java/blackjack/view/object/Command.java @@ -0,0 +1,26 @@ +package blackjack.view.object; + +import java.util.Arrays; + +public enum Command { + + HIT("y"), + STAND("n"); + + private final String name; + + Command(String name) { + this.name = name; + } + + public static Command convertInputToCommand(String input) { + return Arrays.stream(values()) + .filter(command -> command.name.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("입력과 일치하는 명령어가 존재하지 않습니다.")); + } + + public static boolean isHit(Command command) { + return command == HIT; + } +} diff --git a/src/main/java/blackjack/view/object/GameResultOutput.java b/src/main/java/blackjack/view/object/GameResultOutput.java new file mode 100644 index 00000000000..c41a70e3b8d --- /dev/null +++ b/src/main/java/blackjack/view/object/GameResultOutput.java @@ -0,0 +1,26 @@ +package blackjack.view.object; + +import blackjack.domain.gamer.GameResult; +import java.util.Arrays; + +public enum GameResultOutput { + + WIN_OUTPUT(GameResult.WIN, "승"), + LOSE_OUTPUT(GameResult.LOSE, "패"); + + private final GameResult gameResult; + private final String output; + + GameResultOutput(GameResult gameResult, String output) { + this.gameResult = gameResult; + this.output = output; + } + + public static String convertGameResultToOutput(GameResult gameResult) { + return Arrays.stream(values()) + .filter(gameResultOutput -> gameResultOutput.gameResult == gameResult) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("일치하는 게임 결과가 존재하지 않아 문자열을 반환할 수 없습니다.")) + .output; + } +} 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 00000000000..3cb79391241 --- /dev/null +++ b/src/test/java/blackjack/domain/card/CardTest.java @@ -0,0 +1,19 @@ +package blackjack.domain.card; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Objects; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class CardTest { + + @Test + @DisplayName("equals & hashCode 재정의 테스트") + void equalsTest() { + Card card = new Card(CardShape.HEART, CardNumber.KING); + + assertThat(card).isEqualTo(new Card(CardShape.HEART, CardNumber.KING)); + assertThat(Objects.hash(card)).isEqualTo(Objects.hash(new Card(CardShape.HEART, CardNumber.KING))); + } +} 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 00000000000..358bd4d9f03 --- /dev/null +++ b/src/test/java/blackjack/domain/card/DeckTest.java @@ -0,0 +1,41 @@ +package blackjack.domain.card; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class DeckTest { + + private Deck mockDeck; + private Deck realDeck; + + @BeforeEach + void setUP() { + LinkedList cardList = new LinkedList<>(List.of( + new Card(CardShape.HEART, CardNumber.KING), new Card(CardShape.HEART, CardNumber.QUEEN), + new Card(CardShape.HEART, CardNumber.ACE), new Card(CardShape.HEART, CardNumber.TWO), + new Card(CardShape.DIAMOND, CardNumber.KING), new Card(CardShape.DIAMOND, CardNumber.QUEEN), + new Card(CardShape.DIAMOND, CardNumber.ACE), new Card(CardShape.DIAMOND, CardNumber.TWO))); + + mockDeck = new Deck(cardList); + realDeck = new Deck(); + } + + @Test + @DisplayName("카드 덱은 52장의 카드로 이루어져 있다.") + void deckSizeTest() { + assertThat(realDeck.getCards().size()).isEqualTo(52); + } + + @Test + @DisplayName("맨 위의 카드를 한 장 뽑는다.") + void drawTest() { + assertThat(mockDeck.draw()).isEqualTo(new Card(CardShape.HEART, CardNumber.KING)); + assertThat(mockDeck.draw()).isEqualTo(new Card(CardShape.HEART, CardNumber.QUEEN)); + assertThat(mockDeck.draw()).isEqualTo(new Card(CardShape.HEART, CardNumber.ACE)); + } +} diff --git a/src/test/java/blackjack/domain/gamer/DealerTest.java b/src/test/java/blackjack/domain/gamer/DealerTest.java new file mode 100644 index 00000000000..9c98fa3db06 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/DealerTest.java @@ -0,0 +1,39 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardNumber; +import blackjack.domain.card.CardShape; + +class DealerTest { + + Dealer dealer; + + @BeforeEach + void setUP() { + dealer = new Dealer(); + } + + @Test + @DisplayName("카드의 총합이 16 이하이면 카드를 받을 수 있다.") + void receiveCardTest() { + dealer.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + dealer.addCard(new Card(CardShape.HEART, CardNumber.SIX)); + + assertThat(dealer.canReceiveCard()).isTrue(); + } + + @Test + @DisplayName("카드의 총합이 16을 초과하면 카드를 받을 수 없다.") + void cantReceiveCardTest() { + dealer.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + dealer.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + + assertThat(dealer.canReceiveCard()).isFalse(); + } +} diff --git a/src/test/java/blackjack/domain/gamer/HandTest.java b/src/test/java/blackjack/domain/gamer/HandTest.java new file mode 100644 index 00000000000..9c2bbf6ea41 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/HandTest.java @@ -0,0 +1,51 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardNumber; +import blackjack.domain.card.CardShape; + +class HandTest { + + Hand hand; + + @Test + @DisplayName("ACE가 없을때의 숫자 합을 계산한다.") + void sumWithoutAceTest() { + hand = new Hand(List.of( + new Card(CardShape.CLOVER, CardNumber.KING), + new Card(CardShape.HEART, CardNumber.FIVE) + )); + + assertThat(hand.calculateScore()).isEqualTo(15); + } + + @Test + @DisplayName("숫자의 합이 21을 초과하는 경우, ACE를 1로 계산한다.") + void sumWithOneAceTest() { + hand = new Hand(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.KING), + new Card(CardShape.DIAMOND, CardNumber.KING) + )); + + assertThat(hand.calculateScore()).isEqualTo(21); + } + + @Test + @DisplayName("숫자의 합이 21을 초과하지 않으면, ACE를 11로 계산한다.") + void sumWithElevenAceTest() { + hand = new Hand(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.KING) + )); + + assertThat(hand.calculateScore()).isEqualTo(21); + } +} diff --git a/src/test/java/blackjack/domain/gamer/NameTest.java b/src/test/java/blackjack/domain/gamer/NameTest.java new file mode 100644 index 00000000000..453eeac6d21 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/NameTest.java @@ -0,0 +1,26 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class NameTest { + + @ParameterizedTest + @ValueSource(strings = {"a", "abcde"}) + @DisplayName("이름의 길이가 1글자에서 5글자인 경우 예외가 발생되지 않는다.") + void validNameLengthTest(String name) { + assertThatCode(() -> new Name(name)).doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"", "abcdef"}) + @DisplayName("이름의 길이가 0글자이거나, 5글자를 초과하면 예외가 발생된다.") + void invalidNameLengthTest(String name) { + assertThatThrownBy(() -> new Name(name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("이름의 길이는 최소 1글자부터 최대 5글자까지 가능합니다."); + } +} diff --git a/src/test/java/blackjack/domain/gamer/PlayerTest.java b/src/test/java/blackjack/domain/gamer/PlayerTest.java new file mode 100644 index 00000000000..5f1fee38edc --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/PlayerTest.java @@ -0,0 +1,104 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardNumber; +import blackjack.domain.card.CardShape; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class PlayerTest { + + Player player; + + @BeforeEach + void setUP() { + player = new Player(new Name("hogi")); + } + + @Nested + @DisplayName("카드를 받는 조건 테스트") + class CanReceiveCardTest { + + @Test + @DisplayName("카드의 총합이 21 이하이면 카드를 받을 수 있다.") + void receiveCardTest() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.SIX)); + player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); + + assertThat(player.canReceiveCard()).isTrue(); + } + + @Test + @DisplayName("카드의 총합이 21을 초과하면 카드를 받을 수 없다.") + void cantReceiveCardTest() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); + player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + + assertThat(player.canReceiveCard()).isFalse(); + } + } + + @Nested + @DisplayName("플레이어가 승리하는 경우의 수 테스트") + class IsWinTest { + + @Test + @DisplayName("플레이어 점수가 21 이하이고, 딜러의 점수보다 큰 경우 승리한다.") + void bustTest() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.FOUR)); + player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + + assertThat(player.isWin(20)).isEqualTo(GameResult.WIN); + } + + @Test + @DisplayName("플레이어 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다.") + void bustTest1() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.ACE)); + + assertThat(player.isWin(22)).isEqualTo(GameResult.WIN); + } + } + + @Nested + @DisplayName("플레이어가 패배하는 경우의 수 테스트") + class LoseTest { + + @Test + @DisplayName("점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다") + void bustTest2() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); + player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + + assertThat(player.isWin(21)).isEqualTo(GameResult.LOSE); + assertThat(player.isWin(22)).isEqualTo(GameResult.LOSE); + } + + @Test + @DisplayName("플레이어와 딜러의 점수가 모두 21 이하일 때, 딜러의 점수보다 낮으면 패배한다.") + void bustTest3() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.SIX)); + + assertThat(player.isWin(17)).isEqualTo(GameResult.LOSE); + } + + @Test + @DisplayName("플레이어와 딜러의 점수가 모두 21 이하이고 동점인 경우 플레이어가 패배한다.") + void bustTest4() { + player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); + player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + + assertThat(player.isWin(17)).isEqualTo(GameResult.LOSE); + } + } +} diff --git a/src/test/java/blackjack/domain/gamer/PlayersTest.java b/src/test/java/blackjack/domain/gamer/PlayersTest.java new file mode 100644 index 00000000000..06ecd10e521 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/PlayersTest.java @@ -0,0 +1,45 @@ +package blackjack.domain.gamer; + +import static java.util.List.*; +import static org.assertj.core.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PlayersTest { + + @Test + @DisplayName("유효한 입력에 대해서는 예외가 발생되지 않는다.") + void validPlayerNamesTest() { + assertThatCode(() -> new Players(List.of("a", "b"))) + .doesNotThrowAnyException(); + assertThatCode(() -> new Players(List.of("a", "b", "c", "d", "e", "f", "g", "h"))) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("플레이어의 이름은 중복을 허용하지 않는다.") + void duplicatePlayerNamesTest() { + assertThatThrownBy(() -> new Players(of("hogi", "sang", "hogi"))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("플레이어는 적어도 2명 이상이어야 한다.") + void minimumPlayerCountTest() { + assertThatThrownBy(() -> new Players(of("a"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어는 최소 2명에서 최대 8명까지 가능합니다"); + + } + + @Test + @DisplayName("플레이어는 최대 8명까지만 가능하다.") + void maximumPlayerCountTest() { + assertThatThrownBy(() -> new Players(of("a", "b", "c", "d", "e", "f", "g", "h", "g"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("이름은 중복될 수 없습니다."); + } +} From 75656d115a6e776d45b7e93090b09076b6458115 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Tue, 12 Mar 2024 16:30:32 +0900 Subject: [PATCH 02/21] =?UTF-8?q?refactor:=20=EC=B6=9C=EB=A0=A5=EC=97=90?= =?UTF-8?q?=20=EC=9D=98=EC=A1=B4=ED=95=98=EB=8A=94=20Dealer=20=EB=82=B4=20?= =?UTF-8?q?=EC=83=81=EC=88=98=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=B4=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BlackjackController.java | 23 +++--- .../domain/gamer/BlackjackGamer.java | 54 ++++++------- .../java/blackjack/domain/gamer/Dealer.java | 3 +- .../java/blackjack/domain/gamer/Player.java | 50 +++++++------ .../blackjack/dto/DealerInitialHandDto.java | 5 +- src/main/java/blackjack/dto/GamerHandDto.java | 21 ------ .../java/blackjack/dto/GamersHandDto.java | 15 ---- src/main/java/blackjack/dto/HandDto.java | 15 ++++ .../java/blackjack/dto/PlayerHandDto.java | 13 ++++ .../java/blackjack/dto/PlayersHandDto.java | 15 ++++ src/main/java/blackjack/view/OutputView.java | 75 ++++++++++++------- 11 files changed, 156 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/blackjack/dto/GamerHandDto.java delete mode 100644 src/main/java/blackjack/dto/GamersHandDto.java create mode 100644 src/main/java/blackjack/dto/HandDto.java create mode 100644 src/main/java/blackjack/dto/PlayerHandDto.java create mode 100644 src/main/java/blackjack/dto/PlayersHandDto.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index feb65f55e8b..1e1f96666a0 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -8,9 +8,10 @@ import blackjack.domain.gamer.Players; import blackjack.dto.DealerInitialHandDto; import blackjack.dto.DealerResultDto; -import blackjack.dto.GamerHandDto; -import blackjack.dto.GamersHandDto; +import blackjack.dto.HandDto; import blackjack.dto.PlayerGameResultsDto; +import blackjack.dto.PlayerHandDto; +import blackjack.dto.PlayersHandDto; import blackjack.view.InputView; import blackjack.view.OutputView; import blackjack.view.object.Command; @@ -55,7 +56,7 @@ private void setUpInitialHands(Players players, Deck deck, Dealer dealer) { private void printInitialHands(Players players, Dealer dealer) { DealerInitialHandDto dealerInitialHandDto = DealerInitialHandDto.fromDealer(dealer); - GamersHandDto playersInitialHandDto = GamersHandDto.fromPlayers(players); + PlayersHandDto playersInitialHandDto = PlayersHandDto.fromPlayers(players); outputView.printInitialHands(dealerInitialHandDto, playersInitialHandDto); } @@ -69,7 +70,7 @@ private void distributeCardToPlayers(Players players, Deck deck) { private void distributeCardToPlayer(Deck deck, Player player) { while (canDistribute(player)) { player.addCard(deck.draw()); - outputView.printPlayerHand(GamerHandDto.fromBlackjackGamer(player)); + outputView.printPlayerHand(PlayerHandDto.fromPlayer(player)); } } @@ -84,20 +85,22 @@ private Command getCommand(Player player) { private void distributeCardToDealer(Dealer dealer, Deck deck) { while (dealer.canReceiveCard()) { dealer.addCard(deck.draw()); - outputView.printDealerMessage(dealer.getName().value()); + outputView.printDealerMessage(); } } private void printAllGamerScores(Dealer dealer, Players players) { - outputView.printEmptyLine(); - outputView.printScore(GamerHandDto.fromBlackjackGamer(dealer), dealer.getScore()); + printDealerScore(dealer); printPlayersScores(players); } + private void printDealerScore(Dealer dealer) { + outputView.printEmptyLine(); + outputView.printDealerHandScore(HandDto.fromHand(dealer.getHand())); + } + private void printPlayersScores(Players players) { - for (Player player : players.getPlayers()) { - outputView.printScore(GamerHandDto.fromBlackjackGamer(player), player.getScore()); - } + outputView.printPlayersHandScore(PlayersHandDto.fromPlayers(players)); } private void printResult(Dealer dealer, Players players) { diff --git a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java index efab58e7fe7..7af7dba894e 100644 --- a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java +++ b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java @@ -1,47 +1,37 @@ package blackjack.domain.gamer; -import java.util.ArrayList; -import java.util.List; - import blackjack.domain.card.Card; import blackjack.domain.card.Deck; -import blackjack.dto.CardDto; -import blackjack.dto.GamerHandDto; +import java.util.ArrayList; public abstract class BlackjackGamer { - private final Name name; - private final Hand hand; - - public BlackjackGamer(Name name) { - this.name = name; - this.hand = new Hand(new ArrayList<>()); - } + private final Hand hand; - public abstract boolean canReceiveCard(); + public BlackjackGamer() { + this.hand = new Hand(new ArrayList<>()); + } - public void initCard(Deck deck) { - addCard(deck.draw()); - addCard(deck.draw()); - } + public abstract boolean canReceiveCard(); - public void addCard(Card card) { - hand.add(card); - } + public void initCard(Deck deck) { + addCard(deck.draw()); + addCard(deck.draw()); + } - public Card getFirstCard() { - return hand.getFirstCard(); - } + public void addCard(Card card) { + hand.add(card); + } - public int getScore() { - return hand.calculateScore(); - } + public Card getFirstCard() { + return hand.getFirstCard(); + } - public Name getName() { - return name; - } + public int getScore() { + return hand.calculateScore(); + } - public Hand getHand() { - return hand; - } + public Hand getHand() { + return hand; + } } diff --git a/src/main/java/blackjack/domain/gamer/Dealer.java b/src/main/java/blackjack/domain/gamer/Dealer.java index a69e0169554..c05bbe1ab88 100644 --- a/src/main/java/blackjack/domain/gamer/Dealer.java +++ b/src/main/java/blackjack/domain/gamer/Dealer.java @@ -2,11 +2,10 @@ public class Dealer extends BlackjackGamer { - private static final String DEFAULT_DEALER_NAME = "딜러"; private static final int DEALER_DRAW_THRESHOLD = 16; public Dealer() { - super(new Name(DEFAULT_DEALER_NAME)); + super(); } @Override diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java index 4c36a73f221..c87397efa7c 100644 --- a/src/main/java/blackjack/domain/gamer/Player.java +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -2,26 +2,32 @@ public class Player extends BlackjackGamer { - private static final int BLACKJACK_MAX_SCORE = 21; - - public Player(Name name) { - super(name); - } - - @Override - public boolean canReceiveCard() { - return getScore() <= BLACKJACK_MAX_SCORE; - } - - public GameResult isWin(int dealerScore) { - int playerScore = getScore(); - - if (playerScore > BLACKJACK_MAX_SCORE) { - return GameResult.LOSE; - } - if (dealerScore > BLACKJACK_MAX_SCORE || playerScore > dealerScore) { - return GameResult.WIN; - } - return GameResult.LOSE; - } + private static final int BLACKJACK_MAX_SCORE = 21; + + private final Name name; + + public Player(Name name) { + this.name = name; + } + + @Override + public boolean canReceiveCard() { + return getScore() <= BLACKJACK_MAX_SCORE; + } + + public GameResult isWin(int dealerScore) { + int playerScore = getScore(); + + if (playerScore > BLACKJACK_MAX_SCORE) { + return GameResult.LOSE; + } + if (dealerScore > BLACKJACK_MAX_SCORE || playerScore > dealerScore) { + return GameResult.WIN; + } + return GameResult.LOSE; + } + + public Name getName() { + return name; + } } diff --git a/src/main/java/blackjack/dto/DealerInitialHandDto.java b/src/main/java/blackjack/dto/DealerInitialHandDto.java index 37ef322c180..da041600b21 100644 --- a/src/main/java/blackjack/dto/DealerInitialHandDto.java +++ b/src/main/java/blackjack/dto/DealerInitialHandDto.java @@ -3,12 +3,11 @@ import blackjack.domain.card.Card; import blackjack.domain.gamer.Dealer; -public record DealerInitialHandDto(String name, CardDto firstCard) { +public record DealerInitialHandDto(CardDto firstCard) { public static DealerInitialHandDto fromDealer(Dealer dealer) { - String dealerName = dealer.getName().value(); Card first = dealer.getFirstCard(); - return new DealerInitialHandDto(dealerName, CardDto.fromCard(first)); + return new DealerInitialHandDto(CardDto.fromCard(first)); } } diff --git a/src/main/java/blackjack/dto/GamerHandDto.java b/src/main/java/blackjack/dto/GamerHandDto.java deleted file mode 100644 index 52da8a1956a..00000000000 --- a/src/main/java/blackjack/dto/GamerHandDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package blackjack.dto; - -import blackjack.domain.gamer.BlackjackGamer; -import blackjack.domain.gamer.Hand; -import java.util.List; - -public record GamerHandDto(String name, List gamerHand) { - - public static GamerHandDto fromBlackjackGamer(BlackjackGamer blackjackGamer) { - String playerName = blackjackGamer.getName().value(); - List gamerHand = convertHandToCardDto(blackjackGamer.getHand()); - - return new GamerHandDto(playerName, gamerHand); - } - - public static List convertHandToCardDto(Hand hand) { - return hand.getCards().stream() - .map(CardDto::fromCard) - .toList(); - } -} diff --git a/src/main/java/blackjack/dto/GamersHandDto.java b/src/main/java/blackjack/dto/GamersHandDto.java deleted file mode 100644 index e63516b98e7..00000000000 --- a/src/main/java/blackjack/dto/GamersHandDto.java +++ /dev/null @@ -1,15 +0,0 @@ -package blackjack.dto; - -import blackjack.domain.gamer.Players; -import java.util.List; - -public record GamersHandDto(List gamersHandDto) { - - public static GamersHandDto fromPlayers(Players players) { - List gamerHandDtos = players.getPlayers().stream() - .map(GamerHandDto::fromBlackjackGamer) - .toList(); - - return new GamersHandDto(gamerHandDtos); - } -} diff --git a/src/main/java/blackjack/dto/HandDto.java b/src/main/java/blackjack/dto/HandDto.java new file mode 100644 index 00000000000..b0b9f119ae0 --- /dev/null +++ b/src/main/java/blackjack/dto/HandDto.java @@ -0,0 +1,15 @@ +package blackjack.dto; + +import blackjack.domain.gamer.Hand; +import java.util.List; + +public record HandDto(List cardDtos, int handScore) { + + public static HandDto fromHand(Hand hand) { + List cardDtos = hand.getCards().stream() + .map(CardDto::fromCard) + .toList(); + + return new HandDto(cardDtos, hand.calculateScore()); + } +} diff --git a/src/main/java/blackjack/dto/PlayerHandDto.java b/src/main/java/blackjack/dto/PlayerHandDto.java new file mode 100644 index 00000000000..bcf77cd0491 --- /dev/null +++ b/src/main/java/blackjack/dto/PlayerHandDto.java @@ -0,0 +1,13 @@ +package blackjack.dto; + +import blackjack.domain.gamer.Player; + +public record PlayerHandDto(String name, HandDto playerHand) { + + public static PlayerHandDto fromPlayer(Player player) { + String playerName = player.getName().value(); + HandDto playerHand = HandDto.fromHand(player.getHand()); + + return new PlayerHandDto(playerName, playerHand); + } +} diff --git a/src/main/java/blackjack/dto/PlayersHandDto.java b/src/main/java/blackjack/dto/PlayersHandDto.java new file mode 100644 index 00000000000..cdbd5c50714 --- /dev/null +++ b/src/main/java/blackjack/dto/PlayersHandDto.java @@ -0,0 +1,15 @@ +package blackjack.dto; + +import blackjack.domain.gamer.Players; +import java.util.List; + +public record PlayersHandDto(List playersHandDto) { + + public static PlayersHandDto fromPlayers(Players players) { + List playerHandDtos = players.getPlayers().stream() + .map(PlayerHandDto::fromPlayer) + .toList(); + + return new PlayersHandDto(playerHandDtos); + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 393e4d9edb2..cab8521c6dd 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -3,9 +3,10 @@ import blackjack.dto.CardDto; import blackjack.dto.DealerInitialHandDto; import blackjack.dto.DealerResultDto; -import blackjack.dto.GamerHandDto; -import blackjack.dto.GamersHandDto; +import blackjack.dto.HandDto; import blackjack.dto.PlayerGameResultsDto; +import blackjack.dto.PlayerHandDto; +import blackjack.dto.PlayersHandDto; import blackjack.view.object.CardNumberOutput; import blackjack.view.object.CardShapeOutput; import blackjack.view.object.GameResultOutput; @@ -15,20 +16,20 @@ public class OutputView { private static final String DEALER_DEFAULT_NAME = "딜러"; - public void printInitialHands(DealerInitialHandDto dealerInitialHandDto, GamersHandDto playersInitialHandDto) { - System.out.printf("\n%s와 %s에게 2장을 나누었습니다.\n", dealerInitialHandDto.name(), + public void printInitialHands(DealerInitialHandDto dealerInitialHandDto, PlayersHandDto playersInitialHandDto) { + System.out.printf("\n%s와 %s에게 2장을 나누었습니다.\n", DEALER_DEFAULT_NAME, joinPlayerNames(playersInitialHandDto)); - System.out.printf("%s 카드: %s\n", dealerInitialHandDto.name(), formatCardName(dealerInitialHandDto.firstCard())); + System.out.printf("%s 카드: %s\n", DEALER_DEFAULT_NAME, formatCardName(dealerInitialHandDto.firstCard())); printAllPlayerHands(playersInitialHandDto); } - private String joinPlayerNames(GamersHandDto playersInitialHandDto) { + private String joinPlayerNames(PlayersHandDto playersInitialHandDto) { return String.join(", ", getPlayerNames(playersInitialHandDto)); } - private List getPlayerNames(GamersHandDto playersInitialHandDto) { - return playersInitialHandDto.gamersHandDto().stream().map(GamerHandDto::name).toList(); + private List getPlayerNames(PlayersHandDto playersInitialHandDto) { + return playersInitialHandDto.playersHandDto().stream().map(PlayerHandDto::name).toList(); } private String formatCardName(CardDto cardDto) { @@ -36,41 +37,59 @@ private String formatCardName(CardDto cardDto) { cardDto.cardShape()); } - private void printAllPlayerHands(GamersHandDto playersInitialHandDto) { - playersInitialHandDto.gamersHandDto().forEach(this::printPlayerHand); + private void printAllPlayerHands(PlayersHandDto playersInitialHandDto) { + playersInitialHandDto.playersHandDto().forEach(this::printPlayerHand); System.out.println(); } - public void printPlayerHand(GamerHandDto playerHandDto) { - System.out.println(buildPlayerHand(playerHandDto)); + public void printPlayerHand(PlayerHandDto playerHandDto) { + System.out.println(getPlayerNameOutputFormat(playerHandDto)); } - private StringBuilder buildPlayerHand(GamerHandDto gamerHandDto) { + public void printDealerHand(HandDto dealerHandDto) { + System.out.println(getDealerNameOutputFormat(dealerHandDto)); + } + + private StringBuilder getPlayerNameOutputFormat(PlayerHandDto playerHandDto) { + StringBuilder stringBuilder = new StringBuilder(); + return stringBuilder + .append(playerHandDto.name()) + .append("카드: ") + .append(joinCardNames(playerHandDto.playerHand())); + } + + private StringBuilder getDealerNameOutputFormat(HandDto dealerHandDto) { StringBuilder stringBuilder = new StringBuilder(); return stringBuilder - .append(gamerHandDto.name()) - .append(" 카드: ") - .append(joinCardNames(gamerHandDto)); + .append(DEALER_DEFAULT_NAME) + .append("카드: ") + .append(joinCardNames(dealerHandDto)); } - private String joinCardNames(GamerHandDto gamerHandDto) { - return String.join(", ", getCardNames(gamerHandDto)); + private String joinCardNames(HandDto handDto) { + return String.join(", ", getCardNames(handDto)); } - private List getCardNames(GamerHandDto gamerHandDto) { - return gamerHandDto.gamerHand().stream().map(this::formatCardName).toList(); + private List getCardNames(HandDto handDto) { + return handDto.cardDtos().stream().map(this::formatCardName).toList(); + } + + public void printPlayersHandScore(PlayersHandDto playersHandDto) { + for (PlayerHandDto playerHandDto : playersHandDto.playersHandDto()) { + System.out.println(getPlayerNameOutputFormat(playerHandDto) + .append(" - 결과: ") + .append(playerHandDto.playerHand().handScore())); + } } - public void printDealerMessage(String dealerName) { - System.out.printf("\n%s는 16이하라 한장의 카드를 더 받았습니다.\n", dealerName); + public void printDealerHandScore(HandDto dealerHandDto) { + System.out.println(getDealerNameOutputFormat(dealerHandDto) + .append(" - 결과: ") + .append(dealerHandDto.handScore())); } - public void printScore(GamerHandDto gamerHandDto, int score) { - StringBuilder builder = buildPlayerHand(gamerHandDto) - .append(" - ") - .append("결과: ") - .append(score); - System.out.println(builder); + public void printDealerMessage() { + System.out.printf("\n%s는 16이하라 한장의 카드를 더 받았습니다.\n", DEALER_DEFAULT_NAME); } public void printResult(DealerResultDto dealerResultDto, PlayerGameResultsDto playerGameResultsDto) { From 3dce8a7cd06ddd698ea9a43e49a2a8962ff138ea Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Tue, 12 Mar 2024 17:11:53 +0900 Subject: [PATCH 03/21] =?UTF-8?q?refactor(Deck):=20=EC=B9=B4=EB=93=9C=2052?= =?UTF-8?q?=EC=9E=A5=EC=9D=84=20=EC=9E=AC=EC=82=AC=EC=9A=A9=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/card/Deck.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/blackjack/domain/card/Deck.java b/src/main/java/blackjack/domain/card/Deck.java index 430a9aa9d38..fa14135b41f 100644 --- a/src/main/java/blackjack/domain/card/Deck.java +++ b/src/main/java/blackjack/domain/card/Deck.java @@ -5,17 +5,17 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.stream.Collectors; public class Deck { + private static final List CACHE = Arrays.stream(CardShape.values()) + .flatMap(cardShape -> Arrays.stream(CardNumber.values()) + .map(number -> new Card(cardShape, number))).toList(); + private final LinkedList cards; public Deck() { - this.cards = Arrays.stream(CardShape.values()) - .flatMap(cardShape -> Arrays.stream(CardNumber.values()) - .map(number -> new Card(cardShape, number))) - .collect(Collectors.toCollection(LinkedList::new)); + this.cards = new LinkedList<>(CACHE); } public Deck(LinkedList cards) { From 4c41d0fd3e2a293b3fa1684ef3e14f4c558c3d50 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Tue, 12 Mar 2024 17:43:55 +0900 Subject: [PATCH 04/21] =?UTF-8?q?fix:=20dto=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=95=88=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackjack/controller/BlackjackController.java | 12 ++++++------ .../java/blackjack/{ => domain}/dto/CardDto.java | 2 +- .../{ => domain}/dto/DealerInitialHandDto.java | 2 +- .../{ => domain}/dto/DealerResultDto.java | 2 +- .../java/blackjack/{ => domain}/dto/HandDto.java | 2 +- .../{ => domain}/dto/PlayerGameResultsDto.java | 2 +- .../blackjack/{ => domain}/dto/PlayerHandDto.java | 2 +- .../blackjack/{ => domain}/dto/PlayersHandDto.java | 2 +- src/main/java/blackjack/view/OutputView.java | 14 +++++++------- 9 files changed, 20 insertions(+), 20 deletions(-) rename src/main/java/blackjack/{ => domain}/dto/CardDto.java (91%) rename src/main/java/blackjack/{ => domain}/dto/DealerInitialHandDto.java (91%) rename src/main/java/blackjack/{ => domain}/dto/DealerResultDto.java (94%) rename src/main/java/blackjack/{ => domain}/dto/HandDto.java (92%) rename src/main/java/blackjack/{ => domain}/dto/PlayerGameResultsDto.java (95%) rename src/main/java/blackjack/{ => domain}/dto/PlayerHandDto.java (92%) rename src/main/java/blackjack/{ => domain}/dto/PlayersHandDto.java (93%) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 1e1f96666a0..fe14cdb9f60 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,17 +1,17 @@ package blackjack.controller; import blackjack.domain.card.Deck; +import blackjack.domain.dto.DealerInitialHandDto; +import blackjack.domain.dto.DealerResultDto; +import blackjack.domain.dto.HandDto; +import blackjack.domain.dto.PlayerGameResultsDto; +import blackjack.domain.dto.PlayerHandDto; +import blackjack.domain.dto.PlayersHandDto; import blackjack.domain.gamer.Dealer; import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Name; import blackjack.domain.gamer.Player; import blackjack.domain.gamer.Players; -import blackjack.dto.DealerInitialHandDto; -import blackjack.dto.DealerResultDto; -import blackjack.dto.HandDto; -import blackjack.dto.PlayerGameResultsDto; -import blackjack.dto.PlayerHandDto; -import blackjack.dto.PlayersHandDto; import blackjack.view.InputView; import blackjack.view.OutputView; import blackjack.view.object.Command; diff --git a/src/main/java/blackjack/dto/CardDto.java b/src/main/java/blackjack/domain/dto/CardDto.java similarity index 91% rename from src/main/java/blackjack/dto/CardDto.java rename to src/main/java/blackjack/domain/dto/CardDto.java index 274c3a9b632..c802b44e7b9 100644 --- a/src/main/java/blackjack/dto/CardDto.java +++ b/src/main/java/blackjack/domain/dto/CardDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.card.Card; import blackjack.domain.card.CardNumber; diff --git a/src/main/java/blackjack/dto/DealerInitialHandDto.java b/src/main/java/blackjack/domain/dto/DealerInitialHandDto.java similarity index 91% rename from src/main/java/blackjack/dto/DealerInitialHandDto.java rename to src/main/java/blackjack/domain/dto/DealerInitialHandDto.java index da041600b21..ec711477ab6 100644 --- a/src/main/java/blackjack/dto/DealerInitialHandDto.java +++ b/src/main/java/blackjack/domain/dto/DealerInitialHandDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.card.Card; import blackjack.domain.gamer.Dealer; diff --git a/src/main/java/blackjack/dto/DealerResultDto.java b/src/main/java/blackjack/domain/dto/DealerResultDto.java similarity index 94% rename from src/main/java/blackjack/dto/DealerResultDto.java rename to src/main/java/blackjack/domain/dto/DealerResultDto.java index bd1a2fff80f..b8926d57b0c 100644 --- a/src/main/java/blackjack/dto/DealerResultDto.java +++ b/src/main/java/blackjack/domain/dto/DealerResultDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.gamer.GameResult; import java.util.List; diff --git a/src/main/java/blackjack/dto/HandDto.java b/src/main/java/blackjack/domain/dto/HandDto.java similarity index 92% rename from src/main/java/blackjack/dto/HandDto.java rename to src/main/java/blackjack/domain/dto/HandDto.java index b0b9f119ae0..dd72a527e3b 100644 --- a/src/main/java/blackjack/dto/HandDto.java +++ b/src/main/java/blackjack/domain/dto/HandDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.gamer.Hand; import java.util.List; diff --git a/src/main/java/blackjack/dto/PlayerGameResultsDto.java b/src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java similarity index 95% rename from src/main/java/blackjack/dto/PlayerGameResultsDto.java rename to src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java index bacf83827e7..637584d3db8 100644 --- a/src/main/java/blackjack/dto/PlayerGameResultsDto.java +++ b/src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Name; diff --git a/src/main/java/blackjack/dto/PlayerHandDto.java b/src/main/java/blackjack/domain/dto/PlayerHandDto.java similarity index 92% rename from src/main/java/blackjack/dto/PlayerHandDto.java rename to src/main/java/blackjack/domain/dto/PlayerHandDto.java index bcf77cd0491..d3967ce76b0 100644 --- a/src/main/java/blackjack/dto/PlayerHandDto.java +++ b/src/main/java/blackjack/domain/dto/PlayerHandDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.gamer.Player; diff --git a/src/main/java/blackjack/dto/PlayersHandDto.java b/src/main/java/blackjack/domain/dto/PlayersHandDto.java similarity index 93% rename from src/main/java/blackjack/dto/PlayersHandDto.java rename to src/main/java/blackjack/domain/dto/PlayersHandDto.java index cdbd5c50714..4b11f7a63ff 100644 --- a/src/main/java/blackjack/dto/PlayersHandDto.java +++ b/src/main/java/blackjack/domain/dto/PlayersHandDto.java @@ -1,4 +1,4 @@ -package blackjack.dto; +package blackjack.domain.dto; import blackjack.domain.gamer.Players; import java.util.List; diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index cab8521c6dd..61e75337b6d 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -1,12 +1,12 @@ package blackjack.view; -import blackjack.dto.CardDto; -import blackjack.dto.DealerInitialHandDto; -import blackjack.dto.DealerResultDto; -import blackjack.dto.HandDto; -import blackjack.dto.PlayerGameResultsDto; -import blackjack.dto.PlayerHandDto; -import blackjack.dto.PlayersHandDto; +import blackjack.domain.dto.CardDto; +import blackjack.domain.dto.DealerInitialHandDto; +import blackjack.domain.dto.DealerResultDto; +import blackjack.domain.dto.HandDto; +import blackjack.domain.dto.PlayerGameResultsDto; +import blackjack.domain.dto.PlayerHandDto; +import blackjack.domain.dto.PlayersHandDto; import blackjack.view.object.CardNumberOutput; import blackjack.view.object.CardShapeOutput; import blackjack.view.object.GameResultOutput; From cdf6f80e9ca07f0c1ed0368840daf912641b7cd4 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 13 Mar 2024 00:42:52 +0900 Subject: [PATCH 05/21] =?UTF-8?q?docs(README):=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=AC=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e432c782c79..c94da57ce6e 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,17 @@ - [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다. - [x] 이후 플레이어와 딜러의 카드를 출력한다. - [x] 단, 딜러의 카드는 하나만 출력한다. +- [ ] 플레이어는 게임을 시작할 때 원하는 금액을 배팅한다. - [x] 플레이어는 카드의 숫자 합이 21을 초과하지 않는다면 카드를 원하는 만큼 다시 뽑을 수 있다. - [x] 새로 받을 때 마다 해당 플레이어의 카드를 출력한다. - [x] 플레이어가 카드를 다 받으면 딜러의 카드를 확인한다. - [x] 딜러의 카드 합이 17 이상이 될 때 까지 카드를 받는다. -- [x] 딜러와 플레이어의 카드, 결과와 최종 승패를 출력한다. +- [ ] 플레이어의 게임 결과로부터 수익을 계산한다. + - [ ] 블랙잭으로 승리 할 경우 배팅 금액의 1.5배를 딜러로부터 받는다. + - [ ] 무승부인 경우 플레이어는 베팅한 금액을 돌려받는다. + - [ ] 승리할 경우 베팅 금액만큼 받는다. + - [ ] 패배할 경우 배팅 금액을 모두 잃는다. +- [ ] 딜러와 플레이어의 카드, 결과와 최종 수익 결과를 출력한다. ### 카드 @@ -35,8 +41,11 @@ - [x] 플레이어의 이름은 중복될 수 없다. - [x] 플레이어는 최소 2명부터 최대 8명까지 가능하다. -- [x] 딜러의 점수를 입력받아 승,패를 결정한다. - - [x] 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다. - - [x] 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우 패배한다. - - [x] 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다. - - [x] 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 크면 승리한다. +- [ ] 딜러의 점수를 입력받아 승,무,패를 결정한다. + - [ ] (블랙잭) 처음 두 장의 카드 합이 21일 경우 블랙잭. + - [ ] (무승부) 딜러와 플레이어가 동시에 블랙잭인 경우. + - [ ] (무승부) 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우. + - [ ] (승리) 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하는 경우. + - [ ] (승리) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 큰 경우. + - [ ] (패배) 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관. + - [ ] (패배) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 작은 경우. From 7b7d33ff4632006abb4c1cdd2160b410d462640e Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 13 Mar 2024 11:03:59 +0900 Subject: [PATCH 06/21] =?UTF-8?q?refactor(Hand):=20=EA=B8=B0=EC=A1=B4=20Ha?= =?UTF-8?q?nd=EC=97=90=EC=84=9C=20=ED=8C=A8=20=EC=A0=90=EC=88=98=EB=A5=BC?= =?UTF-8?q?=20=EA=B3=84=EC=82=B0=ED=95=98=EB=8D=98=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20HandValue=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/blackjack/domain/dto/HandDto.java | 2 +- .../domain/gamer/BlackjackGamer.java | 12 +- .../java/blackjack/domain/gamer/Dealer.java | 6 + .../java/blackjack/domain/gamer/Hand.java | 46 +----- .../blackjack/domain/gamer/HandValue.java | 72 +++++++++ .../java/blackjack/domain/gamer/Player.java | 14 +- .../java/blackjack/domain/gamer/HandTest.java | 70 ++++----- .../blackjack/domain/gamer/HandValueTest.java | 140 ++++++++++++++++++ 8 files changed, 259 insertions(+), 103 deletions(-) create mode 100644 src/main/java/blackjack/domain/gamer/HandValue.java create mode 100644 src/test/java/blackjack/domain/gamer/HandValueTest.java diff --git a/src/main/java/blackjack/domain/dto/HandDto.java b/src/main/java/blackjack/domain/dto/HandDto.java index dd72a527e3b..1cd8245851c 100644 --- a/src/main/java/blackjack/domain/dto/HandDto.java +++ b/src/main/java/blackjack/domain/dto/HandDto.java @@ -10,6 +10,6 @@ public static HandDto fromHand(Hand hand) { .map(CardDto::fromCard) .toList(); - return new HandDto(cardDtos, hand.calculateScore()); + return new HandDto(cardDtos, hand.getValue().getScore()); } } diff --git a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java index 7af7dba894e..c3b49110fef 100644 --- a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java +++ b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java @@ -23,15 +23,15 @@ public void addCard(Card card) { hand.add(card); } - public Card getFirstCard() { - return hand.getFirstCard(); + public Hand getHand() { + return hand; } - public int getScore() { - return hand.calculateScore(); + public HandValue getHandValue() { + return hand.getValue(); } - public Hand getHand() { - return hand; + public int getScore() { + return getHandValue().getScore(); } } diff --git a/src/main/java/blackjack/domain/gamer/Dealer.java b/src/main/java/blackjack/domain/gamer/Dealer.java index c05bbe1ab88..9b62291a3d7 100644 --- a/src/main/java/blackjack/domain/gamer/Dealer.java +++ b/src/main/java/blackjack/domain/gamer/Dealer.java @@ -1,5 +1,7 @@ package blackjack.domain.gamer; +import blackjack.domain.card.Card; + public class Dealer extends BlackjackGamer { private static final int DEALER_DRAW_THRESHOLD = 16; @@ -12,4 +14,8 @@ public Dealer() { public boolean canReceiveCard() { return getScore() <= DEALER_DRAW_THRESHOLD; } + + public Card getFirstCard() { + return getHand().getFirstCard(); + } } diff --git a/src/main/java/blackjack/domain/gamer/Hand.java b/src/main/java/blackjack/domain/gamer/Hand.java index 41280fb21ea..ad1b04055c2 100644 --- a/src/main/java/blackjack/domain/gamer/Hand.java +++ b/src/main/java/blackjack/domain/gamer/Hand.java @@ -1,13 +1,11 @@ package blackjack.domain.gamer; import blackjack.domain.card.Card; +import java.util.ArrayList; import java.util.List; public class Hand { - private static final int BLACKJACK_MAX_SCORE = 21; - private static final int ACE_VALUE_MODIFIER = 10; - private final List cards; public Hand(List cards) { @@ -18,44 +16,8 @@ public void add(Card card) { cards.add(card); } - public int calculateScore() { - int sum = cards.stream() - .mapToInt(Card::getNumberValue) - .sum(); - - if (hasAce()) { - return adjustSumWithAce(sum); - } - return sum; - } - - private boolean hasAce() { - return cards.stream() - .anyMatch(Card::isAce); - } - - /** - * ACE가 포함된 경우, 21 이하이면서 가장 가능한 큰 값으로 계산한다. - */ - private int adjustSumWithAce(int sum) { - int aceCount = (int) cards.stream() - .filter(Card::isAce) - .count(); - - for (int i = 0; i < aceCount; i++) { - sum = adjust(sum); - } - return sum; - } - - /** - * Ace는 기본적으로 11로 계산되나, 합계가 21을 초과할 경우 1로 계산한다. - */ - private int adjust(int sum) { - if (sum > BLACKJACK_MAX_SCORE) { - sum -= ACE_VALUE_MODIFIER; - } - return sum; + public HandValue getValue() { + return new HandValue(cards); } public Card getFirstCard() { @@ -63,6 +25,6 @@ public Card getFirstCard() { } public List getCards() { - return cards; + return new ArrayList<>(cards); } } diff --git a/src/main/java/blackjack/domain/gamer/HandValue.java b/src/main/java/blackjack/domain/gamer/HandValue.java new file mode 100644 index 00000000000..db54fad31e7 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/HandValue.java @@ -0,0 +1,72 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Card; +import java.util.List; + +public class HandValue { + + private static final int BLACKJACK_MAX_SCORE = 21; + private static final int ACE_VALUE_MODIFIER = 10; + + private final int score; + private final int handSize; + + public HandValue(List cards) { + this.score = calculateScore(cards); + this.handSize = cards.size(); + } + + public int calculateScore(List cards) { + int sum = cards.stream() + .mapToInt(Card::getNumberValue) + .sum(); + + if (hasAce(cards)) { + return adjustSumWithAce(cards, sum); + } + return sum; + } + + private boolean hasAce(List cards) { + return cards.stream() + .anyMatch(Card::isAce); + } + + /** + * ACE가 포함된 경우, 21 이하이면서 가장 가능한 큰 값으로 계산한다. + */ + private int adjustSumWithAce(List cards, int sum) { + int aceCount = (int) cards.stream() + .filter(Card::isAce) + .count(); + + for (int i = 0; i < aceCount; i++) { + sum = adjust(sum); + } + return sum; + } + + /** + * Ace는 기본적으로 11로 계산되나, 합계가 21을 초과할 경우 1로 계산한다. + */ + private int adjust(int sum) { + if (sum > BLACKJACK_MAX_SCORE) { + sum -= ACE_VALUE_MODIFIER; + } + return sum; + } + + public boolean isBlackjack() { + return score == BLACKJACK_MAX_SCORE && handSize == 2; + } + + public boolean isBust() { + return score > BLACKJACK_MAX_SCORE; + } + + public int getScore() { + return score; + } + + +} diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java index c87397efa7c..6110828e7ed 100644 --- a/src/main/java/blackjack/domain/gamer/Player.java +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -12,19 +12,7 @@ public Player(Name name) { @Override public boolean canReceiveCard() { - return getScore() <= BLACKJACK_MAX_SCORE; - } - - public GameResult isWin(int dealerScore) { - int playerScore = getScore(); - - if (playerScore > BLACKJACK_MAX_SCORE) { - return GameResult.LOSE; - } - if (dealerScore > BLACKJACK_MAX_SCORE || playerScore > dealerScore) { - return GameResult.WIN; - } - return GameResult.LOSE; + return getScore() < BLACKJACK_MAX_SCORE; } public Name getName() { diff --git a/src/test/java/blackjack/domain/gamer/HandTest.java b/src/test/java/blackjack/domain/gamer/HandTest.java index 9c2bbf6ea41..fbe2f0fa877 100644 --- a/src/test/java/blackjack/domain/gamer/HandTest.java +++ b/src/test/java/blackjack/domain/gamer/HandTest.java @@ -1,51 +1,39 @@ package blackjack.domain.gamer; -import static org.assertj.core.api.Assertions.*; - -import java.util.List; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import blackjack.domain.card.Card; import blackjack.domain.card.CardNumber; import blackjack.domain.card.CardShape; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; class HandTest { - Hand hand; - - @Test - @DisplayName("ACE가 없을때의 숫자 합을 계산한다.") - void sumWithoutAceTest() { - hand = new Hand(List.of( - new Card(CardShape.CLOVER, CardNumber.KING), - new Card(CardShape.HEART, CardNumber.FIVE) - )); - - assertThat(hand.calculateScore()).isEqualTo(15); - } - - @Test - @DisplayName("숫자의 합이 21을 초과하는 경우, ACE를 1로 계산한다.") - void sumWithOneAceTest() { - hand = new Hand(List.of( - new Card(CardShape.HEART, CardNumber.ACE), - new Card(CardShape.CLOVER, CardNumber.KING), - new Card(CardShape.DIAMOND, CardNumber.KING) - )); - - assertThat(hand.calculateScore()).isEqualTo(21); - } - - @Test - @DisplayName("숫자의 합이 21을 초과하지 않으면, ACE를 11로 계산한다.") - void sumWithElevenAceTest() { - hand = new Hand(List.of( - new Card(CardShape.HEART, CardNumber.ACE), - new Card(CardShape.CLOVER, CardNumber.KING) - )); - - assertThat(hand.calculateScore()).isEqualTo(21); - } + private Hand hand; + + @BeforeEach + void setUp() { + hand = new Hand(List.of( + new Card(CardShape.CLOVER, CardNumber.KING), + new Card(CardShape.HEART, CardNumber.FIVE) + )); + } + + @Test + @DisplayName("핸드의 첫 번째 카드를 반환한다") + void getFirstCardTest() { + Card firstCard = hand.getFirstCard(); + + assertThat(firstCard).isEqualTo(new Card(CardShape.CLOVER, CardNumber.KING)); + } + + @Test + @DisplayName("핸드의 밸류를 정상적으로 생성한다.") + void createHandValueTest() { + assertThatNoException().isThrownBy(() -> hand.getValue()); + } } diff --git a/src/test/java/blackjack/domain/gamer/HandValueTest.java b/src/test/java/blackjack/domain/gamer/HandValueTest.java new file mode 100644 index 00000000000..8dfee3ed2e9 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/HandValueTest.java @@ -0,0 +1,140 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardNumber; +import blackjack.domain.card.CardShape; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class HandValueTest { + + @Nested + @DisplayName("핸드 점수 계산 테스트") + class CalculateScoreTest { + + @Test + @DisplayName("ACE가 없을때의 숫자 합을 계산한다.") + void sumWithoutAceTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.CLOVER, CardNumber.KING), + new Card(CardShape.HEART, CardNumber.FIVE) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.getScore()).isEqualTo(15); + } + + @Test + @DisplayName("핸드 점수 합이 21을 초과하는 경우, ACE를 1로 계산한다.") + void sumWithOneAceTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.KING), + new Card(CardShape.DIAMOND, CardNumber.KING) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.getScore()).isEqualTo(21); + } + + @Test + @DisplayName("핸드 점수 합이 21을 초과하지 않으면, ACE를 11로 계산한다.") + void sumWithElevenAceTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.KING) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.getScore()).isEqualTo(21); + } + } + + @Nested + @DisplayName("블랙잭 테스트") + class BlackjackTest { + + @Test + @DisplayName("카드가 2장이면서 핸드의 점수 합이 21점이면 블랙잭이다.") + void isBlackjackTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.KING) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.isBlackjack()).isTrue(); + } + + @Test + @DisplayName("카드가 2장이 아니면 블랙잭이 아니다") + void isNotBlackjackTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.JACK), + new Card(CardShape.CLOVER, CardNumber.NINE), + new Card(CardShape.HEART, CardNumber.TWO) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.isBlackjack()).isFalse(); + } + + @Test + @DisplayName("핸드 점수 합이 21점이 아니면 블랙잭이 아니다") + void isNotBlackjackTest2() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.JACK), + new Card(CardShape.CLOVER, CardNumber.NINE) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.isBlackjack()).isFalse(); + } + } + + @Nested + @DisplayName("버스트 테스트") + class BustTest { + + @Test + @DisplayName("핸드 점수 합이 21점을 초과하면 버스트다.") + void isBustTest() { + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.ACE), + new Card(CardShape.CLOVER, CardNumber.FIVE), + new Card(CardShape.CLOVER, CardNumber.JACK), + new Card(CardShape.DIAMOND, CardNumber.NINE) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.isBust()).isTrue(); + } + + @Test + @DisplayName("핸드 점수 합이 21점을 초과하지 않으면 버스트가 아니다.") + void isNotBustTest() { + + List cards = new ArrayList<>(List.of( + new Card(CardShape.HEART, CardNumber.ACE), + new Card(CardShape.DIAMOND, CardNumber.NINE) + )); + + HandValue handValue = new HandValue(cards); + + assertThat(handValue.isBust()).isFalse(); + } + } +} From e99482ba6931a568d2198b7e5165774c04200326 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 13 Mar 2024 14:06:24 +0900 Subject: [PATCH 07/21] =?UTF-8?q?feat(Player):=20=EB=94=9C=EB=9F=AC?= =?UTF-8?q?=EC=9D=98=20HandValue=EB=A5=BC=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=EB=A1=9C=20=EB=B0=9B=EC=95=84=20=EC=8A=B9,=EB=AC=B4,?= =?UTF-8?q?=ED=8C=A8,=EB=B8=94=EB=9E=99=EC=9E=AD=20=EC=8A=B9=EB=A6=AC?= =?UTF-8?q?=EB=A5=BC=20=EA=B3=84=EC=82=B0=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/gamer/BlackjackGamer.java | 4 + .../blackjack/domain/gamer/GameResult.java | 16 ++- .../blackjack/domain/gamer/HandValue.java | 7 +- .../java/blackjack/domain/gamer/Player.java | 34 +++++ .../java/blackjack/domain/gamer/Players.java | 4 +- .../blackjack/domain/gamer/PlayerTest.java | 122 ++++++++++++------ 6 files changed, 139 insertions(+), 48 deletions(-) diff --git a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java index c3b49110fef..f83f536ce18 100644 --- a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java +++ b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java @@ -12,6 +12,10 @@ public BlackjackGamer() { this.hand = new Hand(new ArrayList<>()); } + public BlackjackGamer(Hand hand) { + this.hand = hand; + } + public abstract boolean canReceiveCard(); public void initCard(Deck deck) { diff --git a/src/main/java/blackjack/domain/gamer/GameResult.java b/src/main/java/blackjack/domain/gamer/GameResult.java index a7d6d085459..6bd62072d42 100644 --- a/src/main/java/blackjack/domain/gamer/GameResult.java +++ b/src/main/java/blackjack/domain/gamer/GameResult.java @@ -2,10 +2,18 @@ public enum GameResult { - WIN, - LOSE; + WIN(1.0), + LOSE(-1.0), + DRAW(0), + BLACKJACK_WIN(1.5); - public static boolean isLose(GameResult gameResult) { - return LOSE == gameResult; + private final double ratio; + + GameResult(double ratio) { + this.ratio = ratio; + } + + public double getRatio() { + return ratio; } } diff --git a/src/main/java/blackjack/domain/gamer/HandValue.java b/src/main/java/blackjack/domain/gamer/HandValue.java index db54fad31e7..5c5bde52477 100644 --- a/src/main/java/blackjack/domain/gamer/HandValue.java +++ b/src/main/java/blackjack/domain/gamer/HandValue.java @@ -16,6 +16,11 @@ public HandValue(List cards) { this.handSize = cards.size(); } + public HandValue(int score, int handSize) { + this.score = score; + this.handSize = handSize; + } + public int calculateScore(List cards) { int sum = cards.stream() .mapToInt(Card::getNumberValue) @@ -67,6 +72,4 @@ public boolean isBust() { public int getScore() { return score; } - - } diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java index 6110828e7ed..c22fbeaa058 100644 --- a/src/main/java/blackjack/domain/gamer/Player.java +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -10,11 +10,45 @@ public Player(Name name) { this.name = name; } + public Player(Hand hand, Name name) { + super(hand); + this.name = name; + } + @Override public boolean canReceiveCard() { return getScore() < BLACKJACK_MAX_SCORE; } + public GameResult compete(HandValue dealerHandValue) { + HandValue playerHandValue = getHandValue(); + + if (playerHandValue.isBlackjack() && !dealerHandValue.isBlackjack()) { + return GameResult.BLACKJACK_WIN; + } + // 플레이어 점수가 21보다 클경우 패배 + if (playerHandValue.getScore() > BLACKJACK_MAX_SCORE) { + return GameResult.LOSE; + } + // 딜러의 점수가 21보다 클경우 승리 + if (dealerHandValue.getScore() > BLACKJACK_MAX_SCORE) { + return GameResult.WIN; + } + // 플레이어 점수가 딜러 점수보다 작으면 패배 + if (playerHandValue.getScore() < dealerHandValue.getScore()) { + return GameResult.LOSE; + } + // 플레이어 점수가 딜러보다 클 경우 승리 + if (playerHandValue.getScore() > dealerHandValue.getScore()) { + return GameResult.WIN; + } + if (dealerHandValue.isBlackjack() && !playerHandValue.isBlackjack()) { + return GameResult.LOSE; + } + + return GameResult.DRAW; + } + public Name getName() { return name; } diff --git a/src/main/java/blackjack/domain/gamer/Players.java b/src/main/java/blackjack/domain/gamer/Players.java index 646b54606be..f2473e48ea9 100644 --- a/src/main/java/blackjack/domain/gamer/Players.java +++ b/src/main/java/blackjack/domain/gamer/Players.java @@ -47,9 +47,9 @@ public void initAllPlayersCard(Deck deck) { players.forEach(player -> player.initCard(deck)); } - public Map collectPlayerGameResults(int dealerScore) { + public Map collectPlayerGameResults(HandValue dealerHandValue) { Map playerGameResults = new LinkedHashMap<>(); - players.forEach(player -> playerGameResults.put(player.getName(), player.isWin(dealerScore))); + players.forEach(player -> playerGameResults.put(player.getName(), player.compete(dealerHandValue))); return playerGameResults; } diff --git a/src/test/java/blackjack/domain/gamer/PlayerTest.java b/src/test/java/blackjack/domain/gamer/PlayerTest.java index 5f1fee38edc..767fc6dd4e0 100644 --- a/src/test/java/blackjack/domain/gamer/PlayerTest.java +++ b/src/test/java/blackjack/domain/gamer/PlayerTest.java @@ -5,6 +5,7 @@ import blackjack.domain.card.Card; import blackjack.domain.card.CardNumber; import blackjack.domain.card.CardShape; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -12,11 +13,27 @@ class PlayerTest { - Player player; + private Hand score14Hand, score21Hand, bustHand, blackjackHand; @BeforeEach void setUP() { - player = new Player(new Name("hogi")); + score14Hand = new Hand(List.of( + new Card(CardShape.DIAMOND, CardNumber.KING), new Card(CardShape.SPADE, CardNumber.FOUR) + )); + + score21Hand = new Hand(List.of( + new Card(CardShape.CLOVER, CardNumber.KING), new Card(CardShape.SPADE, CardNumber.NINE), + new Card(CardShape.SPADE, CardNumber.TWO) + )); + + bustHand = new Hand(List.of( + new Card(CardShape.HEART, CardNumber.KING), new Card(CardShape.SPADE, CardNumber.JACK), + new Card(CardShape.SPADE, CardNumber.TWO) + )); + + blackjackHand = new Hand(List.of( + new Card(CardShape.SPADE, CardNumber.ACE), new Card(CardShape.SPADE, CardNumber.QUEEN) + )); } @Nested @@ -26,9 +43,7 @@ class CanReceiveCardTest { @Test @DisplayName("카드의 총합이 21 이하이면 카드를 받을 수 있다.") void receiveCardTest() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.SIX)); - player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); + Player player = new Player(score14Hand, new Name("hogi")); assertThat(player.canReceiveCard()).isTrue(); } @@ -36,69 +51,96 @@ void receiveCardTest() { @Test @DisplayName("카드의 총합이 21을 초과하면 카드를 받을 수 없다.") void cantReceiveCardTest() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); - player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + Player player = new Player(bustHand, new Name("jazz")); assertThat(player.canReceiveCard()).isFalse(); } } @Nested - @DisplayName("플레이어가 승리하는 경우의 수 테스트") - class IsWinTest { + @DisplayName("플레이어가 패배하는 경우의 수 테스트") + class PlayerLoseTest { @Test - @DisplayName("플레이어 점수가 21 이하이고, 딜러의 점수보다 큰 경우 승리한다.") - void bustTest() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.FOUR)); - player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + @DisplayName("점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다") + void playerBustTest() { + Player player = new Player(bustHand, new Name("ready")); + HandValue dealerHandValue = new HandValue(22, 3); + + GameResult gameResult = player.compete(dealerHandValue); - assertThat(player.isWin(20)).isEqualTo(GameResult.WIN); + assertThat(gameResult).isEqualTo(GameResult.LOSE); } @Test - @DisplayName("플레이어 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다.") - void bustTest1() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.ACE)); + @DisplayName("플레이어와 딜러의 점수가 모두 21 이하이면서, 딜러의 점수보다 낮으면 패배한다.") + void playerHandValueLowerThanDealer() { + Player player = new Player(score14Hand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(21, 3); - assertThat(player.isWin(22)).isEqualTo(GameResult.WIN); + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.LOSE); + } + + @Test + @DisplayName("딜러가 블랙잭일 때, 플레이어가 블랙잭이 아니면 패배한다.") + void playerLoseWhenDealerBlackjack() { + Player player = new Player(score14Hand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(21, 2); + + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.LOSE); } } @Nested - @DisplayName("플레이어가 패배하는 경우의 수 테스트") - class LoseTest { + @DisplayName("플레이어가 승리하는 경우의 수 테스트") + class PlayerWinTest { @Test - @DisplayName("점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다") - void bustTest2() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.FIVE)); - player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + @DisplayName("플레이어 점수가 21 이하일 때, 딜러의 점수가 21을 초과하면 승리한다.") + void dealerBustTest() { + Player player = new Player(score21Hand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(22, 4); - assertThat(player.isWin(21)).isEqualTo(GameResult.LOSE); - assertThat(player.isWin(22)).isEqualTo(GameResult.LOSE); + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.WIN); } @Test - @DisplayName("플레이어와 딜러의 점수가 모두 21 이하일 때, 딜러의 점수보다 낮으면 패배한다.") - void bustTest3() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.SIX)); + @DisplayName("플레이어 점수가 21 이하이고, 딜러의 점수보다 큰 경우 승리한다.") + void playerHandValueHigherThanDealer() { + Player player = new Player(score21Hand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(14, 2); - assertThat(player.isWin(17)).isEqualTo(GameResult.LOSE); + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.WIN); } + } + + @Nested + @DisplayName("플레이어가 블랙잭 승리하는 경우의 수 테스트") + class PlayerBlackjackWinTest { + + @Test + @DisplayName("플레이어가 블랙잭일 때, 딜러가 블랙잭이 아니면 블랙잭 승리한다.") + void dealerBustTest() { + Player player = new Player(blackjackHand, new Name("jazz")); + HandValue dealerHandValue21 = new HandValue(21, 3); + HandValue dealerBustHand = new HandValue(22, 3); + + assertThat(player.compete(dealerHandValue21)).isEqualTo(GameResult.BLACKJACK_WIN); + assertThat(player.compete(dealerBustHand)).isEqualTo(GameResult.BLACKJACK_WIN); + } + } + + @Nested + @DisplayName("플레이어가 딜러 무승부 테스트") + class PlayerDealerDrawTest { @Test - @DisplayName("플레이어와 딜러의 점수가 모두 21 이하이고 동점인 경우 플레이어가 패배한다.") - void bustTest4() { - player.addCard(new Card(CardShape.CLOVER, CardNumber.KING)); - player.addCard(new Card(CardShape.HEART, CardNumber.SEVEN)); + @DisplayName("플레이어가 블랙잭일 때, 딜러가 블랙잭이면 무승부.") + void dealerBustTest() { + Player player = new Player(blackjackHand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(21, 2); - assertThat(player.isWin(17)).isEqualTo(GameResult.LOSE); + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.DRAW); } } } From 872cb1028c1a1bf20322aed4db997daf2e214b22 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 13 Mar 2024 17:20:33 +0900 Subject: [PATCH 08/21] =?UTF-8?q?move:=20=EC=9D=98=EC=A1=B4=20=EA=B4=80?= =?UTF-8?q?=EA=B3=84=EB=A5=BC=20=EA=B3=A0=EB=A0=A4=ED=95=98=EC=97=AC=20dto?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackjack/controller/BlackjackController.java | 14 +++++++------- .../java/blackjack/{domain => }/dto/CardDto.java | 2 +- .../{domain => }/dto/DealerInitialHandDto.java | 2 +- .../{domain => }/dto/DealerResultDto.java | 4 ++-- .../java/blackjack/{domain => }/dto/HandDto.java | 2 +- .../{domain => }/dto/PlayerGameResultsDto.java | 2 +- .../blackjack/{domain => }/dto/PlayerHandDto.java | 2 +- .../blackjack/{domain => }/dto/PlayersHandDto.java | 2 +- src/main/java/blackjack/view/OutputView.java | 14 +++++++------- 9 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/blackjack/{domain => }/dto/CardDto.java (91%) rename src/main/java/blackjack/{domain => }/dto/DealerInitialHandDto.java (91%) rename src/main/java/blackjack/{domain => }/dto/DealerResultDto.java (85%) rename src/main/java/blackjack/{domain => }/dto/HandDto.java (92%) rename src/main/java/blackjack/{domain => }/dto/PlayerGameResultsDto.java (95%) rename src/main/java/blackjack/{domain => }/dto/PlayerHandDto.java (92%) rename src/main/java/blackjack/{domain => }/dto/PlayersHandDto.java (93%) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index fe14cdb9f60..0ad7bacb400 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,17 +1,17 @@ package blackjack.controller; import blackjack.domain.card.Deck; -import blackjack.domain.dto.DealerInitialHandDto; -import blackjack.domain.dto.DealerResultDto; -import blackjack.domain.dto.HandDto; -import blackjack.domain.dto.PlayerGameResultsDto; -import blackjack.domain.dto.PlayerHandDto; -import blackjack.domain.dto.PlayersHandDto; import blackjack.domain.gamer.Dealer; import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Name; import blackjack.domain.gamer.Player; import blackjack.domain.gamer.Players; +import blackjack.dto.DealerInitialHandDto; +import blackjack.dto.DealerResultDto; +import blackjack.dto.HandDto; +import blackjack.dto.PlayerGameResultsDto; +import blackjack.dto.PlayerHandDto; +import blackjack.dto.PlayersHandDto; import blackjack.view.InputView; import blackjack.view.OutputView; import blackjack.view.object.Command; @@ -104,7 +104,7 @@ private void printPlayersScores(Players players) { } private void printResult(Dealer dealer, Players players) { - Map playerGameResults = players.collectPlayerGameResults(dealer.getScore()); + Map playerGameResults = players.collectPlayerGameResults(dealer.getHandValue()); PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerGameResults(playerGameResults); List playerResults = new ArrayList<>(playerGameResultsDto.resultMap().values()); DealerResultDto dealerResultDto = DealerResultDto.fromPlayerResults(playerResults); diff --git a/src/main/java/blackjack/domain/dto/CardDto.java b/src/main/java/blackjack/dto/CardDto.java similarity index 91% rename from src/main/java/blackjack/domain/dto/CardDto.java rename to src/main/java/blackjack/dto/CardDto.java index c802b44e7b9..274c3a9b632 100644 --- a/src/main/java/blackjack/domain/dto/CardDto.java +++ b/src/main/java/blackjack/dto/CardDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.card.Card; import blackjack.domain.card.CardNumber; diff --git a/src/main/java/blackjack/domain/dto/DealerInitialHandDto.java b/src/main/java/blackjack/dto/DealerInitialHandDto.java similarity index 91% rename from src/main/java/blackjack/domain/dto/DealerInitialHandDto.java rename to src/main/java/blackjack/dto/DealerInitialHandDto.java index ec711477ab6..da041600b21 100644 --- a/src/main/java/blackjack/domain/dto/DealerInitialHandDto.java +++ b/src/main/java/blackjack/dto/DealerInitialHandDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.card.Card; import blackjack.domain.gamer.Dealer; diff --git a/src/main/java/blackjack/domain/dto/DealerResultDto.java b/src/main/java/blackjack/dto/DealerResultDto.java similarity index 85% rename from src/main/java/blackjack/domain/dto/DealerResultDto.java rename to src/main/java/blackjack/dto/DealerResultDto.java index b8926d57b0c..32af44e0fb1 100644 --- a/src/main/java/blackjack/domain/dto/DealerResultDto.java +++ b/src/main/java/blackjack/dto/DealerResultDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.gamer.GameResult; import java.util.List; @@ -7,7 +7,7 @@ public record DealerResultDto(int winCount, int loseCount) { public static DealerResultDto fromPlayerResults(List playerResults) { int dealerWinCount = (int) playerResults.stream() - .filter(GameResult::isLose) + .filter(GameResult::Lose) .count(); int dealerLoseCount = playerResults.size() - dealerWinCount; diff --git a/src/main/java/blackjack/domain/dto/HandDto.java b/src/main/java/blackjack/dto/HandDto.java similarity index 92% rename from src/main/java/blackjack/domain/dto/HandDto.java rename to src/main/java/blackjack/dto/HandDto.java index 1cd8245851c..64925ccc104 100644 --- a/src/main/java/blackjack/domain/dto/HandDto.java +++ b/src/main/java/blackjack/dto/HandDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.gamer.Hand; import java.util.List; diff --git a/src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java b/src/main/java/blackjack/dto/PlayerGameResultsDto.java similarity index 95% rename from src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java rename to src/main/java/blackjack/dto/PlayerGameResultsDto.java index 637584d3db8..bacf83827e7 100644 --- a/src/main/java/blackjack/domain/dto/PlayerGameResultsDto.java +++ b/src/main/java/blackjack/dto/PlayerGameResultsDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Name; diff --git a/src/main/java/blackjack/domain/dto/PlayerHandDto.java b/src/main/java/blackjack/dto/PlayerHandDto.java similarity index 92% rename from src/main/java/blackjack/domain/dto/PlayerHandDto.java rename to src/main/java/blackjack/dto/PlayerHandDto.java index d3967ce76b0..bcf77cd0491 100644 --- a/src/main/java/blackjack/domain/dto/PlayerHandDto.java +++ b/src/main/java/blackjack/dto/PlayerHandDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.gamer.Player; diff --git a/src/main/java/blackjack/domain/dto/PlayersHandDto.java b/src/main/java/blackjack/dto/PlayersHandDto.java similarity index 93% rename from src/main/java/blackjack/domain/dto/PlayersHandDto.java rename to src/main/java/blackjack/dto/PlayersHandDto.java index 4b11f7a63ff..cdbd5c50714 100644 --- a/src/main/java/blackjack/domain/dto/PlayersHandDto.java +++ b/src/main/java/blackjack/dto/PlayersHandDto.java @@ -1,4 +1,4 @@ -package blackjack.domain.dto; +package blackjack.dto; import blackjack.domain.gamer.Players; import java.util.List; diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 61e75337b6d..cab8521c6dd 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -1,12 +1,12 @@ package blackjack.view; -import blackjack.domain.dto.CardDto; -import blackjack.domain.dto.DealerInitialHandDto; -import blackjack.domain.dto.DealerResultDto; -import blackjack.domain.dto.HandDto; -import blackjack.domain.dto.PlayerGameResultsDto; -import blackjack.domain.dto.PlayerHandDto; -import blackjack.domain.dto.PlayersHandDto; +import blackjack.dto.CardDto; +import blackjack.dto.DealerInitialHandDto; +import blackjack.dto.DealerResultDto; +import blackjack.dto.HandDto; +import blackjack.dto.PlayerGameResultsDto; +import blackjack.dto.PlayerHandDto; +import blackjack.dto.PlayersHandDto; import blackjack.view.object.CardNumberOutput; import blackjack.view.object.CardShapeOutput; import blackjack.view.object.GameResultOutput; From cfcf2af4a34cef0ebf11a13aa7b99e85f6f5d922 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 01:27:09 +0900 Subject: [PATCH 09/21] =?UTF-8?q?refactor(Player):=20=EC=8A=B9=EB=AC=B4?= =?UTF-8?q?=ED=8C=A8=EB=A5=BC=20=EA=B3=84=EC=82=B0=ED=95=98=EB=8A=94=20com?= =?UTF-8?q?pete=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackjack/domain/gamer/HandValue.java | 16 +++++++++ .../java/blackjack/domain/gamer/Player.java | 33 +++++++++---------- .../blackjack/domain/gamer/PlayerTest.java | 13 ++++++-- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/main/java/blackjack/domain/gamer/HandValue.java b/src/main/java/blackjack/domain/gamer/HandValue.java index 5c5bde52477..c4ecbc1fb0e 100644 --- a/src/main/java/blackjack/domain/gamer/HandValue.java +++ b/src/main/java/blackjack/domain/gamer/HandValue.java @@ -65,10 +65,26 @@ public boolean isBlackjack() { return score == BLACKJACK_MAX_SCORE && handSize == 2; } + public boolean isNotBlackjack() { + return !isBlackjack(); + } + public boolean isBust() { return score > BLACKJACK_MAX_SCORE; } + public boolean isNotBust() { + return !isBust(); + } + + public boolean isHigherThan(HandValue other) { + return this.score > other.score; + } + + public boolean isLowerThan(HandValue other) { + return this.score < other.score; + } + public int getScore() { return score; } diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java index c22fbeaa058..1affb0828b8 100644 --- a/src/main/java/blackjack/domain/gamer/Player.java +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -22,33 +22,30 @@ public boolean canReceiveCard() { public GameResult compete(HandValue dealerHandValue) { HandValue playerHandValue = getHandValue(); - - if (playerHandValue.isBlackjack() && !dealerHandValue.isBlackjack()) { + if (isOnlyPlayerBlackjack(playerHandValue, dealerHandValue)) { return GameResult.BLACKJACK_WIN; } - // 플레이어 점수가 21보다 클경우 패배 - if (playerHandValue.getScore() > BLACKJACK_MAX_SCORE) { + if (playerHandValue.isBust() || isLowerThanDealerHandValue(playerHandValue, dealerHandValue)) { return GameResult.LOSE; } - // 딜러의 점수가 21보다 클경우 승리 - if (dealerHandValue.getScore() > BLACKJACK_MAX_SCORE) { + if (dealerHandValue.isBust() || isHigherThanDealerHandValue(playerHandValue, dealerHandValue)) { return GameResult.WIN; } - // 플레이어 점수가 딜러 점수보다 작으면 패배 - if (playerHandValue.getScore() < dealerHandValue.getScore()) { - return GameResult.LOSE; - } - // 플레이어 점수가 딜러보다 클 경우 승리 - if (playerHandValue.getScore() > dealerHandValue.getScore()) { - return GameResult.WIN; - } - if (dealerHandValue.isBlackjack() && !playerHandValue.isBlackjack()) { - return GameResult.LOSE; - } - return GameResult.DRAW; } + private boolean isOnlyPlayerBlackjack(HandValue playerHandValue, HandValue dealerHandValue) { + return playerHandValue.isBlackjack() && dealerHandValue.isNotBlackjack(); + } + + private boolean isLowerThanDealerHandValue(HandValue playerHandValue, HandValue dealerHandValue) { + return dealerHandValue.isNotBust() && playerHandValue.isLowerThan(dealerHandValue); + } + + private boolean isHigherThanDealerHandValue(HandValue playerHandValue, HandValue dealerHandValue) { + return playerHandValue.isNotBust() && playerHandValue.isHigherThan(dealerHandValue); + } + public Name getName() { return name; } diff --git a/src/test/java/blackjack/domain/gamer/PlayerTest.java b/src/test/java/blackjack/domain/gamer/PlayerTest.java index 767fc6dd4e0..e55e45b1921 100644 --- a/src/test/java/blackjack/domain/gamer/PlayerTest.java +++ b/src/test/java/blackjack/domain/gamer/PlayerTest.java @@ -131,16 +131,25 @@ void dealerBustTest() { } @Nested - @DisplayName("플레이어가 딜러 무승부 테스트") + @DisplayName("플레이어 딜러 무승부 테스트") class PlayerDealerDrawTest { @Test @DisplayName("플레이어가 블랙잭일 때, 딜러가 블랙잭이면 무승부.") - void dealerBustTest() { + void allBlackjackTest() { Player player = new Player(blackjackHand, new Name("jazz")); HandValue dealerHandValue = new HandValue(21, 2); assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.DRAW); } + + @Test + @DisplayName("플레이어가 블랙잭일 때, 딜러가 블랙잭이면 무승부.") + void tieScoreTest() { + Player player = new Player(score21Hand, new Name("jazz")); + HandValue dealerHandValue = new HandValue(21, 4); + + assertThat(player.compete(dealerHandValue)).isEqualTo(GameResult.DRAW); + } } } From 23a17b09d0dc1c1724fc510839a0d64c0d7a7915 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 01:29:49 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feat(InputView):=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=EB=A1=9C=EB=B6=80=ED=84=B0=20=EB=B0=B0?= =?UTF-8?q?=ED=8C=85=20=EA=B8=88=EC=95=A1=EC=9D=84=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B0=9B=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/view/InputView.java | 31 ++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java index 6adb3dcefcc..e00c7ff40b3 100644 --- a/src/main/java/blackjack/view/InputView.java +++ b/src/main/java/blackjack/view/InputView.java @@ -6,20 +6,25 @@ public class InputView { - private final Scanner scanner; + private final Scanner scanner; - public InputView() { - scanner = new Scanner(System.in); - } + public InputView() { + scanner = new Scanner(System.in); + } - public List receivePlayerNames() { - System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); - String input = scanner.nextLine(); - return List.of(input.split(",")); - } + public List receivePlayerNames() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + String input = scanner.nextLine(); + return List.of(input.split(",")); + } - public Command receiveCommand(String name) { - System.out.println(name + "는(은) 한장의 카드를 더 받겠습니까?(예는 y, 아니오: n)"); - return Command.convertInputToCommand(scanner.nextLine()); - } + public int receivePlayerMoney(String name) { + System.out.printf("\n%s의 베팅 금액은?\n", name); + return Integer.parseInt(scanner.nextLine()); + } + + public Command receiveCommand(String name) { + System.out.printf("%s는(은) 한장의 카드를 더 받겠습니까?(예는 y, 아니오: n)\n", name); + return Command.convertInputToCommand(scanner.nextLine()); + } } From 157d53a215181539407cc9441e1d5b3f5301f03c Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 01:34:20 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feat(GameAccount):=20=EB=B0=B0=ED=8C=85?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=EB=A7=8C=ED=81=BC=20=EA=B8=88=EC=95=A1?= =?UTF-8?q?=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=EC=86=8C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackjack/domain/game/GameAccount.java | 18 +++++++++++++++ .../java/blackjack/domain/game/Money.java | 4 ++++ .../domain/game/GameAccountTest.java | 23 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/main/java/blackjack/domain/game/GameAccount.java create mode 100644 src/main/java/blackjack/domain/game/Money.java create mode 100644 src/test/java/blackjack/domain/game/GameAccountTest.java diff --git a/src/main/java/blackjack/domain/game/GameAccount.java b/src/main/java/blackjack/domain/game/GameAccount.java new file mode 100644 index 00000000000..67c0f1455c8 --- /dev/null +++ b/src/main/java/blackjack/domain/game/GameAccount.java @@ -0,0 +1,18 @@ +package blackjack.domain.game; + +import blackjack.domain.gamer.Player; +import java.util.LinkedHashMap; +import java.util.Map; + +public class GameAccount { + + private static final Map store = new LinkedHashMap<>(); + + public void betMoney(Player player, Money money) { + store.put(player, money); + } + + public Money findMoney(Player player) { + return store.get(player); + } +} diff --git a/src/main/java/blackjack/domain/game/Money.java b/src/main/java/blackjack/domain/game/Money.java new file mode 100644 index 00000000000..fff48d56621 --- /dev/null +++ b/src/main/java/blackjack/domain/game/Money.java @@ -0,0 +1,4 @@ +package blackjack.domain.game; + +public record Money(int value) { +} diff --git a/src/test/java/blackjack/domain/game/GameAccountTest.java b/src/test/java/blackjack/domain/game/GameAccountTest.java new file mode 100644 index 00000000000..94c7b25b56c --- /dev/null +++ b/src/test/java/blackjack/domain/game/GameAccountTest.java @@ -0,0 +1,23 @@ +package blackjack.domain.game; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.gamer.Name; +import blackjack.domain.gamer.Player; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GameAccountTest { + + @Test + @DisplayName("플레이어가 금액을 배팅한다.") + void betMoneyTest() { + GameAccount gameAccount = new GameAccount(); + Player player = new Player(new Name("loki")); + Money money = new Money(50000); + + gameAccount.betMoney(player, money); + + assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(50000)); + } +} From feaa0057d51518e288a8d648de85f8941fcd5d54 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 02:08:19 +0900 Subject: [PATCH 12/21] =?UTF-8?q?feat(GameAccount):=20=EB=B0=B0=ED=8C=85?= =?UTF-8?q?=ED=95=9C=20=EA=B8=88=EC=95=A1=EC=97=90=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=A0=81=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackjack/domain/game/GameAccount.java | 10 ++++++ .../java/blackjack/domain/game/Money.java | 4 +++ .../java/blackjack/domain/gamer/Players.java | 6 ++-- .../domain/game/GameAccountTest.java | 31 ++++++++++++++++--- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/main/java/blackjack/domain/game/GameAccount.java b/src/main/java/blackjack/domain/game/GameAccount.java index 67c0f1455c8..0268b462fec 100644 --- a/src/main/java/blackjack/domain/game/GameAccount.java +++ b/src/main/java/blackjack/domain/game/GameAccount.java @@ -1,5 +1,6 @@ package blackjack.domain.game; +import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Player; import java.util.LinkedHashMap; import java.util.Map; @@ -15,4 +16,13 @@ public void betMoney(Player player, Money money) { public Money findMoney(Player player) { return store.get(player); } + + public void applyGameResults(Map gameResults) { + for (Player player : gameResults.keySet()) { + Money money = store.get(player); + GameResult gameResult = gameResults.get(player); + Money gameResultMoney = money.multipleRatio(gameResult.getRatio()); + store.put(player, gameResultMoney); + } + } } diff --git a/src/main/java/blackjack/domain/game/Money.java b/src/main/java/blackjack/domain/game/Money.java index fff48d56621..ad2c5512a67 100644 --- a/src/main/java/blackjack/domain/game/Money.java +++ b/src/main/java/blackjack/domain/game/Money.java @@ -1,4 +1,8 @@ package blackjack.domain.game; public record Money(int value) { + + public Money multipleRatio(double ratio) { + return new Money((int) (this.value * ratio)); + } } diff --git a/src/main/java/blackjack/domain/gamer/Players.java b/src/main/java/blackjack/domain/gamer/Players.java index f2473e48ea9..d0de3292055 100644 --- a/src/main/java/blackjack/domain/gamer/Players.java +++ b/src/main/java/blackjack/domain/gamer/Players.java @@ -47,9 +47,9 @@ public void initAllPlayersCard(Deck deck) { players.forEach(player -> player.initCard(deck)); } - public Map collectPlayerGameResults(HandValue dealerHandValue) { - Map playerGameResults = new LinkedHashMap<>(); - players.forEach(player -> playerGameResults.put(player.getName(), player.compete(dealerHandValue))); + public Map collectPlayerGameResults(HandValue dealerHandValue) { + Map playerGameResults = new LinkedHashMap<>(); + players.forEach(player -> playerGameResults.put(player, player.compete(dealerHandValue))); return playerGameResults; } diff --git a/src/test/java/blackjack/domain/game/GameAccountTest.java b/src/test/java/blackjack/domain/game/GameAccountTest.java index 94c7b25b56c..a5eac8b4d41 100644 --- a/src/test/java/blackjack/domain/game/GameAccountTest.java +++ b/src/test/java/blackjack/domain/game/GameAccountTest.java @@ -2,22 +2,45 @@ import static org.assertj.core.api.Assertions.assertThat; +import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Name; import blackjack.domain.gamer.Player; +import java.util.LinkedHashMap; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class GameAccountTest { + private GameAccount gameAccount; + private Player player; + private Money money; + + @BeforeEach + void setUp() { + gameAccount = new GameAccount(); + player = new Player(new Name("loki")); + money = new Money(50000); + } + @Test @DisplayName("플레이어가 금액을 배팅한다.") void betMoneyTest() { - GameAccount gameAccount = new GameAccount(); - Player player = new Player(new Name("loki")); - Money money = new Money(50000); - gameAccount.betMoney(player, money); assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(50000)); } + + @Test + @DisplayName("플레이어의 게임 결과를 배팅한 금액에 적용한다") + void applyGameResultsTest() { + Map gameResults = new LinkedHashMap<>(); + gameAccount.betMoney(player, money); + gameResults.put(player, GameResult.BLACKJACK_WIN); + + gameAccount.applyGameResults(gameResults); + + assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(75000)); + } } From 6753755f90f7810751ab6d74fbebfbd09a670a56 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 09:57:48 +0900 Subject: [PATCH 13/21] =?UTF-8?q?feat(GameAccount):=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=EC=9D=98=20=EB=B0=B0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B2=B0=EA=B3=BC=EB=A1=9C=20=EB=94=9C=EB=9F=AC?= =?UTF-8?q?=EC=9D=98=20=EC=88=98=EC=9D=B5=EC=9D=84=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/game/GameAccount.java | 8 ++++++++ .../java/blackjack/domain/game/GameAccountTest.java | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/blackjack/domain/game/GameAccount.java b/src/main/java/blackjack/domain/game/GameAccount.java index 0268b462fec..5488f6376ef 100644 --- a/src/main/java/blackjack/domain/game/GameAccount.java +++ b/src/main/java/blackjack/domain/game/GameAccount.java @@ -25,4 +25,12 @@ public void applyGameResults(Map gameResults) { store.put(player, gameResultMoney); } } + + public Money calculateDealerIncome() { + int dealerIncome = 0; + for (Money money : store.values()) { + dealerIncome += money.value(); + } + return new Money(-dealerIncome); + } } diff --git a/src/test/java/blackjack/domain/game/GameAccountTest.java b/src/test/java/blackjack/domain/game/GameAccountTest.java index a5eac8b4d41..0c179a3bfca 100644 --- a/src/test/java/blackjack/domain/game/GameAccountTest.java +++ b/src/test/java/blackjack/domain/game/GameAccountTest.java @@ -43,4 +43,15 @@ void applyGameResultsTest() { assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(75000)); } + + @Test + @DisplayName("플레이어의 배팅 금액 결과로 딜러의 수익을 계산한다.") + void calculateDealerIncome() { + gameAccount.betMoney(player, money); + gameAccount.betMoney(new Player(new Name("jazz")), new Money(-20000)); + + Money dealerIncome = gameAccount.calculateDealerIncome(); + + assertThat(dealerIncome).isEqualTo(new Money(-30000)); + } } From 920b6cf1a31de3128a48fe4a440be0036ddf6517 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 11:00:08 +0900 Subject: [PATCH 14/21] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=EC=99=80=20?= =?UTF-8?q?=ED=94=8C=EB=A0=88=EC=9D=B4=EC=96=B4=EC=9D=98=20=EC=B5=9C?= =?UTF-8?q?=EC=A2=85=20=EC=88=98=EC=9D=B5=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BlackjackController.java | 28 ++++++++++------- .../blackjack/domain/game/GameAccount.java | 4 +++ .../java/blackjack/dto/DealerResultDto.java | 17 ----------- .../blackjack/dto/PlayerGameResultsDto.java | 16 +++++----- src/main/java/blackjack/view/OutputView.java | 30 +++++-------------- 5 files changed, 37 insertions(+), 58 deletions(-) delete mode 100644 src/main/java/blackjack/dto/DealerResultDto.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 0ad7bacb400..101afd8c07f 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,13 +1,13 @@ package blackjack.controller; import blackjack.domain.card.Deck; +import blackjack.domain.game.GameAccount; +import blackjack.domain.game.Money; import blackjack.domain.gamer.Dealer; import blackjack.domain.gamer.GameResult; -import blackjack.domain.gamer.Name; import blackjack.domain.gamer.Player; import blackjack.domain.gamer.Players; import blackjack.dto.DealerInitialHandDto; -import blackjack.dto.DealerResultDto; import blackjack.dto.HandDto; import blackjack.dto.PlayerGameResultsDto; import blackjack.dto.PlayerHandDto; @@ -15,7 +15,6 @@ import blackjack.view.InputView; import blackjack.view.OutputView; import blackjack.view.object.Command; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -35,11 +34,13 @@ public void run() { Deck deck = new Deck(); deck.shuffle(); + GameAccount gameAccount = new GameAccount(); + betMoney(gameAccount, players); setUpInitialHands(players, deck, dealer); distributeCardToPlayers(players, deck); distributeCardToDealer(dealer, deck); printAllGamerScores(dealer, players); - printResult(dealer, players); + printResult(players, dealer, gameAccount); } private Players getPlayers() { @@ -48,6 +49,13 @@ private Players getPlayers() { return new Players(playerNames); } + private void betMoney(GameAccount gameAccount, Players players) { + for (Player player : players.getPlayers()) { + int betMoney = inputView.receivePlayerMoney(player.getName().value()); + gameAccount.betMoney(player, new Money(betMoney)); + } + } + private void setUpInitialHands(Players players, Deck deck, Dealer dealer) { players.initAllPlayersCard(deck); dealer.initCard(deck); @@ -103,12 +111,12 @@ private void printPlayersScores(Players players) { outputView.printPlayersHandScore(PlayersHandDto.fromPlayers(players)); } - private void printResult(Dealer dealer, Players players) { - Map playerGameResults = players.collectPlayerGameResults(dealer.getHandValue()); - PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerGameResults(playerGameResults); - List playerResults = new ArrayList<>(playerGameResultsDto.resultMap().values()); - DealerResultDto dealerResultDto = DealerResultDto.fromPlayerResults(playerResults); + private void printResult(Players players, Dealer dealer, GameAccount gameAccount) { + Map playerGameResults = players.collectPlayerGameResults(dealer.getHandValue()); + gameAccount.applyGameResults(playerGameResults); + Money dealerIncome = gameAccount.calculateDealerIncome(); - outputView.printResult(dealerResultDto, playerGameResultsDto); + PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerBetResults(gameAccount.getStore()); + outputView.printResult(dealerIncome.value(), playerGameResultsDto); } } diff --git a/src/main/java/blackjack/domain/game/GameAccount.java b/src/main/java/blackjack/domain/game/GameAccount.java index 5488f6376ef..0e0bfebcbf2 100644 --- a/src/main/java/blackjack/domain/game/GameAccount.java +++ b/src/main/java/blackjack/domain/game/GameAccount.java @@ -33,4 +33,8 @@ public Money calculateDealerIncome() { } return new Money(-dealerIncome); } + + public Map getStore() { + return new LinkedHashMap<>(store); + } } diff --git a/src/main/java/blackjack/dto/DealerResultDto.java b/src/main/java/blackjack/dto/DealerResultDto.java deleted file mode 100644 index 32af44e0fb1..00000000000 --- a/src/main/java/blackjack/dto/DealerResultDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package blackjack.dto; - -import blackjack.domain.gamer.GameResult; -import java.util.List; - -public record DealerResultDto(int winCount, int loseCount) { - - public static DealerResultDto fromPlayerResults(List playerResults) { - int dealerWinCount = (int) playerResults.stream() - .filter(GameResult::Lose) - .count(); - - int dealerLoseCount = playerResults.size() - dealerWinCount; - - return new DealerResultDto(dealerWinCount, dealerLoseCount); - } -} diff --git a/src/main/java/blackjack/dto/PlayerGameResultsDto.java b/src/main/java/blackjack/dto/PlayerGameResultsDto.java index bacf83827e7..91b54067564 100644 --- a/src/main/java/blackjack/dto/PlayerGameResultsDto.java +++ b/src/main/java/blackjack/dto/PlayerGameResultsDto.java @@ -1,19 +1,19 @@ package blackjack.dto; -import blackjack.domain.gamer.GameResult; -import blackjack.domain.gamer.Name; +import blackjack.domain.game.Money; +import blackjack.domain.gamer.Player; import java.util.LinkedHashMap; import java.util.Map; -public record PlayerGameResultsDto(Map resultMap) { +public record PlayerGameResultsDto(Map playerIncomeResults) { - public static PlayerGameResultsDto fromPlayerGameResults(Map playerGameResults) { - Map gameResult = new LinkedHashMap<>(); + public static PlayerGameResultsDto fromPlayerBetResults(Map playerBetResults) { + Map playerIncomeResults = new LinkedHashMap<>(); - for (Name playerName : playerGameResults.keySet()) { - gameResult.put(playerName.value(), playerGameResults.get(playerName)); + for (Player player : playerBetResults.keySet()) { + playerIncomeResults.put(player.getName().value(), playerBetResults.get(player).value()); } - return new PlayerGameResultsDto(gameResult); + return new PlayerGameResultsDto(playerIncomeResults); } } diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index cab8521c6dd..2cf5d09bbfe 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -2,14 +2,12 @@ import blackjack.dto.CardDto; import blackjack.dto.DealerInitialHandDto; -import blackjack.dto.DealerResultDto; import blackjack.dto.HandDto; import blackjack.dto.PlayerGameResultsDto; import blackjack.dto.PlayerHandDto; import blackjack.dto.PlayersHandDto; import blackjack.view.object.CardNumberOutput; import blackjack.view.object.CardShapeOutput; -import blackjack.view.object.GameResultOutput; import java.util.List; public class OutputView { @@ -92,34 +90,20 @@ public void printDealerMessage() { System.out.printf("\n%s는 16이하라 한장의 카드를 더 받았습니다.\n", DEALER_DEFAULT_NAME); } - public void printResult(DealerResultDto dealerResultDto, PlayerGameResultsDto playerGameResultsDto) { - System.out.println("\n## 최종 승패"); - printDealerResult(dealerResultDto); + public void printResult(int dealerIncome, PlayerGameResultsDto playerGameResultsDto) { + System.out.println("\n## 최종 수익"); + printDealerResult(dealerIncome); printPlayerResults(playerGameResultsDto); } - private void printDealerResult(DealerResultDto dealerResultDto) { - int winCount = dealerResultDto.winCount(); - int loseCount = dealerResultDto.loseCount(); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder - .append(DEALER_DEFAULT_NAME) - .append(": "); - - if (winCount > 0) { - stringBuilder.append(winCount) - .append("승 "); - } - if (loseCount > 0) { - stringBuilder.append(loseCount) - .append("패"); - } + private void printDealerResult(int dealerIncome) { + String stringBuilder = DEALER_DEFAULT_NAME + ": " + dealerIncome; System.out.println(stringBuilder); } private void printPlayerResults(PlayerGameResultsDto playerGameResultsDto) { - playerGameResultsDto.resultMap().forEach((name, result) -> - System.out.println(name + ": " + GameResultOutput.convertGameResultToOutput(result)) + playerGameResultsDto.playerIncomeResults().forEach((name, money) -> + System.out.println(name + ": " + money) ); } From af934a5924c620526adeaec7a620b2c5d2e54c2a Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 16:04:00 +0900 Subject: [PATCH 15/21] =?UTF-8?q?feat(GameAccount):=20map=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=EC=86=8C=EB=A5=BC=20=EC=B4=88=EA=B8=B0=ED=99=94?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/game/GameAccount.java | 4 ++++ src/test/java/blackjack/domain/game/GameAccountTest.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/blackjack/domain/game/GameAccount.java b/src/main/java/blackjack/domain/game/GameAccount.java index 0e0bfebcbf2..95373698ec2 100644 --- a/src/main/java/blackjack/domain/game/GameAccount.java +++ b/src/main/java/blackjack/domain/game/GameAccount.java @@ -37,4 +37,8 @@ public Money calculateDealerIncome() { public Map getStore() { return new LinkedHashMap<>(store); } + + public void clearStore() { + store.clear(); + } } diff --git a/src/test/java/blackjack/domain/game/GameAccountTest.java b/src/test/java/blackjack/domain/game/GameAccountTest.java index 0c179a3bfca..64e91e1413b 100644 --- a/src/test/java/blackjack/domain/game/GameAccountTest.java +++ b/src/test/java/blackjack/domain/game/GameAccountTest.java @@ -7,6 +7,7 @@ import blackjack.domain.gamer.Player; import java.util.LinkedHashMap; import java.util.Map; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,6 +25,11 @@ void setUp() { money = new Money(50000); } + @AfterEach + void afterEach() { + gameAccount.clearStore(); + } + @Test @DisplayName("플레이어가 금액을 배팅한다.") void betMoneyTest() { From 661c788110e54062e08e3b25b0f173ad6e2b0ab8 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 16:06:36 +0900 Subject: [PATCH 16/21] =?UTF-8?q?refactor(BlackjackController):=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B8=94=EB=9E=99=EC=9E=AD=20=EA=B2=8C=EC=9E=84=20=ED=9D=90?= =?UTF-8?q?=EB=A6=84=EC=9D=84=20=EB=8B=B4=EB=8B=B9=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BlackjackController.java | 80 +++++++------------ .../blackjack/domain/game/BlackjackGame.java | 60 ++++++++++++++ src/main/java/blackjack/view/OutputView.java | 1 + .../view/object/GameResultOutput.java | 26 ------ 4 files changed, 89 insertions(+), 78 deletions(-) create mode 100644 src/main/java/blackjack/domain/game/BlackjackGame.java delete mode 100644 src/main/java/blackjack/view/object/GameResultOutput.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 101afd8c07f..19a8f915697 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,10 +1,8 @@ package blackjack.controller; -import blackjack.domain.card.Deck; -import blackjack.domain.game.GameAccount; +import blackjack.domain.game.BlackjackGame; import blackjack.domain.game.Money; import blackjack.domain.gamer.Dealer; -import blackjack.domain.gamer.GameResult; import blackjack.domain.gamer.Player; import blackjack.domain.gamer.Players; import blackjack.dto.DealerInitialHandDto; @@ -15,6 +13,7 @@ import blackjack.view.InputView; import blackjack.view.OutputView; import blackjack.view.object.Command; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,101 +21,78 @@ public class BlackjackController { private final InputView inputView; private final OutputView outputView; + private final BlackjackGame blackjackGame; public BlackjackController() { this.inputView = new InputView(); this.outputView = new OutputView(); + this.blackjackGame = new BlackjackGame(); } public void run() { Players players = getPlayers(); Dealer dealer = new Dealer(); - Deck deck = new Deck(); - deck.shuffle(); - - GameAccount gameAccount = new GameAccount(); - betMoney(gameAccount, players); - setUpInitialHands(players, deck, dealer); - distributeCardToPlayers(players, deck); - distributeCardToDealer(dealer, deck); + blackjackGame.distributeInitialHand(players, dealer); + blackjackGame.betPlayerMoney(receivePlayersBetMoney(players)); + printInitialHands(players, dealer); + + distributeCardToPlayers(players); + blackjackGame.distributeCardToDealer(dealer); + + printDealerCanReceiveCardMessage(dealer); printAllGamerScores(dealer, players); - printResult(players, dealer, gameAccount); + printResult(players, dealer); } private Players getPlayers() { List playerNames = inputView.receivePlayerNames(); - return new Players(playerNames); } - private void betMoney(GameAccount gameAccount, Players players) { + private Map receivePlayersBetMoney(Players players) { + Map playerBetMoney = new HashMap<>(); for (Player player : players.getPlayers()) { int betMoney = inputView.receivePlayerMoney(player.getName().value()); - gameAccount.betMoney(player, new Money(betMoney)); + playerBetMoney.put(player, new Money(betMoney)); } - } - - private void setUpInitialHands(Players players, Deck deck, Dealer dealer) { - players.initAllPlayersCard(deck); - dealer.initCard(deck); - printInitialHands(players, dealer); + return playerBetMoney; } private void printInitialHands(Players players, Dealer dealer) { - DealerInitialHandDto dealerInitialHandDto = DealerInitialHandDto.fromDealer(dealer); - PlayersHandDto playersInitialHandDto = PlayersHandDto.fromPlayers(players); - - outputView.printInitialHands(dealerInitialHandDto, playersInitialHandDto); + outputView.printInitialHands(DealerInitialHandDto.fromDealer(dealer), PlayersHandDto.fromPlayers(players)); } - private void distributeCardToPlayers(Players players, Deck deck) { + private void distributeCardToPlayers(Players players) { for (Player player : players.getPlayers()) { - distributeCardToPlayer(deck, player); + distributeCardToPlayer(player); } } - private void distributeCardToPlayer(Deck deck, Player player) { - while (canDistribute(player)) { - player.addCard(deck.draw()); + private void distributeCardToPlayer(Player player) { + while (player.canReceiveCard() && Command.isHit(getCommand(player))) { + blackjackGame.addCardToPlayer(player); outputView.printPlayerHand(PlayerHandDto.fromPlayer(player)); } } - private boolean canDistribute(Player player) { - return player.canReceiveCard() && Command.isHit(getCommand(player)); - } - private Command getCommand(Player player) { return inputView.receiveCommand(player.getName().value()); } - private void distributeCardToDealer(Dealer dealer, Deck deck) { - while (dealer.canReceiveCard()) { - dealer.addCard(deck.draw()); + private void printDealerCanReceiveCardMessage(Dealer dealer) { + if (dealer.canReceiveCard()) { outputView.printDealerMessage(); } } private void printAllGamerScores(Dealer dealer, Players players) { - printDealerScore(dealer); - printPlayersScores(players); - } - - private void printDealerScore(Dealer dealer) { - outputView.printEmptyLine(); outputView.printDealerHandScore(HandDto.fromHand(dealer.getHand())); - } - - private void printPlayersScores(Players players) { outputView.printPlayersHandScore(PlayersHandDto.fromPlayers(players)); } - private void printResult(Players players, Dealer dealer, GameAccount gameAccount) { - Map playerGameResults = players.collectPlayerGameResults(dealer.getHandValue()); - gameAccount.applyGameResults(playerGameResults); - Money dealerIncome = gameAccount.calculateDealerIncome(); - - PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerBetResults(gameAccount.getStore()); + private void printResult(Players players, Dealer dealer) { + Money dealerIncome = blackjackGame.calculateDealerIncome(players, dealer); + PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerBetResults(blackjackGame.getStore()); outputView.printResult(dealerIncome.value(), playerGameResultsDto); } } diff --git a/src/main/java/blackjack/domain/game/BlackjackGame.java b/src/main/java/blackjack/domain/game/BlackjackGame.java new file mode 100644 index 00000000000..6a24b501aff --- /dev/null +++ b/src/main/java/blackjack/domain/game/BlackjackGame.java @@ -0,0 +1,60 @@ +package blackjack.domain.game; + +import blackjack.domain.card.Deck; +import blackjack.domain.gamer.Dealer; +import blackjack.domain.gamer.GameResult; +import blackjack.domain.gamer.Player; +import blackjack.domain.gamer.Players; +import java.util.Map; + +public class BlackjackGame { + + private final GameAccount gameAccount; + private final Deck deck; + + public BlackjackGame() { + this.gameAccount = new GameAccount(); + this.deck = new Deck(); + } + + public void distributeInitialHand(Players players, Dealer dealer) { + deck.shuffle(); + setUpInitialHands(players, dealer); + } + + + private void setUpInitialHands(Players players, Dealer dealer) { + players.initAllPlayersCard(deck); + dealer.initCard(deck); + } + + public void betPlayerMoney(Map playersBetMoney) { + for (Player player : playersBetMoney.keySet()) { + gameAccount.betMoney(player, playersBetMoney.get(player)); + } + } + + public void addCardToPlayer(Player player) { + player.addCard(deck.draw()); + } + + public void distributeCardToDealer(Dealer dealer) { + while (dealer.canReceiveCard()) { + dealer.addCard(deck.draw()); + } + } + + public Money calculateDealerIncome(Players players, Dealer dealer) { + applyResultToBetMoney(players, dealer); + return gameAccount.calculateDealerIncome(); + } + + private void applyResultToBetMoney(Players players, Dealer dealer) { + Map playerGameResults = players.collectPlayerGameResults(dealer.getHandValue()); + gameAccount.applyGameResults(playerGameResults); + } + + public Map getStore() { + return gameAccount.getStore(); + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 2cf5d09bbfe..4b261616b15 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -81,6 +81,7 @@ public void printPlayersHandScore(PlayersHandDto playersHandDto) { } public void printDealerHandScore(HandDto dealerHandDto) { + System.out.println(); System.out.println(getDealerNameOutputFormat(dealerHandDto) .append(" - 결과: ") .append(dealerHandDto.handScore())); diff --git a/src/main/java/blackjack/view/object/GameResultOutput.java b/src/main/java/blackjack/view/object/GameResultOutput.java deleted file mode 100644 index c41a70e3b8d..00000000000 --- a/src/main/java/blackjack/view/object/GameResultOutput.java +++ /dev/null @@ -1,26 +0,0 @@ -package blackjack.view.object; - -import blackjack.domain.gamer.GameResult; -import java.util.Arrays; - -public enum GameResultOutput { - - WIN_OUTPUT(GameResult.WIN, "승"), - LOSE_OUTPUT(GameResult.LOSE, "패"); - - private final GameResult gameResult; - private final String output; - - GameResultOutput(GameResult gameResult, String output) { - this.gameResult = gameResult; - this.output = output; - } - - public static String convertGameResultToOutput(GameResult gameResult) { - return Arrays.stream(values()) - .filter(gameResultOutput -> gameResultOutput.gameResult == gameResult) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("일치하는 게임 결과가 존재하지 않아 문자열을 반환할 수 없습니다.")) - .output; - } -} From 0343057bf79cfe0eb33e0a5e9653b051d9e3d036 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Thu, 14 Mar 2024 16:07:46 +0900 Subject: [PATCH 17/21] =?UTF-8?q?docs(README):=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EB=8F=99=EA=B8=B0?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c94da57ce6e..f0776d7826a 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,17 @@ - [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다. - [x] 이후 플레이어와 딜러의 카드를 출력한다. - [x] 단, 딜러의 카드는 하나만 출력한다. -- [ ] 플레이어는 게임을 시작할 때 원하는 금액을 배팅한다. +- [x] 플레이어는 게임을 시작할 때 원하는 금액을 배팅한다. - [x] 플레이어는 카드의 숫자 합이 21을 초과하지 않는다면 카드를 원하는 만큼 다시 뽑을 수 있다. - [x] 새로 받을 때 마다 해당 플레이어의 카드를 출력한다. - [x] 플레이어가 카드를 다 받으면 딜러의 카드를 확인한다. - [x] 딜러의 카드 합이 17 이상이 될 때 까지 카드를 받는다. -- [ ] 플레이어의 게임 결과로부터 수익을 계산한다. - - [ ] 블랙잭으로 승리 할 경우 배팅 금액의 1.5배를 딜러로부터 받는다. - - [ ] 무승부인 경우 플레이어는 베팅한 금액을 돌려받는다. - - [ ] 승리할 경우 베팅 금액만큼 받는다. - - [ ] 패배할 경우 배팅 금액을 모두 잃는다. -- [ ] 딜러와 플레이어의 카드, 결과와 최종 수익 결과를 출력한다. +- [x] 플레이어의 게임 결과로부터 수익을 계산한다. + - [x] 블랙잭으로 승리 할 경우 배팅 금액의 1.5배를 딜러로부터 받는다. + - [x] 무승부인 경우 플레이어는 베팅한 금액을 돌려받는다. + - [x] 승리할 경우 베팅 금액만큼 받는다. + - [x] 패배할 경우 배팅 금액을 모두 잃는다. +- [x] 딜러와 플레이어의 카드, 결과와 최종 수익 결과를 출력한다. ### 카드 @@ -41,11 +41,11 @@ - [x] 플레이어의 이름은 중복될 수 없다. - [x] 플레이어는 최소 2명부터 최대 8명까지 가능하다. -- [ ] 딜러의 점수를 입력받아 승,무,패를 결정한다. - - [ ] (블랙잭) 처음 두 장의 카드 합이 21일 경우 블랙잭. - - [ ] (무승부) 딜러와 플레이어가 동시에 블랙잭인 경우. - - [ ] (무승부) 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우. - - [ ] (승리) 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하는 경우. - - [ ] (승리) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 큰 경우. - - [ ] (패배) 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관. - - [ ] (패배) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 작은 경우. +- [x] 딜러의 점수를 입력받아 승,무,패를 결정한다. + - [x] (블랙잭) 처음 두 장의 카드 합이 21일 경우 블랙잭. + - [x] (무승부) 딜러와 플레이어가 동시에 블랙잭인 경우. + - [x] (무승부) 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우. + - [x] (승리) 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하는 경우. + - [x] (승리) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 큰 경우. + - [x] (패배) 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관. + - [x] (패배) 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 작은 경우. From 19e55eeb1fad4e258129e639ed3c2198f3e7c13d Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 15 Mar 2024 14:00:34 +0900 Subject: [PATCH 18/21] =?UTF-8?q?fix:=20Deck,=20HandValue=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EC=9E=90=20=EC=A0=91=EA=B7=BC=20=EC=A0=9C=ED=95=9C?= =?UTF-8?q?=EC=9E=90=20default=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/card/Deck.java | 2 +- src/main/java/blackjack/domain/gamer/HandValue.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/blackjack/domain/card/Deck.java b/src/main/java/blackjack/domain/card/Deck.java index fa14135b41f..7c582159af7 100644 --- a/src/main/java/blackjack/domain/card/Deck.java +++ b/src/main/java/blackjack/domain/card/Deck.java @@ -18,7 +18,7 @@ public Deck() { this.cards = new LinkedList<>(CACHE); } - public Deck(LinkedList cards) { + Deck(LinkedList cards) { this.cards = cards; } diff --git a/src/main/java/blackjack/domain/gamer/HandValue.java b/src/main/java/blackjack/domain/gamer/HandValue.java index c4ecbc1fb0e..d3e32f15cc0 100644 --- a/src/main/java/blackjack/domain/gamer/HandValue.java +++ b/src/main/java/blackjack/domain/gamer/HandValue.java @@ -16,7 +16,7 @@ public HandValue(List cards) { this.handSize = cards.size(); } - public HandValue(int score, int handSize) { + HandValue(int score, int handSize) { this.score = score; this.handSize = handSize; } From c56511109fababb8440fdfbb54221e81a3befb2a Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 15 Mar 2024 14:02:16 +0900 Subject: [PATCH 19/21] =?UTF-8?q?fix(HandValue):=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=EC=9E=AD=20=EC=9A=94=EA=B5=AC=20=EC=B9=B4=EB=93=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98(2)=20=EC=A1=B0=EA=B1=B4=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/gamer/HandValue.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/blackjack/domain/gamer/HandValue.java b/src/main/java/blackjack/domain/gamer/HandValue.java index d3e32f15cc0..0d31968ce81 100644 --- a/src/main/java/blackjack/domain/gamer/HandValue.java +++ b/src/main/java/blackjack/domain/gamer/HandValue.java @@ -6,6 +6,7 @@ public class HandValue { private static final int BLACKJACK_MAX_SCORE = 21; + private static final int BLACKJACK_HAND_SIZE_CONDITION = 2; private static final int ACE_VALUE_MODIFIER = 10; private final int score; @@ -62,7 +63,7 @@ private int adjust(int sum) { } public boolean isBlackjack() { - return score == BLACKJACK_MAX_SCORE && handSize == 2; + return score == BLACKJACK_MAX_SCORE && handSize == BLACKJACK_HAND_SIZE_CONDITION; } public boolean isNotBlackjack() { From 6134b0616aa885a7cb25f8975c647c1826e38a66 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 15 Mar 2024 16:32:27 +0900 Subject: [PATCH 20/21] =?UTF-8?q?refactor(HandValue):=20=EA=B0=80=EB=8F=85?= =?UTF-8?q?=EC=84=B1=20=ED=96=A5=EC=83=81=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?HandValue=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/gamer/BlackjackGamer.java | 2 +- src/main/java/blackjack/domain/gamer/Hand.java | 2 +- src/main/java/blackjack/dto/HandDto.java | 2 +- src/test/java/blackjack/domain/gamer/HandTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java index f83f536ce18..2de6d351233 100644 --- a/src/main/java/blackjack/domain/gamer/BlackjackGamer.java +++ b/src/main/java/blackjack/domain/gamer/BlackjackGamer.java @@ -32,7 +32,7 @@ public Hand getHand() { } public HandValue getHandValue() { - return hand.getValue(); + return hand.generateValue(); } public int getScore() { diff --git a/src/main/java/blackjack/domain/gamer/Hand.java b/src/main/java/blackjack/domain/gamer/Hand.java index ad1b04055c2..4ee7fdcab34 100644 --- a/src/main/java/blackjack/domain/gamer/Hand.java +++ b/src/main/java/blackjack/domain/gamer/Hand.java @@ -16,7 +16,7 @@ public void add(Card card) { cards.add(card); } - public HandValue getValue() { + public HandValue generateValue() { return new HandValue(cards); } diff --git a/src/main/java/blackjack/dto/HandDto.java b/src/main/java/blackjack/dto/HandDto.java index 64925ccc104..0ffc9b4be13 100644 --- a/src/main/java/blackjack/dto/HandDto.java +++ b/src/main/java/blackjack/dto/HandDto.java @@ -10,6 +10,6 @@ public static HandDto fromHand(Hand hand) { .map(CardDto::fromCard) .toList(); - return new HandDto(cardDtos, hand.getValue().getScore()); + return new HandDto(cardDtos, hand.generateValue().getScore()); } } diff --git a/src/test/java/blackjack/domain/gamer/HandTest.java b/src/test/java/blackjack/domain/gamer/HandTest.java index fbe2f0fa877..63b7730d349 100644 --- a/src/test/java/blackjack/domain/gamer/HandTest.java +++ b/src/test/java/blackjack/domain/gamer/HandTest.java @@ -34,6 +34,6 @@ void getFirstCardTest() { @Test @DisplayName("핸드의 밸류를 정상적으로 생성한다.") void createHandValueTest() { - assertThatNoException().isThrownBy(() -> hand.getValue()); + assertThatNoException().isThrownBy(() -> hand.generateValue()); } } From 43845055c4b6860d7c8c5171d62e8abe0ef83920 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 15 Mar 2024 16:33:02 +0900 Subject: [PATCH 21/21] =?UTF-8?q?refactor(Player):=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/blackjack/domain/gamer/Player.java | 4 +-- .../java/blackjack/domain/gamer/Players.java | 2 +- .../domain/game/GameAccountTest.java | 32 +++++++++++++------ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java index 1affb0828b8..47b8a6c86f6 100644 --- a/src/main/java/blackjack/domain/gamer/Player.java +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -6,8 +6,8 @@ public class Player extends BlackjackGamer { private final Name name; - public Player(Name name) { - this.name = name; + public Player(String name) { + this.name = new Name(name); } public Player(Hand hand, Name name) { diff --git a/src/main/java/blackjack/domain/gamer/Players.java b/src/main/java/blackjack/domain/gamer/Players.java index d0de3292055..e4731f7abc0 100644 --- a/src/main/java/blackjack/domain/gamer/Players.java +++ b/src/main/java/blackjack/domain/gamer/Players.java @@ -18,7 +18,7 @@ public Players(List names) { validateNames(names); this.players = names.stream() - .map(name -> new Player(new Name(name))) + .map(Player::new) .toList(); } diff --git a/src/test/java/blackjack/domain/game/GameAccountTest.java b/src/test/java/blackjack/domain/game/GameAccountTest.java index 64e91e1413b..d8f7b190ddf 100644 --- a/src/test/java/blackjack/domain/game/GameAccountTest.java +++ b/src/test/java/blackjack/domain/game/GameAccountTest.java @@ -3,14 +3,16 @@ import static org.assertj.core.api.Assertions.assertThat; import blackjack.domain.gamer.GameResult; -import blackjack.domain.gamer.Name; import blackjack.domain.gamer.Player; -import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class GameAccountTest { @@ -21,7 +23,7 @@ class GameAccountTest { @BeforeEach void setUp() { gameAccount = new GameAccount(); - player = new Player(new Name("loki")); + player = new Player("loki"); money = new Money(50000); } @@ -38,23 +40,33 @@ void betMoneyTest() { assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(50000)); } - @Test + @ParameterizedTest + @MethodSource("provideGameResultsAndMoney") @DisplayName("플레이어의 게임 결과를 배팅한 금액에 적용한다") - void applyGameResultsTest() { - Map gameResults = new LinkedHashMap<>(); - gameAccount.betMoney(player, money); - gameResults.put(player, GameResult.BLACKJACK_WIN); + void applyGameResultsTest(GameResult gameResult, Money expectedMoney) { + Map gameResults = Map.of(player, gameResult); + gameAccount.betMoney(player, money); gameAccount.applyGameResults(gameResults); - assertThat(gameAccount.findMoney(player)).isEqualTo(new Money(75000)); + assertThat(gameAccount.findMoney(player)).isEqualTo(expectedMoney); } + private static Stream provideGameResultsAndMoney() { + return Stream.of( + Arguments.of(GameResult.BLACKJACK_WIN, new Money(75000)), + Arguments.of(GameResult.WIN, new Money(50000)), + Arguments.of(GameResult.DRAW, new Money(0)), + Arguments.of(GameResult.LOSE, new Money(-50000) + )); + } + + @Test @DisplayName("플레이어의 배팅 금액 결과로 딜러의 수익을 계산한다.") void calculateDealerIncome() { gameAccount.betMoney(player, money); - gameAccount.betMoney(new Player(new Name("jazz")), new Money(-20000)); + gameAccount.betMoney(new Player("jazz"), new Money(-20000)); Money dealerIncome = gameAccount.calculateDealerIncome();