diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..6b49ecae --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,12 @@ +import blackjack.game.GameStarter; + +public class Application { + public static void main(String[] args) { + GameStarter gameStarter = new GameStarter(); + gameStarter.start() + .proceedBattingStep() + .proceedDealingStep() + .proceedPlayStep() + .proceedCalculate(); + } +} diff --git a/src/main/java/blackjack/card/Card.java b/src/main/java/blackjack/card/Card.java new file mode 100644 index 00000000..74cf3327 --- /dev/null +++ b/src/main/java/blackjack/card/Card.java @@ -0,0 +1,47 @@ +package blackjack.card; + +public class Card { + private final Rank rank; + private final Suit suit; + + public Card(Rank rank, Suit suit) { + this.rank = rank; + this.suit = suit; + } + + public String getCardName() { + return this.rank.getMark() + this.suit.getName(); + } + + public boolean isAce() { + return this.rank == Rank.ACE; + } + + public int getNumber() { + return this.rank.getNumber(); + } + + @Override + public int hashCode() { + int result = 17; + result = 37 * result * rank.hashCode(); + result = 37 * result * suit.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (obj.getClass() != this.getClass()) { + return false; + } + + Card compare = (Card) obj; + + return this.suit == compare.suit + && this.rank == compare.rank; + } +} diff --git a/src/main/java/blackjack/card/Deck.java b/src/main/java/blackjack/card/Deck.java new file mode 100644 index 00000000..6c6d0725 --- /dev/null +++ b/src/main/java/blackjack/card/Deck.java @@ -0,0 +1,34 @@ +package blackjack.card; + +import java.util.*; + +public class Deck { + private final List cards; + + public Deck() { + OrderedDeck orderedDeck = OrderedDeck.getInstance(); + this.cards = shuffle(orderedDeck.getDeck()); + } + + private List shuffle(List cards) { + Random random = new Random(); + List shuffledDeck = new LinkedList<>(); + for (int i = cards.size(); i > 0; i--) { + int pick = random.nextInt(cards.size()); + Card picked = cards.remove(pick); + shuffledDeck.add(picked); + } + + return shuffledDeck; + } + + public Card draw() { + if (cards.isEmpty()) { + throw new IllegalArgumentException("덱에 남은 카드가 없습니다."); + } + + Card top = cards.get(0); + cards.remove(0); + return top; + } +} diff --git a/src/main/java/blackjack/card/Hand.java b/src/main/java/blackjack/card/Hand.java new file mode 100644 index 00000000..115f5966 --- /dev/null +++ b/src/main/java/blackjack/card/Hand.java @@ -0,0 +1,58 @@ +package blackjack.card; + +import java.util.ArrayList; +import java.util.List; + +public class Hand { + private final List cards; + + private static final int BLACK_JACK_NUMBER = 21; + + public Hand() { + cards = new ArrayList<>(); + } + + public void addCard(Card card) { + cards.add(card); + } + + public int calculateHand() { + int sum = 0; + for (Card card : cards) { + sum = addNumber(card, sum); + } + + return sum; + } + + private int addNumber(Card card, int sum) { + int number = card.getNumber(); + if (card.isAce() && sum + number > BLACK_JACK_NUMBER) { + return sum + 1; + } + + return sum + number; + } + + public boolean isBust() { + int result = calculateHand(); + return result > BLACK_JACK_NUMBER; + } + + public boolean isBlackJack() { + if (cards.size() != 2) { + return false; + } + + int result = calculateHand(); + return result == BLACK_JACK_NUMBER; + } + + public int size() { + return this.cards.size(); + } + + public Card get(int i) { + return this.cards.get(i); + } +} diff --git a/src/main/java/blackjack/card/OrderedDeck.java b/src/main/java/blackjack/card/OrderedDeck.java new file mode 100644 index 00000000..44ee289a --- /dev/null +++ b/src/main/java/blackjack/card/OrderedDeck.java @@ -0,0 +1,42 @@ +package blackjack.card; + +import java.util.*; + +/** + * 섞기 전의 덱을 캐싱 + */ +public class OrderedDeck { + private static OrderedDeck instance; + private final List cards; + + private OrderedDeck() { + cards = new ArrayList<>(); + for (Suit suit : Suit.values()) { + Set suitCardSet = makeSuitCards(suit); + cards.addAll(suitCardSet); + } + } + + private Set makeSuitCards(Suit suit) { + Set suitCardSet = new LinkedHashSet<>(); + + for (Rank rank : Rank.values()) { + Card card = new Card(rank, suit); + suitCardSet.add(card); + } + + return suitCardSet; + } + + public static OrderedDeck getInstance() { + if (instance == null) { + instance = new OrderedDeck(); + } + + return instance; + } + + public List getDeck() { + return new ArrayList<>(this.cards); + } +} diff --git a/src/main/java/blackjack/card/Rank.java b/src/main/java/blackjack/card/Rank.java new file mode 100644 index 00000000..05aa4574 --- /dev/null +++ b/src/main/java/blackjack/card/Rank.java @@ -0,0 +1,32 @@ +package blackjack.card; + +public enum Rank { + ACE(11, "A"), + TWO(2, "2"), + THREE(3, "3"), + FOUR(4, "4"), + FIVE(5, "5"), + SIX(6, "6"), + SEVEN(7, "7"), + EIGHT(8, "8"), + NINE(9, "9"), + JACK(10, "J"), + QUEEN(10, "Q"), + KING(10, "K"); + + private final int number; + private final String mark; + + Rank(int number, String mark) { + this.number = number; + this.mark = mark; + } + + public int getNumber() { + return this.number; + } + + public String getMark() { + return this.mark; + } +} diff --git a/src/main/java/blackjack/card/Suit.java b/src/main/java/blackjack/card/Suit.java new file mode 100644 index 00000000..53a91855 --- /dev/null +++ b/src/main/java/blackjack/card/Suit.java @@ -0,0 +1,18 @@ +package blackjack.card; + +public enum Suit { + CLUB("클로버"), + DIAMOND("다이아몬드"), + HEART("하트"), + SPADE("스페이드"); + + private final String name; + + Suit (String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/blackjack/game/BattingStep.java b/src/main/java/blackjack/game/BattingStep.java new file mode 100644 index 00000000..5c6c87b6 --- /dev/null +++ b/src/main/java/blackjack/game/BattingStep.java @@ -0,0 +1,38 @@ +package blackjack.game; + +import blackjack.player.Gambler; +import view.GameInputView; + +import java.util.Optional; + +public class BattingStep { + + private final GameStarter gameStarter; + + protected BattingStep(GameStarter gameStarter) { + this.gameStarter = gameStarter; + } + + public DealingStep proceedDealingStep() { + DealingStep dealingStep = new DealingStep(this.gameStarter); + dealingStep.deal(); + return dealingStep; + } + + protected void bat() { + for (Gambler gambler : gameStarter.getGamblers()) { + bat(gambler); + } + } + + private void bat(Gambler gambler) { + Optional in = GameInputView.askBatAmount(gambler.getName()); + if (!in.isPresent()) { + bat(gambler); + return; + } + + Integer batAmount = in.get(); + gambler.setBatAmount(batAmount); + } +} diff --git a/src/main/java/blackjack/game/CalculateStep.java b/src/main/java/blackjack/game/CalculateStep.java new file mode 100644 index 00000000..995f1444 --- /dev/null +++ b/src/main/java/blackjack/game/CalculateStep.java @@ -0,0 +1,76 @@ +package blackjack.game; + +import blackjack.player.Dealer; +import blackjack.player.Gambler; +import view.GameOutputView; + +public class CalculateStep { + private final GameStarter gameStarter; + + public CalculateStep(GameStarter gameStarter) { + this.gameStarter = gameStarter; + } + + public void calculate() { + Dealer dealer = gameStarter.getDealer(); + + for (Gambler gambler : gameStarter.getGamblers()) { + doCalculateChain(gambler); + dealer.addChip(-gambler.getChip()); + } + + GameOutputView.announceFinalProfit(dealer, gameStarter.getGamblers()); + } + + private void doCalculateChain(Gambler gambler) { + calculateGamblerIsBust(gambler); + } + + private void calculateGamblerIsBust(Gambler gambler) { + if (gambler.getHand().isBust()) { + gambler.loss(); + return; + } + + calculateGamblerIsBlackJack(gambler); + } + + private void calculateGamblerIsBlackJack(Gambler gambler) { + if (gambler.getHand().isBlackJack()) { + calculateDealerIsBlackJack(gambler); + return; + } + + calculateDealerIsBust(gambler); + } + + private void calculateDealerIsBlackJack(Gambler gambler) { + if (gameStarter.getDealer().getHand().isBlackJack()) { + return; + } + + gambler.gainWithBlackJack(); + } + + private void calculateDealerIsBust(Gambler gambler) { + if (gameStarter.getDealer().getHand().isBlackJack()) { + gambler.gain(); + return; + } + + compareDealerAndGamblerNumber(gambler); + } + + private void compareDealerAndGamblerNumber(Gambler gambler) { + int playerNumber = gambler.getHand().calculateHand(); + int dealerNumber = gameStarter.getDealer().getHand().calculateHand(); + if (playerNumber > dealerNumber) { + gambler.gain(); + return; + } + + if (playerNumber < dealerNumber) { + gambler.loss(); + } + } +} diff --git a/src/main/java/blackjack/game/DealingStep.java b/src/main/java/blackjack/game/DealingStep.java new file mode 100644 index 00000000..53a41fc7 --- /dev/null +++ b/src/main/java/blackjack/game/DealingStep.java @@ -0,0 +1,42 @@ +package blackjack.game; + +import blackjack.player.Dealer; +import blackjack.player.Gambler; +import blackjack.player.Player; +import view.GameOutputView; + +public class DealingStep { + + private final GameStarter gameStarter; + + protected DealingStep(GameStarter gameStarter) { + this.gameStarter = gameStarter; + } + + public PlayStep proceedPlayStep() { + PlayStep playStep = new PlayStep(this.gameStarter); + playStep.playGambler(); + return playStep; + } + + protected void deal() { + draw(gameStarter.getDealer()); + for (Gambler gambler : gameStarter.getGamblers()) { + draw(gambler); + } + + GameOutputView.announceDealResult(gameStarter.getGamblers()); + } + + private void draw(Player player) { + int repeat = 2; + + if (player instanceof Dealer) { + repeat = 1; + } + + for (int i = 0; i < repeat; i++) { + player.addCardToHand(gameStarter.getDeck().draw()); + } + } +} diff --git a/src/main/java/blackjack/game/GameStarter.java b/src/main/java/blackjack/game/GameStarter.java new file mode 100644 index 00000000..b8562055 --- /dev/null +++ b/src/main/java/blackjack/game/GameStarter.java @@ -0,0 +1,37 @@ +package blackjack.game; + +import blackjack.card.Deck; +import blackjack.player.Dealer; +import blackjack.player.Gambler; + +import java.util.List; + +public class GameStarter { + + private List gamblers; + private final Dealer dealer; + private final Deck deck; + + public GameStarter() { + dealer = new Dealer(); + this.deck = new Deck(); + } + + public PlayerRegistrationStep start() { + PlayerRegistrationStep playerRegistrationStep = new PlayerRegistrationStep(this); + gamblers = playerRegistrationStep.addGambler(); + return playerRegistrationStep; + } + + public List getGamblers() { + return gamblers; + } + + public Dealer getDealer() { + return dealer; + } + + public Deck getDeck() { + return deck; + } +} diff --git a/src/main/java/blackjack/game/PlayStep.java b/src/main/java/blackjack/game/PlayStep.java new file mode 100644 index 00000000..9bf9f7b9 --- /dev/null +++ b/src/main/java/blackjack/game/PlayStep.java @@ -0,0 +1,62 @@ +package blackjack.game; + +import blackjack.player.Dealer; +import blackjack.player.Gambler; +import view.GameInputView; +import view.GameOutputView; + +import java.util.Optional; + +public class PlayStep { + + private final GameStarter gameStarter; + + protected PlayStep(GameStarter gameStarter) { + this.gameStarter = gameStarter; + } + + public void proceedCalculate() { + CalculateStep calculateStep = new CalculateStep(this.gameStarter); + calculateStep.calculate(); + } + + protected void playGambler() { + for (Gambler gambler : gameStarter.getGamblers()) { + GameOutputView.showHand(gambler); + playGambler(gambler); + playDealer(0); + } + } + + private void playGambler(Gambler gambler) { + if (gambler.getHand().isBust()) { + return; + } + + Optional in = GameInputView.askHit(gambler.getName()); + if (!in.isPresent()) { + playGambler(gambler); + return; + } + + Boolean isHit = in.get(); + if (!isHit) { + return; + } + + gambler.addCardToHand(gameStarter.getDeck().draw()); + GameOutputView.showHand(gambler); + playGambler(gambler); + } + + private void playDealer(int count) { + Dealer dealer = gameStarter.getDealer(); + if (dealer.isPlay()) { + dealer.addCardToHand(gameStarter.getDeck().draw()); + playDealer(++count); + return; + } + + GameOutputView.announceDealerPlay(count); + } +} diff --git a/src/main/java/blackjack/game/PlayerRegistrationStep.java b/src/main/java/blackjack/game/PlayerRegistrationStep.java new file mode 100644 index 00000000..ffbc9a8e --- /dev/null +++ b/src/main/java/blackjack/game/PlayerRegistrationStep.java @@ -0,0 +1,46 @@ +package blackjack.game; + +import blackjack.player.Gambler; +import view.GameInputView; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class PlayerRegistrationStep { + + private final GameStarter gameStarter; + + public PlayerRegistrationStep(GameStarter gameStarter) { + this.gameStarter = gameStarter; + } + + public BattingStep proceedBattingStep() { + BattingStep battingStep = new BattingStep(this.gameStarter); + battingStep.bat(); + return battingStep; + } + + protected List addGambler() { + Optional in = GameInputView.askPlayerName(); + if (!in.isPresent()) { + return addGambler(); + } + + String[] names = in.get().split(","); + List gamblers = new ArrayList<>(); + for (String name : names) { + validateNameAndAddGambler(name); + } + + return gamblers; + } + + private void validateNameAndAddGambler(String name) { + if (name.isEmpty()) { + return; + } + + gameStarter.getGamblers().add(new Gambler(name)); + } +} diff --git a/src/main/java/blackjack/player/Dealer.java b/src/main/java/blackjack/player/Dealer.java new file mode 100644 index 00000000..1dcc4ac4 --- /dev/null +++ b/src/main/java/blackjack/player/Dealer.java @@ -0,0 +1,18 @@ +package blackjack.player; + +public class Dealer extends Player { + + public Dealer() { + super("딜러"); + this.chip = 0; + } + + public boolean isPlay() { + int result = this.hands.calculateHand(); + return result <= 16; + } + + public void addChip(double chip) { + this.chip -= chip; + } +} diff --git a/src/main/java/blackjack/player/Gambler.java b/src/main/java/blackjack/player/Gambler.java new file mode 100644 index 00000000..5decdcc7 --- /dev/null +++ b/src/main/java/blackjack/player/Gambler.java @@ -0,0 +1,25 @@ +package blackjack.player; + +public class Gambler extends Player { + private int batAmount; + + public Gambler(String name) { + super(name); + } + + public void setBatAmount(int batAmount) { + this.batAmount = batAmount; + } + + public void gain() { + this.chip += batAmount; + } + + public void gainWithBlackJack() { + this.chip += batAmount * 1.5; + } + + public void loss() { + this.chip -= batAmount; + } +} diff --git a/src/main/java/blackjack/player/Player.java b/src/main/java/blackjack/player/Player.java new file mode 100644 index 00000000..94597395 --- /dev/null +++ b/src/main/java/blackjack/player/Player.java @@ -0,0 +1,31 @@ +package blackjack.player; + +import blackjack.card.Card; +import blackjack.card.Hand; + +public abstract class Player { + protected final String name; + protected final Hand hands; + protected double chip; + + public Player(String name) { + this.name = name; + this.hands = new Hand(); + } + + public String getName() { + return this.name; + } + + public Hand getHand() { + return this.hands; + } + + public double getChip() { + return chip; + } + + public void addCardToHand(Card card) { + hands.addCard(card); + } +} diff --git a/src/main/java/nextstep/fp/Car.java b/src/main/java/nextstep/fp/Car.java deleted file mode 100644 index 2146c112..00000000 --- a/src/main/java/nextstep/fp/Car.java +++ /dev/null @@ -1,35 +0,0 @@ -package nextstep.fp; - -import java.util.Objects; - -public class Car { - private final String name; - private final int position; - - public Car(String name, int position) { - this.name = name; - this.position = position; - } - - public Car move(MoveStrategy moveStrategy) { - if (moveStrategy.isMovable()) { - return new Car(name, position + 1); - } - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Car car = (Car) o; - return position == car.position && - Objects.equals(name, car.name); - } - - @Override - public int hashCode() { - - return Objects.hash(name, position); - } -} diff --git a/src/main/java/nextstep/fp/Lambda.java b/src/main/java/nextstep/fp/Lambda.java deleted file mode 100644 index bd68fe1c..00000000 --- a/src/main/java/nextstep/fp/Lambda.java +++ /dev/null @@ -1,56 +0,0 @@ -package nextstep.fp; - -import java.util.List; - -public class Lambda { - public static void printAllOld(List numbers) { - System.out.println("printAllOld"); - - for (int number : numbers) { - System.out.println(number); - } - } - - public static void printAllLambda(List numbers) { - System.out.println("printAllLambda"); - - numbers.forEach(System.out::println); - } - - public static void runThread() { - new Thread(new Runnable() { - @Override - public void run() { - System.out.println("Hello from thread"); - } - }).start(); - } - - public static int sumAll(List numbers) { - int total = 0; - for (int number : numbers) { - total += number; - } - return total; - } - - public static int sumAllEven(List numbers) { - int total = 0; - for (int number : numbers) { - if (number % 2 == 0) { - total += number; - } - } - return total; - } - - public static int sumAllOverThree(List numbers) { - int total = 0; - for (int number : numbers) { - if (number > 3) { - total += number; - } - } - return total; - } -} diff --git a/src/main/java/nextstep/fp/MoveStrategy.java b/src/main/java/nextstep/fp/MoveStrategy.java deleted file mode 100644 index 1bd8c23c..00000000 --- a/src/main/java/nextstep/fp/MoveStrategy.java +++ /dev/null @@ -1,5 +0,0 @@ -package nextstep.fp; - -public interface MoveStrategy { - boolean isMovable(); -} diff --git a/src/main/java/nextstep/fp/StreamStudy.java b/src/main/java/nextstep/fp/StreamStudy.java deleted file mode 100644 index b446983a..00000000 --- a/src/main/java/nextstep/fp/StreamStudy.java +++ /dev/null @@ -1,44 +0,0 @@ -package nextstep.fp; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class StreamStudy { - - public static long countWords() throws IOException { - String contents = new String(Files.readAllBytes(Paths - .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); - List words = Arrays.asList(contents.split("[\\P{L}]+")); - - long count = 0; - for (String w : words) { - if (w.length() > 12) count++; - } - return count; - } - - public static void printLongestWordTop100() throws IOException { - String contents = new String(Files.readAllBytes(Paths - .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); - List words = Arrays.asList(contents.split("[\\P{L}]+")); - - // TODO 이 부분에 구현한다. - } - - public static List doubleNumbers(List numbers) { - return numbers.stream().map(x -> 2 * x).collect(Collectors.toList()); - } - - public static long sumAll(List numbers) { - return numbers.stream().reduce(0, (x, y) -> x + y); - } - - public static long sumOverThreeAndDouble(List numbers) { - return 0; - } -} \ No newline at end of file diff --git a/src/main/java/nextstep/optional/Computer.java b/src/main/java/nextstep/optional/Computer.java deleted file mode 100644 index cc0af4d7..00000000 --- a/src/main/java/nextstep/optional/Computer.java +++ /dev/null @@ -1,39 +0,0 @@ -package nextstep.optional; - -public class Computer { - private Soundcard soundcard; - - public Computer(Soundcard soundcard) { - this.soundcard = soundcard; - } - - public Soundcard getSoundcard() { - return soundcard; - } - - public static class Soundcard { - private USB usb; - - public Soundcard(USB usb) { - super(); - this.usb = usb; - } - - public USB getUsb() { - return usb; - } - } - - public static class USB { - private String version; - - public USB(String version) { - super(); - this.version = version; - } - - public String getVersion() { - return this.version; - } - } -} diff --git a/src/main/java/nextstep/optional/ComputerStore.java b/src/main/java/nextstep/optional/ComputerStore.java deleted file mode 100644 index 2695c967..00000000 --- a/src/main/java/nextstep/optional/ComputerStore.java +++ /dev/null @@ -1,26 +0,0 @@ -package nextstep.optional; - -import nextstep.optional.Computer.Soundcard; -import nextstep.optional.Computer.USB; - -public class ComputerStore { - public static final String UNKNOWN_VERSION = "UNKNOWN"; - - public static String getVersion(Computer computer) { - String version = UNKNOWN_VERSION; - if (computer != null) { - Soundcard soundcard = computer.getSoundcard(); - if (soundcard != null) { - USB usb = soundcard.getUsb(); - if (usb != null) { - version = usb.getVersion(); - } - } - } - return version; - } - - public static String getVersionOptional(Computer computer) { - return null; - } -} diff --git a/src/main/java/nextstep/optional/Expression.java b/src/main/java/nextstep/optional/Expression.java deleted file mode 100644 index 1c98cd6a..00000000 --- a/src/main/java/nextstep/optional/Expression.java +++ /dev/null @@ -1,25 +0,0 @@ -package nextstep.optional; - -enum Expression { - PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/"); - - private String expression; - - Expression(String expression) { - this.expression = expression; - } - - private static boolean matchExpression(Expression e, String expression) { - return expression.equals(e.expression); - } - - static Expression of(String expression) { - for (Expression v : values()) { - if (matchExpression(v, expression)) { - return v; - } - } - - throw new IllegalArgumentException(String.format("%s는 사칙연산에 해당하지 않는 표현식입니다.", expression)); - } -} diff --git a/src/main/java/nextstep/optional/User.java b/src/main/java/nextstep/optional/User.java deleted file mode 100644 index 9614c2f4..00000000 --- a/src/main/java/nextstep/optional/User.java +++ /dev/null @@ -1,69 +0,0 @@ -package nextstep.optional; - -public class User { - private String name; - private Integer age; - - public User(String name, Integer age) { - this.name = name; - this.age = age; - } - - public String getName() { - return name; - } - - public Integer getAge() { - return age; - } - - public boolean matchName(String name) { - return this.name.equals(name); - } - - public static boolean ageIsInRange1(User user) { - boolean isInRange = false; - - if (user != null && user.getAge() != null - && (user.getAge() >= 30 - && user.getAge() <= 45)) { - isInRange = true; - } - return isInRange; - } - - public static boolean ageIsInRange2(User user) { - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((age == null) ? 0 : age.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - User other = (User) obj; - if (age == null) { - if (other.age != null) - return false; - } else if (!age.equals(other.age)) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; - } -} diff --git a/src/main/java/nextstep/optional/Users.java b/src/main/java/nextstep/optional/Users.java deleted file mode 100644 index 6293040d..00000000 --- a/src/main/java/nextstep/optional/Users.java +++ /dev/null @@ -1,23 +0,0 @@ -package nextstep.optional; - -import java.util.Arrays; -import java.util.List; - -public class Users { - static final User DEFAULT_USER = new User("codesquad", 100); - - List users = Arrays.asList( - new User("crong", 35), - new User("pobi", 30), - new User("jk", 40), - new User("honux", 45)); - - User getUser(String name) { - for (User user : users) { - if (user.matchName(name)) { - return user; - } - } - return DEFAULT_USER; - } -} diff --git a/src/main/java/view/GameInputView.java b/src/main/java/view/GameInputView.java new file mode 100644 index 00000000..d70f575b --- /dev/null +++ b/src/main/java/view/GameInputView.java @@ -0,0 +1,62 @@ +package view; + +import java.io.IOException; +import java.util.Optional; + +public class GameInputView { + + private final static String ASK_PLAYER_MESSAGE = "게임에 참여할 사람의 이름을 입력하세요. (쉼표 기준으로 분리)"; + private final static String INVALID_INPUT_MESSAGE = "입력이 바르지 않습니다"; + private final static String ASK_BAT_AMOUNT_FORMAT = "%s의 배팅 금액은?"; + private final static String AKS_HIT_FORMAT = "%s는 한 장의 카드를 더 받겠습니까? (예는 y, 아니오는 n)"; + private final static String YES = "y"; + private final static String NO = "n"; + + + public static Optional askPlayerName(){ + String names; + try { + names = Terminal.in(ASK_PLAYER_MESSAGE); + } catch (IOException e) { + names = null; + Terminal.outln(INVALID_INPUT_MESSAGE); + } + + return Optional.ofNullable(names); + } + + public static Optional askBatAmount(String name) { + Integer batAmount; + + try { + Terminal.emptyln(); + String in = Terminal.in(String.format(ASK_BAT_AMOUNT_FORMAT, name)); + batAmount = Integer.parseInt(in); + } catch (IOException | NumberFormatException e) { + batAmount = null; + Terminal.outln(INVALID_INPUT_MESSAGE); + } + + return Optional.ofNullable(batAmount); + } + + public static Optional askHit(String name) { + Boolean isHit = null; + + try { + String in = Terminal.in(String.format(AKS_HIT_FORMAT, name)); + + if (in.equalsIgnoreCase(YES)) { + isHit = true; + } + + if (in.equalsIgnoreCase(NO)) { + isHit = false; + } + } catch (IOException e) { + Terminal.outln(INVALID_INPUT_MESSAGE); + } + + return Optional.ofNullable(isHit); + } +} diff --git a/src/main/java/view/GameOutputView.java b/src/main/java/view/GameOutputView.java new file mode 100644 index 00000000..21d0f772 --- /dev/null +++ b/src/main/java/view/GameOutputView.java @@ -0,0 +1,69 @@ +package view; + +import blackjack.card.Hand; +import blackjack.player.Dealer; +import blackjack.player.Gambler; +import blackjack.player.Player; + +import java.util.List; + +public class GameOutputView { + + private final static String DEAL_CARD_ANTECEDENT = "딜러에게 1장, "; + private final static String DEAL_CARD_SUBSEQUENT = "에게 2장의 카드를 나누었습니다."; + private final static String COMMA = ", "; + private final static String SHOW_CARD_ANTECEDENT_FORMAT = "%s 카드 : "; + private final static String SHOW_CARD_SUBSEQUENT_FORMAT = " - 결과: %d"; + private final static String ANNOUNCEMENT_DEALER_PLAY_FORMAT + = "딜러는 손패의 합이 17이상이 될 때까지 %d장의 카드를 더 받았습니다."; + private final static String ANNOUNCEMENT_RESULT = "## 최종 수익"; + private final static String NAME_AND_BAT_AMOUNT_PAIR_FORMAT = "%s: %.0f"; + + public static void announceDealResult(List gamblers) { + Terminal.emptyln(); + StringBuilder sb = new StringBuilder(); + sb.append(DEAL_CARD_ANTECEDENT); + for (int i = 0; i < gamblers.size(); i++) { + if (i != 0) { + sb.append(COMMA); + } + + sb.append(gamblers.get(i).getName()); + } + + sb.append(DEAL_CARD_SUBSEQUENT); + Terminal.outln(sb.toString()); + } + + public static void showHand(Player gambler) { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(SHOW_CARD_ANTECEDENT_FORMAT, gambler.getName())); + + Hand hand = gambler.getHand(); + for (int i = 0; i < hand.size(); i++) { + if (i != 0) { + sb.append(COMMA); + } + + sb.append(hand.get(i).getCardName()); + } + + sb.append(String.format(SHOW_CARD_SUBSEQUENT_FORMAT, hand.calculateHand())); + Terminal.outln(sb.toString()); + } + + public static void announceDealerPlay(int count) { + Terminal.emptyln(); + Terminal.outln(String.format(ANNOUNCEMENT_DEALER_PLAY_FORMAT, count)); + Terminal.emptyln(); + } + + public static void announceFinalProfit(Dealer dealer, List gamblers) { + Terminal.emptyln(); + Terminal.outln(ANNOUNCEMENT_RESULT); + Terminal.outln(String.format(NAME_AND_BAT_AMOUNT_PAIR_FORMAT, dealer.getName(), dealer.getChip())); + for (Gambler gambler : gamblers) { + Terminal.outln(String.format(NAME_AND_BAT_AMOUNT_PAIR_FORMAT, gambler.getName(), gambler.getChip())); + } + } +} diff --git a/src/main/java/view/Terminal.java b/src/main/java/view/Terminal.java new file mode 100644 index 00000000..6daa189e --- /dev/null +++ b/src/main/java/view/Terminal.java @@ -0,0 +1,23 @@ +package view; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Terminal { + + private static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + public static String in(String message) throws IOException { + outln(message); + return br.readLine(); + } + + public static void outln(String message) { + System.out.println(message); + } + + public static void emptyln() { + System.out.println(); + } +} diff --git a/src/test/java/blackjack/DealerTest.java b/src/test/java/blackjack/DealerTest.java new file mode 100644 index 00000000..7c7f6522 --- /dev/null +++ b/src/test/java/blackjack/DealerTest.java @@ -0,0 +1,51 @@ +package blackjack; + +import blackjack.card.Card; +import blackjack.card.Rank; +import blackjack.card.Suit; +import blackjack.player.Dealer; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DealerTest { + + @Test + void 생성() { + // given + Dealer dealer = new Dealer(); + + // when + String name = dealer.getName(); + + // then + assertThat(name).isEqualTo("딜러"); + } + + @Test + void 플레이_16이하() { + // given + Dealer dealer = new Dealer(); + dealer.addCardToHand(new Card(Rank.KING, Suit.HEART)); + + // when + boolean isPlay = dealer.isPlay(); + + // then + assertThat(isPlay).isTrue(); + } + + @Test + void 플레이_17이상() { + // given + Dealer dealer = new Dealer(); + dealer.addCardToHand(new Card(Rank.KING, Suit.HEART)); + dealer.addCardToHand(new Card(Rank.SEVEN, Suit.HEART)); + + // when + boolean isPlay = dealer.isPlay(); + + // then + assertThat(isPlay).isFalse(); + } +} diff --git a/src/test/java/blackjack/GamblerTest.java b/src/test/java/blackjack/GamblerTest.java new file mode 100644 index 00000000..33b12783 --- /dev/null +++ b/src/test/java/blackjack/GamblerTest.java @@ -0,0 +1,120 @@ +package blackjack; + +import blackjack.card.Card; +import blackjack.card.Rank; +import blackjack.card.Suit; +import blackjack.player.Gambler; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GamblerTest { + + @Test + void 생성() { + // given + Gambler gambler = new Gambler("pobi"); + + // when + String name = gambler.getName(); + + // then + assertThat(name).isEqualTo("pobi"); + } + + @Test + void 손_패_추가() { + // given + Gambler gambler = new Gambler("tester"); + + // when + gambler.addCardToHand(new Card(Rank.ACE, Suit.CLUB)); + + // then + assertThat(gambler.getHand().size()).isOne(); + assertThat(gambler.getHand().get(0)).isEqualTo(new Card(Rank.ACE, Suit.CLUB)); + } + + @ParameterizedTest + @CsvSource(value = {"CLUB_KING,HEART_KING,DIAMOND_TWO:22", "CLUB_KING,HEART_KING:20"}, delimiter = ':') + void 정산(String input, int expect) { + // given + Gambler gambler = new Gambler("tester"); + addHandFromInput(input, gambler); + + // when + int result = gambler.getHand().calculateHand(); + + // then + assertThat(result).isEqualTo(expect); + } + + @ParameterizedTest + @ValueSource(strings = {"CLUB_KING,HEART_KING,DIAMOND_ACE", "CLUB_KING,DIAMOND_ACE"}) + void 정산_에이스(String input) { + // given + Gambler gambler = new Gambler("tester"); + addHandFromInput(input, gambler); + + // when + int result = gambler.getHand().calculateHand(); + + // then + assertThat(result).isEqualTo(21); + } + + @ParameterizedTest + @CsvSource(value = {"CLUB_KING,HEART_KING,DIAMOND_TWO:true", "CLUB_KING,HEART_KING:false"}, delimiter = ':') + void 버스트_여부(String input, boolean expect) { + // given + Gambler gambler = new Gambler("tester"); + addHandFromInput(input, gambler); + + // when + boolean isBust = gambler.getHand().isBust(); + + // then + assertThat(isBust).isEqualTo(expect); + } + + @Test + void 블랙잭() { + // given + Gambler gambler = new Gambler("tester"); + gambler.addCardToHand(new Card(Rank.KING, Suit.CLUB)); + gambler.addCardToHand(new Card(Rank.ACE, Suit.DIAMOND)); + + // when + int result = gambler.getHand().calculateHand(); + + // then + assertThat(result).isEqualTo(21); + assertThat(gambler.getHand().isBlackJack()).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = {"CLUB_KING,HEART_SEVEN,DIAMOND_FIVE", "CLUB_KING,HEART_SEVEN", "CLUB_KING,HEART_KING,CLUB_ACE"}) + void 블랙잭_아님(String input) { + // given + Gambler gambler = new Gambler("tester"); + addHandFromInput(input, gambler); + + // when + boolean isBlackJack = gambler.getHand().isBlackJack(); + + // then + assertThat(isBlackJack).isFalse(); + } + + private static void addHandFromInput(String input, Gambler gambler) { + String[] cardNames = input.split(","); + for (String cardName : cardNames) { + String[] suitAndRank = cardName.split("_"); + Card card = new Card(Rank.valueOf(suitAndRank[1]), Suit.valueOf(suitAndRank[0])); + gambler.addCardToHand(card); + } + } +} diff --git a/src/test/java/nextstep/fp/CarTest.java b/src/test/java/nextstep/fp/CarTest.java deleted file mode 100644 index 1ab1106f..00000000 --- a/src/test/java/nextstep/fp/CarTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package nextstep.fp; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class CarTest { - @Test - public void 이동() { - Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return true; - } - }); - assertThat(actual).isEqualTo(new Car("pobi", 1)); - } - - @Test - public void 정지() { - Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return false; - } - }); - assertThat(actual).isEqualTo(new Car("pobi", 0)); - } -} diff --git a/src/test/java/nextstep/fp/LambdaTest.java b/src/test/java/nextstep/fp/LambdaTest.java deleted file mode 100644 index f240ac65..00000000 --- a/src/test/java/nextstep/fp/LambdaTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package nextstep.fp; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LambdaTest { - private List numbers; - - @BeforeEach - public void setup() { - numbers = Arrays.asList(1, 2, 3, 4, 5, 6); - } - - @Test - public void printAllOld() throws Exception { - Lambda.printAllOld(numbers); - } - - @Test - public void printAllLambda() throws Exception { - Lambda.printAllLambda(numbers); - } - - @Test - public void runThread() throws Exception { - Lambda.runThread(); - } - - @Test - public void sumAll() throws Exception { - int sum = Lambda.sumAll(numbers); - assertThat(sum).isEqualTo(21); - } - - @Test - public void sumAllEven() throws Exception { - int sum = Lambda.sumAllEven(numbers); - assertThat(sum).isEqualTo(12); - } - - @Test - public void sumAllOverThree() throws Exception { - int sum = Lambda.sumAllOverThree(numbers); - assertThat(sum).isEqualTo(15); - } -} diff --git a/src/test/java/nextstep/fp/StreamStudyTest.java b/src/test/java/nextstep/fp/StreamStudyTest.java deleted file mode 100644 index 2962521a..00000000 --- a/src/test/java/nextstep/fp/StreamStudyTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package nextstep.fp; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StreamStudyTest { - private List numbers; - - @BeforeEach - public void setup() { - numbers = Arrays.asList(1, 2, 3, 4, 5, 6); - } - - @Test - public void countWords() throws Exception { - long result = StreamStudy.countWords(); - System.out.println("result : " + result); - } - - @Test - public void printLongestWordTop100() throws Exception { - StreamStudy.printLongestWordTop100(); - } - - @Test - public void map() throws Exception { - List doubleNumbers = StreamStudy.doubleNumbers(numbers); - doubleNumbers.forEach(System.out::println); - } - - @Test - public void sumAll() throws Exception { - long sum = StreamStudy.sumAll(numbers); - assertThat(sum).isEqualTo(21); - } - - @Test - public void sumOverThreeAndDouble() throws Exception { - numbers = Arrays.asList(3, 1, 6, 2, 4, 8); - long sum = StreamStudy.sumOverThreeAndDouble(numbers); - assertThat(sum).isEqualTo(36); - } -} diff --git a/src/test/java/nextstep/optional/ComputerStoreTest.java b/src/test/java/nextstep/optional/ComputerStoreTest.java deleted file mode 100644 index b576253a..00000000 --- a/src/test/java/nextstep/optional/ComputerStoreTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package nextstep.optional; - -import nextstep.optional.Computer.Soundcard; -import nextstep.optional.Computer.USB; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ComputerStoreTest { - @Test - public void getVersion() { - String version = "pobi's usb"; - Soundcard soundcard = new Soundcard(new USB(version)); - Computer computer = new Computer(soundcard); - assertThat(ComputerStore.getVersion(computer)).isEqualTo(version); - } - - @Test - public void getVersionWhenComputerIsNull() throws Exception { - assertThat(ComputerStore.getVersion(null)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } - - @Test - public void getVersionWhenSoundcardIsNull() throws Exception { - Computer computer = new Computer(null); - assertThat(ComputerStore.getVersion(computer)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } - - @Test - public void getVersionWhenUSBIsNull() throws Exception { - Computer computer = new Computer(new Soundcard(null)); - assertThat(ComputerStore.getVersion(computer)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } - - @Test - public void getVersionOptional() { - String version = "pobi's usb"; - Soundcard soundcard = new Soundcard(new USB(version)); - Computer computer = new Computer(soundcard); - assertThat(ComputerStore.getVersionOptional(computer)).isEqualTo(version); - } - - @Test - public void getVersionOptionalWhenComputerIsNull() throws Exception { - assertThat(ComputerStore.getVersionOptional(null)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } - - @Test - public void getVersionOptionalWhenSoundcardIsNull() throws Exception { - Computer computer = new Computer(null); - assertThat(ComputerStore.getVersionOptional(computer)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } - - @Test - public void getVersionOptionalWhenUSBIsNull() throws Exception { - Computer computer = new Computer(new Soundcard(null)); - assertThat(ComputerStore.getVersionOptional(computer)).isEqualTo(ComputerStore.UNKNOWN_VERSION); - } -} diff --git a/src/test/java/nextstep/optional/ExpressionTest.java b/src/test/java/nextstep/optional/ExpressionTest.java deleted file mode 100644 index 32356261..00000000 --- a/src/test/java/nextstep/optional/ExpressionTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package nextstep.optional; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - - -public class ExpressionTest { - @Test - public void of() { - assertThat(Expression.PLUS == Expression.of("+")).isTrue(); - } - - @Test - public void notValidExpression() { - assertThatIllegalArgumentException() - .isThrownBy(() -> { - Expression.of("&"); - }); - } -} diff --git a/src/test/java/nextstep/optional/UserTest.java b/src/test/java/nextstep/optional/UserTest.java deleted file mode 100644 index bfc6af49..00000000 --- a/src/test/java/nextstep/optional/UserTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package nextstep.optional; - -import org.junit.jupiter.api.Test; - -import static nextstep.optional.User.ageIsInRange1; -import static nextstep.optional.User.ageIsInRange2; -import static org.assertj.core.api.Assertions.assertThat; - -public class UserTest { - @Test - public void whenFiltersWithoutOptional_thenCorrect() { - assertThat(ageIsInRange1(new User("crong", 35))).isTrue(); - assertThat(ageIsInRange1(new User("crong", 48))).isFalse(); - assertThat(ageIsInRange1(new User("crong", null))).isFalse(); - assertThat(ageIsInRange1(new User("crong", 29))).isFalse(); - assertThat(ageIsInRange1(null)).isFalse(); - } - - @Test - public void whenFiltersWithOptional_thenCorrect() { - assertThat(ageIsInRange2(new User("crong", 35))).isTrue(); - assertThat(ageIsInRange2(new User("crong", 48))).isFalse(); - assertThat(ageIsInRange2(new User("crong", null))).isFalse(); - assertThat(ageIsInRange2(new User("crong", 29))).isFalse(); - assertThat(ageIsInRange2(null)).isFalse(); - } -} diff --git a/src/test/java/nextstep/optional/UsersTest.java b/src/test/java/nextstep/optional/UsersTest.java deleted file mode 100644 index ec0f7329..00000000 --- a/src/test/java/nextstep/optional/UsersTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package nextstep.optional; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class UsersTest { - - @Test - public void getUser() { - Users users = new Users(); - assertThat(users.getUser("crong")).isEqualTo(new User("crong", 35)); - } - - - @Test - public void getDefaultUser() { - Users users = new Users(); - assertThat(users.getUser("codesquard")).isEqualTo(Users.DEFAULT_USER); - } -}