diff --git a/README.md b/README.md index 03ba7ed3..5da5317e 100644 --- a/README.md +++ b/README.md @@ -1 +1,149 @@ -# java-blackjack \ No newline at end of file +# 연료 주입 + +## TDD 기능 구현 사항 + +- [x] Sonata + - [x] `Sonata` String Type 이름을 가져야한다. + - [x] `10km/리터`의 연비 가져야한다. + - [x] 거리 + - [x] 거리를 가져야한다. + - [x] 거리는 `0` 이상 정수이어야 한다. + - [x] 주입해야할 연료량을 구할 수 있다. +- [x] Avante + - [x] `Avante` String Type 이름을 가져야한다. + - [x] `15km/리터`의 연비 가져야한다. + - [x] 거리 가져야한다. + - [x] 거리는 `0` 이상 정수이어야한다. - + - [x] 주입해야할 연료량을 구할 수 있다. +- [x] K5 + - [x] `K5` String Type 이름을 가져야한다. + - [x] `13km/리터`의 연비 가져야한다. + - [x] 거리 가져야한다. + - [x] 거리는 `0` 이상 정수이어야한다. + - [x] 주입해야할 연료량을 구할 수 있다. +- [x] RentCompany + - [x] `List`을 가져야한다. + - [x] `List`에 대한 getter를 가져야한다. + - [x] `create()`, 팩토리 메서드를 구현한다. + - [x] `addCar()`, 차를 추가할 수 있다. + - [x] `List`에 Sonata를 추가할 수 있다. + - [x] `List`에 Avante를 추가할 수 있다. + - [x] `List`에 K5를 추가할 수 있다. + - [x] `generateReport()`는 전체 결과를 출력한다. + +## 기능 구현 사항 + +- 보유 차량 + - Sonata + - 대수: 2대 + - 연비: 10km/리터 + - Avante + - 대수: 1대 + - 연비: 15km/리터 + - K5 + - 대수: 2대 + - 연비: 13km/리터 +- 고객이 인터넷으로부터 예약할 때 여행할 목적지의 대략적인 이동거리를 입력 받을 수 있다. +- 이동거리를 활용해 차량 별로 필요한 연료를 주입할 수 있다. +- 차량 별로 주입해야 할 연료량을 확인할 수 있는 보고서를 생성할 수 있다. + +## 프로그래밍 요구 사항 + +- [x] 상속과 추상 메서드를 활용한다. +- [x] 위 요구사항을 if/else 절을 쓰지 않고 구현해야 한다. +- [x] 인터페이스를 적용해 구현한다. + +--- + +# java-blackjack + +## TDD 기능 구현 사항 + +- [x] User + - [x] Deck을 가지고 있다. + - [x] UserName을 가지고 있다. + - [x] Deck에 카드를 추가할 수 있다. + - [x] 해당 카드의 점수인 score를 반환할 수 있다. +- [x] Dealer + - [x] Deck을 가지고 있다. + - [x] UserName을 가지고 있다. - name은 `dealer`라는 기본 이름을 가진다. + - [x] 현재 score가 16이하 인지를 판단하여 반환할 수 있다. + - [x] 1장의 카드를 추가로 받을 수 있다. +- [x] Player + - [x] Deck을 가지고 있다. + - [x] UserName을 가지고 있다. + - [x] 현재 score가 21을 넘지 않는지를 판단하여 반환할 수 있다. +- [x] Deck - 딜러 또는 플레이어가 가진 Card의 집합 + - [x] List를 가지고 있다. + - [x] 현재 List의 총 score를 계산할 수 있다. + - [x] Deck의 현재 score가 21을 넘는지에 대한 boolean 계산을 할 수 있다. + - [x] 현재 가진 Card 중에서 Ace가 있는 경우, 해당 Card에 대한 Score를 1 또는 11로 계산할 수 있다. + - [x] 21을 초과하지 않으면서, 21에 가깝게 계산할 수 있다. +- [x] Card - Game에서 사용할 카드의 객체 + - [x] CardType type을 가지고 있다. (e.g 다이아몬드, 클로버, 스페이드, 하트 ...) + - [x] CardNumber _String을_ 가지고 있다. (e.g 2, 3, A, K, Q, J ...) + - [x] 카드 숫자와 카드 타입을 입력할때, 주어진 숫자와 타입으로 카드가 생성된다. +- [x] CardType - Card의 타입 + - [x] CardType은 `"다이아몬드", "하트", "클로버", "스페이드"` 이 범위안에 반드시 있어야한다. +- [x] CardNumber - Card의 숫자 + - [x] CardNumber는 `"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"` 이 범위안에 반드시 있어야한다. +- [x] GameCard - 게임에서 사용될 모든 Card의 집합 + - [x] 모든 Card는 중복이 없어야한다. + - [x] 총 52 장이 있어야한다. + - [x] 모든 Card를 셔플할 수 있다. +- [x] GameUser - BlackJack을 수행하는 User의 집합 + - [x] List를 가지고 있다. + - [x] User를 추가할 수 있다. + - [x] List를 반환할 수 있다. +- [x] BlackJack - 게임 로직 수행 + - [x] GameUser를 가지고 있다. + - [x] GameCard를 가지고 있다. + - [x] 게임 진행시 최초로 GameCard를 셔플할 수 있다. + - [x] User별로 초기 카드를 나눠준다. + - [x] GameCard에서 Card를 두 장 뽑기 + - [x] User에게 Card 전달하기 + - [x] Dealer는 총 score가 16이하일 경우, 1장의 카드를 추가로 받는다. + - [x] User별로 턴을 진행할 수 있게 한다. + - [x] GameCard에서 Card를 한 장 뽑기 + - [x] User에게 Card 전달하기 + - [x] Player는 총 score가 21이하일 경우, 1장의 카드를 추가로 받을 수 있다. +- [x] UserStats - User별 승/패에 대한 정보 + - [x] GameUser를 인자로 받아 User별, 승/패 정보를 계산한다. + - [x] User별 Deck의 score를 출력하기 위한 String을 반환할 수 있다. convertTotalScore() + - [x] User별 최종 승/패를 출력하기 위한 String을 반환할 수 있다. convertTotalResult() + - [x] User별 Deck의 score가 21을 초과할 경우, 승/패를 계산할 수 있다. + - [x] Dealer의 score가 21을 초과할 경우, Player가 승리한다. + - [x] Dealer의 score가 21을 초과하지 않고, Player의 score가 21을 초과하는 경우, Dealer가 승리한다. +- [x] Game - 전체적인 게임을 진행할 Controller + - [x] 이름의 배열을 BlackJack에 전달한다. + - [x] 싱글턴 패턴 적용 +- [x] UserName - 게임 참여자의 이름 +- [x] InputView + - [x] 게임에 참여할 이름을 입력받는다. +- [x] OutputView + +## 최초 PR 마감 기한 + +2월 17일 목요일까지 + +### test + +```bash +./gradlew clean check +``` + +### git pull pair + +```bash +git pull pair step1 +``` + +### git multiple author + +```bash +git commit -m "commit message + + +Co-authored-by: hochan222 +Co-authored-by: chanuuuuu +``` diff --git a/src/main/java/blackJack/Application.java b/src/main/java/blackJack/Application.java new file mode 100644 index 00000000..c42aea68 --- /dev/null +++ b/src/main/java/blackJack/Application.java @@ -0,0 +1,11 @@ +package blackJack; + +import blackJack.controller.Game; + +public class Application { + + public static void main(String[] args) { + Game game = Game.getInstance(); + game.run(); + } +} diff --git a/src/main/java/blackJack/controller/Game.java b/src/main/java/blackJack/controller/Game.java new file mode 100644 index 00000000..6e176b81 --- /dev/null +++ b/src/main/java/blackJack/controller/Game.java @@ -0,0 +1,80 @@ +package blackJack.controller; + +import blackJack.domain.BlackJack; +import blackJack.domain.Player; +import blackJack.domain.UserStats; +import blackJack.util.Util; +import blackJack.view.InputView; +import blackJack.view.OutputView; +import java.util.List; + +public class Game { + + private static Game game = null; + private final BlackJack blackJack; + + private Game(List playerNames) { + blackJack = BlackJack.from(playerNames); + } + + public static Game getInstance() { + if (game == null) { + game = new Game(getPlayerName()); + } + return game; + } + + public void run() { + init(); + goPhase(); + summarize(); + } + + private void init() { + blackJack.initCardDraw(); + OutputView.printInitCardDrawFormat(blackJack.getGameUser().convertPlayersName()); + OutputView.printUserStatus(blackJack.getGameUser()); + } + + private void goPhase() { + playerPhase(); + dealerPhase(); + } + + private void playerPhase() { + for (Player player : blackJack.getGamePlayers()) { + useTurn(player); + } + } + + private void useTurn(Player player) { + while (player.isCardDraw()) { + OutputView.printRequestAdditionalCardDrawFormat(player); + if (InputView.readYN()) { + player.appendToDeck(blackJack.drawGameCard()); + OutputView.printPlayerStatus(player); + continue; + } + OutputView.printPlayerStatus(player); + break; + } + } + + private void dealerPhase() { + if (blackJack.getGameDealer().isCardDraw()) { + blackJack.getGameDealer().additionalCardDraw(blackJack.drawGameCard()); + OutputView.printDealerAdditionalCardDraw(); + } + } + + private void summarize() { + UserStats userStats = UserStats.of(blackJack.getGameUser()); + OutputView.printTotalScore(userStats.convertTotalScore()); + OutputView.printTotalResult(userStats.convertTotalResult()); + } + + private static List getPlayerName() { + OutputView.printRequestPlayerNames(); + return Util.stringToStringList(InputView.readPlayerName()); + } +} diff --git a/src/main/java/blackJack/domain/BlackJack.java b/src/main/java/blackJack/domain/BlackJack.java new file mode 100644 index 00000000..dd5a6151 --- /dev/null +++ b/src/main/java/blackJack/domain/BlackJack.java @@ -0,0 +1,59 @@ +package blackJack.domain; + +import java.util.List; + +public class BlackJack { + + private static final int INITIAL_DRAW_CARD_COUNT = 2; + + private final GameUser gameUser; + private final GameCard gameCard; + + private BlackJack(List userNames) { + this.gameUser = GameUser.from(userNames); + this.gameCard = GameCard.create(); + cardShuffle(); + } + + public static BlackJack from(List userNames) { + return new BlackJack(userNames); + } + + private void cardShuffle() { + gameCard.shuffle(); + } + + public void initCardDraw() { + initDealerDraw(); + initPlayerDraw(); + } + + private void initDealerDraw() { + gameUser.getDealer().appendToDeck(gameCard.drawCard(INITIAL_DRAW_CARD_COUNT)); + } + + private void initPlayerDraw() { + gameUser.getPlayers() + .forEach(player -> player.appendToDeck(gameCard.drawCard(INITIAL_DRAW_CARD_COUNT))); + } + + public GameUser getGameUser() { + return gameUser; + } + + public GameCard getGameCard() { + return gameCard; + } + + public List getGamePlayers() { + return gameUser.getPlayers(); + } + + public Dealer getGameDealer() { + return gameUser.getDealer(); + } + + public Card drawGameCard() { + return gameCard.drawCard(); + } +} diff --git a/src/main/java/blackJack/domain/Card.java b/src/main/java/blackJack/domain/Card.java new file mode 100644 index 00000000..214747f1 --- /dev/null +++ b/src/main/java/blackJack/domain/Card.java @@ -0,0 +1,33 @@ +package blackJack.domain; + +public class Card { + + private final CardType cardType; + private final CardNumber cardNumber; + + private Card(String cardType, String cardNumber) { + this.cardType = CardType.from(cardType); + this.cardNumber = CardNumber.from(cardNumber); + } + + public static Card of(String cardType, String cardNumber) { + return new Card(cardType, cardNumber); + } + + public boolean isAce() { + return cardNumber.getNumber().equals(TrumpNumber.ACE.getTrumpNumber()); + } + + public int getCardScore() { + return cardNumber.calculateScore(); + } + + public String getCardType() { + return cardType.getType(); + } + + public String getCardNumber() { + return cardNumber.getNumber(); + } +} + diff --git a/src/main/java/blackJack/domain/CardNumber.java b/src/main/java/blackJack/domain/CardNumber.java new file mode 100644 index 00000000..bd6193b6 --- /dev/null +++ b/src/main/java/blackJack/domain/CardNumber.java @@ -0,0 +1,35 @@ +package blackJack.domain; + +public class CardNumber { + + private static final String JQK_REGEX = "[JQK]"; + private static final int JQK_SCORE = 10; + private static final int ACE_SCORE = 1; + + private final TrumpNumber trumpNumber; + + private CardNumber(String cardNumber) { + this.trumpNumber = TrumpNumber.from(cardNumber); + } + + public static CardNumber from(String cardNumber) { + return new CardNumber(cardNumber); + } + + public String getNumber() { + return trumpNumber.getTrumpNumber(); + } + + public int calculateScore() { + String number = trumpNumber.getTrumpNumber(); + + if (number.matches(JQK_REGEX)) { + return JQK_SCORE; + } + if (number.equals(TrumpNumber.ACE.getTrumpNumber())) { + return ACE_SCORE; + } + + return Integer.parseInt(number); + } +} diff --git a/src/main/java/blackJack/domain/CardType.java b/src/main/java/blackJack/domain/CardType.java new file mode 100644 index 00000000..e169968e --- /dev/null +++ b/src/main/java/blackJack/domain/CardType.java @@ -0,0 +1,18 @@ +package blackJack.domain; + +public class CardType { + + private final Suit suit; + + private CardType(String cardType) { + this.suit = Suit.from(cardType); + } + + public static CardType from(String cardType) { + return new CardType(cardType); + } + + public String getType() { + return suit.getName(); + } +} diff --git a/src/main/java/blackJack/domain/Dealer.java b/src/main/java/blackJack/domain/Dealer.java new file mode 100644 index 00000000..5a6ac5c7 --- /dev/null +++ b/src/main/java/blackJack/domain/Dealer.java @@ -0,0 +1,23 @@ +package blackJack.domain; + +public class Dealer extends User { + + private static final String DEALER_DEFAULT_NAME = "딜러"; + private static final int ADDITIONAL_CARD_DRAW_SCORE_THRESHOLD = 16; + + private Dealer() { + super(Deck.create(), UserName.from(DEALER_DEFAULT_NAME)); + } + + public static Dealer create() { + return new Dealer(); + } + + public boolean isCardDraw() { + return deck.getScore() <= ADDITIONAL_CARD_DRAW_SCORE_THRESHOLD; + } + + public void additionalCardDraw(Card card) { + appendToDeck(card); + } +} diff --git a/src/main/java/blackJack/domain/Deck.java b/src/main/java/blackJack/domain/Deck.java new file mode 100644 index 00000000..7285991c --- /dev/null +++ b/src/main/java/blackJack/domain/Deck.java @@ -0,0 +1,69 @@ +package blackJack.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class Deck { + + private static final int ACE_BONUS_SCORE = 11; + public static final int MATCH_SCORE = 21; + + private final List deck; + + private Deck() { + this.deck = new ArrayList<>(); + } + + private Deck(List deck) { + this.deck = deck; + } + + public static Deck create() { + return new Deck(); + } + + public static Deck from(List deck) { + return new Deck(deck); + } + + public String convertDeckFormat() { + return deck.stream() + .map(card -> String.format("%s%s", card.getCardNumber(), card.getCardType())) + .collect(Collectors.joining(", ")); + } + + public int getScore() { + int aceCount = calculateAceCount(); + int score = calculateDefaultScore(); + + return calculateAceScore(score, aceCount); + } + + private int calculateAceCount() { + return (int) deck.stream() + .filter(Card::isAce) + .count(); + } + + private int calculateDefaultScore() { + return deck.stream() + .mapToInt(Card::getCardScore) + .sum(); + } + + private int calculateAceScore(int score, int count) { + int resultScore = score; + for (int i = 0; i < count; i++) { + if (resultScore + (ACE_BONUS_SCORE - 1) > MATCH_SCORE) { + break; + } + resultScore += (ACE_BONUS_SCORE - 1); + } + return resultScore; + } + + public List getDeck() { + return deck; + } +} diff --git a/src/main/java/blackJack/domain/GameCard.java b/src/main/java/blackJack/domain/GameCard.java new file mode 100644 index 00000000..92adf5af --- /dev/null +++ b/src/main/java/blackJack/domain/GameCard.java @@ -0,0 +1,48 @@ +package blackJack.domain; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GameCard { + + private final List gameCard; + + private GameCard() { + this.gameCard = new ArrayList<>(); + generateGameCard(); + } + + public static GameCard create() { + return new GameCard(); + } + + public List getGameCard() { + return gameCard; + } + + public List drawCard(int count) { + final List cards = new ArrayList<>(); + for (int i = 0; i < count; i++) { + cards.add(gameCard.remove(0)); + } + return cards; + } + + public Card drawCard() { + return gameCard.remove(0); + } + + private void generateGameCard() { + Suit.getSuits().forEach( + type -> TrumpNumber.trumpNumbers().forEach( + number -> gameCard.add(Card.of(type, number)) + ) + ); + } + + public void shuffle() { + Collections.shuffle(gameCard); + } +} diff --git a/src/main/java/blackJack/domain/GameUser.java b/src/main/java/blackJack/domain/GameUser.java new file mode 100644 index 00000000..34ddaf39 --- /dev/null +++ b/src/main/java/blackJack/domain/GameUser.java @@ -0,0 +1,47 @@ +package blackJack.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class GameUser { + + private final Dealer dealer; + private final List players; + + private GameUser(List userNames) { + this.dealer = Dealer.create(); + this.players = new ArrayList<>(); + + userNames.forEach(userName -> this.append(Player.of(userName))); + } + + public static GameUser from(List userNames) { + return new GameUser(userNames); + } + + public List getPlayers() { + return players; + } + + public Dealer getDealer() { + return dealer; + } + + public GameUser append(Player user) { + players.add(user); + return this; + } + + public List getUsers() { + List user = new ArrayList<>(); + user.add(dealer); + user.addAll(players); + + return user; + } + + public List convertPlayersName () { + return players.stream().map(User::getName).collect(Collectors.toList()); + } +} diff --git a/src/main/java/blackJack/domain/Player.java b/src/main/java/blackJack/domain/Player.java new file mode 100644 index 00000000..6ba58746 --- /dev/null +++ b/src/main/java/blackJack/domain/Player.java @@ -0,0 +1,18 @@ +package blackJack.domain; + +public class Player extends User { + + private static final int ADDITIONAL_CARD_DRAW_SCORE_THRESHOLD = 21; + + private Player(String userName) { + super(Deck.create(), UserName.from(userName)); + } + + public static Player of(String userName) { + return new Player(userName); + } + + public boolean isCardDraw() { + return deck.getScore() <= ADDITIONAL_CARD_DRAW_SCORE_THRESHOLD; + } +} diff --git a/src/main/java/blackJack/domain/Suit.java b/src/main/java/blackJack/domain/Suit.java new file mode 100644 index 00000000..6a9f73dc --- /dev/null +++ b/src/main/java/blackJack/domain/Suit.java @@ -0,0 +1,35 @@ +package blackJack.domain; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public enum Suit { + DIAMOND("다이아몬드"), + HEART("하트"), + SPADE("스페이드"), + CLOVER("클로버"); + + private final String name; + + Suit(String name) { + this.name = name; + } + + public static List getSuits() { + return Arrays.stream(values()) + .map(Suit::getName) + .collect(Collectors.toList()); + } + + public static Suit from(String cardType) { + return Arrays.stream(values()) + .filter(suit -> suit.getName().equals(cardType)) + .findAny() + .orElseThrow(() -> new RuntimeException("[ERROR] CardType 범위인 String을 입력해주세요.")); + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/blackJack/domain/TrumpNumber.java b/src/main/java/blackJack/domain/TrumpNumber.java new file mode 100644 index 00000000..db503739 --- /dev/null +++ b/src/main/java/blackJack/domain/TrumpNumber.java @@ -0,0 +1,33 @@ +package blackJack.domain; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public enum TrumpNumber { + ACE("A"), TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"), SEVEN("7"), + EIGHT("8"), NINE("9"), TEN("10"), JACK("J"), QUEEN("Q"), KING("K"); + + private final String trumpNumber; + + TrumpNumber(String trumpNumber) { + this.trumpNumber = trumpNumber; + } + + public static List trumpNumbers() { + return Arrays.stream(values()) + .map(TrumpNumber::getTrumpNumber) + .collect(Collectors.toList()); + } + + public static TrumpNumber from(String cardNumber) { + return Arrays.stream(values()) + .filter(trumpNumber -> trumpNumber.getTrumpNumber().equals(cardNumber)) + .findAny() + .orElseThrow(() -> new RuntimeException("[ERROR] CardNumber 범위인 String을 입력해주세요.")); + } + + public String getTrumpNumber() { + return trumpNumber; + } +} diff --git a/src/main/java/blackJack/domain/User.java b/src/main/java/blackJack/domain/User.java new file mode 100644 index 00000000..8c8d1fcc --- /dev/null +++ b/src/main/java/blackJack/domain/User.java @@ -0,0 +1,40 @@ +package blackJack.domain; + +import java.util.List; + +public abstract class User { + + protected final Deck deck; + protected final UserName userName; + + protected User(Deck deck, UserName userName) { + this.deck = deck; + this.userName = userName; + } + + public List getDeck() { + return deck.getDeck(); + } + + public String getName() { + return userName.getName(); + } + + public void appendToDeck(Card card) { + deck.getDeck().add(card); + } + + public void appendToDeck(List cards) { + cards.forEach(card -> deck.getDeck().add(card)); + } + + public String convertStatus() { + return String.format("%s 카드: %s", userName.getName(), deck.convertDeckFormat()); + } + + public int getScore() { + return deck.getScore(); + } + + public abstract boolean isCardDraw(); +} diff --git a/src/main/java/blackJack/domain/UserName.java b/src/main/java/blackJack/domain/UserName.java new file mode 100644 index 00000000..1daab7c2 --- /dev/null +++ b/src/main/java/blackJack/domain/UserName.java @@ -0,0 +1,18 @@ +package blackJack.domain; + +public class UserName { + + private final String userName; + + private UserName(String userName) { + this.userName = userName; + } + + public static UserName from(String userName) { + return new UserName(userName); + } + + public String getName() { + return userName; + } +} diff --git a/src/main/java/blackJack/domain/UserStats.java b/src/main/java/blackJack/domain/UserStats.java new file mode 100644 index 00000000..3462e31e --- /dev/null +++ b/src/main/java/blackJack/domain/UserStats.java @@ -0,0 +1,70 @@ +package blackJack.domain; + +import java.util.List; +import java.util.stream.Collectors; + +public class UserStats { + + public static final String TOTAL_SCORE_FORMAT = "%s - 결과: %d\n"; + public static final String DEALER_TOTAL_FORMAT = "%s: %d승 %d패\n"; + public static final String PLAYER_WIN_FORMAT = "%s: 승\n"; + public static final String PLAYER_LOSE_FORMAT = "%s: 패\n"; + + private final GameUser gameUser; + + private UserStats(GameUser gameUser) { + this.gameUser = gameUser; + } + + public static UserStats of(GameUser gameUser) { + return new UserStats(gameUser); + } + + public String convertTotalScore() { + List users = gameUser.getUsers(); + return users.stream().map( + user -> String.format( + TOTAL_SCORE_FORMAT, + user.convertStatus(), + user.getScore() + ) + ).collect(Collectors.joining()); + } + + public String convertTotalResult() { + return convertDealerTotalResult() + convertPlayersTotalResult(); + } + + public String convertDealerTotalResult() { + int win = (int) gameUser.getPlayers().stream() + .filter(this::isDealerWin) + .count(); + int total = gameUser.getPlayers().size(); + return String.format( + DEALER_TOTAL_FORMAT, + gameUser.getDealer().getName(), + win, + (total - win) + ); + } + + public String convertPlayersTotalResult() { + return gameUser.getPlayers().stream() + .map(player -> { + if (!isDealerWin(player)) { + return String.format(PLAYER_WIN_FORMAT, player.getName()); + } + return String.format(PLAYER_LOSE_FORMAT, player.getName()); + }).collect(Collectors.joining()); + } + + private boolean isDealerWin(Player player) { + if (gameUser.getDealer().getScore() > Deck.MATCH_SCORE) { + return false; + } + if (player.getScore() > Deck.MATCH_SCORE) { + return true; + } + return player.getScore() < gameUser.getDealer().getScore(); + } +} diff --git a/src/main/java/blackJack/util/Console.java b/src/main/java/blackJack/util/Console.java new file mode 100644 index 00000000..6e53aa6e --- /dev/null +++ b/src/main/java/blackJack/util/Console.java @@ -0,0 +1,39 @@ +package blackJack.util; + +import java.lang.reflect.Field; +import java.util.Objects; +import java.util.Scanner; + +public class Console { + + private static Scanner scanner = getScanner(); + + private Console() { + } + + public static String readLine() { + makeNewScannerIfScannerIsClosed(); + return scanner.nextLine().replace("\\n", "\n"); + } + + private static void makeNewScannerIfScannerIsClosed() { + if (Objects.isNull(scanner) || scannerIsClosed()) { + scanner = getScanner(); + } + } + + private static boolean scannerIsClosed() { + try { + Field sourceClosedField = Scanner.class.getDeclaredField("sourceClosed"); + sourceClosedField.setAccessible(true); + return sourceClosedField.getBoolean(scanner); + } catch (NoSuchFieldException | IllegalAccessException e) { + System.out.println("리플렉션 중 에러 발생"); + } + return true; + } + + private static Scanner getScanner() { + return new Scanner(System.in); + } +} diff --git a/src/main/java/blackJack/util/Util.java b/src/main/java/blackJack/util/Util.java new file mode 100644 index 00000000..d7e9bbb3 --- /dev/null +++ b/src/main/java/blackJack/util/Util.java @@ -0,0 +1,11 @@ +package blackJack.util; + +import java.util.Arrays; +import java.util.List; + +public class Util { + + public static List stringToStringList(String unrefinedString) { + return Arrays.asList(unrefinedString.split(", ")); + } +} diff --git a/src/main/java/blackJack/view/InputView.java b/src/main/java/blackJack/view/InputView.java new file mode 100644 index 00000000..13650df6 --- /dev/null +++ b/src/main/java/blackJack/view/InputView.java @@ -0,0 +1,20 @@ +package blackJack.view; + +import blackJack.util.Console; + +public class InputView { + + public static boolean readYN() { + String yn = ""; + try { + yn = Console.readLine(); + } catch (IllegalArgumentException exception) { + System.err.println(exception.getMessage()); + } + return yn.equals("y"); + } + + public static String readPlayerName() { + return Console.readLine(); + } +} diff --git a/src/main/java/blackJack/view/OutputView.java b/src/main/java/blackJack/view/OutputView.java new file mode 100644 index 00000000..3fbb0bbf --- /dev/null +++ b/src/main/java/blackJack/view/OutputView.java @@ -0,0 +1,58 @@ +package blackJack.view; + +import blackJack.domain.Dealer; +import blackJack.domain.GameUser; +import blackJack.domain.Player; +import java.util.List; + +public class OutputView { + + private static final String PRINT_REQUEST_PLAYER_NAMES = "게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"; + private static final String PRINT_INIT_CARD_DRAW_FORMAT = "%n딜러와 %s에게 2장의 나누었습니다.%n"; + private static final String PRINT_REQUEST_ADDITIONAL_CARD_DRAW_FORMAT = "%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)%n"; + private static final String PRINT_DEALER_ADDITIONAL_CARD_DRAW = "\n딜러는 16이하라 한장의 카드를 더 받았습니다."; + private static final String PRINT_TOTAL_SCORE_FORMAT = "\n%s"; + private static final String PRINT_TOTAL_RESULT_FORMAT = "\n## 최종 승패\n%s"; + + public static void printRequestPlayerNames() { + System.out.println(PRINT_REQUEST_PLAYER_NAMES); + } + + public static void printInitCardDrawFormat(List playerNames) { + System.out.printf(PRINT_INIT_CARD_DRAW_FORMAT, String.join(", ", playerNames)); + } + + public static void printUserStatus(GameUser gameUser) { + printDealerStatus(gameUser.getDealer()); + printPlayersStatus(gameUser.getPlayers()); + System.out.println(); + } + + public static void printDealerStatus(Dealer dealer) { + System.out.println(dealer.convertStatus()); + } + + public static void printPlayersStatus(List players) { + players.forEach(OutputView::printPlayerStatus); + } + + public static void printPlayerStatus(Player player) { + System.out.println(player.convertStatus()); + } + + public static void printRequestAdditionalCardDrawFormat(Player player) { + System.out.printf(PRINT_REQUEST_ADDITIONAL_CARD_DRAW_FORMAT, player.getName()); + } + + public static void printDealerAdditionalCardDraw() { + System.out.println(PRINT_DEALER_ADDITIONAL_CARD_DRAW); + } + + public static void printTotalScore(String totalScore) { + System.out.printf(PRINT_TOTAL_SCORE_FORMAT, totalScore); + } + + public static void printTotalResult(String totalResult) { + System.out.printf(PRINT_TOTAL_RESULT_FORMAT, totalResult); + } +} 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/fuelInjection/RentCompany.java b/src/main/java/fuelInjection/RentCompany.java new file mode 100644 index 00000000..d2841e76 --- /dev/null +++ b/src/main/java/fuelInjection/RentCompany.java @@ -0,0 +1,39 @@ +package fuelInjection; + +import fuelInjection.domain.Car; +import java.util.ArrayList; +import java.util.List; + +public class RentCompany { + + private static final String NEWLINE = System.getProperty("line.separator"); + private static final String REPORT_FORM = "%s : %.0f리터"; + private final List rentCars; + + private RentCompany() { + this.rentCars = new ArrayList<>(); + } + + public static RentCompany create() { + return new RentCompany(); + } + + public List getRentCars() { + return rentCars; + } + + public void addCar(Car car) { + rentCars.add(car); + } + + public String generateReport() { + StringBuilder report = new StringBuilder(); + + rentCars.forEach( + car -> report.append(String.format(REPORT_FORM, car.getName(), car.getChargeQuantity())) + .append(NEWLINE) + ); + + return report.toString(); + } +} diff --git a/src/main/java/fuelInjection/domain/Avante.java b/src/main/java/fuelInjection/domain/Avante.java new file mode 100644 index 00000000..bba54282 --- /dev/null +++ b/src/main/java/fuelInjection/domain/Avante.java @@ -0,0 +1,57 @@ +package fuelInjection.domain; + +import java.util.Objects; + +public class Avante extends Car { + + private static final String NAME = "Avante"; + private static final double DISTANCE_PER_LITER = 15; + private static final double TRIP_DISTANCE_MIN = 0; + + private final double tripDistance; + + public Avante(double tripDistance) { + this.tripDistance = tripDistance; + + validTripDistance(); + } + + public String getName() { + return NAME; + } + + public double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + public double getTripDistance() { + return tripDistance; + } + + private void validTripDistance() { + if (isInvalidTripDistance()) { + throw new IllegalArgumentException("[ERROR] 거리 값을 0 이상 양수값을 입력해주세요."); + } + } + + private boolean isInvalidTripDistance() { + return tripDistance < TRIP_DISTANCE_MIN; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Avante)) { + return false; + } + Avante avante = (Avante) o; + return Double.compare(avante.tripDistance, tripDistance) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(tripDistance); + } +} diff --git a/src/main/java/fuelInjection/domain/Car.java b/src/main/java/fuelInjection/domain/Car.java new file mode 100644 index 00000000..537f0815 --- /dev/null +++ b/src/main/java/fuelInjection/domain/Car.java @@ -0,0 +1,27 @@ +package fuelInjection.domain; + +public abstract class Car implements Vehicle { + + /** + * 리터당 이동 거리. 즉, 연비 + */ + abstract double getDistancePerLiter(); + + /** + * 여행하려는 거리 + */ + abstract double getTripDistance(); + + /** + * 차종의 이름 + */ + public abstract String getName(); + + /** + * 주입해야할 연료량을 구한다. + */ + public double getChargeQuantity() { + return getTripDistance() / getDistancePerLiter(); + } + +} diff --git a/src/main/java/fuelInjection/domain/K5.java b/src/main/java/fuelInjection/domain/K5.java new file mode 100644 index 00000000..daa1760c --- /dev/null +++ b/src/main/java/fuelInjection/domain/K5.java @@ -0,0 +1,57 @@ +package fuelInjection.domain; + +import java.util.Objects; + +public class K5 extends Car { + + private static final String NAME = "K5"; + private static final double DISTANCE_PER_LITER = 13; + private static final double TRIP_DISTANCE_MIN = 0; + + private final double tripDistance; + + public K5(double tripDistance) { + this.tripDistance = tripDistance; + + validTripDistance(); + } + + public String getName() { + return NAME; + } + + public double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + public double getTripDistance() { + return tripDistance; + } + + private void validTripDistance() { + if (isInvalidTripDistance()) { + throw new IllegalArgumentException("[ERROR] 거리 값을 0 이상 양수값을 입력해주세요."); + } + } + + private boolean isInvalidTripDistance() { + return tripDistance < TRIP_DISTANCE_MIN; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof K5)) { + return false; + } + K5 k5 = (K5) o; + return Double.compare(k5.tripDistance, tripDistance) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(tripDistance); + } +} diff --git a/src/main/java/fuelInjection/domain/Sonata.java b/src/main/java/fuelInjection/domain/Sonata.java new file mode 100644 index 00000000..ea9fa9cb --- /dev/null +++ b/src/main/java/fuelInjection/domain/Sonata.java @@ -0,0 +1,57 @@ +package fuelInjection.domain; + +import java.util.Objects; + +public class Sonata extends Car { + + private static final String NAME = "Sonata"; + private static final double DISTANCE_PER_LITER = 10; + private static final double TRIP_DISTANCE_MIN = 0; + + private final double tripDistance; + + public Sonata(double tripDistance) { + this.tripDistance = tripDistance; + + validTripDistance(); + } + + public String getName() { + return NAME; + } + + public double getDistancePerLiter() { + return DISTANCE_PER_LITER; + } + + public double getTripDistance() { + return tripDistance; + } + + private void validTripDistance() { + if (isInvalidTripDistance()) { + throw new IllegalArgumentException("[ERROR] 거리 값을 0 이상 양수값을 입력해주세요."); + } + } + + private boolean isInvalidTripDistance() { + return tripDistance < TRIP_DISTANCE_MIN; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Sonata)) { + return false; + } + Sonata sonata = (Sonata) o; + return Double.compare(sonata.tripDistance, tripDistance) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(tripDistance); + } +} diff --git a/src/main/java/fuelInjection/domain/Vehicle.java b/src/main/java/fuelInjection/domain/Vehicle.java new file mode 100644 index 00000000..d09ba1b7 --- /dev/null +++ b/src/main/java/fuelInjection/domain/Vehicle.java @@ -0,0 +1,5 @@ +package fuelInjection.domain; + +public interface Vehicle { + +} diff --git a/src/test/java/blackJack/domain/BlackJackTest.java b/src/test/java/blackJack/domain/BlackJackTest.java new file mode 100644 index 00000000..f532a7e9 --- /dev/null +++ b/src/test/java/blackJack/domain/BlackJackTest.java @@ -0,0 +1,47 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class BlackJackTest { + + public static final int GAME_CARD_SIZE = 52; + + @Test + void GamePlayer를_가진다() { + List userNames = Arrays.asList("박찬우", "제이슨"); + BlackJack blackJack = BlackJack.from(userNames); + GameUser gameUser = GameUser.from(userNames); + + List blackJackUserNames = blackJack.getGamePlayers().stream() + .map(Player::getName) + .collect(Collectors.toList()); + + List gameUserNames = gameUser.getPlayers().stream() + .map(Player::getName) + .collect(Collectors.toList()); + + assertThat(blackJackUserNames) + .isEqualTo(gameUserNames); + } + + @Test + void GameCard를_가진다() { + BlackJack blackJack = BlackJack.from(Collections.emptyList()); + + assertThat(blackJack.getGameCard().getGameCard().size()).isEqualTo(GAME_CARD_SIZE); + } + + @Test + void GameCard를_섞을_수_있다() { + BlackJack blackJack = BlackJack.from(Collections.emptyList()); + GameCard gameCard = GameCard.create(); + + assertThat(blackJack.getGameCard()).isNotEqualTo(gameCard.getGameCard()); + } +} diff --git a/src/test/java/blackJack/domain/CardNumberTest.java b/src/test/java/blackJack/domain/CardNumberTest.java new file mode 100644 index 00000000..dc246ab0 --- /dev/null +++ b/src/test/java/blackJack/domain/CardNumberTest.java @@ -0,0 +1,52 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +class CardNumberTest { + + @DisplayName("주어진 String으로 CardNumber 생성 후 getCardNumber() 호출시, 주어진 정수와 동일하다.") + @ParameterizedTest + @ValueSource(strings = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}) + void givenNumberWithString_WhenGetCardNumber_ThenEqualToGivenNumber(String number) { + CardNumber cardNumber = CardNumber.from(number); + + assertThat(cardNumber.getNumber()).isEqualTo(number); + } + + @DisplayName("유효하지 않는 CardNumber 범위로 인스턴스가 생성될때, RuntimeException 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"1", "11", "12", "13", "B"}) + void givenInValidCardNumberRange_WhenCreateInstance_ThenThrowRuntimeException(String number) { + assertThatThrownBy(() -> CardNumber.from(number)) + .isInstanceOf(RuntimeException.class); + } + + static Stream generateCardTypeAndAceNumber() { + return Stream.of( + Arguments.of("A", 1), + Arguments.of("3", 3), + Arguments.of("4", 4), + Arguments.of("5", 5), + Arguments.of("6", 6), + Arguments.of("J", 10), + Arguments.of("Q", 10), + Arguments.of("K", 10) + ); + } + + @ParameterizedTest + @MethodSource("generateCardTypeAndAceNumber") + void 스코어를_계산할_수_있다(String cardType, int score) { + CardNumber cardNumber = CardNumber.from(cardType); + + assertThat(cardNumber.calculateScore()).isEqualTo(score); + } +} diff --git a/src/test/java/blackJack/domain/CardTest.java b/src/test/java/blackJack/domain/CardTest.java new file mode 100644 index 00000000..edd2647c --- /dev/null +++ b/src/test/java/blackJack/domain/CardTest.java @@ -0,0 +1,54 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class CardTest { + + static Stream generateCardTypeAndCardNumber() { + return Stream.of( + Arguments.of(Arrays.asList("다이아몬드", "2")), + Arguments.of(Arrays.asList("하트", "3")), + Arguments.of(Arrays.asList("클로버", "4")), + Arguments.of(Arrays.asList("스페이드", "5")), + Arguments.of(Arrays.asList("다이아몬드", "6")), + Arguments.of(Arrays.asList("클로버", "J")) + ); + } + + @DisplayName("카드 숫자와 카드 타입을 입력할때, 주어진 숫자와 타입으로 카드가 생성된다.") + @ParameterizedTest + @MethodSource("generateCardTypeAndCardNumber") + void givenNumberWithStringAndTypeWithString_WhenGetCardNumberAndGetCardType_ThenEqualToGivenNumberAndType( + List cardParameter) { + Card card = Card.of(cardParameter.get(0), cardParameter.get(1)); + + assertThat( + Arrays.asList(card.getCardType(), card.getCardNumber())) + .isEqualTo(cardParameter); + } + + static Stream generateCardTypeAndAceNumber() { + return Stream.of( + Arguments.of(Arrays.asList("다이아몬드", "A")), + Arguments.of(Arrays.asList("하트", "A")), + Arguments.of(Arrays.asList("클로버", "A")), + Arguments.of(Arrays.asList("스페이드", "A")), + Arguments.of(Arrays.asList("클로버", "A")) + ); + } + + @ParameterizedTest + @MethodSource("generateCardTypeAndAceNumber") + void 에이스일결우_isAce가_참이다(List cardParameter) { + Card card = Card.of(cardParameter.get(0), cardParameter.get(1)); + assertThat(card.isAce()).isTrue(); + } +} diff --git a/src/test/java/blackJack/domain/CardTypeTest.java b/src/test/java/blackJack/domain/CardTypeTest.java new file mode 100644 index 00000000..90136bd9 --- /dev/null +++ b/src/test/java/blackJack/domain/CardTypeTest.java @@ -0,0 +1,29 @@ +package blackJack.domain; + +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.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CardTypeTest { + + @DisplayName("주어진 String type 으로 CardType 생성 후 getCardType() 호출시, 주어진 type과 동일하다.") + @ParameterizedTest + @ValueSource(strings = {"다이아몬드", "하트", "스페이드", "클로버"}) + void givenCardTypeWithString_WhenGetCardType_ThenEqualToGivenCardType(String type) { + CardType cardType = CardType.from(type); + + assertThat(cardType.getType()) + .isEqualTo(type); + } + + @DisplayName("유효하지 않는 CardType 범위로 인스턴스가 생성될때, RuntimeException 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"네모", "세모", "동그라미"}) + void givenInValidCardTypeRange_WhenCreateInstance_ThenThrowRuntimeException(String type) { + assertThatThrownBy(() -> CardType.from(type)) + .isInstanceOf(RuntimeException.class); + } +} diff --git a/src/test/java/blackJack/domain/DealerTest.java b/src/test/java/blackJack/domain/DealerTest.java new file mode 100644 index 00000000..cf20c00a --- /dev/null +++ b/src/test/java/blackJack/domain/DealerTest.java @@ -0,0 +1,49 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DealerTest { + + @DisplayName("Dealer의 기본 이름은 dealer 이다.") + @Test + void givenDefaultName_WhenGetName_ThenEqualToGivenName() { + Dealer dealer = Dealer.create(); + + assertThat(dealer.getName()) + .isEqualTo("딜러"); + } + + @DisplayName("String 이름과 Card가 주어질때 appendToDeck 메소드를 실행시, Card로 만든 리스트와 일치한다.") + @Test + void givenDealerParameter_WhenAppendToDeck_ThenEqualToCardList() { + Dealer dealer = Dealer.create(); + Card card = Card.of("다이아몬드", "2"); + + dealer.appendToDeck(card); + + assertThat(dealer.getDeck()) + .isEqualTo(Arrays.asList(card)); + } + + @Test + void 기준값_이하일경우_isCardDraw가_참이다() { + Dealer dealer = Dealer.create(); + dealer.appendToDeck(Card.of("다이아몬드", "10")); + dealer.appendToDeck(Card.of("하트", "5")); + + assertThat(dealer.isCardDraw()).isTrue(); + } + + @Test + void 기준값_이상일경우_isCardDraw가_거짓이다() { + Dealer dealer = Dealer.create(); + dealer.appendToDeck(Card.of("다이아몬드", "10")); + dealer.appendToDeck(Card.of("하트", "10")); + + assertThat(dealer.isCardDraw()).isFalse(); + } +} diff --git a/src/test/java/blackJack/domain/DeckTest.java b/src/test/java/blackJack/domain/DeckTest.java new file mode 100644 index 00000000..8f83ebea --- /dev/null +++ b/src/test/java/blackJack/domain/DeckTest.java @@ -0,0 +1,93 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +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; + +class DeckTest { + + @DisplayName("Deck은 Card의 배열을 가지고 있다.") + @Test + void Card의_배열을_가지고_있다() { + Deck deck = Deck.create(); + Card card = Card.of("스페이드", "3"); + deck.getDeck().add(card); + assertThat(deck.getDeck()).isEqualTo(Collections.singletonList(card)); + } + + + static Stream generateNormalDeck() { + return Stream.of( + arguments(Collections.singletonList(Card.of("다이아몬드", "3")), 3), + arguments(Collections.singletonList(Card.of("다이아몬드", "9")), 9), + arguments(Collections.singletonList(Card.of("스페이드", "10")), 10) + ); + } + + @DisplayName("일반적인 Deck의 score를 계산할 수 있다.") + @ParameterizedTest + @MethodSource("generateNormalDeck") + void 일반적인_deck의_score를_계산할_수_있다(List cards, int score) { + Deck deck = Deck.from(cards); + assertThat(deck.getScore()).isEqualTo(score); + } + + + static Stream generateCharTypeDeck() { + return Stream.of( + arguments(Collections.singletonList(Card.of("다이아몬드", "J")), 10), + arguments(Collections.singletonList(Card.of("스페이드", "Q")), 10), + arguments(Collections.singletonList(Card.of("하트", "K")), 10) + ); + } + + @DisplayName("JQK 카드를 가진 덱의 score를 계산할 수 있다.") + @ParameterizedTest + @MethodSource("generateCharTypeDeck") + void JQK의_score는_10이다(List cards, int score) { + Deck deck = Deck.from(cards); + assertThat(deck.getScore()).isEqualTo(score); + } + + + static Stream generateAceDeck() { + return Stream.of( + arguments(Collections.singletonList(Card.of("다이아몬드", "3")), 3), + arguments(Arrays.asList( + Card.of("하트", "3"), + Card.of("스페이드", "A"), + Card.of("클로버", "9") + ), 13), + arguments(Arrays.asList( + Card.of("하트", "10"), + Card.of("스페이드", "A") + ), 21), + arguments(Arrays.asList( + Card.of("하트", "A"), + Card.of("스페이드", "A") + ), 12), + arguments(Arrays.asList( + Card.of("하트", "A"), + Card.of("스페이드", "A"), + Card.of("클로버", "A") + ), 13) + ); + } + + @DisplayName("ACE의 score를 계산할 수 있다.") + @ParameterizedTest + @MethodSource("generateAceDeck") + void A_score를_계산할_수_있다(List cards, int score) { + Deck deck = Deck.from(cards); + assertThat(deck.getScore()).isEqualTo(score); + } +} diff --git a/src/test/java/blackJack/domain/GameCardTest.java b/src/test/java/blackJack/domain/GameCardTest.java new file mode 100644 index 00000000..f72def86 --- /dev/null +++ b/src/test/java/blackJack/domain/GameCardTest.java @@ -0,0 +1,22 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashSet; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GameCardTest { + + @DisplayName("GameCard 에는 52장의 서로 다른 카드가 존재한다.") + @Test + void givenNumberWithString_WhenGetCardNumber_ThenEqualToGivenNumber() { + GameCard gameCard = GameCard.create(); + + Set removedDuplicateGameCard = new HashSet<>(gameCard.getGameCard()); + + assertThat(removedDuplicateGameCard.size()) + .isEqualTo(52); + } +} diff --git a/src/test/java/blackJack/domain/GameUserTest.java b/src/test/java/blackJack/domain/GameUserTest.java new file mode 100644 index 00000000..191cce8e --- /dev/null +++ b/src/test/java/blackJack/domain/GameUserTest.java @@ -0,0 +1,34 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class GameUserTest { + + private static final String DEALER_DEFAULT_NAME = "딜러"; + + @Test + void GameUser의_Dealer의_이름은_dealer이다() { + GameUser gameUser = GameUser.from(Arrays.asList()); + String dealerName = gameUser.getDealer().getName(); + + assertThat(dealerName) + .isEqualTo(DEALER_DEFAULT_NAME); + } + + @Test + void GameUser는_Player_리스트를_가진다() { + List userNames = Arrays.asList("제이슨", "박찬우"); + GameUser gameUser = GameUser.from(userNames); + List gameUserNames = gameUser.getPlayers().stream() + .map(User::getName) + .collect(Collectors.toList()); + + assertThat(userNames) + .isEqualTo(gameUserNames); + } +} diff --git a/src/test/java/blackJack/domain/PlayerTest.java b/src/test/java/blackJack/domain/PlayerTest.java new file mode 100644 index 00000000..d720cd27 --- /dev/null +++ b/src/test/java/blackJack/domain/PlayerTest.java @@ -0,0 +1,53 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PlayerTest { + + @DisplayName("String 이름이 주어질때, getName 메소드의 값은 주어진 이름과 동일하다.") + @ParameterizedTest + @ValueSource(strings = {"이호찬", "박찬우", "holee", "12345"}) + void givenNameWithString_WhenGetName_ThenEqualToGivenName(String name) { + Player player = Player.of(name); + + assertThat(player.getName()) + .isEqualTo(name); + } + + @DisplayName("String 이름과 Card가 주어질때 appendToDeck 메소드를 실행시, Card로 만든 리스트와 일치한다.") + @Test + void givenPlayerParameter_WhenAppendToDeck_ThenEqualToCardList() { + Player player = Player.of("제이슨"); + Card card = Card.of("다이아몬드", "2"); + + player.appendToDeck(card); + + assertThat(player.getDeck()) + .isEqualTo(Arrays.asList(card)); + } + + @Test + void 기준값_이하일경우_isCardDraw가_참이다() { + Dealer dealer = Dealer.create(); + dealer.appendToDeck(Card.of("다이아몬드", "10")); + dealer.appendToDeck(Card.of("하트", "5")); + + assertThat(dealer.isCardDraw()).isTrue(); + } + + @Test + void 기준값_이상일경우_isCardDraw가_거짓이다() { + Dealer dealer = Dealer.create(); + dealer.appendToDeck(Card.of("다이아몬드", "10")); + dealer.appendToDeck(Card.of("하트", "10")); + dealer.appendToDeck(Card.of("스페이드", "3")); + + assertThat(dealer.isCardDraw()).isFalse(); + } +} diff --git a/src/test/java/blackJack/domain/UserNameTest.java b/src/test/java/blackJack/domain/UserNameTest.java new file mode 100644 index 00000000..d714d6c5 --- /dev/null +++ b/src/test/java/blackJack/domain/UserNameTest.java @@ -0,0 +1,20 @@ +package blackJack.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class UserNameTest { + + @DisplayName("String 이름이 주어질때, getUserName 메소드의 값은 주어진 이름과 동일하다.") + @ParameterizedTest + @ValueSource(strings = {"이호찬", "박찬우", "holee", "12345"}) + void givenNameWithString_WhenGetUserName_ThenEqualToGivenName(String name) { + UserName userName = UserName.from(name); + + assertThat(userName.getName()) + .isEqualTo(name); + } +} \ No newline at end of file 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/fuelInjection/RentCompanyTest.java b/src/test/java/fuelInjection/RentCompanyTest.java new file mode 100644 index 00000000..a9b2f991 --- /dev/null +++ b/src/test/java/fuelInjection/RentCompanyTest.java @@ -0,0 +1,77 @@ +package fuelInjection; + +import static org.assertj.core.api.Assertions.assertThat; + +import fuelInjection.domain.Avante; +import fuelInjection.domain.Car; +import fuelInjection.domain.K5; +import fuelInjection.domain.Sonata; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class RentCompanyTest { + + private static final String NEWLINE = System.getProperty("line.separator"); + int TEMP_DISTANCE = 10; + + @Test + void Car의_List를_가져야한다() { + RentCompany company = RentCompany.create(); + + assertThat(company.getRentCars().size()) + .isEqualTo(0); + } + + @Test + void Car의_List에_Sonata를_추가할_수_있다() { + RentCompany company = RentCompany.create(); + Sonata sonata = new Sonata(TEMP_DISTANCE); + List cars = Collections.singletonList(sonata); + + company.addCar(sonata); + assertThat(company.getRentCars().equals(cars)) + .isTrue(); + } + + @Test + void Car의_List에_Avante를_추가할_수_있다() { + RentCompany company = RentCompany.create(); + Avante avante = new Avante(TEMP_DISTANCE); + List cars = Collections.singletonList(avante); + + company.addCar(avante); + assertThat(company.getRentCars().equals(cars)) + .isTrue(); + } + + @Test + void Car의_List에_K5를_추가할_수_있다() { + RentCompany company = RentCompany.create(); + K5 k5 = new K5(TEMP_DISTANCE); + List cars = Collections.singletonList(k5); + + company.addCar(k5); + assertThat(company.getRentCars().equals(cars)) + .isTrue(); + } + + @Test + public void report() { + 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리터" + NEWLINE + ); + } +} diff --git a/src/test/java/fuelInjection/domain/AvanteTest.java b/src/test/java/fuelInjection/domain/AvanteTest.java new file mode 100644 index 00000000..3ac5975b --- /dev/null +++ b/src/test/java/fuelInjection/domain/AvanteTest.java @@ -0,0 +1,70 @@ +package fuelInjection.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +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; +import org.junit.jupiter.params.provider.ValueSource; + +class AvanteTest { + int TEMP_DISTANCE = 10; + + @DisplayName("`Avante` String Type 이름을 가져야한다.") + @Test + public void givenAvanteClass_whenCreateInstance_thenInstanceNameIsAvante () { + Avante avante = new Avante(TEMP_DISTANCE); + + assertThat(avante.getName()) + .isEqualTo("Avante"); + } + + @DisplayName("`15km/리터`의 연비 가져야한다.") + @Test + public void givenAvanteClass_whenCreateInstance_thenDistancePerLiterIs10 () { + Avante avante = new Avante(TEMP_DISTANCE); + + assertThat(avante.getDistancePerLiter()) + .isEqualTo(15); + } + + @DisplayName("거리 가져야한다.") + @ParameterizedTest + @ValueSource(doubles = {0, 10, 30, 100, 1.5}) + public void givenTripDistanceOverZeroTypeWithDouble_whenGetTripDistance_thenNotThrowException (double tripDistance) { + Avante avante = new Avante(tripDistance); + + assertThat(avante.getTripDistance()) + .isEqualTo(tripDistance); + } + + @DisplayName("0이하 정수 값이 TripDistanceUnder으로 주어졌을때, IllegalArgumentException이 발생한다.") + @ParameterizedTest + @ValueSource(doubles = {-1, -10, -100}) + public void givenTripDistanceBelowZeroTypeWithDouble_whenGetTripDistance_thenThrowIllegalArgumentException (double tripDistance) { + assertThatThrownBy(() -> new Avante(tripDistance)) + .isInstanceOf(IllegalArgumentException.class); + } + + static Stream generateTripDistanceAndChargeQuantity() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(15, 1), + Arguments.of(150, 10), + Arguments.of(1500, 100) + ); + } + + @DisplayName("주입해야할 연료량을 구할 수 있다.") + @ParameterizedTest + @MethodSource("generateTripDistanceAndChargeQuantity") + public void givenTripDistanceOverZeroTypeWithDouble_whenGetChargeQuantity_thenCanCalculateChargeQuantity (double tripDistance, double chargeQuantity) { + assertThat(new Avante(tripDistance).getChargeQuantity()) + .isEqualTo(chargeQuantity); + } +} diff --git a/src/test/java/fuelInjection/domain/K5Test.java b/src/test/java/fuelInjection/domain/K5Test.java new file mode 100644 index 00000000..12205c43 --- /dev/null +++ b/src/test/java/fuelInjection/domain/K5Test.java @@ -0,0 +1,70 @@ +package fuelInjection.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +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; +import org.junit.jupiter.params.provider.ValueSource; + +class K5Test { + int TEMP_DISTANCE = 10; + + @DisplayName("`K5` String Type 이름을 가져야한다.") + @Test + public void givenK5Class_whenCreateInstance_thenInstanceNameIsK5 () { + K5 k5 = new K5(TEMP_DISTANCE); + + assertThat(k5.getName()) + .isEqualTo("K5"); + } + + @DisplayName("`13km/리터`의 연비 가져야한다.") + @Test + public void givenK5Class_whenCreateInstance_thenDistancePerLiterIs10 () { + K5 k5 = new K5(TEMP_DISTANCE); + + assertThat(k5.getDistancePerLiter()) + .isEqualTo(13); + } + + @DisplayName("거리 가져야한다.") + @ParameterizedTest + @ValueSource(doubles = {0, 10, 30, 100, 1.5}) + public void givenTripDistanceOverZeroTypeWithDouble_whenGetTripDistance_thenNotThrowException (double tripDistance) { + K5 k5 = new K5(tripDistance); + + assertThat(k5.getTripDistance()) + .isEqualTo(tripDistance); + } + + @DisplayName("0이하 정수 값이 TripDistanceUnder으로 주어졌을때, IllegalArgumentException이 발생한다.") + @ParameterizedTest + @ValueSource(doubles = {-1, -10, -100}) + public void givenTripDistanceBelowZeroTypeWithDouble_whenGetTripDistance_thenThrowIllegalArgumentException (double tripDistance) { + assertThatThrownBy(() -> new K5(tripDistance)) + .isInstanceOf(IllegalArgumentException.class); + } + + static Stream generateTripDistanceAndChargeQuantity() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(13, 1), + Arguments.of(130, 10), + Arguments.of(1300, 100) + ); + } + + @DisplayName("주입해야할 연료량을 구할 수 있다.") + @ParameterizedTest + @MethodSource("generateTripDistanceAndChargeQuantity") + public void givenTripDistanceOverZeroTypeWithDouble_whenGetChargeQuantity_thenCanCalculateChargeQuantity (double tripDistance, double chargeQuantity) { + assertThat(new K5(tripDistance).getChargeQuantity()) + .isEqualTo(chargeQuantity); + } +} diff --git a/src/test/java/fuelInjection/domain/SonataTest.java b/src/test/java/fuelInjection/domain/SonataTest.java new file mode 100644 index 00000000..8792d39d --- /dev/null +++ b/src/test/java/fuelInjection/domain/SonataTest.java @@ -0,0 +1,70 @@ +package fuelInjection.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; +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; +import org.junit.jupiter.params.provider.ValueSource; + +class SonataTest { + int TEMP_DISTANCE = 10; + + @DisplayName("`Sonata` String Type 이름을 가져야한다.") + @Test + public void givenSonataClass_whenCreateInstance_thenInstanceNameIsSonata () { + Sonata sonata = new Sonata(TEMP_DISTANCE); + + assertThat(sonata.getName()) + .isEqualTo("Sonata"); + } + + @DisplayName("`10km/리터`의 연비 가져야한다.") + @Test + public void givenSonataClass_whenCreateInstance_thenDistancePerLiterIs10 () { + Sonata sonata = new Sonata(TEMP_DISTANCE); + + assertThat(sonata.getDistancePerLiter()) + .isEqualTo(10); + } + + @DisplayName("거리 가져야한다.") + @ParameterizedTest + @ValueSource(doubles = {0, 10, 30, 100, 1.5}) + public void givenTripDistanceOverZeroTypeWithDouble_whenGetTripDistance_thenNotThrowException (double tripDistance) { + Sonata sonata = new Sonata(tripDistance); + + assertThat(sonata.getTripDistance()) + .isEqualTo(tripDistance); + } + + @DisplayName("0이하 정수 값이 TripDistanceUnder으로 주어졌을때, IllegalArgumentException이 발생한다.") + @ParameterizedTest + @ValueSource(doubles = {-1, -10, -100}) + public void givenTripDistanceBelowZeroTypeWithDouble_whenGetTripDistance_thenThrowIllegalArgumentException (double tripDistance) { + assertThatThrownBy(() -> new Sonata(tripDistance)) + .isInstanceOf(IllegalArgumentException.class); + } + + static Stream generateTripDistanceAndChargeQuantity() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(10, 1), + Arguments.of(100, 10), + Arguments.of(1000, 100), + Arguments.of(15, 1.5) + ); + } + + @DisplayName("주입해야할 연료량을 구할 수 있다.") + @ParameterizedTest + @MethodSource("generateTripDistanceAndChargeQuantity") + public void givenTripDistanceOverZeroTypeWithDouble_whenGetChargeQuantity_thenCanCalculateChargeQuantity (double tripDistance, double chargeQuantity) { + assertThat(new Sonata(tripDistance).getChargeQuantity()) + .isEqualTo(chargeQuantity); + } +} \ No newline at end of file