diff --git a/README.md b/README.md index 556099c4de..f6974380ad 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,68 @@ ## 우아한테크코스 코드리뷰 - [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) + +## Controller +- [x] 게임에 참여할 플레이어의 이름을 입력받는다. +- [x] 딜러와 플레이어들에게 카드를 두 장씩 랜덤하게 나눠준다. +- [x] 딜러와 플레이어들이 받은 카드를 출력한다. + - [x] 딜러는 한장의 카드만 공개한다. +- [x] 플레이어 별로 카드를 더 받을지 물어본다. + - [x] 플레이어는 카드를 한 장 뽑고 가진 카드 현황을 출력한다. + - [x] 플레이어가 가진 카드 숫자의 총합이 21을 초과하면 그만 받도록 한다. + - [x] 플레이어가 가진 카드 숫자의 총합이 21 이하라면 플레이어의 선택에 따라 카드를 계속 받을 수 있다. +- [x] 딜러는 자신의 숫자 카드 합이 17 이상이 되도록 카드를 더 뽑는다. +- [x] 딜러와 플레이어의 카드 합 결과를 계산한다. +- [x] 딜러와 플레이어 최종 카드 현황과 각 합을 출력한다. +- [x] 게임결과를 출력하고 게임을 종료한다. + - [x] 딜러는 총 몇 승 몇 패를 했는지 출력한다. + - [x] 플레이어는 각자의 승패 결과를 출력한다. + +## Model +- [x] 블랙잭 전체 카드 생성 + - [x] 전체 카드 개수는 52장 + - [x] 문양은 하트, 다이아, 클로버, 스페이드 + - [x] 각 문양 별 Ace, 2~10, K,Q,J 로 구성 + - [x] Ace는 1 또는 11로 계산할 수 있다. + - [x] K,Q,J는 각각 10으로 계산한다. + - [x] 52장 카드는 중복되지 않는다. +- [x] 블랙잭 카드 드로우 + - [x] 모든 카드는 랜덤하게 셔플된다. + - [x] 드로우는 셔플된 카드에서 순서대로 가져간다. +- [x] 블랙잭 카드 현황 저장한다. + - [x] 전체 카드에서 남은 카드 현황 + - [x] 드로우된 카드는 제외한다. + - [x] 딜러 카드 현황 + - [x] 플레이어 카드 현황 +- [x] 블랙잭 게임 진행 + - [x] 게임의 플레이어 수는 딜러 제외 5명으로 제한한다. + - [x] 플레이어와 딜러는 게임을 시작하며 카드를 2장씩 드로우한다. + - [x] 딜러는 처음에 뽑은 카드 1장만 공개하고, 남은 카드는 최종 결과 확인 전까지 비공개한다. + - [x] 보유한 카드의 숫자 합산 + - [x] 보유한 카드의 숫자 합산 유효성 확인 + - [x] 합산 결과가 21을 초과하면 더 이상 카드를 뽑지 않는다. +- [x] 딜러와 플레이어 간 승패 결정 + - [x] 딜러와 플레이어의 카드 숫자 합산 비교 + - [x] 딜러와 플레이어 둘 다 버스트일 시 딜러 승 + - [x] 딜러와 플레이어 결과가 무승부일 때 딜러 승 + +## View +### InputView +- [x] 플레이어 이름 입력 + - [x] [예외처리] 쉼표 기준으로 분리하다(pobi,jason) +- [x] 카드 추가로 받을지 말지 여부 입력 + - [x] [예외처리] 'y' 또는 'n'이 아닌 입력 +### OutputView +- [x] 초기 게임 세팅 + - [x] 플레이어 이름 입력 메세지 출력 + - [x] 딜러와 플레이어 첫 카드 세팅 결과 출력 + - [x] 딜러와 플레이어 별로 가진 카드를 출력 +- [x] 게임 진행 + - [x] 플레이어가 카드를 추가로 받을지 여부 메세지 출력 + - [x] 플레이어가 가진 카드 현황을 출력 + - [x] 딜러 추가 카드 수령 메세지 +- [x] 게임 결과 + - [x] 딜러와 플레이어 최종 카드 결과 출력 + - [x] 딜러와 플레이어 최종 승패 결과 출력 + +## TODO diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 0000000000..c50d8ac0e5 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,12 @@ +import controller.BlackJackGameController; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + InputView inputview = new InputView(); + OutputView outputView = new OutputView(); + BlackJackGameController blackJackGameController = new BlackJackGameController(inputview, outputView); + blackJackGameController.run(); + } +} diff --git a/src/main/java/controller/BlackJackGameController.java b/src/main/java/controller/BlackJackGameController.java new file mode 100644 index 0000000000..54a42ffc54 --- /dev/null +++ b/src/main/java/controller/BlackJackGameController.java @@ -0,0 +1,120 @@ +package controller; + +import domain.DrawCommand; +import domain.card.Card; +import domain.card.GameDeck; +import domain.card.ShuffleDeckGenerator; +import domain.game.BlackJackGame; +import domain.game.GameResult; +import domain.user.Dealer; +import domain.user.Name; +import domain.user.Names; +import domain.user.Player; +import domain.user.PlayerStatus; +import domain.user.User; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import view.InputView; +import view.OutputView; + +public class BlackJackGameController { + private final InputView inputView; + private final OutputView outputView; + + public BlackJackGameController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + BlackJackGame blackJackGame = setUp(); + playGame(blackJackGame); + } + + private BlackJackGame setUp() { + GameDeck gameDeck = new GameDeck(new ShuffleDeckGenerator()); + Dealer dealer = new Dealer(gameDeck.drawForFirstTurn()); + List players = setUpPlayers(gameDeck); + showSetUpResult(dealer, players); + return new BlackJackGame(players, dealer, gameDeck); + } + + private List setUpPlayers(GameDeck gameDeck) { + return readUsersName().stream() + .map(name -> new Player(name, gameDeck.drawForFirstTurn())) + .collect(Collectors.toList()); + } + + private List readUsersName() { + outputView.printInputPlayerNameMessage(); + Names names = new Names(inputView.readPlayersName()); + return names.getNames(); + } + + private void showSetUpResult(Dealer dealer, List players) { + HashMap> setUpResult = new LinkedHashMap<>(); + setUpResult.put("딜러", dealer.getCards().subList(0, 1)); + players.forEach(player -> setUpResult.put(player.getName(), player.getCards())); + outputView.printSetUpResult(setUpResult); + } + + private void playGame(BlackJackGame blackJackGame) { + progressPlayersTurn(blackJackGame); + progressDealerTurn(blackJackGame); + showUsersCardResult(blackJackGame); + GameResult gameResult = new GameResult(blackJackGame.getPlayerNames()); + gameResult.saveResults(blackJackGame.getDealer(), blackJackGame.getPlayers()); + showFinalResult(gameResult); + } + + private void progressPlayersTurn(BlackJackGame blackJackGame) { + List players = blackJackGame.getPlayers(); + for (Player player : players) { + progressPlayerTurn(blackJackGame, player); + } + } + + private void progressPlayerTurn(BlackJackGame blackJackGame, Player player) { + while (player.isUserStatus(PlayerStatus.NORMAL) && readDrawCommand(player).equals(DrawCommand.DRAW)) { + blackJackGame.drawOneMoreCardForPlayer(player); + showDrawResult(player); + } + if (player.isUserStatus(PlayerStatus.NORMAL)) { + showDrawResult(player); + } + } + + private DrawCommand readDrawCommand(Player player) { + outputView.printAskOneMoreCardMessage(player.getName()); + return inputView.readDrawCommand(); + } + + private void showDrawResult(Player player) { + outputView.printPlayerDrawResult(player.getName(), player.getCards()); + } + + private void progressDealerTurn(BlackJackGame blackJackGame) { + blackJackGame.drawCardUntilOverSixteen(); + + Dealer dealer = blackJackGame.getDealer(); + int dealerDrawCount = dealer.getCards().size() - 2; + + if (dealerDrawCount > 0) { + outputView.printDealerDrawResult(dealerDrawCount); + } + } + + private void showUsersCardResult(BlackJackGame blackJackGame) { + Map> userResult = new LinkedHashMap<>(); + userResult.put(blackJackGame.getDealer(), blackJackGame.getDealer().getCards()); + blackJackGame.getPlayers().forEach(player -> userResult.put(player, player.getCards())); + outputView.printUsersCardResult(userResult); + } + + private void showFinalResult(GameResult gameResult) { + outputView.printFinalResult(gameResult.getDealerResult(), gameResult.getPlayerResults()); + } +} diff --git a/src/main/java/domain/DrawCommand.java b/src/main/java/domain/DrawCommand.java new file mode 100644 index 0000000000..24d588b71e --- /dev/null +++ b/src/main/java/domain/DrawCommand.java @@ -0,0 +1,31 @@ +package domain; + +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public enum DrawCommand { + DRAW("y"), + STOP("n"); + + private static final Map inputDrawCommandMap = Stream.of(values()) + .collect(Collectors.toMap(DrawCommand::getCommand, Function.identity())); + + private final String command; + + DrawCommand(String command) { + this.command = command; + } + + public static DrawCommand of(String inputCommand) { + if(inputDrawCommandMap.containsKey(inputCommand)) { + return inputDrawCommandMap.get(inputCommand); + } + throw new IllegalArgumentException("[ERROR] 카드 드로우 커맨드는 y,n 둘 중 하나입니다."); + } + + private String getCommand() { + return command; + } +} diff --git a/src/main/java/domain/Number.java b/src/main/java/domain/Number.java new file mode 100644 index 0000000000..2c818d380c --- /dev/null +++ b/src/main/java/domain/Number.java @@ -0,0 +1,33 @@ +package domain; + +public enum Number { + ACE(11, "A"), + TWO(2, "2"), + THREE(3, "3"), + FOUR(4, "4"), + FIVE(5, "5"), + SIX(6, "6"), + SEVEN(7, "7"), + EIGHT(8, "8"), + NINE(9, "9"), + TEN(10, "10"), + JACK(10, "J"), + QUEEN(10, "Q"), + KING(10, "K"); + + private final int score; + private final String number; + + Number(int score, String number) { + this.score = score; + this.number = number; + } + + public int getScore() { + return score; + } + + public String getNumber() { + return number; + } +} diff --git a/src/main/java/domain/Pattern.java b/src/main/java/domain/Pattern.java new file mode 100644 index 0000000000..3383367b81 --- /dev/null +++ b/src/main/java/domain/Pattern.java @@ -0,0 +1,18 @@ +package domain; + +public enum Pattern { + HEART("하트"), + DIAMOND("다이아몬드"), + CLOVER("클로버"), + SPADE("스페이드"); + + private final String pattern; + + Pattern(String pattern) { + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } +} diff --git a/src/main/java/domain/card/Card.java b/src/main/java/domain/card/Card.java new file mode 100644 index 0000000000..d62cc4de1b --- /dev/null +++ b/src/main/java/domain/card/Card.java @@ -0,0 +1,7 @@ +package domain.card; + +public interface Card { + int getScore(); + + String getSymbol(); +} diff --git a/src/main/java/domain/card/CloverCard.java b/src/main/java/domain/card/CloverCard.java new file mode 100644 index 0000000000..cc51b9b83b --- /dev/null +++ b/src/main/java/domain/card/CloverCard.java @@ -0,0 +1,38 @@ +package domain.card; + +import domain.Number; +import domain.Pattern; + +public enum CloverCard implements Card { + CLOVER_ACE(Pattern.CLOVER, Number.ACE), + CLOVER_TWO(Pattern.CLOVER, Number.TWO), + CLOVER_THREE(Pattern.CLOVER, Number.THREE), + CLOVER_FOUR(Pattern.CLOVER, Number.FOUR), + CLOVER_FIVE(Pattern.CLOVER, Number.FIVE), + CLOVER_SIX(Pattern.CLOVER, Number.SIX), + CLOVER_SEVEN(Pattern.CLOVER, Number.SEVEN), + CLOVER_EIGHT(Pattern.CLOVER, Number.EIGHT), + CLOVER_NINE(Pattern.CLOVER, Number.NINE), + CLOVER_TEN(Pattern.CLOVER, Number.TEN), + CLOVER_JACK(Pattern.CLOVER, Number.JACK), + CLOVER_QUEEN(Pattern.CLOVER, Number.QUEEN), + CLOVER_KING(Pattern.CLOVER, Number.KING); + + private final Pattern pattern; + private final Number number; + + CloverCard(Pattern pattern, Number number) { + this.pattern = pattern; + this.number = number; + } + + @Override + public String getSymbol() { + return number.getNumber() + pattern.getPattern(); + } + + @Override + public int getScore() { + return number.getScore(); + } +} diff --git a/src/main/java/domain/card/DeckGenerator.java b/src/main/java/domain/card/DeckGenerator.java new file mode 100644 index 0000000000..a0b7b001be --- /dev/null +++ b/src/main/java/domain/card/DeckGenerator.java @@ -0,0 +1,7 @@ +package domain.card; + +import java.util.List; + +public interface DeckGenerator { + public abstract List generate(); +} diff --git a/src/main/java/domain/card/DiamondCard.java b/src/main/java/domain/card/DiamondCard.java new file mode 100644 index 0000000000..b5ec14ddda --- /dev/null +++ b/src/main/java/domain/card/DiamondCard.java @@ -0,0 +1,38 @@ +package domain.card; + +import domain.Number; +import domain.Pattern; + +public enum DiamondCard implements Card { + DIAMOND_ACE(Pattern.DIAMOND, Number.ACE), + DIAMOND_TWO(Pattern.DIAMOND, Number.TWO), + DIAMOND_THREE(Pattern.DIAMOND, Number.THREE), + DIAMOND_FOUR(Pattern.DIAMOND, Number.FOUR), + DIAMOND_FIVE(Pattern.DIAMOND, Number.FIVE), + DIAMOND_SIX(Pattern.DIAMOND, Number.SIX), + DIAMOND_SEVEN(Pattern.DIAMOND, Number.SEVEN), + DIAMOND_EIGHT(Pattern.DIAMOND, Number.EIGHT), + DIAMOND_NINE(Pattern.DIAMOND, Number.NINE), + DIAMOND_TEN(Pattern.DIAMOND, Number.TEN), + DIAMOND_JACK(Pattern.DIAMOND, Number.JACK), + DIAMOND_QUEEN(Pattern.DIAMOND, Number.QUEEN), + DIAMOND_KING(Pattern.DIAMOND, Number.KING); + + private final Pattern pattern; + private final Number number; + + DiamondCard(Pattern pattern, Number number) { + this.pattern = pattern; + this.number = number; + } + + @Override + public String getSymbol() { + return number.getNumber() + pattern.getPattern(); + } + + @Override + public int getScore() { + return number.getScore(); + } +} diff --git a/src/main/java/domain/card/GameDeck.java b/src/main/java/domain/card/GameDeck.java new file mode 100644 index 0000000000..2c6061fd1c --- /dev/null +++ b/src/main/java/domain/card/GameDeck.java @@ -0,0 +1,31 @@ +package domain.card; + +import java.util.ArrayList; +import java.util.List; + +public class GameDeck { + private final List cards; + + public GameDeck(DeckGenerator deckGenerator) { + cards = deckGenerator.generate(); + } + + public Card drawCard() { + if (isEmpty()) { + throw new IllegalStateException("[ERROR] 뽑을 카드가 더 이상 존재하지 않습니다."); + } + return cards.remove(0); + } + + public List drawForFirstTurn() { + List firstTurnCards = new ArrayList<>(); + firstTurnCards.add(drawCard()); + firstTurnCards.add(drawCard()); + + return firstTurnCards; + } + + private boolean isEmpty() { + return cards.isEmpty(); + } +} diff --git a/src/main/java/domain/card/HeartCard.java b/src/main/java/domain/card/HeartCard.java new file mode 100644 index 0000000000..3c817898a6 --- /dev/null +++ b/src/main/java/domain/card/HeartCard.java @@ -0,0 +1,38 @@ +package domain.card; + +import domain.Number; +import domain.Pattern; + +public enum HeartCard implements Card { + HEART_ACE(Pattern.HEART, Number.ACE), + HEART_TWO(Pattern.HEART, Number.TWO), + HEART_THREE(Pattern.HEART, Number.THREE), + HEART_FOUR(Pattern.HEART, Number.FOUR), + HEART_FIVE(Pattern.HEART, Number.FIVE), + HEART_SIX(Pattern.HEART, Number.SIX), + HEART_SEVEN(Pattern.HEART, Number.SEVEN), + HEART_EIGHT(Pattern.HEART, Number.EIGHT), + HEART_NINE(Pattern.HEART, Number.NINE), + HEART_TEN(Pattern.HEART, Number.TEN), + HEART_JACK(Pattern.HEART, Number.JACK), + HEART_QUEEN(Pattern.HEART, Number.QUEEN), + HEART_KING(Pattern.HEART, Number.KING); + + private final Pattern pattern; + private final Number number; + + HeartCard(Pattern pattern, Number number) { + this.pattern = pattern; + this.number = number; + } + + @Override + public String getSymbol() { + return number.getNumber() + pattern.getPattern(); + } + + @Override + public int getScore() { + return number.getScore(); + } +} diff --git a/src/main/java/domain/card/ShuffleDeckGenerator.java b/src/main/java/domain/card/ShuffleDeckGenerator.java new file mode 100644 index 0000000000..2b8e08fd5d --- /dev/null +++ b/src/main/java/domain/card/ShuffleDeckGenerator.java @@ -0,0 +1,25 @@ +package domain.card; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ShuffleDeckGenerator implements DeckGenerator{ + @Override + public List generate() { + List originDeck = addAllCards(); + Collections.shuffle(originDeck); + return originDeck; + } + + private List addAllCards() { + List cards = new ArrayList<>(); + cards.addAll(Arrays.asList(CloverCard.values())); + cards.addAll(Arrays.asList(DiamondCard.values())); + cards.addAll(Arrays.asList(HeartCard.values())); + cards.addAll(Arrays.asList(SpadeCard.values())); + + return cards; + } +} diff --git a/src/main/java/domain/card/SpadeCard.java b/src/main/java/domain/card/SpadeCard.java new file mode 100644 index 0000000000..b205b0b1a9 --- /dev/null +++ b/src/main/java/domain/card/SpadeCard.java @@ -0,0 +1,38 @@ +package domain.card; + +import domain.Number; +import domain.Pattern; + +public enum SpadeCard implements Card { + SPADE_ACE(Pattern.SPADE, Number.ACE), + SPADE_TWO(Pattern.SPADE, Number.TWO), + SPADE_THREE(Pattern.SPADE, Number.THREE), + SPADE_FOUR(Pattern.SPADE, Number.FOUR), + SPADE_FIVE(Pattern.SPADE, Number.FIVE), + SPADE_SIX(Pattern.SPADE, Number.SIX), + SPADE_SEVEN(Pattern.SPADE, Number.SEVEN), + SPADE_EIGHT(Pattern.SPADE, Number.EIGHT), + SPADE_NINE(Pattern.SPADE, Number.NINE), + SPADE_TEN(Pattern.SPADE, Number.TEN), + SPADE_JACK(Pattern.SPADE, Number.JACK), + SPADE_QUEEN(Pattern.SPADE, Number.QUEEN), + SPADE_KING(Pattern.SPADE, Number.KING); + + private final Pattern pattern; + private final Number number; + + SpadeCard(Pattern pattern, Number number) { + this.pattern = pattern; + this.number = number; + } + + @Override + public String getSymbol() { + return number.getNumber() + pattern.getPattern(); + } + + @Override + public int getScore() { + return number.getScore(); + } +} diff --git a/src/main/java/domain/game/BlackJackGame.java b/src/main/java/domain/game/BlackJackGame.java new file mode 100644 index 0000000000..caf869c360 --- /dev/null +++ b/src/main/java/domain/game/BlackJackGame.java @@ -0,0 +1,46 @@ +package domain.game; + +import domain.card.GameDeck; +import domain.user.Dealer; +import domain.user.DealerStatus; +import domain.user.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class BlackJackGame { + private final List players; + private final Dealer dealer; + private final GameDeck gameDeck; + + public BlackJackGame(List players, Dealer dealer, GameDeck gameDeck) { + this.players = new ArrayList<>(players); + this.dealer = dealer; + this.gameDeck = gameDeck; + } + + public void drawOneMoreCardForPlayer(Player player) { + player.receiveCard(gameDeck.drawCard()); + } + + public void drawCardUntilOverSixteen() { + while (dealer.isUserStatus(DealerStatus.UNDER_SEVENTEEN)) { + dealer.receiveCard(gameDeck.drawCard()); + } + } + + public Dealer getDealer() { + return dealer; + } + + public List getPlayers() { + return players; + } + + public List getPlayerNames() { + return players.stream() + .map(Player::getName) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/domain/game/GameResult.java b/src/main/java/domain/game/GameResult.java new file mode 100644 index 0000000000..26b10771e2 --- /dev/null +++ b/src/main/java/domain/game/GameResult.java @@ -0,0 +1,70 @@ +package domain.game; + +import domain.user.Dealer; +import domain.user.DealerStatus; +import domain.user.Player; +import domain.user.PlayerStatus; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class GameResult { + private final Map playerResults = new LinkedHashMap<>(); + private final Map dealerResult = new HashMap<>(); + + public GameResult(List playerNames) { + playerNames.forEach(name -> playerResults.put(name, false)); + dealerResult.put(true, 0); + dealerResult.put(false, 0); + } + + public void saveResults(Dealer dealer, List players) { + judgeWinner(dealer, players); + } + + public void judgeWinner(Dealer dealer, List players) { + for (Player player : players) { + compareDealerStatusWithPlayer(dealer, player); + } + } + + public Map getPlayerResults() { + return new LinkedHashMap<>(playerResults); + } + + public Map getDealerResult() { + return new HashMap<>(dealerResult); + } + + private void compareDealerStatusWithPlayer(Dealer dealer, Player player) { + if (player.isUserStatus(PlayerStatus.BUST)) { + dealerWin(player); + return; + } + if (player.isUserStatus(PlayerStatus.NORMAL) && dealer.isUserStatus(DealerStatus.BUST)) { + playerWin(player); + return; + } + compareScore(dealer, player); + } + + private void compareScore(Dealer dealer, Player player) { + if (dealer.getScore() >= player.getScore()) { + dealerWin(player); + return; + } + playerWin(player); + } + + private void playerWin(Player player) { + dealerResult.put(false, dealerResult.get(false)+1); + playerResults.put(player.getName(), true); + } + + private void dealerWin(Player player) { + dealerResult.put(true, dealerResult.get(true)+1); + playerResults.put(player.getName(), false); + } +} diff --git a/src/main/java/domain/user/Dealer.java b/src/main/java/domain/user/Dealer.java new file mode 100644 index 0000000000..c241287f0d --- /dev/null +++ b/src/main/java/domain/user/Dealer.java @@ -0,0 +1,37 @@ +package domain.user; + +import domain.card.Card; + +import java.util.List; + +public class Dealer extends User { + private DealerStatus status; + + public Dealer(List firstTurnCards) { + super(firstTurnCards); + checkBustByScore(); + } + + @Override + protected void checkBustByScore() { + if (score.getScore() > BLACKJACK) { + status = DealerStatus.BUST; + return; + } + if (score.getScore() <= 16) { + status = DealerStatus.UNDER_SEVENTEEN; + return; + } + status = DealerStatus.NORMAL; + } + + @Override + public boolean isUserStatus(UserStatus status) { + return this.status.equals(status); + } + + @Override + public String getName() { + return "딜러"; + } +} diff --git a/src/main/java/domain/user/DealerStatus.java b/src/main/java/domain/user/DealerStatus.java new file mode 100644 index 0000000000..f64deece32 --- /dev/null +++ b/src/main/java/domain/user/DealerStatus.java @@ -0,0 +1,7 @@ +package domain.user; + +public enum DealerStatus implements UserStatus { + UNDER_SEVENTEEN, + NORMAL, + BUST +} diff --git a/src/main/java/domain/user/Name.java b/src/main/java/domain/user/Name.java new file mode 100644 index 0000000000..24373683d1 --- /dev/null +++ b/src/main/java/domain/user/Name.java @@ -0,0 +1,28 @@ +package domain.user; + +import java.util.Objects; + +public class Name { + private final String name; + + public Name(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null || getClass() != other.getClass()) return false; + Name name1 = (Name) other; + return Objects.equals(name, name1.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/domain/user/Names.java b/src/main/java/domain/user/Names.java new file mode 100644 index 0000000000..2f9d764695 --- /dev/null +++ b/src/main/java/domain/user/Names.java @@ -0,0 +1,32 @@ +package domain.user; + +import java.util.ArrayList; +import java.util.List; + +public class Names { + private static final int MAX_PLAYER_SIZE = 5; + + private final List names = new ArrayList<>(); + + public Names(List inputNames) { + validateDuplicatedName(inputNames); + validateNamesSize(inputNames); + inputNames.forEach(name -> names.add(new Name(name))); + } + + public List getNames() { + return new ArrayList<>(names); + } + + private void validateDuplicatedName(List names) { + if(names.size() != names.stream().distinct().count()) { + throw new IllegalArgumentException("[ERROR] 플레이어 이름은 중복될 수 없습니다."); + } + } + + private void validateNamesSize(List names) { + if (names.size() > MAX_PLAYER_SIZE) { + throw new IllegalArgumentException("[ERROR] 플레이어는 최대 5명입니다."); + } + } +} diff --git a/src/main/java/domain/user/Player.java b/src/main/java/domain/user/Player.java new file mode 100644 index 0000000000..9403280797 --- /dev/null +++ b/src/main/java/domain/user/Player.java @@ -0,0 +1,33 @@ +package domain.user; + +import domain.card.Card; + +import java.util.List; +import java.util.Objects; + +public class Player extends User { + private final Name name; + private PlayerStatus status = PlayerStatus.NORMAL; + + public Player(Name name, List firstTurnCards) { + super(firstTurnCards); + this.name = name; + } + + @Override + protected void checkBustByScore() { + if (score.getScore() > BLACKJACK) { + status = PlayerStatus.BUST; + } + } + + @Override + public boolean isUserStatus(UserStatus status) { + return this.status.equals(status); + } + + @Override + public String getName() { + return name.getName(); + } +} diff --git a/src/main/java/domain/user/PlayerStatus.java b/src/main/java/domain/user/PlayerStatus.java new file mode 100644 index 0000000000..abe0dface8 --- /dev/null +++ b/src/main/java/domain/user/PlayerStatus.java @@ -0,0 +1,6 @@ +package domain.user; + +public enum PlayerStatus implements UserStatus { + NORMAL, + BUST +} diff --git a/src/main/java/domain/user/Score.java b/src/main/java/domain/user/Score.java new file mode 100644 index 0000000000..dd38d4a4ad --- /dev/null +++ b/src/main/java/domain/user/Score.java @@ -0,0 +1,60 @@ +package domain.user; + +import domain.card.Card; +import domain.Number; +import java.util.List; +import java.util.stream.Collectors; + +public class Score { + private static final int BLACKJACK = 21; + private static final int ZERO = 0; + private static final int ACE_ONE = 1; + + private int score; + + public Score(List cards) { + calculate(cards); + } + + public void calculate(List cards) { + List numbers = convertCardsToNumbers(cards); + int aceCount = countOfAce(numbers); + int sum = sum(numbers); + + if (sum > BLACKJACK) { + sum = calculateAceAsOne(aceCount, sum); + } + score = sum; + } + + private List convertCardsToNumbers(List cards) { + return cards.stream() + .map(Card::getScore) + .collect(Collectors.toUnmodifiableList()); + } + + private int countOfAce(List numbers) { + return (int) numbers.stream() + .filter(number -> number == Number.ACE.getScore()) + .count(); + } + + private int sum(List numbers) { + return numbers.stream() + .mapToInt(number -> number) + .sum(); + } + + private int calculateAceAsOne(int aceCount, int sum) { + while (aceCount > ZERO && sum > BLACKJACK) { + sum -= Number.ACE.getScore(); + sum += ACE_ONE; + aceCount--; + } + return sum; + } + + public int getScore() { + return score; + } +} diff --git a/src/main/java/domain/user/User.java b/src/main/java/domain/user/User.java new file mode 100644 index 0000000000..5283cfd9a6 --- /dev/null +++ b/src/main/java/domain/user/User.java @@ -0,0 +1,38 @@ +package domain.user; + +import domain.card.Card; + +import java.util.ArrayList; +import java.util.List; + +public abstract class User { + protected static final int BLACKJACK = 21; + + private final List cards; + protected final Score score; + + public User(List firstTurnCards) { + cards = new ArrayList<>(firstTurnCards); + score = new Score(firstTurnCards); + } + + public void receiveCard(Card card) { + cards.add(card); + score.calculate(cards); + checkBustByScore(); + } + + public List getCards() { + return cards; + } + + public int getScore() { + return score.getScore(); + } + + public abstract boolean isUserStatus(UserStatus status); + + protected abstract void checkBustByScore(); + + public abstract String getName(); +} diff --git a/src/main/java/domain/user/UserStatus.java b/src/main/java/domain/user/UserStatus.java new file mode 100644 index 0000000000..6be0ab66e0 --- /dev/null +++ b/src/main/java/domain/user/UserStatus.java @@ -0,0 +1,4 @@ +package domain.user; + +public interface UserStatus { +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000000..acf83dffd0 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,23 @@ +package view; + +import domain.DrawCommand; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + private final Scanner scanner = new Scanner(System.in); + + public List readPlayersName() { + List playersName = Arrays.asList(scanner.nextLine().split(",")); + + return playersName.stream() + .map(String::strip) + .collect(Collectors.toList()); + } + + public DrawCommand readDrawCommand() { + return DrawCommand.of(scanner.nextLine()); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000000..a6fff81582 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,81 @@ +package view; + +import domain.card.Card; +import domain.user.User; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +public class OutputView { + public void printInputPlayerNameMessage() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + } + + public void printSetUpResult(HashMap> setUpResult) { + printSetUpCompleteMessage(setUpResult); + printUserCards(setUpResult); + } + + public void printAskOneMoreCardMessage(String name) { + System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)\n", name); + } + + public void printPlayerDrawResult(String name, List cards) { + String cardSymbols = cards.stream() + .map(Card::getSymbol) + .collect(Collectors.joining(", ")); + + System.out.println(name + "카드 : " + cardSymbols); + } + + private void printSetUpCompleteMessage(HashMap> setUpResult) { + String playerNames = String.join(", ", + new ArrayList<>(setUpResult.keySet()).subList(1, setUpResult.size())); + + System.out.printf("\n딜러와 %s에게 2장을 나누었습니다.\n", playerNames); + } + + private void printUserCards(HashMap> setUpResult) { + for (Entry> cardsByUser : setUpResult.entrySet()) { + String name = cardsByUser.getKey(); + String cards = cardsByUser.getValue().stream() + .map(Card::getSymbol) + .collect(Collectors.joining(", ")); + + System.out.println(name + "카드 : " + cards); + } + System.out.println(); + } + + public void printDealerDrawResult(int dealerDrawCount) { + System.out.printf("\n딜러는 16이하라 %d장의 카드를 더 받았습니다.\n\n", dealerDrawCount); + } + + public void printUsersCardResult(Map> userResult) { + for (Entry> cardsByUser : userResult.entrySet()) { + String name = cardsByUser.getKey().getName(); + String cards = cardsByUser.getValue().stream() + .map(Card::getSymbol) + .collect(Collectors.joining(", ")); + int score = cardsByUser.getKey().getScore(); + + System.out.println(name + "카드 : " + cards + " - 결과: " + score); + } + System.out.println(); + } + + public void printFinalResult(Map dealerResult, Map userResult) { + System.out.println("## 최종 승패"); + System.out.printf("딜러: %d승 %d패\n", dealerResult.get(true), dealerResult.get(false)); + for (Entry userFinalResult : userResult.entrySet()) { + if (userFinalResult.getValue()) { + System.out.println(userFinalResult.getKey() + ": 승"); + continue; + } + System.out.println(userFinalResult.getKey() + ": 패"); + } + } +} diff --git a/src/test/java/domain/DrawCommandTest.java b/src/test/java/domain/DrawCommandTest.java new file mode 100644 index 0000000000..8a8cfc3ef5 --- /dev/null +++ b/src/test/java/domain/DrawCommandTest.java @@ -0,0 +1,29 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +@DisplayName("DrawCommand는 ") +class DrawCommandTest { + @ParameterizedTest(name = "{0} 입력값이 들어오면 {1}") + @MethodSource("createDrawCommandTestCase") + void createDrawCommandTest(String input, DrawCommand expected) { + DrawCommand drawCommand = DrawCommand.of(input); + + assertThat(drawCommand).isEqualTo(expected); + } + + static Stream createDrawCommandTestCase() { + return Stream.of( + Arguments.of("y", Named.of("카드를 뽑는다.", DrawCommand.DRAW)), + Arguments.of("n", Named.of("카드를 뽑지 않는다.", DrawCommand.STOP)) + ); + } +} diff --git a/src/test/java/domain/NumberTest.java b/src/test/java/domain/NumberTest.java new file mode 100644 index 0000000000..f65b2b2456 --- /dev/null +++ b/src/test/java/domain/NumberTest.java @@ -0,0 +1,16 @@ +package domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class NumberTest { + @Test + @DisplayName("블랙잭 게임 카드 숫자는 1~11의 값만 가진다.") + void generateNumberTest() { + for (Number number : Number.values()) { + Assertions.assertThat(number.getScore()) + .isBetween(1, 11); + } + } +} diff --git a/src/test/java/domain/PatternTest.java b/src/test/java/domain/PatternTest.java new file mode 100644 index 0000000000..93b226efeb --- /dev/null +++ b/src/test/java/domain/PatternTest.java @@ -0,0 +1,21 @@ +package domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.IntStream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class PatternTest { + @Test + @DisplayName("블랙잭 게임 카드 문양은 하트, 다이아몬드, 클로버, 스페이드의 값만 가진다.") + void generatePatternTest() { + List patterns = new ArrayList<>(Arrays.asList(Pattern.values())); + List answers = List.of("하트", "다이아몬드", "클로버", "스페이드"); + + IntStream.range(0, answers.size()) + .forEach(index -> Assertions.assertThat(patterns.get(index).getPattern()).isEqualTo(answers.get(index))); + } +} diff --git a/src/test/java/domain/card/CardTest.java b/src/test/java/domain/card/CardTest.java new file mode 100644 index 0000000000..bff6732d45 --- /dev/null +++ b/src/test/java/domain/card/CardTest.java @@ -0,0 +1,33 @@ +package domain.card; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("블랙잭 게임의 ") +public class CardTest { + @Test + @DisplayName("하트 카드는 문양 당 13장을 생성한다.") + void generateHeartCardTest() { + assertThat(HeartCard.values().length).isEqualTo(13); + } + + @Test + @DisplayName("다이아몬드 카드는 문양 당 13장을 생성한다.") + void generateDiamondCardTest() { + assertThat(DiamondCard.values().length).isEqualTo(13); + } + + @Test + @DisplayName("클로버 카드는 문양 당 13장을 생성한다.") + void generateCloverCardTest() { + assertThat(CloverCard.values().length).isEqualTo(13); + } + + @Test + @DisplayName("스페이드 카드는 문양 당 13장을 생성한다.") + void generateSpadeCardTest() { + assertThat(SpadeCard.values().length).isEqualTo(13); + } +} diff --git a/src/test/java/domain/card/GameDeckTest.java b/src/test/java/domain/card/GameDeckTest.java new file mode 100644 index 0000000000..48520e4db5 --- /dev/null +++ b/src/test/java/domain/card/GameDeckTest.java @@ -0,0 +1,66 @@ +package domain.card; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("블랙잭 게임 ") +class GameDeckTest { + @Test + @DisplayName("카드는 52장까지 뽑을 수 있다.") + void drawCardTest() { + //given + GameDeck gameDeck = new GameDeck(new ShuffleDeckGenerator()); + + //when + IntStream.range(0,52).forEach(index -> gameDeck.drawCard()); + + //then + assertThrows(IllegalStateException.class, gameDeck::drawCard); + } + + @Test + @DisplayName("시작 직후 카드를 두 장씩 분배한다.") + void drawForFirstTurnTest() { + GameDeck gameDeck = new GameDeck(new ShuffleDeckGenerator()); + + List firstTurnCards = gameDeck.drawForFirstTurn(); + + assertThat(firstTurnCards.size()).isEqualTo(2); + } + + @Test + @DisplayName("카드는 덱에서 순서대로 뽑아간다.") + void drawCard() { + //given + List cards = new ArrayList<>(List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_THREE, + CloverCard.CLOVER_FIVE)); + GameDeck gameDeck = new GameDeck(new TestDeckGenerator(cards)); + List drawCards = new ArrayList<>(); + + //when + IntStream.range(0, cards.size()).forEach(trial -> drawCards.add(gameDeck.drawCard())); + + //then + assertThat(drawCards).isEqualTo(List.of(CloverCard.CLOVER_ACE, + CloverCard.CLOVER_THREE, CloverCard.CLOVER_FIVE)); + } + + static class TestDeckGenerator implements DeckGenerator { + private final List cards; + + public TestDeckGenerator(List cards) { + this.cards = cards; + } + + @Override + public List generate() { + return cards; + } + } +} diff --git a/src/test/java/domain/game/GameResultTest.java b/src/test/java/domain/game/GameResultTest.java new file mode 100644 index 0000000000..63dafd6bdc --- /dev/null +++ b/src/test/java/domain/game/GameResultTest.java @@ -0,0 +1,62 @@ +package domain.game; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import domain.card.CloverCard; +import domain.card.HeartCard; +import domain.user.Dealer; +import domain.user.Name; +import domain.user.Player; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +@DisplayName("게임 결과는 ") +class GameResultTest { + @Test + @DisplayName("계산되기 위해 GameResult 객체 생성을 할 수 있다.") + void createTest() { + assertDoesNotThrow(() -> new GameResult(List.of("pobi", "neo"))); + } + + @Test + @DisplayName("전체 플레이어의 결과를 포함한다.") + void judgePlayerResultsTest() { + //given + Dealer dealer = new Dealer(List.of(CloverCard.CLOVER_SIX, CloverCard.CLOVER_THREE)); + Player pobi = new Player(new Name("pobi"), List.of(CloverCard.CLOVER_FIVE, CloverCard.CLOVER_EIGHT)); + Player neo = new Player(new Name("neo"), List.of(HeartCard.HEART_TWO, HeartCard.HEART_THREE)); + List players = List.of(pobi, neo); + GameResult gameResult = new GameResult(List.of("pobi", "neo")); + gameResult.saveResults(dealer, players); + + //when + Map playerResult = gameResult.getPlayerResults(); + + //then + assertThat(playerResult.get("pobi")).isTrue(); + assertThat(playerResult.get("neo")).isFalse(); + } + + @Test + @DisplayName("딜러의 결과를 포함한다.") + void judgeDealerResultsTest() { + //given + Dealer dealer = new Dealer(List.of(CloverCard.CLOVER_SIX, CloverCard.CLOVER_THREE)); + Player pobi = new Player(new Name("pobi"), List.of(CloverCard.CLOVER_FIVE, CloverCard.CLOVER_EIGHT)); + Player neo = new Player(new Name("neo"), List.of(HeartCard.HEART_TWO, HeartCard.HEART_THREE)); + List players = List.of(pobi, neo); + GameResult gameResult = new GameResult(List.of("pobi", "neo")); + gameResult.saveResults(dealer, players); + + //when + Map dealerResult = gameResult.getDealerResult(); + + //then + assertThat(dealerResult.get(true)).isEqualTo(1); + assertThat(dealerResult.get(false)).isEqualTo(1); + } +} diff --git a/src/test/java/domain/user/DealerTest.java b/src/test/java/domain/user/DealerTest.java new file mode 100644 index 0000000000..f7bf7f8853 --- /dev/null +++ b/src/test/java/domain/user/DealerTest.java @@ -0,0 +1,41 @@ +package domain.user; + +import static org.assertj.core.api.Assertions.assertThat; + +import domain.card.Card; +import domain.card.CloverCard; + +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@DisplayName("딜러는 ") +class DealerTest { + @ParameterizedTest(name = "{2} 상태 값을 확인할 수 있다.") + @MethodSource("isDealerStatusTestCase") + @DisplayName("자신의 상태값을 확인할 수 있다.") + void isPlayerStatusTest(List firstTurnCards, Card drawCard, DealerStatus dealerStatus) { + //given + Dealer dealer = new Dealer(firstTurnCards); + + //when + dealer.receiveCard(drawCard); + + //then + assertThat(dealer.isUserStatus(dealerStatus)).isTrue(); + + } + + static Stream isDealerStatusTestCase() { + return Stream.of( + Arguments.of(List.of(CloverCard.CLOVER_TEN, CloverCard.CLOVER_KING), CloverCard.CLOVER_QUEEN, Named.of("버스트", DealerStatus.BUST)), + Arguments.of(List.of(CloverCard.CLOVER_TWO, CloverCard.CLOVER_EIGHT), CloverCard.CLOVER_SEVEN, Named.of("노멀", DealerStatus.NORMAL)), + Arguments.of(List.of(CloverCard.CLOVER_TWO, CloverCard.CLOVER_THREE), CloverCard.CLOVER_FOUR, Named.of("17미만", DealerStatus.UNDER_SEVENTEEN)) + ); + } +} diff --git a/src/test/java/domain/user/NamesTest.java b/src/test/java/domain/user/NamesTest.java new file mode 100644 index 0000000000..16ae8dfc85 --- /dev/null +++ b/src/test/java/domain/user/NamesTest.java @@ -0,0 +1,36 @@ +package domain.user; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +@DisplayName("입력된 이름 값들은 ") +public class NamesTest { + @Test + @DisplayName("하나일 수 있다.") + void createSingleNameTest() { + Names singleName = new Names(List.of("pobi")); + + assertThat(singleName.getNames()).isEqualTo(List.of(new Name("pobi"))); + } + + @Test + @DisplayName("중복될 시 예외처리 된다.") + void validateDuplicatedNamesTest() { + assertThatThrownBy(() -> new Names(List.of("pobi", "neo", "pobi"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 플레이어 이름은 중복될 수 없습니다."); + } + + @Test + @DisplayName("5개가 초과될 시 예외처리 된다.") + void validateNamesSizeTest() { + assertThatThrownBy(() -> new Names(List.of("pobi", "neo", "hiiro", "mako", "ako", "split"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 플레이어는 최대 5명입니다."); + } +} diff --git a/src/test/java/domain/user/PlayerTest.java b/src/test/java/domain/user/PlayerTest.java new file mode 100644 index 0000000000..5cc8ef4ef5 --- /dev/null +++ b/src/test/java/domain/user/PlayerTest.java @@ -0,0 +1,70 @@ +package domain.user; + +import static org.assertj.core.api.Assertions.assertThat; + +import domain.card.Card; +import domain.card.CloverCard; + +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; +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; + +@DisplayName("플레이어는 ") +class PlayerTest { + @Test + @DisplayName("처음에 2장의 카드를 받는다.") + void generatePlayerTest() { + //given + List firstTurnCards = List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_FIVE); + Player player = new Player(new Name("플레이어"), firstTurnCards); + + //when + List cards = player.getCards(); + + //then + assertThat(cards.size()).isEqualTo(2); + } + + @Test + @DisplayName("카드 한 장을 받아 패에 넣는다.") + void receiveCardTest() { + //given + List firstTurnCards = List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_FIVE); + Player player = new Player(new Name("플레이어"), firstTurnCards); + List cards = player.getCards(); + + //when + player.receiveCard(CloverCard.CLOVER_FOUR); + + //then + assertThat(cards.size()).isEqualTo(3); + } + + @ParameterizedTest(name = "{2} 상태값을 확인할 수 있다.") + @MethodSource("isPlayerStatusTestCase") + @DisplayName("자신의 상태값을 확인할 수 있다.") + void isPlayerStatusTest(List firstTurnCards, Card drawCard, PlayerStatus playerStatus) { + //given + Player player = new Player(new Name("플레이어"), firstTurnCards); + + //when + player.receiveCard(drawCard); + + //then + assertThat(player.isUserStatus(playerStatus)).isTrue(); + + } + + static Stream isPlayerStatusTestCase() { + return Stream.of( + Arguments.of(List.of(CloverCard.CLOVER_TEN, CloverCard.CLOVER_KING), CloverCard.CLOVER_QUEEN, Named.of("버스트", PlayerStatus.BUST)), + Arguments.of(List.of(CloverCard.CLOVER_TWO, CloverCard.CLOVER_THREE), CloverCard.CLOVER_FOUR, Named.of("노멀", PlayerStatus.NORMAL)) + ); + } +} diff --git a/src/test/java/domain/user/ScoreTest.java b/src/test/java/domain/user/ScoreTest.java new file mode 100644 index 0000000000..edc5faaa92 --- /dev/null +++ b/src/test/java/domain/user/ScoreTest.java @@ -0,0 +1,48 @@ +package domain.user; + +import domain.card.Card; +import domain.card.CloverCard; +import java.util.List; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +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; + +@DisplayName("블랙잭 게임 점수는 ") +class ScoreTest { + @Test + @DisplayName("카드 숫자 값들이 주어지면 단순 합산으로 계산할 수 있다.") + void calculateScoreTest() { + //given + List cards = List.of(CloverCard.CLOVER_TWO, CloverCard.CLOVER_THREE, CloverCard.CLOVER_FOUR, CloverCard.CLOVER_FIVE); + + //when + Score score = new Score(cards); + + //then + Assertions.assertThat(score.getScore()).isEqualTo(14); + } + + @ParameterizedTest + @MethodSource("calculateScoreWithAceCase") + @DisplayName("에이스를 포함하며 21 초과 시 에이스를 1점으로 계산한다.") + void calculateScoreWithAceTest(List cards, int expected) { + Score score = new Score(cards); + + Assertions.assertThat(score.getScore()).isEqualTo(expected); + } + + static Stream calculateScoreWithAceCase() { + return Stream.of( + Arguments.of(List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_SEVEN, + CloverCard.CLOVER_EIGHT), 16), + Arguments.of(List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_ACE, + CloverCard.CLOVER_EIGHT), 20), + Arguments.of(List.of(CloverCard.CLOVER_ACE, CloverCard.CLOVER_ACE, CloverCard.CLOVER_TEN, + CloverCard.CLOVER_NINE), 21) + ); + } +}