diff --git a/README.md b/README.md index 8be9782ef41..4a7dc1b573c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # java-blackjack -# 블랙잭 미션 저장소 - -# 블랙잭 미션 요구사항 정리 - -# User Requirement +## User Requirement - 플레이어의 이름을 입력한다. - 시스템은 딜러와 각 플레이어에게 카드를 두 장싹 분배한다. @@ -12,40 +8,42 @@ - 모든 플레이어의 차례가 끝나면 딜러가 규칙에 따라 카드를 추가로 받는다. - 딜러와 플레이어의 점수를 비교해서 21을 초과하지 않되, 21에 더 근접한 사람이 승리한다. -# System Requirement -- [X] 참가자는 딜러와 플레이어 모두를 의미한다. +## System Requirement + +- [x] 참가자는 딜러와 플레이어 모두를 의미한다. #### 게임 환경 세팅 -- [X] 게임에 참여할 플레이어의 이름을 쉼표를 기준으로 분리하여 입력받는다. - - [X] 앞 뒤의 공백은 제거한다. - - [X] 입력이 비어있으면 예외를 발생시킨다. - - [X] 플레이어의 이름이 중복되는 경우 예외를 발생시킨다. - - [X] 구분자인 쉼표가 맨 앞에 있는 경우 이를 없애고 정상 입력으로 처리한다. - - [X] 구분자인 쉼표가 연속되어 나오는 경우 이를 없애고 정상 입력으로 처리한다. - - [X] 플레이어 수는 최대 5인으로 제한한다. +- [x] 게임에 참여할 플레이어의 이름을 쉼표를 기준으로 분리하여 입력받는다. + - [x] 앞 뒤의 공백은 제거한다. + - [x] 입력이 비어있으면 예외를 발생시킨다. + - [x] 플레이어의 이름이 중복되는 경우 예외를 발생시킨다. + - [x] 구분자인 쉼표가 맨 앞에 있는 경우 이를 없애고 정상 입력으로 처리한다. + - [x] 구분자인 쉼표가 연속되어 나오는 경우 이를 없애고 정상 입력으로 처리한다. + - [x] 플레이어 수는 최대 5인으로 제한한다. - [x] 플레이어의 이름은 최대 5자로 제한한다. -- [X] 중복되지 않은 52장의 카드 덱을 만든다. -- [X] 카드 묶음을 랜덤하게 섞는다. -- [X] 딜러와 각 플레이어에게 카드 두 장을 분배한다. +- [x] 각 플레이어마다 베팅할 금액을 입력한다. +- [x] 중복되지 않은 52장의 카드 덱을 만든다. +- [x] 카드 묶음을 랜덤하게 섞는다. +- [x] 딜러와 각 플레이어에게 카드 두 장을 분배한다. - [x] 나누어진 카드를 화면에 출력한다. #### 카드 점수 계산 -- [X] 2~10 사이의 숫자 카드는 해당 숫자만큼의 점수로 처리한다. -- [X] J, Q, K 카드는 10점으로 처리한다. -- [X] ACE 카드는 기본 11점으로 처리한다. -- [X] 카드의 합이 21을 넘고 ACE 카드가 존재하는 경우, 카드의 합이 21을 넘지 않되 21에 가장 근접하도록 계산한다. -- [X] 플레이어가 지니고 있는 카드의 점수를 합산하여 반환한다. +- [x] 2~10 사이의 숫자 카드는 해당 숫자만큼의 점수로 처리한다. +- [x] J, Q, K 카드는 10점으로 처리한다. +- [x] ACE 카드는 기본 11점으로 처리한다. +- [x] 카드의 합이 21을 넘고 ACE 카드가 존재하는 경우, 카드의 합이 21을 넘지 않되 21에 가장 근접하도록 계산한다. +- [x] 플레이어가 지니고 있는 카드의 점수를 합산하여 반환한다. #### 플레이어 턴 진행 -- [X] 덱에 여분의 카드가 존재하지 않는 경우 예외를 발생시킨다. -- [X] 덱에서 카드를 한 장 뽑는다. +- [x] 덱에 여분의 카드가 존재하지 않는 경우 예외를 발생시킨다. +- [x] 덱에서 카드를 한 장 뽑는다. - [x] 플레이어의 카드의 합이 21 미만인 경우 더 받을지 묻는다. - [x] 'y'를 입력하는 경우 덱에서 카드 한 장을 뽑아 플레이어에게 제공한다. -- [x] 'n'를 입력하거나, 카드의 합이 21 이상이면 해당 플레이어의 차례를 종료한다. -- [x] 'y'나 'n'이외의 다른 값이 입력되면 예외를 처리하고 다시 입력받는다. +- [x] 'n'를 입력하거나, 카드의 합이 21을 초과하면 해당 플레이어의 차례를 종료한다. +- [x] 'y'나 'n'이외의 다른 값이 입력되면 예외를 발생시킨다. #### 딜러 턴 진행 @@ -58,6 +56,16 @@ - [x] 플레이어의 카드 점수의 합이 21을 초과했는지 계산한다. - [x] 딜러의 카드 점수의 합이 21을 초과했는지 계산한다. - [x] 딜러와 플레이어 중 카드 점수의 합이 21을 초과하지 않되, 21에 더 가까운 사람을 승자로 처리한다. + - [x] 플레이어가 승리하면, 플레이어는 자신이 베팅한 금액만큼 딜러에게 받는다. + - [x] 딜러가 승리하면, 플레이어는 자신이 베팅한 금액을 딜러에게 준다. +- [x] 점수가 같은 경우 무승부로 처리한다. + - [x] 이 경우 플레이어는 베팅한 금액을 돌려받는다. +- [x] 블랙잭은 처음 받은 두 장의 카드의 합이 21인 경우를 의미한다. + - [x] 플레이어는 블랙잭이고, 딜러는 블랙잭이 아니라면 플레이어는 승리한다. 이 경우에는 플레이어는 베팅한 금액의 1.5배를 딜러에게 받는다. + - [x] 딜러는 블랙잭이고, 플레이어는 블랙잭이 아니라면 플레이어는 패배한다. + - [x] 둘다 블랙잭인 경우, 무승부로 처리한다. - [x] 점수가 같은 경우 무승부로 처리한다. + - [x] 이 경우 플레이어는 베팅한 금액을 돌려받는다. - [x] 딜러와 각 플레이어의 최종 카드 목록과 점수를 출력한다. -- [x] 최종 승패를 출력한다. +- [x] 딜러와 플레이어가 모두 동시에 블랙잭인 경우 플레이어는 베팅한 금액을 돌려받는다. +- [x] 최종 수익을 계산하여 출력한다. diff --git a/src/main/java/controller/BlackjackGame.java b/src/main/java/controller/BlackjackGame.java index 16c85202969..48f5de2bd4c 100644 --- a/src/main/java/controller/BlackjackGame.java +++ b/src/main/java/controller/BlackjackGame.java @@ -30,9 +30,15 @@ public BlackjackGame(InputView inputView, OutputView outputView) { public void run() { String names = inputView.getNames(); - List parsedName = InputParser.parseName(names); + List parsedNames = InputParser.parseName(names); + + Players players = new Players(parsedNames + .stream() + .map(Player::new).toList() + ); + + players.getPlayers().forEach(player -> player.bet(inputView.getBetAmount(player.name()))); - Players players = new Players(parsedName); Dealer dealer = new Dealer(DEALER_NAME); CardShuffleStrategy cardShuffleStrategy = new RandomShuffleStrategy(); @@ -70,10 +76,17 @@ private void dealerTurn(Dealer dealer, Deck deck) { private void playerTurn(Player player, Deck deck) { while (player.canDraw()) { - if (inputView.getChoice(player.name()).equals("n")) { + String playerName = player.name(); + String choice = inputView.getChoice(playerName); + + if (choice.equals("n")) { break; } + if (!choice.equals("y")) { + throw new IllegalArgumentException(); + } + player.receive(deck.draw()); outputView.printParticipantCards(player); } @@ -85,6 +98,6 @@ private void showGameResult(Players players, Dealer dealer) { participants.forEach(outputView::printFinalResult); GameResult gameResult = new GameResult(players, dealer); - outputView.printGameResult(gameResult, dealer); + outputView.printGameResult(gameResult, players, dealer); } } diff --git a/src/main/java/domain/game/GameResult.java b/src/main/java/domain/game/GameResult.java index 93c8b4d3713..7a42dc32b95 100644 --- a/src/main/java/domain/game/GameResult.java +++ b/src/main/java/domain/game/GameResult.java @@ -1,45 +1,34 @@ package domain.game; import domain.participant.Dealer; +import domain.participant.Participant; import domain.participant.Player; import domain.participant.Players; -import dto.DealerResultInfo; -import dto.PlayerResultInfo; +import dto.ParticipantResultInfo; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; +import java.math.BigDecimal; +import java.util.HashMap; import java.util.Map; -import static java.util.Collections.frequency; +import static domain.game.ProfitCalculator.calculatePlayerProfit; public class GameResult { - private final Map playerWinningStatus = new LinkedHashMap<>(); + private final Map participantsProfits = new HashMap<>(); public GameResult(Players players, Dealer dealer) { - for (Player player : players.getPlayers()) { - playerWinningStatus.put(player, WinningStatus.of(player, dealer)); - } - } - - public List getPlayersResult() { - List result = new ArrayList<>(); + BigDecimal playersProfitSum = BigDecimal.ZERO; - for (Map.Entry entry : playerWinningStatus.entrySet()) { - String name = entry.getKey().name(); - WinningStatus status = entry.getValue(); + for (Player player : players.getPlayers()) { + BigDecimal profit = calculatePlayerProfit(player, dealer); + playersProfitSum = playersProfitSum.add(profit); - result.add(new PlayerResultInfo(name, status)); + participantsProfits.put(player, profit); } - - return result; + participantsProfits.put(dealer, playersProfitSum.negate()); } - public DealerResultInfo getDealerResult() { - int winCount = frequency(playerWinningStatus.values(), WinningStatus.LOSE); - int tieCount = frequency(playerWinningStatus.values(), WinningStatus.TIE); - int loseCount = frequency(playerWinningStatus.values(), WinningStatus.WIN); - - return new DealerResultInfo(winCount, tieCount, loseCount); + public ParticipantResultInfo participantResultInfo(Participant participant) { + return new ParticipantResultInfo(participant.name(), participantsProfits.get(participant)); } } + diff --git a/src/main/java/domain/game/ProfitCalculator.java b/src/main/java/domain/game/ProfitCalculator.java new file mode 100644 index 00000000000..13910f5ae2b --- /dev/null +++ b/src/main/java/domain/game/ProfitCalculator.java @@ -0,0 +1,27 @@ +package domain.game; + +import domain.participant.Dealer; +import domain.participant.Player; + +import java.math.BigDecimal; + +public class ProfitCalculator { + public static BigDecimal calculatePlayerProfit(Player player, Dealer dealer) { + WinningStatus winningStatus = WinningStatus.of(player, dealer); + BigDecimal betAmount = player.betAmount(); + + if (player.isBlackjack() && winningStatus == WinningStatus.WIN) { + return betAmount.multiply(BigDecimal.valueOf(1.5)); + } + + if (winningStatus == WinningStatus.WIN) { + return betAmount; + } + + if (winningStatus == WinningStatus.TIE) { + return BigDecimal.ZERO; + } + + return betAmount.negate(); + } +} diff --git a/src/main/java/domain/game/WinningStatus.java b/src/main/java/domain/game/WinningStatus.java index a872072897d..a3fe70f1343 100644 --- a/src/main/java/domain/game/WinningStatus.java +++ b/src/main/java/domain/game/WinningStatus.java @@ -3,7 +3,7 @@ import domain.participant.Dealer; import domain.participant.Player; -import static domain.BlackjackRule.BLACK_JACK; +import java.util.Optional; public enum WinningStatus { WIN, @@ -11,17 +11,35 @@ public enum WinningStatus { LOSE; public static WinningStatus of(Player player, Dealer dealer) { - int playerScore = player.score(); - int dealerScore = dealer.score(); + if (dealer.isBust()) { + return WIN; + } - if (playerScore > BLACK_JACK) { + if (player.isBust()) { return LOSE; } - if (dealerScore > BLACK_JACK) { - return WIN; + Optional winningStatus = judgeBlackjack(player, dealer); + return winningStatus.orElseGet(() -> compareScore(player.score(), dealer.score())); + } + + private static Optional judgeBlackjack(Player player, Dealer dealer) { + boolean isPlayerBlackjack = player.isBlackjack(); + boolean isDealerBlackjack = dealer.isBlackjack(); + + if (isPlayerBlackjack && !isDealerBlackjack) { + return Optional.of(WIN); } - return compareScore(playerScore, dealerScore); + + if (!isPlayerBlackjack && isDealerBlackjack) { + return Optional.of(LOSE); + } + + if (isPlayerBlackjack && isDealerBlackjack) { + return Optional.of(TIE); + } + + return Optional.empty(); } private static WinningStatus compareScore(int playerScore, int dealerScore) { @@ -31,6 +49,7 @@ private static WinningStatus compareScore(int playerScore, int dealerScore) { if (playerScore < dealerScore) { return LOSE; } + return TIE; } } diff --git a/src/main/java/domain/participant/Hand.java b/src/main/java/domain/participant/Hand.java index e52a9398e50..3814ef2ae47 100644 --- a/src/main/java/domain/participant/Hand.java +++ b/src/main/java/domain/participant/Hand.java @@ -6,6 +6,7 @@ import java.util.List; import static domain.BlackjackRule.BLACK_JACK; +import static domain.BlackjackRule.INITIAL_CARDS_COUNT; public class Hand { public static final int ACE_ADJUST_VALUE = 10; @@ -24,6 +25,10 @@ public boolean isBust() { return score() > BLACK_JACK; } + public boolean isBlackjack() { + return score() == BLACK_JACK && size() == INITIAL_CARDS_COUNT; + } + public int score() { int total = cards.sum(); int aceCount = cards.countAce(); @@ -36,7 +41,7 @@ public int score() { return total; } - public Card peek(){ + public Card peek() { return cards.peek(); } diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 176f1089fe4..dd7a03c443b 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -24,6 +24,14 @@ public void receiveInitialCards(Cards cards) { cards.cards().forEach(this::receive); } + public boolean isBlackjack() { + return hand.isBlackjack(); + } + + public boolean isBust() { + return hand.isBust(); + } + public void receive(Card card) { hand.add(card); } diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 0ca96128682..f8e71b1859d 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -1,8 +1,11 @@ package domain.participant; +import java.math.BigDecimal; + import static domain.BlackjackRule.BLACK_JACK; public class Player extends Participant { + private BigDecimal betAmount = BigDecimal.ZERO; public Player(String name) { super(name); @@ -10,6 +13,14 @@ public Player(String name) { @Override public boolean canDraw() { - return super.score() <= BLACK_JACK; + return super.score() < BLACK_JACK; + } + + public void bet(BigDecimal betAmount) { + this.betAmount = betAmount; + } + + public BigDecimal betAmount() { + return betAmount; } } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index add71a64c0b..686970c7ae1 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -6,13 +6,10 @@ public class Players { private static final int PLAYER_THRESHOLD = 5; - private final List players = new ArrayList<>(); + private final List players; - public Players(List names) { - for (String name : names) { - Player player = new Player(name); - players.add(player); - } + public Players(List players) { + this.players = new ArrayList<>(players); validatePlayerCount(players); validateDuplicatedName(players); @@ -42,6 +39,6 @@ public List getPlayerNames() { } public List getPlayers() { - return players; + return List.copyOf(players); } } diff --git a/src/main/java/dto/DealerResultInfo.java b/src/main/java/dto/DealerResultInfo.java deleted file mode 100644 index c07823f0e75..00000000000 --- a/src/main/java/dto/DealerResultInfo.java +++ /dev/null @@ -1,8 +0,0 @@ -package dto; - -public record DealerResultInfo( - int winCount, - int tieCount, - int loseCount -) { -} diff --git a/src/main/java/dto/ParticipantResultInfo.java b/src/main/java/dto/ParticipantResultInfo.java new file mode 100644 index 00000000000..0465af0ff33 --- /dev/null +++ b/src/main/java/dto/ParticipantResultInfo.java @@ -0,0 +1,9 @@ +package dto; + +import java.math.BigDecimal; + +public record ParticipantResultInfo( + String name, + BigDecimal profit +) { +} diff --git a/src/main/java/dto/PlayerResultInfo.java b/src/main/java/dto/PlayerResultInfo.java deleted file mode 100644 index 98124a5d6db..00000000000 --- a/src/main/java/dto/PlayerResultInfo.java +++ /dev/null @@ -1,9 +0,0 @@ -package dto; - -import domain.game.WinningStatus; - -public record PlayerResultInfo( - String name, - WinningStatus winningStatus -) { -} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 0b65aea4dd1..e25feec87db 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,5 +1,6 @@ package view; +import java.math.BigDecimal; import java.util.Scanner; public class InputView { @@ -10,6 +11,16 @@ public String getNames() { return scanner.nextLine(); } + public BigDecimal getBetAmount(String name) { + System.out.println(name + "의 배팅 금액은?"); + + try { + return new BigDecimal(scanner.nextLine()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(); + } + } + public String getChoice(String name) { System.out.println(name + "는 한 장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); return scanner.nextLine(); diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index e77207a1977..6a3a0f9c31d 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,30 +1,22 @@ package view; import domain.game.GameResult; -import domain.game.WinningStatus; import domain.card.Card; import domain.participant.Dealer; import domain.participant.Participant; import domain.participant.Player; import domain.participant.Players; -import dto.DealerResultInfo; -import dto.PlayerResultInfo; +import dto.ParticipantResultInfo; -import java.util.ArrayList; -import java.util.List; import java.util.stream.Collectors; public class OutputView { public static final String DEALER_ONE_MORE_CARD_MESSAGE = "딜러는 16이하라 한 장의 카드를 더 받았습니다."; - private static final String FINAL_WIN_OR_LOSE_MESSAGE = "## 최종 승패"; + private static final String FINAL_PROFIT_MESSAGE = "## 최종 수익"; private static final String COMMA = ", "; - private static final String COLON = ": "; private static final String SCORE_MESSAGE = " - 결과: %s"; private static final String DISTRIBUTION_MESSAGE = "%s와 %s에게 2장을 나누었습니다."; private static final String CARD_MESSAGE = "%s카드: "; - private static final String WIN = "승"; - private static final String TIE = "무"; - private static final String LOSE = "패"; public void printInitialDistribution(Players players, Dealer dealer) { printDistributionMessage(dealer, players); @@ -32,10 +24,16 @@ public void printInitialDistribution(Players players, Dealer dealer) { printPlayersInitialCards(players); } - public void printGameResult(GameResult gameResult, Dealer dealer) { - printWinOrLoseMessage(); - printDealerResult(dealer.name(), gameResult.getDealerResult()); - printPlayersResult(gameResult.getPlayersResult()); + public void printGameResult(GameResult gameResult, Players players, Dealer dealer) { + printFinalProfitMessage(); + + for (Player player : players.getPlayers()) { + ParticipantResultInfo participantResultInfo = gameResult.participantResultInfo(player); + System.out.println(participantResultInfo.name() + ": " + participantResultInfo.profit()); + } + + ParticipantResultInfo dealerResultInfo = gameResult.participantResultInfo(dealer); + System.out.println(dealerResultInfo.name() + ": " + dealerResultInfo.profit()); } public void printParticipantCards(Participant participant) { @@ -83,43 +81,7 @@ private String formatParticipantCards(Participant participant) { return String.format(CARD_MESSAGE, participant.name()) + joinedCards; } - private void printWinOrLoseMessage() { - System.out.println(FINAL_WIN_OR_LOSE_MESSAGE); - } - - private void printDealerResult(String dealerName, DealerResultInfo dealerResult) { - List result = new ArrayList<>(); - - if (dealerResult.winCount() > 0) { - result.add(dealerResult.winCount() + WIN); - } - if (dealerResult.tieCount() > 0) { - result.add(dealerResult.tieCount() + TIE); - } - if (dealerResult.loseCount() > 0) { - result.add(dealerResult.loseCount() + LOSE); - } - - System.out.println(dealerName + ": " + String.join(" ", result)); - } - - private void printPlayersResult(List playersResult) { - for (PlayerResultInfo playerResult : playersResult) { - printPlayerResult(playerResult); - } - } - - private void printPlayerResult(PlayerResultInfo playerResult) { - if (playerResult.winningStatus() == WinningStatus.WIN) { - System.out.println(playerResult.name() + COLON + WIN); - } - - if (playerResult.winningStatus() == WinningStatus.TIE) { - System.out.println(playerResult.name() + COLON + TIE); - } - - if (playerResult.winningStatus() == WinningStatus.LOSE) { - System.out.println(playerResult.name() + COLON + LOSE); - } + private void printFinalProfitMessage() { + System.out.println(FINAL_PROFIT_MESSAGE); } } diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java index 6ee6e706de1..7e21f9d101a 100644 --- a/src/test/java/domain/GameResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -1,44 +1,100 @@ package domain; +import domain.card.Card; +import domain.card.Cards; +import domain.card.Rank; +import domain.card.Suit; import domain.game.GameResult; -import domain.game.WinningStatus; import domain.participant.Dealer; +import domain.participant.Player; import domain.participant.Players; -import dto.DealerResultInfo; -import dto.PlayerResultInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.math.BigDecimal; import java.util.List; import static domain.BlackjackRule.DEALER_NAME; import static org.assertj.core.api.Assertions.assertThat; class GameResultTest { + Player pobi; + Players players; + Dealer dealer; + + @BeforeEach + void setUp() { + pobi = new Player("pobi"); + players = new Players(List.of(pobi)); + + pobi.bet(BigDecimal.valueOf(1000)); + + dealer = new Dealer(DEALER_NAME); + } @Test - void 플레이어의_게임_결과를_반환하다() { - Players players = new Players(List.of("pobi")); - Dealer dealer = new Dealer(DEALER_NAME); + void 플레이어가_처음_받은_카드_두_장의_합이_21이고_딜러는_아닐_경우_자신이_베팅한_금액의_1_5배를_딜러에게_받는다() { + Cards playerCards = cards(card(Rank.ACE, Suit.HEART), card(Rank.JACK, Suit.HEART)); + pobi.receiveInitialCards(playerCards); + + Cards dealerCards = cards(card(Rank.SEVEN, Suit.HEART), card(Rank.EIGHT, Suit.HEART)); + dealer.receiveInitialCards(dealerCards); + dealer.receive(card(Rank.SIX, Suit.HEART)); + GameResult gameResult = new GameResult(players, dealer); - List playersResult = gameResult.getPlayersResult(); + assertThat(gameResult.participantResultInfo(pobi).profit()).isEqualByComparingTo(BigDecimal.valueOf(1500)); + assertThat(gameResult.participantResultInfo(dealer).profit()).isEqualByComparingTo(BigDecimal.valueOf(-1500)); + } + + @Test + void 플레이어가_승리할_경우_자신이_베팅한_금액만큼_딜러에게_받는다() { + Cards playerCards = cards(card(Rank.ACE, Suit.HEART), card(Rank.NINE, Suit.HEART)); + pobi.receiveInitialCards(playerCards); + + Cards dealerCards = cards(card(Rank.THREE, Suit.HEART), card(Rank.FOUR, Suit.HEART)); + dealer.receiveInitialCards(dealerCards); + + GameResult gameResult = new GameResult(players, dealer); - assertThat(playersResult).hasSize(1); - assertThat(playersResult.getFirst().name()).isEqualTo("pobi"); - assertThat(playersResult.getFirst().winningStatus()).isEqualTo(WinningStatus.TIE); + assertThat(gameResult.participantResultInfo(pobi).profit()).isEqualByComparingTo(BigDecimal.valueOf(1000)); + assertThat(gameResult.participantResultInfo(dealer).profit()).isEqualByComparingTo(BigDecimal.valueOf(-1000)); } @Test - void 딜러의_게임_결과를_반환하다() { - Players players = new Players(List.of("pobi")); - Dealer dealer = new Dealer(DEALER_NAME); + void 딜러가_승리할_경우_플레이어는_자신이_베팅한_금액을_딜러에게_준다() { + Cards playerCards = cards(card(Rank.ACE, Suit.HEART), card(Rank.TWO, Suit.HEART)); + pobi.receiveInitialCards(playerCards); + + Cards dealerCards = cards(card(Rank.ACE, Suit.CLOVER), card(Rank.THREE, Suit.HEART)); + dealer.receiveInitialCards(dealerCards); + dealer.receive(card(Rank.FOUR, Suit.HEART)); GameResult gameResult = new GameResult(players, dealer); - DealerResultInfo dealerResult = gameResult.getDealerResult(); + assertThat(gameResult.participantResultInfo(pobi).profit()).isEqualByComparingTo(BigDecimal.valueOf(-1000)); + assertThat(gameResult.participantResultInfo(dealer).profit()).isEqualByComparingTo(BigDecimal.valueOf(1000)); + } + + @Test + void 무승부일_경우_플레이어는_자신이_베팅한_금액을_돌려받는다() { + Cards playerCards = cards(card(Rank.TWO, Suit.HEART), card(Rank.JACK, Suit.HEART)); + pobi.receiveInitialCards(playerCards); + + Cards dealerCards = cards(card(Rank.TWO, Suit.CLOVER), new Card(Rank.JACK, Suit.CLOVER)); + dealer.receiveInitialCards(dealerCards); + + GameResult gameResult = new GameResult(players, dealer); + + assertThat(gameResult.participantResultInfo(pobi).profit()).isEqualByComparingTo(BigDecimal.valueOf(0)); + assertThat(gameResult.participantResultInfo(dealer).profit()).isEqualByComparingTo(BigDecimal.valueOf(0)); + } + + private Cards cards(Card... cards) { + return new Cards(List.of(cards)); + } - assertThat(dealerResult.winCount()).isEqualTo(0); - assertThat(dealerResult.tieCount()).isEqualTo(1); - assertThat(dealerResult.loseCount()).isEqualTo(0); + private Card card(Rank rank, Suit suit) { + return new Card(rank, suit); } } diff --git a/src/test/java/domain/HandTest.java b/src/test/java/domain/HandTest.java index 7ed9bc9c1d3..224fa6bf30c 100644 --- a/src/test/java/domain/HandTest.java +++ b/src/test/java/domain/HandTest.java @@ -28,7 +28,7 @@ private List createCards(Rank... ranks) { void 참가자가_가진_카드_목록을_반환한다() { Hand hand = new Hand(); - Card card1 = new Card(Rank.ACE, Suit.HEART); + Card card1 = new Card(Rank.TWO, Suit.HEART); Card card2 = new Card(Rank.ACE, Suit.HEART); hand.add(card1); @@ -39,7 +39,20 @@ private List createCards(Rank... ranks) { } @Test - void 플레이어의_카드의_합이_21을_초과하는지_반환한다() { + void 참가자가_가진_카드_두_장의_합이_21인지_반환한다() { + Hand hand = new Hand(); + + Card card1 = new Card(Rank.JACK, Suit.HEART); + Card card2 = new Card(Rank.ACE, Suit.HEART); + + hand.add(card1); + hand.add(card2); + + assertThat(hand.isBlackjack()).isTrue(); + } + + @Test + void 참가자가_가진_카드의_합이_21을_초과하는지_반환한다() { List cards = createCards(Rank.JACK, Rank.QUEEN, Rank.KING); Hand hand = new Hand(cards); @@ -59,7 +72,7 @@ private List createCards(Rank... ranks) { } @Test - void 카드_중_에이스_카드가_하나_존재하고_카드의_합이_21_이하인_경우_합이_21에_근접하되_21을_초과하지_않도록_계산한다() { + void 참가자가_가진_카드_중_에이스_카드가_하나_존재하고_카드의_합이_21_이하인_경우_합이_21에_근접하되_21을_초과하지_않도록_계산한다() { List cards = createCards(Rank.ACE, Rank.QUEEN); Hand hand = new Hand(cards); @@ -69,7 +82,7 @@ private List createCards(Rank... ranks) { } @Test - void 카드_중_에이스_카드가_여러장_존재하고_카드의_합이_21을_초과하는_경우_합이_21에_근접하되_21을_초과하지_않도록_계산한다() { + void 참가자가_가진_카드_중_에이스_카드가_여러장_존재하고_카드의_합이_21을_초과하는_경우_합이_21에_근접하되_21을_초과하지_않도록_계산한다() { List cards = createCards(Rank.ACE, Rank.ACE, Rank.QUEEN); Hand hand = new Hand(cards); diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java index 93394d7641b..9442a0f9da7 100644 --- a/src/test/java/domain/PlayerTest.java +++ b/src/test/java/domain/PlayerTest.java @@ -15,7 +15,7 @@ class PlayerTest { @Test - void 플레이어의_카드의_합이_21_이하일_경우_플레이어는_카드를_받을_수_있다() { + void 플레이어의_카드의_합이_21_미만일_경우_플레이어는_카드를_받을_수_있다() { Participant player = new Player("pobi"); List cards = List.of( @@ -30,13 +30,13 @@ class PlayerTest { } @Test - void 플레이어의_카드의_합이_21을_초과할_경우_플레이어는_카드를_받을_수_없다() { + void 플레이어의_카드의_합이_21_이상일_경우_플레이어는_카드를_받을_수_없다() { Participant player = new Player("pobi"); List cards = List.of( new Card(Rank.SEVEN, Suit.HEART), new Card(Rank.SEVEN, Suit.CLOVER), - new Card(Rank.EIGHT, Suit.CLOVER) + new Card(Rank.SEVEN, Suit.SPADE) ); cards.forEach(player::receive); diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index 076d894769b..092ccb092db 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -1,5 +1,6 @@ package domain; +import domain.participant.Player; import domain.participant.Players; import org.junit.jupiter.api.Test; @@ -13,16 +14,24 @@ class PlayersTest { @Test void 플레이어의_이름이_중복되는_경우_예외를_발생시킨다() { List names = List.of("pobi", "pobi"); + List players = (names + .stream() + .map(Player::new).toList() + ); - assertThatThrownBy(() -> new Players(names)) + assertThatThrownBy(() -> new Players(players)) .isInstanceOf(IllegalArgumentException.class); } @Test void 플레이어의_수가_5인을_초과한_경우_예외를_발생시킨다() { List names = List.of("pobi", "jason", "neo", "brown", "woni", "lisa"); + List players = (names + .stream() + .map(Player::new).toList() + ); - assertThatThrownBy(() -> new Players(names)) + assertThatThrownBy(() -> new Players(players)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/WinningStatusTest.java b/src/test/java/domain/WinningStatusTest.java index ef7b8dbec68..34e8f8a486f 100644 --- a/src/test/java/domain/WinningStatusTest.java +++ b/src/test/java/domain/WinningStatusTest.java @@ -53,10 +53,30 @@ private Dealer createDealer(Rank... ranks) { assertThat(status).isEqualTo(WinningStatus.WIN); } + @Test + void 플레이어가_처음_받은_카드_두_장의_합이_21이고_딜러는_아닐_경우_플레이어가_승리한다(){ + Player player = createPlayer(Rank.TEN, Rank.ACE); + Dealer dealer = createDealer(Rank.EIGHT, Rank.JACK, Rank.THREE); + + WinningStatus status = WinningStatus.of(player, dealer); + + assertThat(status).isEqualTo(WinningStatus.WIN); + } + + @Test + void 딜러가_처음_받은_카드_두_장의_합이_21이고_플레이어는_아닐_경우_딜러가_승리한다(){ + Player player = createPlayer(Rank.EIGHT, Rank.JACK, Rank.THREE); + Dealer dealer = createDealer(Rank.TEN, Rank.ACE); + + WinningStatus status = WinningStatus.of(player, dealer); + + assertThat(status).isEqualTo(WinningStatus.LOSE); + } + @Test void 딜러와_플레이어의_카드의_합이_동일한_경우_무승부로_처리한다() { - Player player = createPlayer(Rank.TEN, Rank.TWO); - Dealer dealer = createDealer(Rank.TEN, Rank.TWO); + Player player = createPlayer(Rank.TEN, Rank.ACE); + Dealer dealer = createDealer(Rank.TEN, Rank.ACE); WinningStatus status = WinningStatus.of(player, dealer);