diff --git a/README.md b/README.md index add4665c21c..0f89905631d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ## 기본 기능 구현 - 플레이어 이름을 등록한다. +- 플레이어는 배팅 금액을 입력한다. - 참여자(플레이어 + 딜러)에게 각각 2장의 카드를 랜덤으로 발급한다. - 딜러 카드는 하나만 출력한다. - 각 플레이어의 카드는 모두(2장) 출력한다. @@ -24,10 +25,11 @@ - 조건: 출력 순서는 딜러 먼저 출력하며, 입력받은 플레이어 순서로 이어 출력한다. - 게임 결과를 출력한다. - - 최종 승패를 출력한다. - - 딜러는 승패전적을 출력한다. (예: 딜러: 1승 1패) - - 플레이어는 승패 여부를 출력한다. (예: pobi: 승) - - 조건: 출력 순서는 딜러 먼저 출력하며, 입력받은 플레이어 순서로 이어 출력한다. + - 딜러의 수익률을 출력한다. + - 각 플레이어의 수익률을 출력한다. ## 블랙잭 상세 규칙 -- 플레이어가 Bust인 경우에는 자동 패배 처리된다. 이때, 딜러의 카드상태에 의존되지 않고, 자동 패배한다. +- 딜러가 버스트된 경우 살아있는 플레이어는 모두 승리한다. +- 블랙잭은 1.5배의 수익률로 승리한다. +- 딜러와 플레이어가 모두 블랙잭인 경우 무승부로 처리한다. +- 딜러와 플레이어가 모두 버스트된 경우 딜러 승리로 처리한다. diff --git a/src/main/java/team/blackjack/Application.java b/src/main/java/team/blackjack/Application.java index 522c7a37cca..1a82d700dba 100644 --- a/src/main/java/team/blackjack/Application.java +++ b/src/main/java/team/blackjack/Application.java @@ -1,12 +1,12 @@ package team.blackjack; import team.blackjack.config.AppConfig; -import team.blackjack.controler.BlackJackController; +import team.blackjack.control.BlackJackController; public class Application { public static void main(String[] args) { AppConfig appConfig = AppConfig.getInstance(); - BlackJackController blackJackController = appConfig.blackJackController(); - blackJackController.run(); + BlackJackController controller = appConfig.blackJackController(); + controller.run(); } } \ No newline at end of file diff --git a/src/main/java/team/blackjack/config/AppConfig.java b/src/main/java/team/blackjack/config/AppConfig.java index e43fcc3ea81..1d26fa6546c 100644 --- a/src/main/java/team/blackjack/config/AppConfig.java +++ b/src/main/java/team/blackjack/config/AppConfig.java @@ -1,31 +1,20 @@ package team.blackjack.config; -import team.blackjack.controler.BlackJackController; +import team.blackjack.control.BlackJackController; import team.blackjack.service.BlackJackService; public class AppConfig { - private static volatile AppConfig instance; + private static final AppConfig instance = new AppConfig(); + private final BlackJackService blackJackService = new BlackJackService(); + private final BlackJackController blackJackController = new BlackJackController(blackJackService); - private AppConfig() { - } + private AppConfig() {} public static AppConfig getInstance() { - if (instance == null) { - synchronized (AppConfig.class) { - if (instance == null) { - instance = new AppConfig(); - } - } - } - return instance; } - public BlackJackService blackJackService() { - return new BlackJackService(); - } - public BlackJackController blackJackController() { - return new BlackJackController(blackJackService()); + return blackJackController; } } diff --git a/src/main/java/team/blackjack/control/BlackJackController.java b/src/main/java/team/blackjack/control/BlackJackController.java new file mode 100644 index 00000000000..4404fe6a481 --- /dev/null +++ b/src/main/java/team/blackjack/control/BlackJackController.java @@ -0,0 +1,116 @@ +package team.blackjack.control; + +import java.util.List; +import team.blackjack.service.dto.DrawResult; +import team.blackjack.service.dto.RevenueResult; +import team.blackjack.service.dto.ScoreResult; +import team.blackjack.service.BlackJackService; +import team.blackjack.view.InputView; +import team.blackjack.view.OutputView; + +public class BlackJackController { + private final BlackJackService blackJackService; + + public BlackJackController(BlackJackService blackJackService) { + this.blackJackService = blackJackService; + } + + public void run() { + List playerNames = readPlayerNames(); + blackJackService.initGame(playerNames); + blackJackService.drawInitialCards(); + + readAllPlayerBattingMoneyRetry(blackJackService.getAllPlayerNames()); + + DrawResult drawResult = blackJackService.getDrawResult(); + OutputView.printDrawResult(drawResult); + + readPlayerHitDecision(blackJackService.getAllPlayerNames()); + + while (blackJackService.shouldDealerHit()) { + OutputView.printDealerHitMessage(); + blackJackService.hitDealer(); + } + + ScoreResult scoreResult = blackJackService.calculateAllParticipantScore(); + OutputView.printParticipantScoreResult(scoreResult); + + RevenueResult revenueResult = blackJackService.getRevenueResult(); + OutputView.printRevenueResult(revenueResult); + } + + public void readAllPlayerBattingMoneyRetry(List playerNames) { + playerNames.forEach(playerName -> { + int battingMoney = readPlayerBattingMoneyRetry(playerName); + blackJackService.batMoney(playerName, battingMoney); + }); + } + + private int readPlayerBattingMoneyRetry(String playerName) { + int battingMoney; + + do { + battingMoney = readPlayerBattingMoney(playerName); + } while (battingMoney <= 0); + + return battingMoney; + } + + private int readPlayerBattingMoney(String playerName) { + int battingMoney = -1; + OutputView.printAskBettingMoney(playerName); + try { + battingMoney = InputView.readPlayerBattingMoney(); + } catch (NumberFormatException e) { + OutputView.printWrongDecisionInputMessage(); + } + + return battingMoney; + } + + private List readPlayerNames(){ + OutputView.printPlayerNameRequest(); + List playerNames = InputView.readPlayerNames(); + + while (hasDuplicatedName(playerNames)) { + OutputView.printDuplicatedNameMessage(); + OutputView.printPlayerNameRequest(); + playerNames = InputView.readPlayerNames(); + } + return playerNames; + } + + private boolean hasDuplicatedName(List playerNames) { + return playerNames.size() != playerNames.stream().distinct().count(); + } + + private void readPlayerHitDecision(List playerNames) { + playerNames.forEach(this::processPlayerHit); + } + + private void processPlayerHit(String playerName) { + while (readPlayerHitDecision(playerName)) { + blackJackService.hitPlayer(playerName); + OutputView.printPlayerCards(playerName, blackJackService.findPlayerCardNamesByName(playerName)); + } + } + + private boolean readPlayerHitDecision(String playerName) { + final boolean isPlayerBust = blackJackService.isPlayerBust(playerName); + + if (isPlayerBust) { + OutputView.printBustMessage(); + return false; + } + + OutputView.printAskDrawCard(playerName); + String hitYn = InputView.readHitDecision(); + + while (!"y".equalsIgnoreCase(hitYn) && !"n".equalsIgnoreCase(hitYn)) { + OutputView.printWrongDecisionInputMessage(); + hitYn = InputView.readHitDecision(); + } + + return "y".equalsIgnoreCase(hitYn); + } +} diff --git a/src/main/java/team/blackjack/controler/BlackJackController.java b/src/main/java/team/blackjack/controler/BlackJackController.java deleted file mode 100644 index 6619226724d..00000000000 --- a/src/main/java/team/blackjack/controler/BlackJackController.java +++ /dev/null @@ -1,83 +0,0 @@ -package team.blackjack.controler; - -import java.util.List; -import team.blackjack.service.dto.DrawResult; -import team.blackjack.service.dto.MatchResult; -import team.blackjack.service.dto.ScoreResult; -import team.blackjack.service.BlackJackService; -import team.blackjack.view.InputView; -import team.blackjack.view.OutputView; - -public class BlackJackController { - private final BlackJackService blackJackService; - - public BlackJackController(BlackJackService blackJackService) { - this.blackJackService = blackJackService; - } - - public void run() { - List playerNames = readPlayerNames(); - blackJackService.initGame(playerNames); - blackJackService.drawInitialCards(); - - DrawResult drawResult = blackJackService.getDrawResult(); - OutputView.printDrawResult(drawResult); - - readHitDecision(blackJackService.getAllPlayerNames()); - - while (blackJackService.shouldDealerHit()) { - OutputView.printDealerHitMessage(); - blackJackService.hitDealer(); - } - - ScoreResult scoreResult = blackJackService.calculateAllParticipantScore(); - OutputView.printParticipantScoreResult(scoreResult); - - MatchResult matchResult = blackJackService.getGameResult(); - OutputView.printGameResult(matchResult); - } - - private List readPlayerNames(){ - OutputView.printPlayerNameRequest(); - List playerNames = InputView.readPlayerNames(); - - // 중복된 이름은 허용되지 않음 - while (hasDuplicatedName(playerNames)) { - OutputView.printDuplicatedNameMessage(); - OutputView.printPlayerNameRequest(); - playerNames = InputView.readPlayerNames(); - } - return playerNames; - } - - private boolean hasDuplicatedName(List playerNames) { - return playerNames.size() != playerNames.stream().distinct().count(); - } - - private void readHitDecision(List playerNames) { - playerNames.forEach(this::processHit); - } - - private void processHit(String playerName) { - while (blackJackService.shouldPlayerHit(playerName)) { - OutputView.printAskDrawCard(playerName); - - String hitYn = InputView.readHitDecision(); - - while (!hitYn.equalsIgnoreCase("y") && !hitYn.equalsIgnoreCase("n")) { - OutputView.printWrongInputMessage(); - hitYn = InputView.readHitDecision(); - } - - final boolean isStand = hitYn.equalsIgnoreCase("n"); - if (isStand) { - return; - } - - blackJackService.hitPlayer(playerName); - OutputView.printPlayerCards(playerName, blackJackService.findPlayerCardNamesByName(playerName)); - } - - OutputView.printBustMessage(); - } -} diff --git a/src/main/java/team/blackjack/domain/BlackjackGame.java b/src/main/java/team/blackjack/domain/BlackjackGame.java index cc4cf6b809d..7daf78d156a 100644 --- a/src/main/java/team/blackjack/domain/BlackjackGame.java +++ b/src/main/java/team/blackjack/domain/BlackjackGame.java @@ -1,10 +1,13 @@ package team.blackjack.domain; -import java.util.HashMap; +import static team.blackjack.domain.rule.DefaultBlackjackRule.DEALER_STAND_SCORE; + +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class BlackjackGame { + private final Dealer dealer; private final Players players; private final Deck deck; @@ -15,15 +18,98 @@ public BlackjackGame(Dealer dealer, Players players) { this.deck = new Deck(); } - public Dealer getDealer() { - return dealer; + public void drawInitialCards() { + this.players.initPlayerHands(deck); + + this.dealer.hit(dealer.draw(deck)); + this.dealer.hit(dealer.draw(deck)); + } + + public Map calculateAllPlayerRevenue() { + final LinkedHashMap result = new LinkedHashMap<>(); + for (Player player : players.getPlayerList()) { + result.put(player.getName(), calculateMoney(player)); + } + + return result; + } + + public double calculateDealerRevenue() { + return calculateAllPlayerRevenue().values().stream() + .mapToDouble(Double::doubleValue) + .sum() * -1; + } + + private double calculateMoney(Player player) { + final Result result = judge(player); + return result.getOdds() * player.getBatMoney(); + } + + private Result judge(Player player) { + if (player.isBust()) { + return Result.LOSE; + } + if (dealer.isBust()) { + return Result.WIN; + } + + final int score = player.getScore(); + final int dealerScore = dealer.getScore(); + + if (score < dealerScore) { + return Result.LOSE; + } + if (player.isBlackjack() && !dealer.isBlackjack()) { + return Result.BLACKJACK; + } + if (score > dealerScore) { + return Result.WIN; + } + return Result.DRAW; + } + + public void batMoney(String name, int money) { + this.players.getPlayerByName(name).bat(money); + } + + public boolean isPlayerBust(String name) { + return this.players.getPlayerByName(name).isBust(); + } + + public void hitPlayer(String name) { + this.players.getPlayerByName(name) + .hit(deck.draw()); + } + + public boolean shouldDealerHit() { + return this.dealer.getScore() < DEALER_STAND_SCORE; + } + + public void hitDealer() { + this.dealer.hit(deck.draw()); + } + + public int getDealerScore() { + return this.dealer.getScore(); + } + + public Map getAllPlayerScore() { + return this.players.getPlayerScoresByPlayer(); + } + + public List getDealerCards() { + return this.dealer.getCards(); + } + + public List getPlayerCardsByName(String name) { + return this.players.getPlayerByName(name).getCards(); } - public Players getPlayers() { - return players; + public Map> getAllPlayerCards() { + return this.players.getCardsByPlayer(); } - public Deck getDeck() { - return deck; + public List getAllPlayerNames() { + return this.players.getPlayerNames(); } } diff --git a/src/main/java/team/blackjack/domain/Card.java b/src/main/java/team/blackjack/domain/Card.java index 81925f4e5f6..0f1fabbc85a 100644 --- a/src/main/java/team/blackjack/domain/Card.java +++ b/src/main/java/team/blackjack/domain/Card.java @@ -1,6 +1,7 @@ package team.blackjack.domain; import java.util.List; +import java.util.Set; public enum Card { ACE_OF_HEARTS(Suit.HEARTS, Number.ACE), @@ -75,8 +76,8 @@ public boolean isAce() { return this.number == Number.ACE; } - public List getScore() { - return this.number.score; + public Set getScore() { + return Set.copyOf(this.number.score); } public enum Suit { @@ -87,11 +88,11 @@ public enum Suit { SPADES("스페이드", false); private final String name; - private final boolean isRed; + private final boolean red; - Suit(String name, boolean isRed) { + Suit(String name, boolean red) { this.name = name; - this.isRed = isRed; + this.red = red; } public String getName() { @@ -101,24 +102,24 @@ public String getName() { public enum Number { - ACE("A", List.of(1, 11)), - TWO("2", List.of(2)), - THREE("3", List.of(3)), - FOUR("4", List.of(4)), - FIVE("5", List.of(5)), - SIX("6", List.of(6)), - SEVEN("7", List.of(7)), - EIGHT("8", List.of(8)), - NINE("9", List.of(9)), - TEN("10", List.of(10)), - JACK("J", List.of(10)), - QUEEN("Q", List.of(10)), - KING("K", List.of(10)); + ACE("A", Set.of(1, 11)), + TWO("2", Set.of(2)), + THREE("3", Set.of(3)), + FOUR("4", Set.of(4)), + FIVE("5", Set.of(5)), + SIX("6", Set.of(6)), + SEVEN("7", Set.of(7)), + EIGHT("8", Set.of(8)), + NINE("9", Set.of(9)), + TEN("10", Set.of(10)), + JACK("J", Set.of(10)), + QUEEN("Q", Set.of(10)), + KING("K", Set.of(10)); private final String name; - private final List score; + private final Set score; - Number(String name, List score) { + Number(String name, Set score) { this.name = name; this.score = score; } diff --git a/src/main/java/team/blackjack/domain/Dealer.java b/src/main/java/team/blackjack/domain/Dealer.java index 991952d2072..d10e73e8e2d 100644 --- a/src/main/java/team/blackjack/domain/Dealer.java +++ b/src/main/java/team/blackjack/domain/Dealer.java @@ -1,28 +1,9 @@ package team.blackjack.domain; -import team.blackjack.domain.rule.DefaultBlackjackRule; - -public class Dealer { - - private final Hand hand; - - public Dealer() { - this.hand = new Hand(); - } +public class Dealer extends Participant { public Card draw(Deck deck) { return deck.draw(); } - public Hand getHand() { - return this.hand; - } - - public int getScore(){ - return DefaultBlackjackRule.calculateBestScore(this.getHand().getCards()); - } - - public void hit(Card card) { - this.hand.addCard(card); - } } diff --git a/src/main/java/team/blackjack/domain/Deck.java b/src/main/java/team/blackjack/domain/Deck.java index aa54339aafa..1070c230f8b 100644 --- a/src/main/java/team/blackjack/domain/Deck.java +++ b/src/main/java/team/blackjack/domain/Deck.java @@ -1,25 +1,34 @@ package team.blackjack.domain; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; public class Deck { - private final List cards; + private final Set cards; public Deck() { this.cards = Arrays.stream(Card.values()) - .collect(Collectors.toList()); - - Collections.shuffle(this.cards); + .collect(Collectors.toSet()); } public Card draw() { - try { - return cards.getFirst(); - } finally { - cards.removeFirst(); + if (cards.isEmpty()) { + throw new IllegalStateException("덱에 카드가 없습니다."); } + + final Card drawnCard = getShuffledCards().getFirst(); + cards.remove(drawnCard); + + return drawnCard; + } + + private List getShuffledCards() { + final List cardList = new ArrayList<>(cards); + Collections.shuffle(cardList); + return cardList; } } diff --git a/src/main/java/team/blackjack/domain/Hand.java b/src/main/java/team/blackjack/domain/Hand.java index af3b8dc0e2a..a2e199c9318 100644 --- a/src/main/java/team/blackjack/domain/Hand.java +++ b/src/main/java/team/blackjack/domain/Hand.java @@ -1,8 +1,13 @@ package team.blackjack.domain; +import static team.blackjack.domain.rule.DefaultBlackjackRule.BLACKJACK; +import static team.blackjack.domain.rule.DefaultBlackjackRule.BLACKJACK_CARD_COUNT; + import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import team.blackjack.domain.rule.DefaultBlackjackRule; public class Hand { @@ -23,7 +28,61 @@ public List getCardNames() { .toList(); } - public int getScore(){ - return DefaultBlackjackRule.calculateBestScore(this.getCards()); + public boolean isBust() { + return getScore() > BLACKJACK; + } + + public boolean isBlackjack() { + if (cards.size() != BLACKJACK_CARD_COUNT) { + return false; + } + return getScore() == BLACKJACK; + } + + + public int getScore() { + if (containsAceCard(cards)) { + final Map> result = cards.stream() + .collect(Collectors.partitioningBy(Card::isAce, Collectors.toSet())); + + final Set aceCards = result.get(true); + final Set nonAceCards = result.get(false); + return calculateBestSumWithAce(nonAceCards, aceCards); + } + return calculateBestSumWithoutAce(cards); + } + + private boolean containsAceCard(Set cards) { + return cards.stream() + .anyMatch(Card::isAce); + } + + private int calculateBestSumWithAce(Set cardsWithoutAces, Set aceCards) { + int currentSum = calculateBestSumWithoutAce(cardsWithoutAces); + + for (Card card : aceCards) { + currentSum += aceScore(card, currentSum); + } + + return currentSum; + } + + private int calculateBestSumWithoutAce(Set cards) { + return cards.stream() + .flatMap(card -> card.getScore().stream()) + .mapToInt(Integer::intValue) + .sum(); + } + + private int aceScore(Card card, int currentSum) { + if (currentSum <= 10) { + return card.getScore().stream() + .max(Integer::compareTo) + .orElseThrow(() -> new IllegalStateException("ACE 카드의 점수가 존재하지 않습니다.")); + } + + return card.getScore().stream() + .min(Integer::compareTo) + .orElseThrow(() -> new IllegalStateException("ACE 카드의 점수가 존재하지 않습니다.")); } } diff --git a/src/main/java/team/blackjack/domain/Participant.java b/src/main/java/team/blackjack/domain/Participant.java new file mode 100644 index 00000000000..51af73a34c5 --- /dev/null +++ b/src/main/java/team/blackjack/domain/Participant.java @@ -0,0 +1,35 @@ +package team.blackjack.domain; + +import java.util.List; + +public class Participant { + private final Hand hand; + + public Participant() { + this.hand = new Hand(); + } + + public int getScore() { + return this.hand.getScore(); + } + + public void hit(Card card) { + if (isBust()) { + throw new IllegalStateException("이미 Bust 상태입니다."); + } + + this.hand.addCard(card); + } + + public List getCards() { + return hand.getCards(); + } + + public boolean isBust() { + return hand.isBust(); + } + + public boolean isBlackjack() { + return hand.isBlackjack(); + } +} diff --git a/src/main/java/team/blackjack/domain/Player.java b/src/main/java/team/blackjack/domain/Player.java index 256981cded1..894abc3622d 100644 --- a/src/main/java/team/blackjack/domain/Player.java +++ b/src/main/java/team/blackjack/domain/Player.java @@ -1,48 +1,23 @@ package team.blackjack.domain; -import java.util.ArrayList; -import java.util.List; - -public class Player { +public class Player extends Participant { private final String name; - private final List hands; + private double batMoney; public Player(String name) { this.name = name; - this.hands = initHands(); - } - public List getHands() { - return List.copyOf(hands); } public String getName() { return this.name; } - /** - * TODO: 추후 기능 확장시 한 라운드에 여러 개의 hand가 생기는 경우, 해당 메소드 수정 필요. - * @return - */ - public int getScore(){ - return this.hands.getFirst().getScore(); - } - - public void hit(Card card) { - this.hands.getFirst().addCard(card); - } - - private List initHands(){ - List hands = new ArrayList<>(); - hands.add(new Hand()); - return hands; + public void bat(double money) { + this.batMoney = money; } - public List getCardInAllHand() { - return hands.stream() - .map(Hand::getCards) - .flatMap(List::stream) - .map(Card::getCardName) - .toList(); + public double getBatMoney() { + return this.batMoney; } } diff --git a/src/main/java/team/blackjack/domain/Players.java b/src/main/java/team/blackjack/domain/Players.java index b5f397f0b25..57b9badf5ef 100644 --- a/src/main/java/team/blackjack/domain/Players.java +++ b/src/main/java/team/blackjack/domain/Players.java @@ -16,7 +16,6 @@ public List getPlayerList() { return List.copyOf(players); } - // 플레이어 카드 초기화 public void initPlayerHands(Deck deck) { for (Player player : players) { player.hit(deck.draw()); @@ -24,10 +23,10 @@ public void initPlayerHands(Deck deck) { } } - public Map> getCardsByPlayer(){ - final HashMap> result = new HashMap<>(); + public Map> getCardsByPlayer(){ + final HashMap> result = new HashMap<>(); for (Player player : players) { - result.put(player.getName(), player.getCardInAllHand()); + result.put(player.getName(), player.getCards()); } return result; diff --git a/src/main/java/team/blackjack/domain/Result.java b/src/main/java/team/blackjack/domain/Result.java index e0509c7ff3a..7e354c3d1e5 100644 --- a/src/main/java/team/blackjack/domain/Result.java +++ b/src/main/java/team/blackjack/domain/Result.java @@ -1,28 +1,24 @@ package team.blackjack.domain; public enum Result { - WIN("승"), - DRAW("무"), - LOSE("패"); + BLACKJACK("승", 1.5), + WIN("승", 1), + DRAW("무", 0), + LOSE("패", -1); private final String name; + private final double odds; - Result(String name) { - + Result(String name, double odds) { this.name = name; + this.odds = odds; } public String getName(){ return this.name; } - public Result reverse(){ - if (this == WIN) { - return LOSE; - } - if (this == LOSE) { - return WIN; - } - return DRAW; + public double getOdds() { + return this.odds; } } diff --git a/src/main/java/team/blackjack/domain/rule/DefaultBlackjackRule.java b/src/main/java/team/blackjack/domain/rule/DefaultBlackjackRule.java index 41e3743d1c4..07fff7f8c0b 100644 --- a/src/main/java/team/blackjack/domain/rule/DefaultBlackjackRule.java +++ b/src/main/java/team/blackjack/domain/rule/DefaultBlackjackRule.java @@ -1,94 +1,11 @@ package team.blackjack.domain.rule; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import team.blackjack.domain.Card; -import team.blackjack.domain.Result; - public class DefaultBlackjackRule { + public static final int DEALER_STAND_SCORE = 17; public static final int BLACKJACK = 21; public static final int BLACKJACK_CARD_COUNT = 2; - public static final int DEALER_STAND_SCORE = 17; - - public static boolean isBust(int score) { - return score > BLACKJACK; - } - - public static boolean isBlackjack(int score, int cardCount) { - if (cardCount != BLACKJACK_CARD_COUNT) { - return false; - } - return score == BLACKJACK; - } - - public static boolean isDealerMustDraw(int score) { - return score < DEALER_STAND_SCORE; - } - - public static boolean canUseAceAsEleven(int currentSum) { - return currentSum <= 10; - } - - // 딜러와 플레이어의 승패를 결정하는 메서드 - public static Result judgeResult(int myScore, int targetScore) { - if(myScore > BLACKJACK){ - return Result.LOSE; - } - if(myScore > targetScore){ - return Result.WIN; - } - if(myScore < targetScore){ - return Result.LOSE; - } - return Result.DRAW; - } - - /** - * 모든 카드를 발급한 이후에, 최종 점수 계산시에 사용하는 함수 - */ - public static int calculateBestScore(List cards) { - if (existAceInCards(cards)) { - final Map> result = cards.stream() - .collect(Collectors.partitioningBy(Card::isAce)); - - final List aceCards = result.get(true); - final List nonAceCards = result.get(false); - return calculateBestSumWithAce(nonAceCards, aceCards); - } - return calculateBestSumWithoutAce(cards); - } - - private static int calculateBestSumWithAce(List cardsWithoutAces, List aceCards) { - int currentSum = calculateBestSumWithoutAce(cardsWithoutAces); - - for (Card card : aceCards) { - currentSum += aceScore(card, currentSum); - } - return currentSum; + private DefaultBlackjackRule() { } - private static int aceScore(Card card, int currentSum) { - if (DefaultBlackjackRule.canUseAceAsEleven(currentSum)) { - return card.getScore().getLast(); - } - - return card.getScore().getFirst(); - } - - private static int calculateBestSumWithoutAce(List cards) { - return cards.stream() - .mapToInt(card -> card.getScore().getFirst()) - .sum(); - } - - private static boolean existAceInCards(List cards) { - for (Card card : cards) { - if (card.isAce()) { - return true; - } - } - return false; - } } diff --git a/src/main/java/team/blackjack/service/BlackJackService.java b/src/main/java/team/blackjack/service/BlackJackService.java index bb2f25e3153..1c6b5e68a85 100644 --- a/src/main/java/team/blackjack/service/BlackJackService.java +++ b/src/main/java/team/blackjack/service/BlackJackService.java @@ -1,21 +1,16 @@ package team.blackjack.service; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import team.blackjack.domain.BlackjackGame; import team.blackjack.domain.Card; +import team.blackjack.domain.Dealer; +import team.blackjack.domain.Player; import team.blackjack.domain.Players; import team.blackjack.service.dto.DrawResult; -import team.blackjack.service.dto.MatchResult; -import team.blackjack.service.dto.MatchResult.DealerResult; -import team.blackjack.service.dto.MatchResult.PlayerResult; +import team.blackjack.service.dto.RevenueResult; import team.blackjack.service.dto.ScoreResult; -import team.blackjack.domain.BlackjackGame; -import team.blackjack.domain.Dealer; -import team.blackjack.domain.Deck; -import team.blackjack.domain.Player; -import team.blackjack.domain.rule.DefaultBlackjackRule; public class BlackJackService { private BlackjackGame blackjackGame; @@ -30,52 +25,45 @@ public void initGame(List playerNames) { } public void drawInitialCards() { - final Deck deck = blackjackGame.getDeck(); - final Dealer dealer = blackjackGame.getDealer(); - - // 플레이어 카드 초기화 - getPlayers().initPlayerHands(deck); - - // 딜러 카드 초기화 - dealer.hit(dealer.draw(deck)); - dealer.hit(dealer.draw(deck)); + blackjackGame.drawInitialCards(); } - public boolean shouldPlayerHit(String name) { - final Player player = getPlayers().getPlayerByName(name); - - return !DefaultBlackjackRule.isBust(player.getScore()); + public boolean isPlayerBust(String name) { + return blackjackGame.isPlayerBust(name); } public void hitPlayer(String name) { - getPlayers() - .getPlayerByName(name) - .hit(blackjackGame.getDeck().draw()); + blackjackGame.hitPlayer(name); } - public boolean shouldDealerHit() { - final int score = blackjackGame.getDealer().getScore(); - - return DefaultBlackjackRule.isDealerMustDraw(score); + return blackjackGame.shouldDealerHit(); } public void hitDealer() { - final Dealer dealer = blackjackGame.getDealer(); - - dealer.hit(blackjackGame.getDeck().draw()); + blackjackGame.hitDealer(); } public ScoreResult calculateAllParticipantScore() { final List playerNames = getAllPlayerNames(); - final Map> playerCards = getPlayers().getCardsByPlayer(); - final Map playerScores = getPlayers().getPlayerScoresByPlayer(); + final Map playerScores = this.blackjackGame.getAllPlayerScore(); + final Map> playerCards = this.blackjackGame.getAllPlayerCards() + .entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().stream() + .map(Card::getCardName) + .toList() + )); - final Dealer dealer = blackjackGame.getDealer(); + final int dealerScore = this.blackjackGame.getDealerScore(); + final List dealerCardNames = this.blackjackGame.getDealerCards().stream() + .map(Card::getCardName) + .toList(); return new ScoreResult( - dealer.getHand().getCardNames(), - dealer.getScore(), + dealerCardNames, + dealerScore, playerNames, playerCards, playerScores @@ -83,40 +71,38 @@ public ScoreResult calculateAllParticipantScore() { } public List getAllPlayerNames() { - return getPlayers().getPlayerNames(); + return this.blackjackGame.getAllPlayerNames(); } public List findPlayerCardNamesByName(String name) { - return getPlayers().getPlayerByName(name).getCardInAllHand(); + return this.blackjackGame.getPlayerCardsByName(name).stream() + .map(Card::getCardName) + .toList(); } public DrawResult getDrawResult() { final List playerNames = getAllPlayerNames(); - final List cards = blackjackGame.getDealer().getHand().getCards(); - final Map> playerCards = getPlayers().getCardsByPlayer(); + final List cards = this.blackjackGame.getDealerCards(); + final Map> playerCards = this.blackjackGame.getAllPlayerCards() + .entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().stream() + .map(Card::getCardName) + .toList() + )); return new DrawResult(playerNames, cards.getFirst().getCardName(), playerCards); } - public MatchResult getGameResult() { - final Map playerResults = calculatePlayersResultMap(blackjackGame.getDealer().getScore()); - final DealerResult dealerResult = DealerResult.from(playerResults.values()); + public RevenueResult getRevenueResult() { + final double dealerRevenue = blackjackGame.calculateDealerRevenue(); + final Map allPlayerRevenue = blackjackGame.calculateAllPlayerRevenue(); - return new MatchResult(dealerResult, playerResults); + return new RevenueResult(dealerRevenue, allPlayerRevenue); } - private Map calculatePlayersResultMap(int dealerScore) { - return getPlayers().getPlayerList().stream() - .collect(Collectors.toMap( - Player::getName, - player -> new PlayerResult(DefaultBlackjackRule.judgeResult(player.getScore(), dealerScore)), - (existing, replacement) -> existing, - LinkedHashMap::new - )); - } - - - private Players getPlayers() { - return this.blackjackGame.getPlayers(); + public void batMoney(String playerName, int battingMoney) { + this.blackjackGame.batMoney(playerName, battingMoney); } } diff --git a/src/main/java/team/blackjack/service/dto/MatchResult.java b/src/main/java/team/blackjack/service/dto/MatchResult.java deleted file mode 100644 index e57da347958..00000000000 --- a/src/main/java/team/blackjack/service/dto/MatchResult.java +++ /dev/null @@ -1,38 +0,0 @@ -package team.blackjack.service.dto; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import team.blackjack.domain.Result; - -public record MatchResult( - DealerResult dealerResult, - Map playerResultMap -) { - - public record DealerResult( - List results - ){ - public static DealerResult from(Collection playerResults) { - final List dealerResults = new ArrayList<>(); - - for (PlayerResult playerResult : playerResults) { - dealerResults.add(playerResult.result().reverse()); - } - - return new DealerResult(dealerResults); - } - - public long countBy(Result target) { - return results.stream() - .filter(result -> result == target) - .count(); - } - } - - public record PlayerResult( - Result result - ){ - } -} diff --git a/src/main/java/team/blackjack/service/dto/RevenueResult.java b/src/main/java/team/blackjack/service/dto/RevenueResult.java new file mode 100644 index 00000000000..c92b1592703 --- /dev/null +++ b/src/main/java/team/blackjack/service/dto/RevenueResult.java @@ -0,0 +1,8 @@ +package team.blackjack.service.dto; + +import java.util.Map; + +public record RevenueResult( + double dealerRevenue, + Map playerRevenueMap +) { } diff --git a/src/main/java/team/blackjack/view/InputView.java b/src/main/java/team/blackjack/view/InputView.java index 9fc949f4b8b..f15cc41a268 100644 --- a/src/main/java/team/blackjack/view/InputView.java +++ b/src/main/java/team/blackjack/view/InputView.java @@ -16,11 +16,11 @@ public static List readPlayerNames() { .toList(); } - /** - * 플레이어가 한장의 카드를 더 받을지 여부를 입력받는다. - * @return - */ public static String readHitDecision() { return readInput(); } + + public static int readPlayerBattingMoney() { + return Integer.parseInt(readInput()); + } } diff --git a/src/main/java/team/blackjack/view/OutputView.java b/src/main/java/team/blackjack/view/OutputView.java index 70ef3749fba..f53f0fae4e6 100644 --- a/src/main/java/team/blackjack/view/OutputView.java +++ b/src/main/java/team/blackjack/view/OutputView.java @@ -1,14 +1,10 @@ package team.blackjack.view; import java.util.List; -import java.util.Map; import java.util.Map.Entry; import team.blackjack.service.dto.DrawResult; -import team.blackjack.service.dto.MatchResult; -import team.blackjack.service.dto.MatchResult.DealerResult; -import team.blackjack.service.dto.MatchResult.PlayerResult; +import team.blackjack.service.dto.RevenueResult; import team.blackjack.service.dto.ScoreResult; -import team.blackjack.domain.Result; public class OutputView { @@ -51,34 +47,32 @@ public static void printParticipantScoreResult(ScoreResult scoreResult) { scoreResult.playerScores().get(playerName))); } } - - public static void printGameResult(MatchResult result) { - final DealerResult dealerResult = result.dealerResult(); - final Map playeredResultMap = result.playerResultMap(); - - println(""); - println("## 최종 승패:"); - println("딜러: %d승 %d패 %d무".formatted( - dealerResult.countBy(Result.WIN), - dealerResult.countBy(Result.LOSE), - dealerResult.countBy(Result.DRAW)) - ); - - playeredResultMap.entrySet().stream() - .map(entry -> "%s: %s".formatted(entry.getKey(), entry.getValue().result().getName())) - .forEach(OutputView::println); - - } - public static void printBustMessage() { println("버스트 되었습니다. 더 이상 카드를 받을 수 없습니다."); } - public static void printWrongInputMessage() { + public static void printWrongDecisionInputMessage() { println("잘못된 입력입니다. y, n 중 하나를 입력해주세요."); } public static void printDuplicatedNameMessage() { println("중복된 이름은 허용되지 않습니다. 다시 입력해주세요."); } + + public static void printAskBettingMoney(String playerName) { + println("%s의 의 배팅 금액은?".formatted(playerName)); + } + + public static void printWrongBattingMoneyInputMessage() { + println("잘못된 입력입니다. 양수인 숫자를 입력해주세요."); + } + + public static void printRevenueResult(RevenueResult revenueResult) { + println(""); + println("## 최종 수익:"); + println("딜러: %.2f".formatted(revenueResult.dealerRevenue())); + for (Entry entry : revenueResult.playerRevenueMap().entrySet()) { + println("%s: %.2f".formatted(entry.getKey(), entry.getValue())); + } + } } diff --git a/src/test/java/team/blackjack/domain/BlackjackGameTest.java b/src/test/java/team/blackjack/domain/BlackjackGameTest.java new file mode 100644 index 00000000000..8c3b77c2ec5 --- /dev/null +++ b/src/test/java/team/blackjack/domain/BlackjackGameTest.java @@ -0,0 +1,298 @@ +package team.blackjack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BlackjackGameTest { + + public Dealer dealer; + public Player pobi; + public Player jason; + public Players players; + public BlackjackGame game; + + @BeforeEach + void setUp() { + dealer = new Dealer(); + pobi = new Player("pobi"); + jason = new Player("jason"); + players = new Players(List.of( + pobi, + jason + )); + game = new BlackjackGame(dealer, players); + } + + @Test + void 초기화_이후에는_참여자_모두_카드_2장() { + game.drawInitialCards(); + + assertThat(game.getAllPlayerNames()).containsExactly("pobi", "jason"); + assertThat(game.getPlayerCardsByName("pobi")).hasSize(2); + assertThat(game.getPlayerCardsByName("jason")).hasSize(2); + assertThat(game.getDealerCards()).hasSize(2); + } + + @Test + void batMoney_호출시_해당_플레이어_배팅금이_설정된다() { + int pobiBatMoney = 1000; + int jasonBatMoney = 500; + game.batMoney("pobi", pobiBatMoney); + game.batMoney("jason", jasonBatMoney); + + assertThat(pobi.getBatMoney()).isEqualTo(pobiBatMoney); + assertThat(jason.getBatMoney()).isEqualTo(jasonBatMoney); + } + + @Test + void 딜러의_수익은_플레이어_수익_합의_음수이다() { + game.batMoney("pobi", 1000); + game.batMoney("jason", 1000); + game.drawInitialCards(); + + Map playerRevenue = game.calculateAllPlayerRevenue(); + double expectedDealerRevenue = -playerRevenue.values().stream() + .mapToDouble(Double::doubleValue) + .sum(); + + assertThat(game.calculateDealerRevenue()).isEqualTo(expectedDealerRevenue); + } + + @Test + void 플레이어_승_시_수익은_100프로() { + hitCards(pobi, Card.KING_OF_HEARTS, Card.QUEEN_OF_HEARTS); // 20 + hitCards(dealer, Card.KING_OF_CLUBS, Card.EIGHT_OF_CLUBS); // 18 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(1000.0); // WIN odds 1 + } + + @Test + void 플레이어_패_시_수익은_전체_마이너스_100프로() { + hitCards(pobi, Card.KING_OF_HEARTS, Card.EIGHT_OF_HEARTS); // 18 + hitCards(dealer, Card.KING_OF_CLUBS, Card.QUEEN_OF_CLUBS); // 20 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(-1000.0); // LOSE odds -1 + } + + @Test + void 동점_시_무_수익은_제로() { + hitCards(pobi, Card.KING_OF_HEARTS, Card.SEVEN_OF_HEARTS); // 17 + hitCards(dealer, Card.KING_OF_CLUBS, Card.SEVEN_OF_CLUBS); // 17 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(0.0); // DRAW odds 0 + } + + @Test + void 플레이어_버스트_할_경우_수익은_전체_손실() { + hitCards(pobi, Card.KING_OF_HEARTS, Card.SEVEN_OF_HEARTS, Card.FIVE_OF_HEARTS); // 22 + hitCards(dealer, Card.KING_OF_CLUBS, Card.QUEEN_OF_CLUBS); // 20 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(-1000.0); // LOSE (bust) + } + + @Test + void 플레이어_블랙잭_딜러는_블랙잭이_아닌경우_수익_150프로() { + hitCards(pobi, Card.ACE_OF_HEARTS, Card.KING_OF_HEARTS); // blackjack + hitCards(dealer, Card.KING_OF_CLUBS, Card.NINE_OF_CLUBS); // 19 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(1500.0); // BLACKJACK odds 1.5 + } + + @Test + void 딜러_버스트_시_버스트가_아닌_플레이어는_승리() { + hitCards(pobi, Card.KING_OF_HEARTS, Card.TEN_OF_HEARTS); // 20 + hitCards(dealer, Card.KING_OF_CLUBS, Card.SEVEN_OF_CLUBS, Card.SIX_OF_CLUBS); // 23 + game.batMoney("pobi", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("pobi")).isEqualTo(1000.0); // WIN (dealer bust) + } + + @Test + void 딜러가_버스트_여도_이미_버스트였던_플레이어는_패배() { + hitCards(jason, Card.KING_OF_SPADES,Card.KING_OF_DIAMONDS, Card.FIVE_OF_HEARTS); // 25 + hitCards(dealer, Card.KING_OF_CLUBS, Card.SEVEN_OF_CLUBS, Card.SIX_OF_CLUBS); // 23 + game.batMoney("jason", 1000); + + Map revenue = game.calculateAllPlayerRevenue(); + + assertThat(revenue.get("jason")).isEqualTo(-1000.0); // WIN (dealer bust) + } + + private void hitCards(Participant participant, Card... cards) { + for (Card card : cards) { + participant.hit(card); + } + } + + @Test + void _30과_20에_대한_버스트_여부를_반환한다() { + pobi.hit(Card.KING_OF_HEARTS); + pobi.hit(Card.QUEEN_OF_HEARTS); + pobi.hit(Card.JACK_OF_HEARTS); // 30으로 버스트 + + jason.hit(Card.TEN_OF_HEARTS); + jason.hit(Card.SIX_OF_HEARTS); // 16으로 버스트 아님 + + boolean pobiShouldHit = game.isPlayerBust("pobi"); + boolean jasonShouldHit = game.isPlayerBust("jason"); + + // shouldPlayerHit은 해당 플레이어의 버스트 여부를 반환 (현재 구현: isBust() 그대로 반환) + assertThat(pobiShouldHit).isIn(true); + assertThat(jasonShouldHit).isIn(false); + } + + @Test + void 플레이어는_hit을_하는_경우_카드가_한_장_늘어난다() { + game.drawInitialCards(); + int sizeBefore = game.getPlayerCardsByName("pobi").size(); + + game.hitPlayer("pobi"); + + assertThat(game.getPlayerCardsByName("pobi")).hasSize(sizeBefore + 1); + } + + @Test + void 딜러는_점수가_17_미만이면_Hit을_해야한다() { + game.drawInitialCards(); + int dealerScore = game.getDealerScore(); + + boolean shouldHit = game.shouldDealerHit(); + + assertThat(shouldHit).isEqualTo(dealerScore < 17); + } + + @Test + void 딜러가_hit하는경우_딜러_카드가_한_장_늘어난다() { + game.drawInitialCards(); + int sizeBefore = game.getDealerCards().size(); + + game.hitDealer(); + + assertThat(game.getDealerCards()).hasSize(sizeBefore + 1); + } + + @Test + void getDealerScore_딜러_점수_반환() { + game.drawInitialCards(); + + int score = game.getDealerScore(); + + assertThat(score).isBetween(0, 21); + } + + @Test + void 플레이어별_카드_목록_반환() { + game.drawInitialCards(); + + Map> allCards = game.getAllPlayerCards(); + + assertThat(allCards).containsKeys("pobi", "jason"); + assertThat(allCards.get("pobi")).hasSize(2); + assertThat(allCards.get("jason")).hasSize(2); + } + + @Test + void 플레이어_이름_목록_반환() { + assertThat(game.getAllPlayerNames()).containsExactly("pobi", "jason"); + } + + // --- 실제 게임 흐름 시나리오 테스트 --- + + @Test + void 한_판_진행_배팅_초기카드_수익계산_끝까지_정상_동작() { + game.batMoney("pobi", 1000); + game.batMoney("jason", 500); + + game.drawInitialCards(); + + Map playerRevenue = game.calculateAllPlayerRevenue(); + double dealerRevenue = game.calculateDealerRevenue(); + + assertThat(game.getAllPlayerNames()).containsExactly("pobi", "jason"); + assertThat(game.getPlayerCardsByName("pobi")).hasSize(2); + assertThat(game.getPlayerCardsByName("jason")).hasSize(2); + assertThat(game.getDealerCards()).hasSize(2); + assertThat(playerRevenue).containsOnlyKeys("pobi", "jason"); + assertThat(dealerRevenue).isEqualTo(-playerRevenue.values().stream().mapToDouble(Double::doubleValue).sum()); + } + + @Test + void 한_판_진행_플레이어_히트_후_수익계산() { + game.batMoney("pobi", 1000); + game.batMoney("jason", 1000); + game.drawInitialCards(); + + while (!game.isPlayerBust("pobi") && game.getPlayerCardsByName("pobi").size() < 5) { + game.hitPlayer("pobi"); + } + + Map playerRevenue = game.calculateAllPlayerRevenue(); + double dealerRevenue = game.calculateDealerRevenue(); + + assertThat(playerRevenue).containsOnlyKeys("pobi", "jason"); + assertThat(dealerRevenue).isEqualTo(-playerRevenue.values().stream().mapToDouble(Double::doubleValue).sum()); + } + + @Test + void 한_판_진행_딜러_17까지_히트_후_수익계산() { + game.batMoney("pobi", 1000); + game.batMoney("jason", 1000); + game.drawInitialCards(); + + while (game.shouldDealerHit()) { + game.hitDealer(); + } + + assertThat(game.getDealerScore()).isGreaterThanOrEqualTo(17); + Map playerRevenue = game.calculateAllPlayerRevenue(); + double dealerRevenue = game.calculateDealerRevenue(); + assertThat(dealerRevenue).isEqualTo(-playerRevenue.values().stream().mapToDouble(Double::doubleValue).sum()); + } + + @Test + void 한_게임의_전체_흐름_플레이어_히트_딜러_히트_수익계산() { + game.batMoney("pobi", 1000); + game.batMoney("jason", 1000); + + // 초기 카드 강제로 설정 (실제 게임에서는 랜덤이지만 테스트에서는 고정) + // 19 + pobi.hit(Card.ACE_OF_SPADES); + pobi.hit(Card.EIGHT_OF_HEARTS); + + // jason은 20으로 시작해서 히트해서 버스트 시도 + jason.hit(Card.TEN_OF_HEARTS); + jason.hit(Card.KING_OF_HEARTS); + jason.hit(Card.FIVE_OF_DIAMONDS); // 25로 버스트 + + // 딜러는 17로 시작해서 히트해서 18로 만듦 + dealer.hit(Card.KING_OF_CLUBS); + dealer.hit(Card.KING_OF_SPADES); + + Map playerRevenue = game.calculateAllPlayerRevenue(); + double dealerRevenue = game.calculateDealerRevenue(); + + assertThat(playerRevenue).containsOnlyKeys("pobi", "jason"); + assertThat(dealerRevenue).isEqualTo(-playerRevenue.values().stream().mapToDouble(Double::doubleValue).sum()); + } +} diff --git a/src/test/java/team/blackjack/domain/DealerTest.java b/src/test/java/team/blackjack/domain/DealerTest.java index b38ab02dea8..b9f2753df56 100644 --- a/src/test/java/team/blackjack/domain/DealerTest.java +++ b/src/test/java/team/blackjack/domain/DealerTest.java @@ -12,7 +12,7 @@ class DealerTest { dealer.hit(Card.ACE_OF_HEARTS); dealer.hit(Card.KING_OF_HEARTS); - assertThat(dealer.getHand().getCards()) + assertThat(dealer.getCards()) .containsExactly(Card.ACE_OF_HEARTS, Card.KING_OF_HEARTS); } @Test diff --git a/src/test/java/team/blackjack/domain/PlayerTest.java b/src/test/java/team/blackjack/domain/PlayerTest.java index 8449071c70f..2db952b6d37 100644 --- a/src/test/java/team/blackjack/domain/PlayerTest.java +++ b/src/test/java/team/blackjack/domain/PlayerTest.java @@ -11,7 +11,7 @@ class PlayerTest { player.hit(Card.ACE_OF_HEARTS); - assertThat(player.getHands().getFirst().getCards()) + assertThat(player.getCards()) .containsExactly(Card.ACE_OF_HEARTS); } diff --git a/src/test/java/team/blackjack/domain/rule/DefaultBlackjackRuleTest.java b/src/test/java/team/blackjack/domain/rule/DefaultBlackjackRuleTest.java deleted file mode 100644 index 39929f3476c..00000000000 --- a/src/test/java/team/blackjack/domain/rule/DefaultBlackjackRuleTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package team.blackjack.domain.rule; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import team.blackjack.domain.Card; -import team.blackjack.domain.Result; - -class DefaultBlackjackRuleTest { - - - @ParameterizedTest - @CsvSource({ - "22, true", - "21, false" - }) - void 버스트_판정(int handScore, boolean expected) { - boolean isBust = DefaultBlackjackRule.isBust(handScore); - assertEquals(expected, isBust); - } - - @ParameterizedTest - @CsvSource({ - "21, 2, true", - "21, 3, false", - "20, 2, false" - }) - void 블랙잭_판정(int handScore, int cardCount, boolean expected) { - boolean isBlackjack = DefaultBlackjackRule.isBlackjack(handScore, cardCount); - assertEquals(expected, isBlackjack); - } - - @ParameterizedTest - @CsvSource({ - "16, true", - "17, false" - }) - void 딜러_카드_추가_여부(int dealerScore, boolean expected) { - boolean isDealerMustDraw = DefaultBlackjackRule.isDealerMustDraw(dealerScore); - assertEquals(expected, isDealerMustDraw); - } - - @ParameterizedTest - @CsvSource({ - "20,18,WIN", - "18,20,LOSE", - "17,17,DRAW", - "22,20,LOSE" - }) - void 승패_판정(int myScore, int opponentScore, Result expected) { - assertEquals(expected, DefaultBlackjackRule.judgeResult(myScore, opponentScore)); - } - - @ParameterizedTest - @CsvSource({ - "10, true", - "11, false" - }) - void Ace를_11로_사용_가능한지(int score, boolean expected) { - assertEquals(expected, DefaultBlackjackRule.canUseAceAsEleven(score)); - } - - - @Test - void 숫자10과_6이후에_ACE가_2개_오는_경우_각각_1로_정상_해석되는지_테스트() { - List cards = List.of(Card.KING_OF_CLUBS, Card.SIX_OF_HEARTS, Card.ACE_OF_SPADES, Card.ACE_OF_HEARTS); - - int score = DefaultBlackjackRule.calculateBestScore(cards); - - assertEquals(18, score); - } - - @Test - void Ace가_1장있는_경우_최적의_합_정상_계산_테스트() { - List cards = List.of(Card.FIVE_OF_CLUBS, Card.FIVE_OF_DIAMONDS, Card.ACE_OF_SPADES); - int score = DefaultBlackjackRule.calculateBestScore(cards); - - assertEquals(21, score); - } -} diff --git a/src/test/java/team/blackjack/service/BlackJackServiceTest.java b/src/test/java/team/blackjack/service/BlackJackServiceTest.java index 77e3db19a74..540413e63de 100644 --- a/src/test/java/team/blackjack/service/BlackJackServiceTest.java +++ b/src/test/java/team/blackjack/service/BlackJackServiceTest.java @@ -34,7 +34,7 @@ void setUp() { blackJackService.drawInitialCards(); List playerCards = blackJackService.findPlayerCardNamesByName(pobi); - assertThat(playerCards.getFirst()).hasSize(2); + assertThat(playerCards).hasSize(2); ScoreResult scoreResult = blackJackService.calculateAllParticipantScore(); assertThat(scoreResult.dealerCard()).hasSize(2);