diff --git a/README.md b/README.md index 03ba7ed3..77a8660f 100644 --- a/README.md +++ b/README.md @@ -1 +1,88 @@ -# java-blackjack \ No newline at end of file +# Black-Jack + +## 기능 목록 + +- [X] 참여할 사람의 이름 입력받기 + +- [X] 카드 나눠주기 + +- [X] 카드 수령 여부 + + - [X] 딜러의 카드 합이 16 이하이면 무조건 1장을 받아야한다. + +- [X] 결과 판정하기 + +## 기능 요구 사항 +블랙잭 게임을 변형한 프로그램을 구현한다. + +블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다. + +카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다. + +게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다. + +딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다. + +게임을 완료한 후 각 플레이어별로 승패를 출력한다. + +## 프로그래밍 요구 사항 + +* 자바 코드 컨벤션을 지키면서 프로그래밍한다. + * 기본적으로 Google Java Style Guide을 원칙으로 한다. + * 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다. +* indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. + * 예를 들어 while문 안에 if문이 있복으면 들여쓰기는 2이다. + * 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. +* 3항 연산자를 쓰지 않는다. +* else 예약어를 쓰지 않는다. + * else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. + * 힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다. +* 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외 + * 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다. + * UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다. +* 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. + * 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라. +* 배열 대신 컬렉션을 사용한다. +* 모든 원시 값과 문자열을 포장한다 +* 줄여 쓰지 않는다(축약 금지). +* 일급 컬렉션을 쓴다. +## 추가된 요구 사항 +* 모든 엔티티를 작게 유지한다. +* 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. +* 딜러와 플레이어에서 발생하는 중복 코드를 제거해야 한다. + +# 연료 주입 + +## 기능 목록 + +- [X] 차량 별 주입 연료 필요량 구하기 + +- [X] 보고서 생성 + +## 기능 요구 사항 + +우리 회사는 렌터카를 운영하고 있다. + +현재 보유하고 있는 차량은 Sonata 2대, Avante 1대, K5 2대로 총 5대의 차량을 보유하고 있다. + +고객이 인터넷으로부터 예약할 때 여행할 목적지의 대략적인 이동거리를 입력 받는다. + +이 이동거리를 활용해 차량 별로 필요한 연료를 주입한다. + +차량 별로 주입해야 할 연료량을 확인할 수 있는 보고서를 생성해야 한다. + +각 차량별 연비는 다음과 같다. + +* Sonata : 10km/리터 + +* Avante : 15km/리터 + +* K5 : 13km/리터 + +## 프로그래밍 요구 사항 + +* 상속과 추상 메서드를 활용한다. + +* 위 요구사항을 if/else 절을 쓰지 않고 구현해야 한다. + +* 인터페이스를 적용해 구현한다. \ No newline at end of file diff --git a/src/main/java/blackjack/BlackjackApplication.java b/src/main/java/blackjack/BlackjackApplication.java new file mode 100644 index 00000000..ce7ea021 --- /dev/null +++ b/src/main/java/blackjack/BlackjackApplication.java @@ -0,0 +1,14 @@ +package blackjack; + +import blackjack.controller.BlackJack; +import blackjack.domain.request.UserNamesRequest; +import blackjack.view.InputView; + +public class BlackjackApplication { + + public static void main(String[] args) { + String playerNames = InputView.getPlayerNames(); + BlackJack blackJack = BlackJack.init(UserNamesRequest.from(playerNames)); + blackJack.runGame(); + } +} diff --git a/src/main/java/blackjack/controller/BlackJack.java b/src/main/java/blackjack/controller/BlackJack.java new file mode 100644 index 00000000..70592199 --- /dev/null +++ b/src/main/java/blackjack/controller/BlackJack.java @@ -0,0 +1,92 @@ +package blackjack.controller; + +import blackjack.domain.card.CardFactory; +import blackjack.domain.card.Deck; +import blackjack.domain.report.GameReports; +import blackjack.domain.request.DrawRequest; +import blackjack.domain.request.UserNamesRequest; +import blackjack.domain.user.Dealer; +import blackjack.domain.user.Player; +import blackjack.domain.user.Players; +import blackjack.view.InputView; +import blackjack.view.OutputView; +import java.util.List; +import java.util.stream.Collectors; + +public class BlackJack { + + private final Players players; + private final Deck deck; + + private BlackJack(Players players, Deck deck) { + this.players = players; + this.deck = deck; + } + + public static BlackJack init(UserNamesRequest playerNames) { + Dealer dealer = new Dealer(); + Players candidates = playerNames.userNames() + .stream() + .map(Player::new) + .collect(Collectors.collectingAndThen(Collectors.toList(), + players -> new Players(dealer, players))); + CardFactory cardFactory = CardFactory.getInstance(); + Deck deck = new Deck(cardFactory.createCards()); + return new BlackJack(candidates, deck); + } + + public void runGame() { + spreadStartCards(); + if (!players.hasBlackJack()) { + drawPlayers(); + drawDealer(); + } + GameReports reports = getResult(); + showResult(reports); + } + + private void spreadStartCards() { + players.drawStartCards(deck); + OutputView.printAllPlayersCard(players); + } + + private void drawPlayers() { + for (Player player : players.findOnlyPlayers()) { + drawEachPlayer(player); + } + } + + private void drawEachPlayer(Player player) { + while (player.isDrawable() && getPlayerRequest(player)) { + player.drawCard(deck.spreadCard()); + OutputView.printEachCardInfo(player); + } + } + + private boolean getPlayerRequest(Player player) { + String drawRequest = InputView.getDrawRequest(player); + return DrawRequest.valueOf(drawRequest) + .isDrawable(); + } + + private void drawDealer() { + Dealer dealer = players.findDealer(); + while (dealer.isDrawable()) { + dealer.drawCard(deck.spreadCard()); + OutputView.printDealerGetCard(); + } + } + + private GameReports getResult() { + Dealer dealer = players.findDealer(); + List candidates = players.findOnlyPlayers(); + return candidates.stream() + .map(dealer::createReport) + .collect(Collectors.collectingAndThen(Collectors.toList(), GameReports::new)); + } + + private void showResult(GameReports reports) { + OutputView.printResultStatus(players.all()); + OutputView.printReports(reports); + } +} diff --git a/src/main/java/blackjack/domain/card/Card.java b/src/main/java/blackjack/domain/card/Card.java new file mode 100644 index 00000000..fa1afe43 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Card.java @@ -0,0 +1,47 @@ +package blackjack.domain.card; + +import java.util.Objects; + +public class Card { + + private final Suit suit; + private final Number number; + + public Card(Suit suit, Number number) { + this.suit = suit; + this.number = number; + } + + public boolean isAce() { + return number == Number.ACE; + } + + public String message() { + return number.message(); + } + + public String suit() { + return suit.suit(); + } + + public int value() { + return number.score(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Card card = (Card) o; + return suit == card.suit && number == card.number; + } + + @Override + public int hashCode() { + return Objects.hash(suit, number); + } +} diff --git a/src/main/java/blackjack/domain/card/CardBundle.java b/src/main/java/blackjack/domain/card/CardBundle.java new file mode 100644 index 00000000..975c7736 --- /dev/null +++ b/src/main/java/blackjack/domain/card/CardBundle.java @@ -0,0 +1,42 @@ +package blackjack.domain.card; + +import blackjack.domain.score.ScoreCalculator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CardBundle { + + private static final int BLACK_JACK_SCORE = 21; + + private final List cards; + + private CardBundle() { + this.cards = new ArrayList<>(); + } + + public static CardBundle emptyBundle() { + return new CardBundle(); + } + + public void addCard(Card card) { + cards.add(card); + } + + public int calculateScore() { + return ScoreCalculator.findByCards(cards) + .calculateScore(cards); + } + + public List getCards() { + return Collections.unmodifiableList(cards); + } + + public boolean isBurst() { + return calculateScore() > BLACK_JACK_SCORE; + } + + public boolean isBlackJack() { + return calculateScore() == BLACK_JACK_SCORE; + } +} diff --git a/src/main/java/blackjack/domain/card/CardFactory.java b/src/main/java/blackjack/domain/card/CardFactory.java new file mode 100644 index 00000000..247894e5 --- /dev/null +++ b/src/main/java/blackjack/domain/card/CardFactory.java @@ -0,0 +1,35 @@ +package blackjack.domain.card; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CardFactory { + + public static CardFactory INSTANCE; + + private CardFactory() { + } + + public static CardFactory getInstance() { + if (INSTANCE == null) { + INSTANCE = new CardFactory(); + } + return INSTANCE; + } + + public List createCards() { + List cards = new ArrayList<>(); + for (Suit suit : Suit.values()) { + createBySuit(cards, suit); + } + Collections.shuffle(cards); + return cards; + } + + private void createBySuit(List cards, Suit suit) { + for (Number number : Number.values()) { + cards.add(new Card(suit, number)); + } + } +} diff --git a/src/main/java/blackjack/domain/card/Deck.java b/src/main/java/blackjack/domain/card/Deck.java new file mode 100644 index 00000000..5f591d8c --- /dev/null +++ b/src/main/java/blackjack/domain/card/Deck.java @@ -0,0 +1,22 @@ +package blackjack.domain.card; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class Deck { + + private final Queue deck; + + public Deck(List cards) { + this.deck = new LinkedList<>(cards); + } + + public Card spreadCard() { + return deck.poll(); + } + + public int remainCardSize() { + return deck.size(); + } +} diff --git a/src/main/java/blackjack/domain/card/Number.java b/src/main/java/blackjack/domain/card/Number.java new file mode 100644 index 00000000..8d1e2977 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Number.java @@ -0,0 +1,34 @@ +package blackjack.domain.card; + +public enum Number { + + ACE(1, "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 message; + + Number(int score, String message) { + this.score = score; + this.message = message; + } + + public int score() { + return score; + } + + public String message() { + return message; + } +} diff --git a/src/main/java/blackjack/domain/card/Suit.java b/src/main/java/blackjack/domain/card/Suit.java new file mode 100644 index 00000000..3a16e147 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Suit.java @@ -0,0 +1,19 @@ +package blackjack.domain.card; + +public enum Suit { + + SPADE("스페이드"), + DIAMOND("다이아몬드"), + HEART("하트"), + CLOVER("클로버"); + + private final String suit; + + Suit(String suit) { + this.suit = suit; + } + + public String suit() { + return this.suit; + } +} diff --git a/src/main/java/blackjack/domain/report/GameReport.java b/src/main/java/blackjack/domain/report/GameReport.java new file mode 100644 index 00000000..8637c637 --- /dev/null +++ b/src/main/java/blackjack/domain/report/GameReport.java @@ -0,0 +1,51 @@ +package blackjack.domain.report; + +import java.util.Objects; + +public class GameReport { + + private final String name; + private final GameResult result; + + public GameReport(String name, GameResult result) { + this.name = name; + this.result = result; + } + + public String name() { + return name; + } + + public String message() { + return result.message(); + } + + public boolean isWin() { + return result == GameResult.WIN; + } + + public boolean isDraw() { + return result == GameResult.DRAW; + } + + public boolean isLose() { + return result == GameResult.LOSE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GameReport report = (GameReport) o; + return Objects.equals(name, report.name) && result == report.result; + } + + @Override + public int hashCode() { + return Objects.hash(name, result); + } +} diff --git a/src/main/java/blackjack/domain/report/GameReports.java b/src/main/java/blackjack/domain/report/GameReports.java new file mode 100644 index 00000000..a39b4148 --- /dev/null +++ b/src/main/java/blackjack/domain/report/GameReports.java @@ -0,0 +1,35 @@ +package blackjack.domain.report; + +import java.util.Collections; +import java.util.List; + +public class GameReports { + + private final List reports; + + public GameReports(List reports) { + this.reports = reports; + } + + public int getPlayerWinCount() { + return (int) reports.stream() + .filter(GameReport::isWin) + .count(); + } + + public int getPlayerDrawCount() { + return (int) reports.stream() + .filter(GameReport::isDraw) + .count(); + } + + public int getPlayerLoseCount() { + return (int) reports.stream() + .filter(GameReport::isLose) + .count(); + } + + public List reports() { + return Collections.unmodifiableList(reports); + } +} diff --git a/src/main/java/blackjack/domain/report/GameResult.java b/src/main/java/blackjack/domain/report/GameResult.java new file mode 100644 index 00000000..0d876d5e --- /dev/null +++ b/src/main/java/blackjack/domain/report/GameResult.java @@ -0,0 +1,52 @@ +package blackjack.domain.report; + +import blackjack.domain.card.CardBundle; +import java.util.Arrays; + +public enum GameResult { + + WIN(1, "승"), + DRAW(0, "무"), + LOSE(-1, "패"); + + private final int result; + private final String message; + + GameResult(int result, String message) { + this.result = result; + this.message = message; + } + + public static GameResult comparing(CardBundle playerCardBundle, CardBundle dealerCardBundle) { + isComparable(playerCardBundle, dealerCardBundle); + if (playerCardBundle.isBurst()) { + return GameResult.LOSE; + } + if (dealerCardBundle.isBurst()) { + return GameResult.WIN; + } + int result = Integer.compare(playerCardBundle.calculateScore(), + dealerCardBundle.calculateScore()); + return findResult(result); + } + + public String message() { + return message; + } + + private static void isComparable(CardBundle dealerCardBundle, CardBundle playerCardBundle) { + if (dealerCardBundle == null) { + throw new IllegalArgumentException("[ERROR] 딜러의 카드가 비었습니다"); + } + if (playerCardBundle == null) { + throw new IllegalArgumentException("[ERROR] 플레이어의 카드가 비었습니다."); + } + } + + private static GameResult findResult(int result) { + return Arrays.stream(values()) + .filter(gameResult -> gameResult.result == result) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 올바르지 않은 값 입니다")); + } +} diff --git a/src/main/java/blackjack/domain/request/DrawRequest.java b/src/main/java/blackjack/domain/request/DrawRequest.java new file mode 100644 index 00000000..1e58e2a3 --- /dev/null +++ b/src/main/java/blackjack/domain/request/DrawRequest.java @@ -0,0 +1,32 @@ +package blackjack.domain.request; + +public class DrawRequest { + + private final boolean request; + + private DrawRequest(boolean request) { + this.request = request; + } + + public static DrawRequest valueOf(String command) { + validateCommand(command); + return new DrawRequest(findByCommand(command)); + } + + public boolean isDrawable() { + return request; + } + + private static boolean findByCommand(String command) { + return "y".equals(command); + } + + private static void validateCommand(String command) { + if (command == null || command.trim().length() == 0) { + throw new IllegalArgumentException("[ERROR] 아무 요청이 입력되지 않았습니다."); + } + if (!"y".equals(command) && !"n".equals(command)) { + throw new IllegalArgumentException(String.format("[ERROR] %s는 올바른 요청이 아닙니다", command)); + } + } +} diff --git a/src/main/java/blackjack/domain/request/UserNamesRequest.java b/src/main/java/blackjack/domain/request/UserNamesRequest.java new file mode 100644 index 00000000..c4800851 --- /dev/null +++ b/src/main/java/blackjack/domain/request/UserNamesRequest.java @@ -0,0 +1,45 @@ +package blackjack.domain.request; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class UserNamesRequest { + + private static final String USER_NAME_DELIMITER = ","; + + private final List userNames; + + private UserNamesRequest(List userNames) { + this.userNames = userNames; + } + + public static UserNamesRequest from(String userNames) { + validateUserNames(userNames); + List splitUserNames = Arrays.stream(userNames.split(USER_NAME_DELIMITER)) + .map(String::trim) + .collect(Collectors.toList()); + validateDuplicate(splitUserNames); + return new UserNamesRequest(splitUserNames); + } + + public List userNames() { + return Collections.unmodifiableList(userNames); + } + + private static void validateUserNames(String userNames) { + if (userNames == null || userNames.trim().isEmpty()) { + throw new IllegalArgumentException("[ERROR] 이름을 입력해 주세요"); + } + } + + private static void validateDuplicate(List splitUserNames) { + Set removeDuplicate = new HashSet<>(splitUserNames); + if (removeDuplicate.size() != splitUserNames.size()) { + throw new IllegalArgumentException("[ERROR] 플레이어 이름은 중복될 수 없습니다"); + } + } +} diff --git a/src/main/java/blackjack/domain/score/AceScoreStrategy.java b/src/main/java/blackjack/domain/score/AceScoreStrategy.java new file mode 100644 index 00000000..00908a75 --- /dev/null +++ b/src/main/java/blackjack/domain/score/AceScoreStrategy.java @@ -0,0 +1,41 @@ +package blackjack.domain.score; + +import blackjack.domain.card.Card; +import java.util.List; + +public class AceScoreStrategy implements ScoreStrategy { + + private static final int BLACK_JACK_SCORE = 21; + private static final int ACE_WEIGHT_SCORE = 10; + + private int getAceCount(List cards) { + return (int) cards.stream() + .filter(Card::isAce) + .count(); + } + + private int convertScore(Card card) { + if (card.isAce()) { + return card.value() + ACE_WEIGHT_SCORE; + } + return card.value(); + } + + @Override + public boolean isSupportable(List cards) { + return getAceCount(cards) > 0; + } + + @Override + public int calculateScore(List cards) { + int score = cards.stream() + .mapToInt(this::convertScore) + .sum(); + int aceCount = getAceCount(cards); + while (score > BLACK_JACK_SCORE && aceCount > 0) { + score -= ACE_WEIGHT_SCORE; + aceCount--; + } + return score; + } +} diff --git a/src/main/java/blackjack/domain/score/DefaultScoreStrategy.java b/src/main/java/blackjack/domain/score/DefaultScoreStrategy.java new file mode 100644 index 00000000..8a1d154f --- /dev/null +++ b/src/main/java/blackjack/domain/score/DefaultScoreStrategy.java @@ -0,0 +1,19 @@ +package blackjack.domain.score; + +import blackjack.domain.card.Card; +import java.util.List; + +public class DefaultScoreStrategy implements ScoreStrategy { + + @Override + public boolean isSupportable(List cards) { + return true; + } + + @Override + public int calculateScore(List cards) { + return cards.stream() + .mapToInt(Card::value) + .sum(); + } +} diff --git a/src/main/java/blackjack/domain/score/ScoreCalculator.java b/src/main/java/blackjack/domain/score/ScoreCalculator.java new file mode 100644 index 00000000..2afd189f --- /dev/null +++ b/src/main/java/blackjack/domain/score/ScoreCalculator.java @@ -0,0 +1,32 @@ +package blackjack.domain.score; + +import blackjack.domain.card.Card; +import java.util.Arrays; +import java.util.List; + +public enum ScoreCalculator { + + ACE(new AceScoreStrategy()), + DEFAULT(new DefaultScoreStrategy()); + + ScoreStrategy scoreStrategy; + + ScoreCalculator(ScoreStrategy scoreStrategy) { + this.scoreStrategy = scoreStrategy; + } + + public static ScoreCalculator findByCards(List cards) { + return Arrays.stream(values()) + .filter(scoreCalculator -> scoreCalculator.isSupportable(cards)) + .findFirst() + .orElse(DEFAULT); + } + + public int calculateScore(List cards) { + return this.scoreStrategy.calculateScore(cards); + } + + private boolean isSupportable(List cards) { + return this.scoreStrategy.isSupportable(cards); + } +} diff --git a/src/main/java/blackjack/domain/score/ScoreStrategy.java b/src/main/java/blackjack/domain/score/ScoreStrategy.java new file mode 100644 index 00000000..6214cbd6 --- /dev/null +++ b/src/main/java/blackjack/domain/score/ScoreStrategy.java @@ -0,0 +1,11 @@ +package blackjack.domain.score; + +import blackjack.domain.card.Card; +import java.util.List; + +public interface ScoreStrategy { + + boolean isSupportable(List cards); + + int calculateScore(List cards); +} diff --git a/src/main/java/blackjack/domain/user/Dealer.java b/src/main/java/blackjack/domain/user/Dealer.java new file mode 100644 index 00000000..bbc1bee5 --- /dev/null +++ b/src/main/java/blackjack/domain/user/Dealer.java @@ -0,0 +1,33 @@ +package blackjack.domain.user; + +import blackjack.domain.report.GameResult; +import blackjack.domain.report.GameReport; + +public class Dealer extends Player { + + private static final int DEALER_MUST_DRAW_SCORE = 16; + + public Dealer() { + super("딜러"); + } + + public GameReport createReport(Player player) { + GameResult gameResult = GameResult.comparing(player.cardBundle, this.cardBundle); + return new GameReport(player.name(), gameResult); + } + + @Override + public boolean isPlayer() { + return false; + } + + @Override + public boolean isDealer() { + return true; + } + + @Override + public boolean isDrawable() { + return score() <= DEALER_MUST_DRAW_SCORE; + } +} diff --git a/src/main/java/blackjack/domain/user/Player.java b/src/main/java/blackjack/domain/user/Player.java new file mode 100644 index 00000000..e5523b8e --- /dev/null +++ b/src/main/java/blackjack/domain/user/Player.java @@ -0,0 +1,55 @@ +package blackjack.domain.user; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardBundle; +import java.util.List; + +public class Player { + + protected final CardBundle cardBundle; + private final String name; + + public Player(String name) { + validateName(name); + this.name = name; + this.cardBundle = CardBundle.emptyBundle(); + } + + private void validateName(String name) { + if (name == null || name.trim().length() == 0) { + throw new IllegalArgumentException("[ERROR] 올바르지 않은 이름의 입력 값입니다."); + } + } + + public void drawCard(Card card) { + this.cardBundle.addCard(card); + } + + public String name() { + return name; + } + + public boolean isPlayer() { + return true; + } + + public boolean isDealer() { + return false; + } + + public int score() { + return cardBundle.calculateScore(); + } + + public boolean isDrawable() { + return !cardBundle.isBlackJack() && !cardBundle.isBurst(); + } + + public List getCardBundle() { + return cardBundle.getCards(); + } + + public boolean isBlackJack() { + return cardBundle.isBlackJack(); + } +} diff --git a/src/main/java/blackjack/domain/user/Players.java b/src/main/java/blackjack/domain/user/Players.java new file mode 100644 index 00000000..461b2af8 --- /dev/null +++ b/src/main/java/blackjack/domain/user/Players.java @@ -0,0 +1,47 @@ +package blackjack.domain.user; + +import blackjack.domain.card.Deck; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class Players { + + public static final int START_CARD_INIT_SIZE = 2; + + private final List players = new ArrayList<>(); + + public Players(Dealer dealer, List players) { + this.players.add(dealer); + this.players.addAll(players); + } + + public List findOnlyPlayers() { + return players.stream() + .filter(Player::isPlayer) + .collect(Collectors.toList()); + } + + public Dealer findDealer() { + return (Dealer) players.stream() + .filter(Player::isDealer) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 딜러가 존재하지 않습니다.")); + } + + public boolean hasBlackJack() { + return players.stream() + .anyMatch(Player::isBlackJack); + } + + public void drawStartCards(Deck deck) { + for (int i = 0; i < START_CARD_INIT_SIZE; i++) { + players.forEach(player -> player.drawCard(deck.spreadCard())); + } + } + + public List all() { + return Collections.unmodifiableList(players); + } +} diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java new file mode 100644 index 00000000..cc4e40d0 --- /dev/null +++ b/src/main/java/blackjack/view/InputView.java @@ -0,0 +1,22 @@ +package blackjack.view; + +import blackjack.domain.user.Player; +import java.util.Scanner; + +public class InputView { + + private static final Scanner scanner = new Scanner(System.in); + + private InputView() { + } + + public static String getPlayerNames() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + return scanner.nextLine(); + } + + public static String getDrawRequest(Player player) { + System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)", player.name()); + return scanner.nextLine(); + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java new file mode 100644 index 00000000..3ba30dfa --- /dev/null +++ b/src/main/java/blackjack/view/OutputView.java @@ -0,0 +1,82 @@ +package blackjack.view; + +import static blackjack.domain.user.Players.START_CARD_INIT_SIZE; + +import blackjack.domain.report.GameReports; +import blackjack.domain.card.Card; +import blackjack.domain.user.Player; +import blackjack.domain.user.Players; +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + + private OutputView() { + } + + public static void printAllPlayersCard(Players players) { + List candiates = players.findOnlyPlayers(); + Player dealer = players.findDealer(); + System.out.printf("\n딜러와 %s에게 %d장 나누었습니다.\n", collectPlayerNames(candiates), + START_CARD_INIT_SIZE); + System.out.printf("%s : %s\n", dealer.name(), collectDealerCard(dealer)); + candiates.forEach(OutputView::printEachCardInfo); + System.out.println(); + } + + public static void printEachCardInfo(Player player) { + System.out.printf("%s : %s\n", player.name(), collectPlayerCard(player)); + } + + public static void printDealerGetCard() { + System.out.println("\n딜러는 16이하라 한장의 카드를 더 받았습니다."); + } + + public static void printResultStatus(List players) { + System.out.println(); + players.forEach(OutputView::showEachResult); + } + + public static void printReports(GameReports reports) { + System.out.println("\n## 최종 승패"); + showDealerReports(reports); + reports.reports() + .stream() + .map(report -> String.format("%s: %s", report.name(), report.message())) + .forEach(System.out::println); + } + + private static void showDealerReports(GameReports reports) { + int dealerWinCount = reports.getPlayerLoseCount(); + int drawCount = reports.getPlayerDrawCount(); + int dealerLoseCount = reports.getPlayerWinCount(); + System.out.printf("딜러: %d승 %d무 %d패\n", dealerWinCount, drawCount, dealerLoseCount); + } + + private static String collectPlayerNames(List candiates) { + return candiates.stream() + .map(Player::name) + .collect(Collectors.joining(",")); + } + + private static String collectDealerCard(Player dealer) { + List cards = dealer.getCardBundle(); + return makeCardInfo(cards.get(0)); + } + + private static String makeCardInfo(Card card) { + return String.join("", card.message(), card.suit()); + } + + private static String collectPlayerCard(Player player) { + List cards = player.getCardBundle(); + return cards.stream() + .map(OutputView::makeCardInfo) + .collect(Collectors.joining(", ")); + } + + private static void showEachResult(Player player) { + System.out.printf("%s카드: %s - 결과 : %d\n", player.name(), collectPlayerCard(player), + player.score()); + } +} diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/rentcar/domain/Avante.java b/src/main/java/rentcar/domain/Avante.java new file mode 100644 index 00000000..117e3a8a --- /dev/null +++ b/src/main/java/rentcar/domain/Avante.java @@ -0,0 +1,36 @@ +package rentcar.domain; + +public class Avante extends Car { + + private static final String NAME = "Avante"; + private static final double DISTANCE_PER_LITER = 15; + private static final String VALIDATE_TRIP_DISTANCE_MESSAGE = "[ERROR] 여행거리는 0 이상입니다."; + + private double tripDistance; + + public Avante(double tripDistance) { + validateTripDistance(tripDistance); + this.tripDistance = tripDistance; + } + + private void validateTripDistance(double tripDistance) { + if (tripDistance < 0) { + throw new IllegalArgumentException(VALIDATE_TRIP_DISTANCE_MESSAGE); + } + } + + @Override + double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + @Override + double getTripDistance() { + return tripDistance; + } + + @Override + String getName() { + return NAME; + } +} diff --git a/src/main/java/rentcar/domain/Car.java b/src/main/java/rentcar/domain/Car.java new file mode 100644 index 00000000..5fd55819 --- /dev/null +++ b/src/main/java/rentcar/domain/Car.java @@ -0,0 +1,31 @@ +package rentcar.domain; + +public abstract class Car implements Reportable { + + /** + * 리터당 이동 거리. 즉, 연비 + */ + abstract double getDistancePerLiter(); + + /** + * 여행하려는 거리 + */ + abstract double getTripDistance(); + + /** + * 차종의 이름 + */ + abstract String getName(); + + /** + * 주입해야할 연료량을 구한다. + */ + double getChargeQuantity() { + return getTripDistance() / getDistancePerLiter(); + } + + @Override + public String generateReport() { + return getName() + " : " + (int) getChargeQuantity() + "리터"; + } +} diff --git a/src/main/java/rentcar/domain/K5.java b/src/main/java/rentcar/domain/K5.java new file mode 100644 index 00000000..b7fdfb34 --- /dev/null +++ b/src/main/java/rentcar/domain/K5.java @@ -0,0 +1,36 @@ +package rentcar.domain; + +public class K5 extends Car { + + private static final String NAME = "K5"; + private static final double DISTANCE_PER_LITER = 13; + private static final String VALIDATE_TRIP_DISTANCE_MESSAGE = "[ERROR] 여행거리는 0 이상입니다."; + + private double tripDistance; + + public K5(double tripDistance) { + validateTripDistance(tripDistance); + this.tripDistance = tripDistance; + } + + private void validateTripDistance(double tripDistance) { + if (tripDistance < 0) { + throw new IllegalArgumentException(VALIDATE_TRIP_DISTANCE_MESSAGE); + } + } + + @Override + double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + @Override + double getTripDistance() { + return tripDistance; + } + + @Override + String getName() { + return NAME; + } +} diff --git a/src/main/java/rentcar/domain/RentCompany.java b/src/main/java/rentcar/domain/RentCompany.java new file mode 100644 index 00000000..f2962d4b --- /dev/null +++ b/src/main/java/rentcar/domain/RentCompany.java @@ -0,0 +1,28 @@ +package rentcar.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class RentCompany { + + private final List rentCars; + + private RentCompany() { + this.rentCars = new ArrayList<>(); + } + + public static RentCompany create() { + return new RentCompany(); + } + + public String generateReport() { + return rentCars.stream() + .map(Car::generateReport) + .collect(Collectors.joining("\n")); + } + + public void addCar(Car car) { + rentCars.add(car); + } +} diff --git a/src/main/java/rentcar/domain/Reportable.java b/src/main/java/rentcar/domain/Reportable.java new file mode 100644 index 00000000..d9f4af2e --- /dev/null +++ b/src/main/java/rentcar/domain/Reportable.java @@ -0,0 +1,7 @@ +package rentcar.domain; + +public interface Reportable { + + String generateReport(); + +} diff --git a/src/main/java/rentcar/domain/Sonata.java b/src/main/java/rentcar/domain/Sonata.java new file mode 100644 index 00000000..066d6b90 --- /dev/null +++ b/src/main/java/rentcar/domain/Sonata.java @@ -0,0 +1,36 @@ +package rentcar.domain; + +public class Sonata extends Car { + + private static final String NAME = "Sonata"; + private static final double DISTANCE_PER_LITER = 10; + private static final String VALIDATE_TRIP_DISTANCE_MESSAGE = "[ERROR] 여행거리는 0 이상입니다."; + + private double tripDistance; + + public Sonata(double tripDistance) { + validateTripDistance(tripDistance); + this.tripDistance = tripDistance; + } + + private void validateTripDistance(double tripDistance) { + if (tripDistance < 0) { + throw new IllegalArgumentException(VALIDATE_TRIP_DISTANCE_MESSAGE); + } + } + + @Override + double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + @Override + double getTripDistance() { + return tripDistance; + } + + @Override + String getName() { + return NAME; + } +} diff --git a/src/test/java/blackjack/controller/BlackJackTest.java b/src/test/java/blackjack/controller/BlackJackTest.java new file mode 100644 index 00000000..e6e4a6e7 --- /dev/null +++ b/src/test/java/blackjack/controller/BlackJackTest.java @@ -0,0 +1,16 @@ +package blackjack.controller; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import blackjack.domain.request.UserNamesRequest; +import org.junit.jupiter.api.Test; + +class BlackJackTest { + + @Test + void 플레이어들의_이름을_입력받아_블랙잭_게임을_생성할_수_있다() { + String playerNames = "pobi, jason, toby"; + BlackJack blackJack = BlackJack.init(UserNamesRequest.from(playerNames)); + assertThat(blackJack).isInstanceOf(BlackJack.class); + } +} diff --git a/src/test/java/blackjack/domain/card/CardBundleTest.java b/src/test/java/blackjack/domain/card/CardBundleTest.java new file mode 100644 index 00000000..8781714e --- /dev/null +++ b/src/test/java/blackjack/domain/card/CardBundleTest.java @@ -0,0 +1,26 @@ +package blackjack.domain.card; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class CardBundleTest { + + @Test + void 카드_번들_내_카드_값의_합을_구할_수_있다() { + CardBundle cardBundle = CardBundle.emptyBundle(); + cardBundle.addCard(new Card(Suit.HEART, Number.TWO)); + cardBundle.addCard(new Card(Suit.CLOVER, Number.TWO)); + assertThat(cardBundle.calculateScore()).isEqualTo(4); + cardBundle.addCard(new Card(Suit.DIAMOND, Number.THREE)); + assertThat(cardBundle.calculateScore()).isEqualTo(7); + } + + @Test + void 카드_번들_내_ACE가_존재하고_21점_미만이라면_11로_계산한다() { + CardBundle cardBundle = CardBundle.emptyBundle(); + cardBundle.addCard(new Card(Suit.HEART, Number.ACE)); + cardBundle.addCard(new Card(Suit.CLOVER, Number.TWO)); + assertThat(cardBundle.calculateScore()).isEqualTo(13); + } +} diff --git a/src/test/java/blackjack/domain/card/CardFactoryTest.java b/src/test/java/blackjack/domain/card/CardFactoryTest.java new file mode 100644 index 00000000..1808f10e --- /dev/null +++ b/src/test/java/blackjack/domain/card/CardFactoryTest.java @@ -0,0 +1,20 @@ +package blackjack.domain.card; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CardFactoryTest { + + @Test + void 총_52장의_서로_다른_카드를_생성한다() { + CardFactory cardFactory = CardFactory.getInstance(); + List cards = cardFactory.createCards(); + assertThat(cards.size()).isEqualTo(52); + Set removeDuplicates = new HashSet<>(cards); + assertThat(removeDuplicates.size()).isEqualTo(52); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/card/DeckTest.java b/src/test/java/blackjack/domain/card/DeckTest.java new file mode 100644 index 00000000..22c5f2b3 --- /dev/null +++ b/src/test/java/blackjack/domain/card/DeckTest.java @@ -0,0 +1,23 @@ +package blackjack.domain.card; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class DeckTest { + + @Test + void 카드뭉치를_제대로_받는지_테스트() { + CardFactory cardFactory = CardFactory.getInstance(); + Deck deck = new Deck(cardFactory.createCards()); + assertThat(deck.remainCardSize()).isEqualTo(52); + } + + @Test + void 카드를_한장_뽑아준다() { + CardFactory cardFactory = CardFactory.getInstance(); + Deck deck = new Deck(cardFactory.createCards()); + deck.spreadCard(); + assertThat(deck.remainCardSize()).isEqualTo(51); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/report/GameReportsTest.java b/src/test/java/blackjack/domain/report/GameReportsTest.java new file mode 100644 index 00000000..1b390ea3 --- /dev/null +++ b/src/test/java/blackjack/domain/report/GameReportsTest.java @@ -0,0 +1,40 @@ +package blackjack.domain.report; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class GameReportsTest { + + static GameReports gameReports; + + @BeforeAll + static void setup() { + List reports = new ArrayList<>(); + reports.add(new GameReport("tester1", GameResult.WIN)); + reports.add(new GameReport("tester2", GameResult.WIN)); + reports.add(new GameReport("tester3", GameResult.WIN)); + reports.add(new GameReport("tester4", GameResult.DRAW)); + reports.add(new GameReport("tester5", GameResult.DRAW)); + reports.add(new GameReport("tester6", GameResult.LOSE)); + gameReports = new GameReports(reports); + } + + @Test + void 게임_결과_보고들의_승리_수를_구할_수_있다() { + assertThat(gameReports.getPlayerWinCount()).isEqualTo(3); + } + + @Test + void 게임_결과_보고들의_무승부_수를_구할_수_있다() { + assertThat(gameReports.getPlayerDrawCount()).isEqualTo(2); + } + + @Test + void 게임_결과_보고들의_패배_수를_구할_수_있다() { + assertThat(gameReports.getPlayerLoseCount()).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/report/GameResultTest.java b/src/test/java/blackjack/domain/report/GameResultTest.java new file mode 100644 index 00000000..4229e623 --- /dev/null +++ b/src/test/java/blackjack/domain/report/GameResultTest.java @@ -0,0 +1,45 @@ +package blackjack.domain.report; + + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.CardBundle; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import org.junit.jupiter.api.Test; + +class GameResultTest { + + @Test + void 값이_큰_카드번들과_작은_카드번들을_비교하면_승리를_반환한다() { + CardBundle largerCardBundle = CardBundle.emptyBundle(); + largerCardBundle.addCard(new Card(Suit.SPADE, Number.ACE)); + largerCardBundle.addCard(new Card(Suit.SPADE, Number.JACK)); + CardBundle smallerCardBundle = CardBundle.emptyBundle(); + smallerCardBundle.addCard(new Card(Suit.CLOVER, Number.TWO)); + GameResult actualResult = GameResult.comparing(largerCardBundle, smallerCardBundle); + assertThat(actualResult).isEqualTo(GameResult.WIN); + } + + @Test + void 값이_같은_카드번들을_비교하면_무승부를_반환한다() { + CardBundle cardBundle1 = CardBundle.emptyBundle(); + cardBundle1.addCard(new Card(Suit.CLOVER, Number.ACE)); + CardBundle cardBundle2 = CardBundle.emptyBundle(); + cardBundle2.addCard(new Card(Suit.DIAMOND, Number.ACE)); + GameResult actualResult = GameResult.comparing(cardBundle1, cardBundle2); + assertThat(actualResult).isEqualTo(GameResult.DRAW); + } + + @Test + void 값이_작은_카드번들과_큰_카드번들을_비교하면_패배를_반환한다() { + CardBundle largerCardBundle = CardBundle.emptyBundle(); + largerCardBundle.addCard(new Card(Suit.SPADE, Number.ACE)); + largerCardBundle.addCard(new Card(Suit.SPADE, Number.JACK)); + CardBundle smallerCardBundle = CardBundle.emptyBundle(); + smallerCardBundle.addCard(new Card(Suit.CLOVER, Number.TWO)); + GameResult actualResult = GameResult.comparing(smallerCardBundle, largerCardBundle); + assertThat(actualResult).isEqualTo(GameResult.LOSE); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/request/DrawRequestTest.java b/src/test/java/blackjack/domain/request/DrawRequestTest.java new file mode 100644 index 00000000..be308320 --- /dev/null +++ b/src/test/java/blackjack/domain/request/DrawRequestTest.java @@ -0,0 +1,45 @@ +package blackjack.domain.request; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class DrawRequestTest { + + @Test + void 입력받은_요청으로_올바르게_생성자를_생성할_수_있다() { + assertThat(DrawRequest.valueOf("y")).isInstanceOf(DrawRequest.class); + assertThat(DrawRequest.valueOf("n")).isInstanceOf(DrawRequest.class); + } + + @Test + void 올바르지_않은_요청일_경우_예외가_발생한다() { + assertAll( + () -> assertThatThrownBy(() -> DrawRequest.valueOf("no")).isInstanceOf( + IllegalArgumentException.class), + () -> assertThatThrownBy(() -> DrawRequest.valueOf("yes")).isInstanceOf( + IllegalArgumentException.class) + ); + } + + @Test + void 빈_요청일_경우_예외가_발생한다() { + assertAll( + () -> assertThatThrownBy(() -> DrawRequest.valueOf(" ")).isInstanceOf( + IllegalArgumentException.class), + () -> assertThatThrownBy(() -> DrawRequest.valueOf(null)).isInstanceOf( + IllegalArgumentException.class) + ); + } + + @ParameterizedTest + @CsvSource(value = {"y|true", "n|false"}, delimiter = '|') + void 입력받은_요청에_따라_더_뽑을_수_있는지_확인할_수_있다(String request, boolean result) { + DrawRequest drawRequest = DrawRequest.valueOf(request); + assertThat(drawRequest.isDrawable()).isEqualTo(result); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/request/UserNamesRequestTest.java b/src/test/java/blackjack/domain/request/UserNamesRequestTest.java new file mode 100644 index 00000000..7c5e5d57 --- /dev/null +++ b/src/test/java/blackjack/domain/request/UserNamesRequestTest.java @@ -0,0 +1,33 @@ +package blackjack.domain.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class UserNamesRequestTest { + + @Test + void 사용자의_쉼표로_구분한_입력으로_사용자_이름_목록을_만들_수_있다() { + UserNamesRequest userNamesRequest = UserNamesRequest.from("jason,pobi"); + assertThat(userNamesRequest.userNames()).isEqualTo(Arrays.asList("jason", "pobi")); + } + + @Test + void 입력된_이름은_중복될_때_예외가_발생된다() { + assertThatThrownBy(() -> UserNamesRequest.from("jason,pobi,jason")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 빈_값이_입력되면_예외가_발생한다() { + assertAll( + () -> assertThatThrownBy(() -> UserNamesRequest.from(" ")) + .isInstanceOf(IllegalArgumentException.class), + () -> assertThatThrownBy(() -> UserNamesRequest.from(null)) + .isInstanceOf(IllegalArgumentException.class) + ); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/score/ScoreCalculatorTest.java b/src/test/java/blackjack/domain/score/ScoreCalculatorTest.java new file mode 100644 index 00000000..289bfd8e --- /dev/null +++ b/src/test/java/blackjack/domain/score/ScoreCalculatorTest.java @@ -0,0 +1,47 @@ +package blackjack.domain.score; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ScoreCalculatorTest { + + static List aceContains; + static List defaultCards; + + @BeforeAll + static void setUp() { + aceContains = Arrays.asList(new Card(Suit.DIAMOND, Number.ACE), + new Card(Suit.CLOVER, Number.JACK)); + defaultCards = Arrays.asList(new Card(Suit.CLOVER, Number.EIGHT), + new Card(Suit.SPADE, Number.FOUR)); + } + + @Test + void ACE_포함시_ACE_전략을_가진_계산기를_반환한다() { + ScoreCalculator scoreCalculator = ScoreCalculator.findByCards(aceContains); + assertThat(scoreCalculator).isEqualTo(ScoreCalculator.ACE); + } + + @Test + void ACE가_없을_시_기본_전략을_가진_계산기를_반환한다() { + ScoreCalculator scoreCalculator = ScoreCalculator.findByCards(defaultCards); + assertThat(scoreCalculator).isEqualTo(ScoreCalculator.DEFAULT); + } + + @Test + void 각_카드에_맞는_전략에_따라_값을_계산할_수_있다() { + int aceScore = ScoreCalculator.findByCards(aceContains) + .calculateScore(aceContains); + int defaultScore = ScoreCalculator.findByCards(defaultCards) + .calculateScore(defaultCards); + assertThat(aceScore).isEqualTo(21); + assertThat(defaultScore).isEqualTo(12); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/score/ScoreStrategyTest.java b/src/test/java/blackjack/domain/score/ScoreStrategyTest.java new file mode 100644 index 00000000..bcc4ae1d --- /dev/null +++ b/src/test/java/blackjack/domain/score/ScoreStrategyTest.java @@ -0,0 +1,43 @@ +package blackjack.domain.score; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ScoreStrategyTest { + + static List aceContains; + static List defaultCards; + + @BeforeAll + static void setUp() { + aceContains = Arrays.asList(new Card(Suit.DIAMOND, Number.ACE), + new Card(Suit.CLOVER, Number.JACK)); + defaultCards = Arrays.asList(new Card(Suit.CLOVER, Number.EIGHT), + new Card(Suit.SPADE, Number.FOUR)); + } + + @Test + void ACE전략으로_ACE를_갖고_있다면_11로_점수를_계산한다() { + ScoreStrategy scoreStrategy = new AceScoreStrategy(); + assertThat(scoreStrategy.isSupportable(aceContains)).isTrue(); + assertThat(scoreStrategy.isSupportable(defaultCards)).isFalse(); + assertThat(scoreStrategy.calculateScore(aceContains)).isEqualTo(21); + assertThat(scoreStrategy.calculateScore(defaultCards)).isEqualTo(12); + } + + @Test + void 기본전략으로_모든_카드의_합을_구할_수_있다() { + ScoreStrategy scoreStrategy = new DefaultScoreStrategy(); + assertThat(scoreStrategy.isSupportable(aceContains)).isTrue(); + assertThat(scoreStrategy.isSupportable(defaultCards)).isTrue(); + assertThat(scoreStrategy.calculateScore(aceContains)).isEqualTo(11); + assertThat(scoreStrategy.calculateScore(defaultCards)).isEqualTo(12); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/user/DealerTest.java b/src/test/java/blackjack/domain/user/DealerTest.java new file mode 100644 index 00000000..287d81a0 --- /dev/null +++ b/src/test/java/blackjack/domain/user/DealerTest.java @@ -0,0 +1,65 @@ +package blackjack.domain.user; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import blackjack.domain.report.GameReport; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class DealerTest { + + static Dealer dealer; + + @BeforeAll + static void setUp() { + dealer = new Dealer(); + dealer.drawCard(new Card(Suit.CLOVER, Number.FIVE)); + dealer.drawCard(new Card(Suit.CLOVER, Number.SIX)); + } + + @Test + void 딜러인지_확인할_수_있다() { + assertThat(dealer.isDealer()).isTrue(); + assertThat(dealer.isPlayer()).isFalse(); + } + + @Test + void 딜러가_가진_패의_합을_확인_할_수_있다() { + assertThat(dealer.score()).isEqualTo(11); + } + + @Test + void 딜러가_가진_패의_합이_16이하라면_패를_뽑아야_한다() { + assertThat(dealer.isDrawable()).isTrue(); + } + + @Test + void 딜러는_자신보다_낮은_패를_가진_플레이어와_비교해_패배_리포트를_생성할_수_있다() { + Player player = new Player("loser"); + player.drawCard(new Card(Suit.DIAMOND, Number.FOUR)); + player.drawCard(new Card(Suit.DIAMOND, Number.TWO)); + GameReport gameReport = dealer.createReport(player); + assertThat(gameReport.isLose()).isTrue(); + } + + @Test + void 딜러는_자신보다_높은_패를_가진_플레이어와_비교해_승리_리포트를_생성할_수_있다() { + Player player = new Player("winner"); + player.drawCard(new Card(Suit.DIAMOND, Number.FOUR)); + player.drawCard(new Card(Suit.DIAMOND, Number.EIGHT)); + GameReport gameReport = dealer.createReport(player); + assertThat(gameReport.isWin()).isTrue(); + } + + @Test + void 딜러는_자신과_같은_패를_가진_플레이어와_비교해_무승부_리포트를_생성할_수_있다() { + Player player = new Player("drawer"); + player.drawCard(new Card(Suit.DIAMOND, Number.SIX)); + player.drawCard(new Card(Suit.DIAMOND, Number.FIVE)); + GameReport gameReport = dealer.createReport(player); + assertThat(gameReport.isDraw()).isTrue(); + } +} diff --git a/src/test/java/blackjack/domain/user/PlayerTest.java b/src/test/java/blackjack/domain/user/PlayerTest.java new file mode 100644 index 00000000..fa0aa04f --- /dev/null +++ b/src/test/java/blackjack/domain/user/PlayerTest.java @@ -0,0 +1,52 @@ +package blackjack.domain.user; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PlayerTest { + + @ParameterizedTest + @ValueSource(strings = {"jason", "pobi"}) + void 이름을_가진_플레이어를_생성한다(String name) { + Player player = new Player(name); + assertThat(player.name()).isEqualTo(name); + } + + @Test + void 이름은_공백이_들어올_수_없다() { + assertThatThrownBy(() -> new Player(" ")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @Test + void 해당_플레이어가_딜러인지_확인할_수_있다() { + Player player = new Player("name"); + assertThat(player.isDealer()).isFalse(); + assertThat(player.isPlayer()).isTrue(); + } + + @Test + void 플레이어_카드의_합을_구할_수_있다() { + Player player = new Player("name"); + player.drawCard(new Card(Suit.CLOVER, Number.FIVE)); + player.drawCard(new Card(Suit.CLOVER, Number.SEVEN)); + assertThat(player.score()).isEqualTo(12); + } + + @Test + void 플레이어_카드의_합이_21이라면_승리한다() { + Player player = new Player("name"); + player.drawCard(new Card(Suit.CLOVER, Number.FIVE)); + player.drawCard(new Card(Suit.CLOVER, Number.SEVEN)); + player.drawCard(new Card(Suit.CLOVER, Number.NINE)); + assertThat(player.isBlackJack()).isTrue(); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/user/PlayersTest.java b/src/test/java/blackjack/domain/user/PlayersTest.java new file mode 100644 index 00000000..0736b9c1 --- /dev/null +++ b/src/test/java/blackjack/domain/user/PlayersTest.java @@ -0,0 +1,70 @@ +package blackjack.domain.user; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Number; +import blackjack.domain.card.Suit; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class PlayersTest { + + @Test + void 딜러와_플레이어를_이용해_참가자를_구성할_수_있다() { + //given + Dealer dealer = new Dealer(); + List players = new ArrayList<>(); + players.add(new Player("Jason")); + players.add(new Player("Pobi")); + //when + Players createPlayers = new Players(dealer, players); + //then + assertThat(createPlayers).isInstanceOf(Players.class); + } + + @Test + void 참가자들_중_딜러만_반환할_수_있다() { + //given + Dealer dealer = new Dealer(); + List players = new ArrayList<>(); + players.add(new Player("Jason")); + players.add(new Player("Pobi")); + //when + Players createPlayers = new Players(dealer, players); + //then + assertThat(createPlayers.findDealer()).isEqualTo(dealer); + } + + @Test + void 참가자들_중_플레이어들만_반환할_수_있다() { + Dealer dealer = new Dealer(); + List players = new ArrayList<>(); + players.add(new Player("Jason")); + players.add(new Player("Pobi")); + //when + Players createPlayers = new Players(dealer, players); + //then + assertThat(createPlayers.findOnlyPlayers()).isEqualTo(players); + } + + @Test + void 참가자들_중_블랙잭이_있는지_확인할_수_있다() { + //given + Dealer dealer = new Dealer(); + dealer.drawCard(new Card(Suit.CLOVER, Number.ACE)); + dealer.drawCard(new Card(Suit.CLOVER, Number.KING)); + List players = new ArrayList<>(); + Player jason = new Player("jason"); + jason.drawCard(new Card(Suit.DIAMOND, Number.FIVE)); + jason.drawCard(new Card(Suit.DIAMOND, Number.SIX)); + Player pobi = new Player("pobi"); + pobi.drawCard(new Card(Suit.SPADE, Number.EIGHT)); + pobi.drawCard(new Card(Suit.SPADE, Number.NINE)); + //when + Players createPlayers = new Players(dealer, players); + //then + assertThat(createPlayers.hasBlackJack()).isTrue(); + } +} diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/java/rentcar/domain/RentCompanyTest.java b/src/test/java/rentcar/domain/RentCompanyTest.java new file mode 100644 index 00000000..3f7ec6a0 --- /dev/null +++ b/src/test/java/rentcar/domain/RentCompanyTest.java @@ -0,0 +1,29 @@ +package rentcar.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.jupiter.api.Test; + +public class RentCompanyTest { + + private static final String NEWLINE = System.getProperty("line.separator"); + + @Test + public void report() throws Exception { + RentCompany company = RentCompany.create(); // factory method를 사용해 생성 + company.addCar(new Sonata(150)); + company.addCar(new K5(260)); + company.addCar(new Sonata(120)); + company.addCar(new Avante(300)); + company.addCar(new K5(390)); + + String report = company.generateReport(); + assertThat(report).isEqualTo( + "Sonata : 15리터" + NEWLINE + + "K5 : 20리터" + NEWLINE + + "Sonata : 12리터" + NEWLINE + + "Avante : 20리터" + NEWLINE + + "K5 : 30리터" + ); + } +}