diff --git a/README.md b/README.md index 03ba7ed3..a58c1db9 100644 --- a/README.md +++ b/README.md @@ -1 +1,60 @@ -# java-blackjack \ No newline at end of file +# java-blackjack + +# 연료주입 + +### 기능요구사항 +- [x] Sonata 2대, Avante 1대, K5 2대로 총 5대의 차량이 있다. +- [x] 여행할 목적지의 대략적인 이동거리를 입력받는다. +- [x] 차량 별로 필요한 연료를 주입받는다. +- [x] 차량 별로 주입해야할 연료량을 확인할 수 있는 보고서를 생성한다. + +### 프로그래밍 요구 사항 +- 상속과 추상 메서드를 활용한다. +- 위 요구사항을 if/else 절을 쓰지 않고 구현해야 한다. + +# 블랙잭 + +### 기능요구사항 +- [x] 게임에 참여할 사람의 이름을 입력받을 수 있다. 이름은 쉼표를 기준으로 분리한다 + ex) pobi, jason +- [x] 카드의 숫자 계산은 카드 숫자를 기본으로 한다. + - [x] 예외로 Ace는 1 또는 11로 계산할 수 있다. + - [x] King, Queen, Jack은 각각 10으로 계산한다. +- [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다. + - [x] 숫자 합이 21을 넘지 않으면 카드를 계속 뽑을 수 있다. + - [x] 딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다. +- [x] 가지고 있는 카드 숫자 합이 21을 초과하면 게임에서 진다. +- [x] 가지고 있는 카드 숫자 합이 21이거나 21을 초과하지 않으면서 21에 가장 가까운 플레이어가 승리한다. +- [x] 게임을 완료한 후 각 플레이어별로 승패를 출력한다. + +### 프로그래밍 요구 사항 +- 자바 코드 컨벤션을 지키면서 프로그래밍한다. +- 기본적으로 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개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. +- 딜러와 플레이어에서 발생하는 중복 코드를 제거해야 한다. + +# multiple authors +git commit -m "commit message + + +Co-authored-by: seungyeonjeong +Co-authored-by: YuYangWoo diff --git a/src/main/java/blackjack/Application.java b/src/main/java/blackjack/Application.java new file mode 100644 index 00000000..a65c4515 --- /dev/null +++ b/src/main/java/blackjack/Application.java @@ -0,0 +1,12 @@ +package blackjack; + +import blackjack.controller.GameLauncher; + +public class Application { + + public static void main(String[] args) { + GameLauncher gameLauncher = new GameLauncher(); + gameLauncher.start(); + } + +} diff --git a/src/main/java/blackjack/controller/GameLauncher.java b/src/main/java/blackjack/controller/GameLauncher.java new file mode 100644 index 00000000..04f7e401 --- /dev/null +++ b/src/main/java/blackjack/controller/GameLauncher.java @@ -0,0 +1,50 @@ +package blackjack.controller; + +import blackjack.domain.gamer.Dealer; +import blackjack.domain.gamer.Gamer; +import blackjack.domain.matchInfo.MatchResultBoard; +import blackjack.domain.gamer.Player; +import blackjack.domain.gamer.Players; +import blackjack.view.InputView; +import blackjack.view.OutputView; + +public class GameLauncher { + + private static final int BLACK_JACK_SUM_LIMIT = 21; + + public void start() { + String[] playerNames = InputView.readPlayerName(); + OutputView.printGamePlayer(playerNames); + + OutputView.printCardsSetting(playerNames); + + Dealer dealer = new Dealer(); + OutputView.printDealerCardsSetting(dealer, true); + + Players players = new Players(playerNames); + OutputView.printPlayersStatus(players); + for (Player player : players.getPlayers()) { + getCardOrNot(player); + } + + if (dealer.getCardOrNot(dealer)) { + OutputView.printDealerAddCard(); + } + + OutputView.printDealerCardSum(dealer); + OutputView.printPlayerCardSum(players); + + OutputView.printFinalGameResult(); + MatchResultBoard matchResultBoard = players.playMatch(dealer); + OutputView.printDealerMatchResult(dealer, matchResultBoard.getDealerMatchResultInfo()); + OutputView.printPlayersMatchResult(matchResultBoard.getPlayersMatchResultInfo()); + + } + + private void getCardOrNot(Gamer player) { + while (InputView.readAddCardOrNot(player) && player.calcScore(player) < BLACK_JACK_SUM_LIMIT) { + player.addCard(player.getCards()); + OutputView.printPlayerStatus(player); + } + } +} 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..17c094ce --- /dev/null +++ b/src/main/java/blackjack/domain/Card/Suit.java @@ -0,0 +1,18 @@ +package blackjack.domain.card; + +public enum Suit { + CLUBS("클로버"), + DIAMONDS("다이아몬드"), + HEARTS("하트"), + SPADES("스페이드"); + + private final String value; + + Suit(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} 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..b45bfc53 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Card.java @@ -0,0 +1,39 @@ +package blackjack.domain.card; + +import java.util.Objects; + +public class Card { + private final Denomination denomination; + private final Suit suit; + + public Card(final Denomination denomination, final Suit suit) { + this.denomination = denomination; + this.suit = suit; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Card card = (Card) o; + return denomination == card.denomination && suit == card.suit; + } + + @Override + public int hashCode() { + return Objects.hash(denomination, suit); + } + + public Denomination getDenomination() { + return denomination; + } + + public Suit getSuit() { + return suit; + } + +} diff --git a/src/main/java/blackjack/domain/card/Cards.java b/src/main/java/blackjack/domain/card/Cards.java new file mode 100644 index 00000000..1a15be12 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Cards.java @@ -0,0 +1,22 @@ +package blackjack.domain.card; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Cards { + private static List cardList = new ArrayList<>(); + + static { + for(Denomination denomination : Denomination.values()) { + for(Suit suit : Suit.values()) { + cardList.add(new Card(denomination, suit)); + } + } + } + + public static List getCardList() { + return cardList; + } + +} diff --git a/src/main/java/blackjack/domain/card/Denomination.java b/src/main/java/blackjack/domain/card/Denomination.java new file mode 100644 index 00000000..2a43f4f7 --- /dev/null +++ b/src/main/java/blackjack/domain/card/Denomination.java @@ -0,0 +1,37 @@ +package blackjack.domain.card; + +public enum Denomination { + ACE("A", 1), + 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("J", 10), + QUEEN("Q", 10), + KING("K", 10); + + private final String name; + private final int value; + + Denomination(final String name, final int value) { + this.name = name; + this.value = value; + } + + public boolean isAce() { + return this == ACE; + } + + public String getName() { + return name; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Dealer.java b/src/main/java/blackjack/domain/gamer/Dealer.java new file mode 100644 index 00000000..176412b8 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Dealer.java @@ -0,0 +1,24 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Card; +import java.util.List; + +public class Dealer extends Gamer { + + private static final int DEALER_SUM_LIMIT = 16; + public Dealer() { + super("딜러"); + } + + public Dealer(List cards) { + super("딜러", cards); + } + + public boolean getCardOrNot(Dealer dealer) { + if (dealer.calcScore(dealer) < DEALER_SUM_LIMIT) { + dealer.addCard(dealer.getCards()); + return true; + } + return false; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Gamer.java b/src/main/java/blackjack/domain/gamer/Gamer.java new file mode 100644 index 00000000..91e95eab --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Gamer.java @@ -0,0 +1,96 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Cards; +import blackjack.domain.card.Denomination; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class Gamer { + private static final String ERROR_NOT_ENOUGH_CARD = "덱에 남아있는 카드가 없습니다."; + private static final int TEN = 10; + private static final int THRESHOLD = 21; + private static final int INIT_CARD_COUNT = 2; + + private List cardsBundle = Cards.getCardList(); + private List cards = new ArrayList<>(); + private String name; + + public Gamer(String name) { + this.name = name; + this.cards = initSetting(); + } + + public Gamer(String name, List cards) { + this.name = name; + for(Card card : cards) { + this.cards.add(card); + } + for(Card card : cards) { + cardsBundle.remove(card); + } + } + + private List initSetting() { + Collections.shuffle(cardsBundle); + this.cards = cardsBundle.stream() + .limit(INIT_CARD_COUNT) + .collect(Collectors.toList()); + removeCard(); + removeCard(); + return this.cards; + } + + public int calcScore(Gamer player) { + int score = player.cards.stream() + .map(Card::getDenomination) + .mapToInt(Denomination::getValue) + .sum(); + + long aceCount = player.cards.stream().filter(card -> card.getDenomination().isAce()) + .count(); + for (int i = 0; i < aceCount; i++) { + score = adjustScore(score); + } + return score; + } + + private int adjustScore(int score) { + if (score + TEN <= THRESHOLD) { + score += TEN; + } + return score; + } + + public List addCard(List cards) { + cards.add(cardsBundle.get(0)); + removeCard(); + return cards; + } + + private void removeCard() { + try { + cardsBundle.remove(0); + } catch (RuntimeException runtimeException) { + throw new RuntimeException(ERROR_NOT_ENOUGH_CARD); + } + } + + public boolean isBlackJack(Gamer player) { + return calcScore(player) == THRESHOLD; + } + + public boolean isBust(Gamer player) { + return calcScore(player) > THRESHOLD; + } + + public List getCards() { + return cards; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/blackjack/domain/gamer/Player.java b/src/main/java/blackjack/domain/gamer/Player.java new file mode 100644 index 00000000..242d40a0 --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Player.java @@ -0,0 +1,21 @@ +package blackjack.domain.gamer; + +import blackjack.domain.card.Card; +import blackjack.domain.matchInfo.MatchResult; +import java.util.List; + +public class Player extends Gamer { + + public Player(final String name) { + super(name); + } + + public Player(final String name, final List cards) { + super(name, cards); + } + + public MatchResult getMatchResult(final Gamer player, final Gamer dealer) { + return MatchResult.calcMatchResult(player, dealer); + } + +} diff --git a/src/main/java/blackjack/domain/gamer/Players.java b/src/main/java/blackjack/domain/gamer/Players.java new file mode 100644 index 00000000..ca16ec2f --- /dev/null +++ b/src/main/java/blackjack/domain/gamer/Players.java @@ -0,0 +1,36 @@ +package blackjack.domain.gamer; + +import blackjack.domain.matchInfo.MatchResultBoard; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class Players { + + private final List players = new ArrayList<>(); + private final String[] playerNames; + + public Players(String[] playerNames) { + this.playerNames = playerNames; + init(); + } + + private void init() { + for (String playerName : playerNames) { + players.add(new Player(playerName)); + } + } + + public MatchResultBoard playMatch(Gamer dealer) { + return new MatchResultBoard(players.stream() + .collect( + Collectors.toMap(player -> player, player -> player.getMatchResult(player, dealer), + (player1, player2) -> player1, LinkedHashMap::new))); + } + + public List getPlayers() { + return Collections.unmodifiableList(players); + } +} diff --git a/src/main/java/blackjack/domain/matchInfo/DealerMatchResultInfo.java b/src/main/java/blackjack/domain/matchInfo/DealerMatchResultInfo.java new file mode 100644 index 00000000..3f80b3c4 --- /dev/null +++ b/src/main/java/blackjack/domain/matchInfo/DealerMatchResultInfo.java @@ -0,0 +1,42 @@ +package blackjack.domain.matchInfo; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class DealerMatchResultInfo { + private final List matchScores; + + public DealerMatchResultInfo(final List matchScores) { + this.matchScores = matchScores; + } + + @Override + public String toString() { + return "DealerMatchScoreInfo{" + + "matchScores=" + matchScores + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DealerMatchResultInfo that = (DealerMatchResultInfo) o; + return Objects.equals(matchScores, that.matchScores); + } + + @Override + public int hashCode() { + return Objects.hash(matchScores); + } + + public List getMatchResult() { + return Collections.unmodifiableList(matchScores); + } + +} diff --git a/src/main/java/blackjack/domain/matchInfo/MatchResult.java b/src/main/java/blackjack/domain/matchInfo/MatchResult.java new file mode 100644 index 00000000..8e4ede00 --- /dev/null +++ b/src/main/java/blackjack/domain/matchInfo/MatchResult.java @@ -0,0 +1,51 @@ +package blackjack.domain.matchInfo; + +import blackjack.domain.gamer.Gamer; +import java.util.Arrays; + +public enum MatchResult { + WIN(1, "승"), + DRAW(0, "무"), + LOSE(-1, "패"); + + private static final String WRONG_MATCH_SCORE_KEY_ERR_MSG = "잘못된 매치 결과 키값입니다."; + private static final String UNREACHABLE_POINT_ERR_MSG = "예기치 않은 오류입니다."; + + private final int key; + private final String name; + + MatchResult(final int key, final String name) { + this.key = key; + this.name = name; + } + + public String getName() { + return name; + } + + private static MatchResult of(final int value) { + return Arrays.stream(MatchResult.values()) + .filter(result -> result.key == value) + .findFirst() + .orElseThrow(() -> new RuntimeException(WRONG_MATCH_SCORE_KEY_ERR_MSG)); + } + + public static MatchResult calcMatchResult(Gamer player, Gamer dealer) { + if (player.isBust(player)) return LOSE; + if (dealer.isBust(dealer)) return WIN; + + if (player.isBlackJack(player) && dealer.isBlackJack(dealer)) return DRAW; + if (player.isBlackJack(player)) return WIN; + if (dealer.isBlackJack(dealer)) return LOSE; + + if (player.calcScore(player) == dealer.calcScore(dealer)) return DRAW; + if (player.calcScore(player) > dealer.calcScore(dealer)) return WIN; + if (player.calcScore(player) < dealer.calcScore(dealer)) return LOSE; + + throw new RuntimeException(UNREACHABLE_POINT_ERR_MSG); + } + + public MatchResult oppositeMatchResult() { + return MatchResult.of(-key); + } +} diff --git a/src/main/java/blackjack/domain/matchInfo/MatchResultBoard.java b/src/main/java/blackjack/domain/matchInfo/MatchResultBoard.java new file mode 100644 index 00000000..2ac60442 --- /dev/null +++ b/src/main/java/blackjack/domain/matchInfo/MatchResultBoard.java @@ -0,0 +1,43 @@ +package blackjack.domain.matchInfo; + +import blackjack.domain.gamer.Player; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class MatchResultBoard { + + private final Map matchResultMap; + + public MatchResultBoard(final Map matchResultMap) { + this.matchResultMap = matchResultMap; + } + + public List getPlayersMatchResultInfo() { + return Collections.unmodifiableList(matchResultMap + .entrySet() + .stream() + .map(map -> + new PlayerMatchResultInfo( + map.getKey().getName(), + map.getValue().getName() + )) + .collect(Collectors.toList())); + } + + public DealerMatchResultInfo getDealerMatchResultInfo() { + return new DealerMatchResultInfo( + matchResultMap + .values() + .stream() + .map(MatchResult::oppositeMatchResult) + .collect(Collectors.groupingBy(o -> o, Collectors.counting())) + .entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .map(map -> map.getValue() + map.getKey().getName()) + .collect(Collectors.toList()) + ); + } +} diff --git a/src/main/java/blackjack/domain/matchInfo/PlayerMatchResultInfo.java b/src/main/java/blackjack/domain/matchInfo/PlayerMatchResultInfo.java new file mode 100644 index 00000000..320fc6ea --- /dev/null +++ b/src/main/java/blackjack/domain/matchInfo/PlayerMatchResultInfo.java @@ -0,0 +1,48 @@ +package blackjack.domain.matchInfo; + +import java.util.Objects; + +public class PlayerMatchResultInfo { + private final String name; + private final String matchScore; + + public PlayerMatchResultInfo(final String name, final String matchScore) { + this.name = name; + this.matchScore = matchScore; + } + + public String getName() { + return name; + } + + public String getMatchResult() { + return matchScore; + } + + @Override + public String toString() { + return "PlayerMatchScoreInfo{" + + "name='" + name + '\'' + + ", matchScore='" + matchScore + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlayerMatchResultInfo that = (PlayerMatchResultInfo) o; + return Objects.equals(name, that.name) && Objects.equals(matchScore, + that.matchScore); + } + + @Override + public int hashCode() { + return Objects.hash(name, matchScore); + } + +} diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java new file mode 100644 index 00000000..68c66327 --- /dev/null +++ b/src/main/java/blackjack/view/InputView.java @@ -0,0 +1,33 @@ +package blackjack.view; + +import blackjack.domain.gamer.Gamer; +import java.util.Scanner; + +public class InputView { + private InputView() {} + + public static final String[] readPlayerName() { + Scanner scanner = new Scanner(System.in); + OutputView.requestPlayersName(); + + try { + String playerNames = scanner.nextLine(); + return playerNames.split(","); + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + } + return readPlayerName(); + } + + public static final boolean readAddCardOrNot(Gamer player) { + Scanner scanner = new Scanner(System.in); + OutputView.requestAddCardOrNot(player); + + try { + if("y".equals(scanner.nextLine())) return true; + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + } + return false; + } +} diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java new file mode 100644 index 00000000..1ac51dec --- /dev/null +++ b/src/main/java/blackjack/view/OutputView.java @@ -0,0 +1,105 @@ +package blackjack.view; + +import blackjack.domain.card.Card; +import blackjack.domain.gamer.Gamer; +import blackjack.domain.matchInfo.DealerMatchResultInfo; +import blackjack.domain.matchInfo.PlayerMatchResultInfo; +import blackjack.domain.gamer.Player; +import blackjack.domain.gamer.Players; +import java.util.List; + +public class OutputView { + private static final String REQUEST_PLAYERS_NAME = "게임에 참여할 사람의 이름을 입력하세요"; + private static final String DELIMITER = ", "; + private static final String REQUEST_RECEIVE_CARD = "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"; + private static final String DEALER_ADD_CARD = "딜러는 16이하라 한장의 카드를 더 받았습니다."; + private static final String FINAL_GAME_RESULT = "## 최종 승패"; + private static final String MATCH_SCORE_INFO_FMT = "%s: %s\n"; + private static final String DEALER_MATCH_SCORE_DELIMITER = " "; + + private OutputView() {} + + public static void requestPlayersName() { + System.out.println(REQUEST_PLAYERS_NAME); + } + + public static void printGamePlayer(String[] players) { + System.out.println(String.join(DELIMITER, players)); + } + + public static void printCardsSetting(String[] players) { + System.out.println("딜러와 " + String.join(DELIMITER, players) + "에게 2장의 카드를 나누었습니다."); + } + + public static void printDealerCardsSetting(Gamer dealer, boolean flag) { + System.out.print(dealer.getName() + ": "); + printPlayerCards(dealer.getCards(), flag); + } + + public static void printPlayersStatus(Players players) { + for(Player player : players.getPlayers()) { + System.out.print(player.getName() + "카드: "); + printPlayerCards(player.getCards(), true); + } + } + + public static void printPlayerCards(List cards, boolean flag) { + for(Card card : cards) { + System.out.print(card.getDenomination().getName() + card.getSuit().getValue()); + } + if(flag) System.out.println(); + } + + public static void requestAddCardOrNot(Gamer player) { + System.out.println(player.getName() + REQUEST_RECEIVE_CARD); + } + + public static void printPlayerStatus(Gamer player) { + System.out.print(player.getName() + ": "); + printPlayerCards(player.getCards(), true); + } + + public static void printDealerAddCard() { + System.out.println(DEALER_ADD_CARD); + System.out.println(); + } + + public static void printDealerCardSum(Gamer dealer) { + printDealerCardsSetting(dealer, false); + System.out.println("- 결과:" + dealer.calcScore(dealer)); + + } + + public static void printPlayerCardSum(Players players) { + for (Player player : players.getPlayers()) { + System.out.print(player.getName() + ": "); + printPlayerCards(player.getCards(), false); + System.out.println("- 결과" + player.calcScore(player)); + } + } + + public static void printFinalGameResult() { + System.out.println(FINAL_GAME_RESULT); + } + + public static void printDealerMatchResult(Gamer dealer, DealerMatchResultInfo dealerMatchScoreInfo) { + System.out.format( + MATCH_SCORE_INFO_FMT, + dealer.getName(), + String.join( + DEALER_MATCH_SCORE_DELIMITER, + dealerMatchScoreInfo.getMatchResult() + ) + ); + } + + public static void printPlayersMatchResult(List playerMatchScoreInfos) { + for(PlayerMatchResultInfo playerMatchScoreInfo : playerMatchScoreInfos) { + printPlayerMatchResult(playerMatchScoreInfo); + } + } + + public static void printPlayerMatchResult(PlayerMatchResultInfo playerMatchScoreInfo) { + System.out.println(playerMatchScoreInfo.getName() + ":" + playerMatchScoreInfo.getMatchResult()); + } +} 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/fuel/Application.java b/src/main/java/fuel/Application.java new file mode 100644 index 00000000..2f1a5f93 --- /dev/null +++ b/src/main/java/fuel/Application.java @@ -0,0 +1,31 @@ +package fuel; + +import fuel.domain.Avante; +import fuel.domain.K5; +import fuel.domain.RentCompany; +import fuel.domain.Sonata; +import fuel.view.InputView; +import fuel.view.OutputView; + +public class Application { + public static void main(String[] args) { + RentCompany rentCompany = new RentCompany(); + + OutputView.printSonataDistance(); + rentCompany.addCar(new Sonata(InputView.readDistance())); + + OutputView.printK5Distance(); + rentCompany.addCar(new K5(InputView.readDistance())); + + OutputView.printSonataDistance(); + rentCompany.addCar(new Sonata(InputView.readDistance())); + + OutputView.printAvanteDistance(); + rentCompany.addCar(new Avante(InputView.readDistance())); + + OutputView.printK5Distance(); + rentCompany.addCar(new K5(InputView.readDistance())); + + OutputView.printReport(rentCompany.generateReport()); + } +} diff --git a/src/main/java/fuel/domain/Avante.java b/src/main/java/fuel/domain/Avante.java new file mode 100644 index 00000000..c9c958a3 --- /dev/null +++ b/src/main/java/fuel/domain/Avante.java @@ -0,0 +1,14 @@ +package fuel.domain; + +public class Avante extends Car{ + private static final int FUEL_EFFICIENCY = 15; + + public Avante(final double distance) { + super(distance, "Avante"); + } + + @Override + double getDistancePerLiter() { + return FUEL_EFFICIENCY; + } +} diff --git a/src/main/java/fuel/domain/Car.java b/src/main/java/fuel/domain/Car.java new file mode 100644 index 00000000..efd4e960 --- /dev/null +++ b/src/main/java/fuel/domain/Car.java @@ -0,0 +1,26 @@ +package fuel.domain; + +public abstract class Car { + + private final double distance; + private final String carName; + + public Car(final double distance, final String carName) { + this.distance = distance; + this.carName = carName; + } + + abstract double getDistancePerLiter(); + + protected double getTripDistance() { + return distance; + } + + protected String getName() { + return carName; + } + + protected double getChargeQuantity() { + return getTripDistance() / getDistancePerLiter(); + } +} diff --git a/src/main/java/fuel/domain/K5.java b/src/main/java/fuel/domain/K5.java new file mode 100644 index 00000000..c8ff5e27 --- /dev/null +++ b/src/main/java/fuel/domain/K5.java @@ -0,0 +1,14 @@ +package fuel.domain; + +public class K5 extends Car { + private static final int FUEL_EFFICIENCY = 13; + + public K5(final double distance) { + super(distance, "K5"); + } + + @Override + double getDistancePerLiter() { + return FUEL_EFFICIENCY; + } +} diff --git a/src/main/java/fuel/domain/RentCompany.java b/src/main/java/fuel/domain/RentCompany.java new file mode 100644 index 00000000..b4cb461f --- /dev/null +++ b/src/main/java/fuel/domain/RentCompany.java @@ -0,0 +1,27 @@ +package fuel.domain; + +import java.util.ArrayList; +import java.util.List; + +public class RentCompany { + private static final String NEWLINE = System.getProperty("line.separator"); + + private final List carLists = new ArrayList<>(); + + public static RentCompany create() { + return new RentCompany(); + } + + public void addCar(Car car) { + carLists.add(car); + } + + public String generateReport(){ + StringBuilder stringBuilder = new StringBuilder(); + for (Car car : carLists) { + stringBuilder.append(car.getName()).append(" : ").append(car.getChargeQuantity()).append("리터").append(NEWLINE); + } + return stringBuilder.toString(); + } + +} diff --git a/src/main/java/fuel/domain/Sonata.java b/src/main/java/fuel/domain/Sonata.java new file mode 100644 index 00000000..79daad14 --- /dev/null +++ b/src/main/java/fuel/domain/Sonata.java @@ -0,0 +1,14 @@ +package fuel.domain; + +public class Sonata extends Car { + private static final int FUEL_EFFICIENCY = 10; + + public Sonata(final double distance) { + super(distance, "Sonata"); + } + + @Override + double getDistancePerLiter() { + return FUEL_EFFICIENCY; + } +} diff --git a/src/main/java/fuel/view/InputView.java b/src/main/java/fuel/view/InputView.java new file mode 100644 index 00000000..c41c13b5 --- /dev/null +++ b/src/main/java/fuel/view/InputView.java @@ -0,0 +1,16 @@ +package fuel.view; + +import java.util.Scanner; + +public class InputView { + private static final Scanner scanner = new Scanner(System.in); + + private InputView() { + + } + + public static Double readDistance() { + Double carDistance = scanner.nextDouble(); + return carDistance; + } +} diff --git a/src/main/java/fuel/view/OutputView.java b/src/main/java/fuel/view/OutputView.java new file mode 100644 index 00000000..c17b5d8b --- /dev/null +++ b/src/main/java/fuel/view/OutputView.java @@ -0,0 +1,24 @@ +package fuel.view; + +public class OutputView { + + private OutputView() { + + } + + public static void printReport(String report) { + System.out.println(report); + } + + public static void printSonataDistance() { + System.out.println("소나타의 대략적인 이동거리를 입력해주세요."); + } + + public static void printAvanteDistance() { + System.out.println("아반테의 대략젹인 이동거리를 입력해주세요."); + } + + public static void printK5Distance() { + System.out.println("K5의 대략적인 이동거리를 입력해주세요."); + } +} diff --git a/src/test/java/blackjack/domain/CardTest.java b/src/test/java/blackjack/domain/CardTest.java new file mode 100644 index 00000000..92da3b9a --- /dev/null +++ b/src/test/java/blackjack/domain/CardTest.java @@ -0,0 +1,28 @@ +package blackjack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import org.junit.jupiter.api.Test; + +class CardTest { + + @Test + void 카드를_생성한다() { + Card card1 = new Card(Denomination.ACE, Suit.CLUBS); + assertThat(new StringBuilder().append(card1.getDenomination().getValue()).append(card1.getSuit()).toString()).isEqualTo("1CLUBS"); + + Card card2 = new Card(Denomination.KING, Suit.DIAMONDS); + assertThat(new StringBuilder().append(card2.getDenomination().getValue()).append(card2.getSuit()).toString()).isEqualTo("10DIAMONDS"); + + Card card3 = new Card(Denomination.JACK, Suit.HEARTS); + assertThat(card3.getDenomination().getValue()).isEqualTo(10); + assertThat(card3.getSuit().getValue()).isEqualTo("하트"); + + Card card4 = new Card(Denomination.TWO, Suit.HEARTS); + assertThat(card4.getDenomination().getValue()).isEqualTo(2); + assertThat(card4.getSuit().getValue()).isEqualTo("하트"); + } +} diff --git a/src/test/java/blackjack/domain/CardsTest.java b/src/test/java/blackjack/domain/CardsTest.java new file mode 100644 index 00000000..a04482d6 --- /dev/null +++ b/src/test/java/blackjack/domain/CardsTest.java @@ -0,0 +1,24 @@ +package blackjack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +class CardsTest { + + @Test + void 모든_카드는_52장이다() { + List cardList = new ArrayList<>(); + for(Denomination denomination : Denomination.values()) { + for(Suit suit : Suit.values()) { + cardList.add(new Card(denomination, suit)); + } + } + assertThat(cardList.size()).isEqualTo(52); + } +} diff --git a/src/test/java/blackjack/domain/DenominationTest.java b/src/test/java/blackjack/domain/DenominationTest.java new file mode 100644 index 00000000..9d47b856 --- /dev/null +++ b/src/test/java/blackjack/domain/DenominationTest.java @@ -0,0 +1,29 @@ +package blackjack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Denomination; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DenominationTest { + + @DisplayName(value = "KING의 계산값은 10으로 정의한다") + @Test + void 킹의_계산값은_10이다() { + assertThat(Denomination.KING.getValue()).isEqualTo(10); + } + + @DisplayName(value = "퀸의 계산값은 10으로 정의한다") + @Test + void 퀸의_계산값은_10이다() { + assertThat(Denomination.QUEEN.getValue()).isEqualTo(10); + } + + @DisplayName(value = "JACK의 계산값은 10으로 정의한다") + @Test + void 잭의_계산값은_10이다() { + assertThat(Denomination.JACK.getValue()).isEqualTo(10); + } + +} diff --git a/src/test/java/blackjack/domain/PlayerTest.java b/src/test/java/blackjack/domain/PlayerTest.java new file mode 100644 index 00000000..e67ba471 --- /dev/null +++ b/src/test/java/blackjack/domain/PlayerTest.java @@ -0,0 +1,27 @@ +package blackjack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import blackjack.domain.gamer.Player; +import org.junit.jupiter.api.Test; + +class PlayerTest { + + @Test + void 초기에_카드는_섞여서_2개가_주어진다() { + Player player = new Player("yangwoo"); + assertThat(player.getCards().size()).isEqualTo(2); + Player player1 = new Player("seungyun"); + assertThat(player1.getCards().size()).isEqualTo(2); + } + + @Test + void ACE는_1이나_11로_계산될_수_있다() { + Player player = new Player("yang"); + player.getCards().add(new Card(Denomination.ACE, Suit.DIAMONDS)); + player.calcScore(player); + } +} diff --git a/src/test/java/blackjack/domain/gamer/DealerTest.java b/src/test/java/blackjack/domain/gamer/DealerTest.java new file mode 100644 index 00000000..1ff6bdd4 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/DealerTest.java @@ -0,0 +1,32 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class DealerTest { + + @Test + void 초기에_카드는_섞여서_2개가_주어진다() { + Dealer dealer = new Dealer(); + assertThat(dealer.getCards().size()).isEqualTo(2); + } + + @Test + void 두_카드의_합이_16_이하일_경우_카드를_추가로_한장_받는다() { + Dealer dealer = new Dealer(Arrays.asList(new Card(Denomination.TWO, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + assertThat(dealer.getCardOrNot(dealer)).isTrue(); + } + + @Test + void 두_카드의_합이_16_초과일_경우_카드를_추가로_받지_않는다() { + Dealer dealer = new Dealer(Arrays.asList(new Card(Denomination.NINE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + assertThat(dealer.getCardOrNot(dealer)).isFalse(); + } +} diff --git a/src/test/java/blackjack/domain/gamer/GamerTest.java b/src/test/java/blackjack/domain/gamer/GamerTest.java new file mode 100644 index 00000000..7303bb18 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/GamerTest.java @@ -0,0 +1,59 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GamerTest { + + @Test + void 모든_게이머는_처음에_2장의_카드를_받는다() { + Gamer player = new Player("yang"); + Gamer dealer = new Dealer(); + assertThat(player.getCards().size()).isEqualTo(2); + assertThat(dealer.getCards().size()).isEqualTo(2); + } + + @Test + void 플레이어의_카드_총합을_계산한다() { + Gamer player = new Player("yang", Arrays.asList(new Card(Denomination.FOUR, Suit.DIAMONDS), + new Card(Denomination.NINE, Suit.DIAMONDS))); + assertThat(player.calcScore(player)).isEqualTo(13); + } + + @Test + void ACE는_1이나_11로_계산될_수_있다() { + Gamer player = new Player("yang", Arrays.asList(new Card(Denomination.FOUR, Suit.DIAMONDS), + new Card(Denomination.ACE, Suit.DIAMONDS))); + assertThat(player.calcScore(player)).isEqualTo(15); + } + + @Test + void 플레이어는_카드를_한_장더_받을_수_있다() { + Gamer player = new Player("yang"); + assertThat(player.addCard(player.getCards()).size()).isEqualTo(3); + } + + @Test + void 카드의_총합이_21이면_블랙잭이다() { + Gamer player = new Player("yang", Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + assertThat(player.isBlackJack(player)).isTrue(); + } + + @Test + void 카드의_총합이_21을_넘으면_버스트이다() { + Gamer player = new Player("yang", Arrays.asList(new Card(Denomination.FIVE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS), new Card(Denomination.TEN, Suit.CLUBS))); + assertThat(player.isBust(player)).isTrue(); + } + +} diff --git a/src/test/java/blackjack/domain/gamer/PlayerTest.java b/src/test/java/blackjack/domain/gamer/PlayerTest.java new file mode 100644 index 00000000..4f20b1f1 --- /dev/null +++ b/src/test/java/blackjack/domain/gamer/PlayerTest.java @@ -0,0 +1,43 @@ +package blackjack.domain.gamer; + +import static org.assertj.core.api.Assertions.assertThat; + +import blackjack.domain.card.Card; +import blackjack.domain.card.Denomination; +import blackjack.domain.card.Suit; +import blackjack.domain.matchInfo.MatchResult; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class PlayerTest { + + @Test + void 플레이어가_딜러랑_카드합이_같으면_무승부다() { + Player player = new Player("yang", Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + Dealer dealer = new Dealer(Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + MatchResult matchResult = player.getMatchResult(player, dealer); + assertThat(matchResult.getName()).isEqualTo("무"); + } + + @Test + void 플레이어가_딜러보다_카드합이_크면_승리한다() { + Player player = new Player("yang", Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.TEN, Suit.DIAMONDS))); + Dealer dealer = new Dealer(Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.FIVE, Suit.DIAMONDS))); + MatchResult matchResult = player.getMatchResult(player, dealer); + assertThat(matchResult.getName()).isEqualTo("승"); + } + + @Test + void 플레이어가_딜러보다_카드합이_작으면_패배한다() { + Player player = new Player("yang", Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.TWO, Suit.DIAMONDS))); + Dealer dealer = new Dealer(Arrays.asList(new Card(Denomination.ACE, Suit.DIAMONDS), + new Card(Denomination.FIVE, Suit.DIAMONDS))); + MatchResult matchResult = player.getMatchResult(player, dealer); + assertThat(matchResult.getName()).isEqualTo("패"); + } +} 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/fuel/domain/RentCompanyTest.java b/src/test/java/fuel/domain/RentCompanyTest.java new file mode 100644 index 00000000..08e37003 --- /dev/null +++ b/src/test/java/fuel/domain/RentCompanyTest.java @@ -0,0 +1,27 @@ +package fuel.domain; + +import static org.assertj.core.api.Assertions.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.0리터" + NEWLINE + + "K5 : 20.0리터" + NEWLINE + + "Sonata : 12.0리터" + NEWLINE + + "Avante : 20.0리터" + NEWLINE + + "K5 : 30.0리터" + NEWLINE + ); + } +} \ No newline at end of file