diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 077745658a..687147a995 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -5,9 +5,8 @@ import domain.player.Name; import domain.player.Player; import domain.player.dealer.Dealer; -import domain.player.dealer.DealerResult; +import domain.player.participant.Money; import domain.player.participant.Participant; -import domain.player.participant.ParticipantResult; import view.InputView; import view.OutputView; @@ -16,8 +15,6 @@ import java.util.Map; import java.util.stream.Collectors; -import static java.util.stream.Collectors.counting; - public class BlackJackController { public void run() { @@ -29,96 +26,103 @@ public void run() { final Dealer dealer = createDealer(); final List players = createPlayers(participants, dealer); - deal(cardTable, players); - - printStateAfterDeal(participants, dealer); - hittingPlayer(cardTable, participants, dealer); - printStateAfterHit(participants, dealer); + firstDeal(cardTable, players); + printStateAfterFirstDeal(participants, dealer); - final Map participantsResult = cardTable.determineWinner(participants, dealer); - final Map scoreBoard = countDealerResult(participantsResult); - - printPlayerScoreBoard(participants, participantsResult, scoreBoard); - } - - private static List createPlayers(final List participants, final Dealer dealer) { - List players = new ArrayList<>(participants); - players.add(dealer); + finalDeal(cardTable, participants, dealer); + printStateAfterFinalDeal(participants, dealer); - return players; + printPlayersMoneyBoard(cardTable, participants, dealer); } - private static void deal(final CardTable cardTable, final List players) { + private void firstDeal(final CardTable cardTable, final List players) { dealCard(cardTable, players); dealCard(cardTable, players); } - private static void dealCard(final CardTable cardTable, final List players) { + private void dealCard(final CardTable cardTable, final List players) { players.forEach(cardTable::dealCardTo); } - private static Dealer createDealer() { - return new Dealer(); + private void printStateAfterFirstDeal(final List participants, final Dealer dealer) { + OutputView.showDealtCardTo(participants); + OutputView.showStateOf(dealer); + OutputView.showStateOf(participants); } - private static List createParticipants() { - return InputView.readParticipantsName() - .stream() - .map(Name::new) - .map(Participant::new) - .collect(Collectors.toList()); + private void finalDeal(final CardTable cardTable, final List participants, final Dealer dealer) { + hitForParticipants(cardTable, participants); + hitForDealer(cardTable, dealer); } - private static void printPlayerScoreBoard(final List participants, - final Map playersResult, - final Map scoreBoard) { - OutputView.showDealerScoreBoard(scoreBoard); - OutputView.showParticipantsScoreBoard(playersResult, participants); + private void hitForParticipants(final CardTable cardTable, final List participants) { + participants.stream() + .filter(Participant::isNotBlackjack) + .forEach(participant -> hitForParticipant(cardTable, participant)); + } - private static void printStateAfterHit(final List participants, final Dealer dealer) { + private void hitForParticipant(final CardTable cardTable, final Participant participant) { + while (participant.canHit() && selectHitOrStand(participant)) { + cardTable.dealCardTo(participant); + OutputView.showStateOf(participant); + } + } + + private void hitForDealer(final CardTable cardTable, final Dealer dealer) { + do { + OutputView.dealerOneMoreCard(); + cardTable.dealCardTo(dealer); + } while (dealer.canHit()); + } + + private void printStateAfterFinalDeal(final List participants, final Dealer dealer) { OutputView.showPlayerStateResult(dealer); OutputView.showParticipantsStateResult(participants); } - private static void printStateAfterDeal(final List participants, final Dealer dealer) { - OutputView.showDealtCardTo(participants); - OutputView.showStateOf(dealer); - OutputView.showStateOf(participants); + private void printPlayersMoneyBoard(final CardTable cardTable, final List participants, + final Dealer dealer) { + printParticipantsMoneyBoard(cardTable, participants, dealer); + printDealerMoneyBoard(cardTable, participants, dealer); } - private static Map countDealerResult( - final Map playersResult) { - return playersResult.keySet() - .stream() - .collect(Collectors.groupingBy(participant -> playersResult.get(participant) - .convertToDealerResult(), - counting())); + private void printParticipantsMoneyBoard(final CardTable cardTable, final List participants, + final Dealer dealer) { + final Map participantsResult = cardTable.determineParticipantsBettingMoney(participants, + dealer); + OutputView.showBettingMoneyBoard(participantsResult); } - private void hittingPlayer(final CardTable cardTable, final List participants, final Dealer dealer) { - hitForParticipants(cardTable, participants); - hitForDealer(cardTable, dealer); + private void printDealerMoneyBoard(final CardTable cardTable, final List participants, + final Dealer dealer) { + final Money money = cardTable.determineDealerMoney(participants, dealer); + OutputView.showDealerMoneyBoard(money); } - private void hitForDealer(final CardTable cardTable, final Dealer dealer) { - do { - OutputView.dealerOneMoreCard(); - } while (cardTable.dealCardTo(dealer)); + private List createPlayers(final List participants, final Dealer dealer) { + List players = new ArrayList<>(participants); + players.add(dealer); + + return players; } - private void hitForParticipants(final CardTable cardTable, final List participants) { - participants.forEach(participant -> hitForParticipant(cardTable, participant)); + private Dealer createDealer() { + return new Dealer(); } - private void hitForParticipant(final CardTable cardTable, final Participant participant) { - while (inputHitOrStay(participant)) { - cardTable.dealCardTo(participant); - OutputView.showStateOf(participant); - } + private List createParticipants() { + return InputView.readParticipantsName() + .stream() + .map(Name::new) + .map(name -> { + final int bettingMoney = InputView.readBettingMoney(name); + return new Participant(name, Money.wons(bettingMoney)); + }) + .collect(Collectors.toList()); } - private boolean inputHitOrStay(final Participant participant) { - return InputView.readMoreCard(participant).equals("y"); + private boolean selectHitOrStand(final Participant participant) { + return InputView.readMoreCard(participant); } } diff --git a/src/main/java/domain/Score.java b/src/main/java/domain/Score.java index e0c322b8fc..4869ce97bd 100644 --- a/src/main/java/domain/Score.java +++ b/src/main/java/domain/Score.java @@ -8,7 +8,7 @@ public class Score { private static final Score UPPER_LIMIT_SCORE = new Score(21); - private static final Score REMAIN_SCORE_ACE = new Score(10); + private static final Score SOFT_HAND_SCORE = new Score(10); private final int value; @@ -36,11 +36,11 @@ public boolean isGreaterThan(final Score other) { return value > other.value; } - public Score plusTenIfNotBurst() { - final Score plusScore = this.plus(REMAIN_SCORE_ACE); + public Score plusSoftHand() { + final Score plusScore = this.plus(SOFT_HAND_SCORE); if (plusScore.isLessEqualThan(UPPER_LIMIT_SCORE)) { - return this.plus(REMAIN_SCORE_ACE); + return this.plus(SOFT_HAND_SCORE); } return this; @@ -50,6 +50,14 @@ public Score plus(Score other) { return new Score(value + other.value); } + public boolean isSumTwentyOne() { + return this.equals(UPPER_LIMIT_SCORE); + } + + public boolean isSame(final Score other) { + return this.equals(other); + } + @Override public boolean equals(final Object o) { if (this == o) return true; diff --git a/src/main/java/domain/card/Card.java b/src/main/java/domain/card/Card.java index 7aa46e7c82..ab4e2cb53b 100644 --- a/src/main/java/domain/card/Card.java +++ b/src/main/java/domain/card/Card.java @@ -22,8 +22,12 @@ public CardValue cardValue() { @Override public boolean equals(final Object o) { - if (this == o) return true; - if (!(o instanceof Card)) return false; + if (this == o) { + return true; + } + if (!(o instanceof Card)) { + return false; + } final Card card = (Card) o; return cardShape == card.cardShape && cardValue == card.cardValue; } diff --git a/src/main/java/domain/cardtable/CardTable.java b/src/main/java/domain/cardtable/CardTable.java index 8f02a9dd76..53c660ed3c 100644 --- a/src/main/java/domain/cardtable/CardTable.java +++ b/src/main/java/domain/cardtable/CardTable.java @@ -3,8 +3,9 @@ import domain.deck.CardDeck; import domain.player.Player; import domain.player.dealer.Dealer; +import domain.player.participant.Money; import domain.player.participant.Participant; -import domain.player.participant.ParticipantResult; +import domain.player.participant.betresult.resultfinder.BetResultFinder; import java.util.List; import java.util.Map; @@ -14,45 +15,41 @@ public class CardTable { private final CardDeck cardDeck; + private final BetResultFinder betResultFinder; private CardTable(final CardDeck cardDeck) { this.cardDeck = cardDeck; + this.betResultFinder = new BetResultFinder(); } public static CardTable readyToPlayBlackjack(final CardDeck cardDeck) { return new CardTable(cardDeck); } - public Map determineWinner(final List participants, - final Dealer dealer) { + public Map determineParticipantsBettingMoney(final List participants, + final Dealer dealer) { + return participants.stream() .collect(Collectors.toMap( Function.identity(), - participant -> matchBetween(participant, dealer)) - ); + participant -> participant.determineBetMoney( + betResultFinder.findStateOf(participant, dealer)) + )); } - private ParticipantResult matchBetween(final Participant participant, final Dealer dealer) { - if (participant.isBust()) { - return ParticipantResult.LOSER; - } - if (dealer.isBust()) { - return ParticipantResult.WINNER; - } - if (participant.score().isGreaterThan(dealer.score())) { - return ParticipantResult.WINNER; - } - if (participant.score().equals(dealer.score())) { - return ParticipantResult.DRAWER; - } - return ParticipantResult.LOSER; + public Money determineDealerMoney(final List participants, final Dealer dealer) { + + final Map participantsResultMoney = determineParticipantsBettingMoney(participants, dealer); + + return participantsResultMoney.values() + .stream() + .reduce(Money.MIN, Money::plus) + .lose(); } - public boolean dealCardTo(Player player) { + public void dealCardTo(Player player) { if (player.canHit()) { player.hit(cardDeck.draw()); - return true; } - return false; } } diff --git a/src/main/java/domain/area/CardArea.java b/src/main/java/domain/hand/Hand.java similarity index 74% rename from src/main/java/domain/area/CardArea.java rename to src/main/java/domain/hand/Hand.java index f002e55ec0..a33bcfec55 100644 --- a/src/main/java/domain/area/CardArea.java +++ b/src/main/java/domain/hand/Hand.java @@ -1,4 +1,4 @@ -package domain.area; +package domain.hand; import domain.Score; import domain.card.Card; @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; -public class CardArea { +public class Hand { private final List cards = new ArrayList<>(); @@ -21,8 +21,8 @@ public void addCard(final Card card) { public Score calculate() { Score score = score(); - if (hasAce()) { - score = score.plusTenIfNotBurst(); + if (isSoftHand()) { + return score.plusSoftHand(); } return score; @@ -35,7 +35,7 @@ private Score score() { } - private boolean hasAce() { + private boolean isSoftHand() { return cards.stream() .anyMatch(card -> card.cardValue().isAce()); } @@ -48,7 +48,15 @@ public boolean isBust() { return calculate().isBust(); } + public boolean isBlackjack() { + return cards.size() == 2 && calculate().isSumTwentyOne(); + } + public Card firstCard() { return cards.get(0); } + + public Card secondCard() { + return cards.get(1); + } } diff --git a/src/main/java/domain/player/Player.java b/src/main/java/domain/player/Player.java index 89b488952c..dbd0f31357 100644 --- a/src/main/java/domain/player/Player.java +++ b/src/main/java/domain/player/Player.java @@ -1,38 +1,54 @@ package domain.player; import domain.Score; -import domain.area.CardArea; import domain.card.Card; +import domain.hand.Hand; + +import java.util.List; public abstract class Player { - protected final CardArea cardArea; + protected final Hand hand; private final Name name; protected Player(final Name name) { this.name = name; - cardArea = new CardArea(); + hand = new Hand(); } public Name name() { return name; } - public CardArea cardArea() { - return cardArea; + public Hand hand() { + return hand; } public boolean isBust() { - return cardArea.isBust(); + return hand.isBust(); + } + + public boolean isNotBust() { + return !isBust(); } public void hit(final Card card) { - cardArea.addCard(card); + hand.addCard(card); } public abstract boolean canHit(); public Score score() { - return cardArea.calculate(); + return hand.calculate(); + } + + public boolean isBlackjack() { + return hand.isBlackjack(); + } + + public boolean isNotBlackjack() { + return !isBlackjack(); } + + public abstract List faceUpFirstDeal(); } diff --git a/src/main/java/domain/player/dealer/Dealer.java b/src/main/java/domain/player/dealer/Dealer.java index b3153718d9..535fc88ea0 100644 --- a/src/main/java/domain/player/dealer/Dealer.java +++ b/src/main/java/domain/player/dealer/Dealer.java @@ -5,6 +5,8 @@ import domain.player.Name; import domain.player.Player; +import java.util.List; + public class Dealer extends Player { private static final int DEALER_LIMIT_SCORE = 16; @@ -19,7 +21,8 @@ public boolean canHit() { return score().isLessEqualThan(new Score(DEALER_LIMIT_SCORE)); } - public Card faceUpFirstCard() { - return cardArea.firstCard(); + @Override + public List faceUpFirstDeal() { + return List.of(hand.firstCard()); } } diff --git a/src/main/java/domain/player/dealer/DealerResult.java b/src/main/java/domain/player/dealer/DealerResult.java deleted file mode 100644 index 8ce8fb1604..0000000000 --- a/src/main/java/domain/player/dealer/DealerResult.java +++ /dev/null @@ -1,8 +0,0 @@ -package domain.player.dealer; - -public enum DealerResult { - - WINNER, - LOSER, - DRAWER; -} diff --git a/src/main/java/domain/player/participant/Money.java b/src/main/java/domain/player/participant/Money.java new file mode 100644 index 0000000000..292165bc5d --- /dev/null +++ b/src/main/java/domain/player/participant/Money.java @@ -0,0 +1,59 @@ +package domain.player.participant; + +import java.math.BigDecimal; +import java.util.Objects; + +public class Money { + + public static final Money MIN = new Money(BigDecimal.valueOf(0)); + private static final int LOSE_MONEY = -1; + + private final BigDecimal value; + + private Money(BigDecimal value) { + this.value = value; + } + + public static Money wons(int amount) { + return new Money(BigDecimal.valueOf(amount)); + } + + public static Money wons(double amount) { + return new Money(BigDecimal.valueOf(amount)); + } + + public BigDecimal value() { + return value; + } + + public Money breakEven() { + return this; + } + + public Money times(final double percent) { + final BigDecimal percentage = BigDecimal.valueOf(percent); + + return new Money(value.multiply(percentage)); + } + + public Money lose() { + return new Money(value.multiply(BigDecimal.valueOf(LOSE_MONEY))); + } + + public Money plus(Money other) { + return new Money(value.add(other.value)); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Money money = (Money) o; + return value.compareTo(money.value) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/src/main/java/domain/player/participant/Participant.java b/src/main/java/domain/player/participant/Participant.java index 1af8f1dcd1..c440b3e76c 100644 --- a/src/main/java/domain/player/participant/Participant.java +++ b/src/main/java/domain/player/participant/Participant.java @@ -1,16 +1,32 @@ package domain.player.participant; +import domain.card.Card; import domain.player.Name; import domain.player.Player; +import domain.player.participant.betresult.resultstate.BetResultState; + +import java.util.List; public class Participant extends Player { - public Participant(final Name name) { + private final Money money; + + public Participant(final Name name, final Money money) { super(name); + this.money = money; } @Override public boolean canHit() { - return cardArea.canMoreCard(); + return hand.canMoreCard(); + } + + public Money determineBetMoney(BetResultState betResultState) { + return betResultState.calculateBetOutcomeOf(money); + } + + @Override + public List faceUpFirstDeal() { + return List.of(hand.firstCard(), hand.secondCard()); } } diff --git a/src/main/java/domain/player/participant/ParticipantResult.java b/src/main/java/domain/player/participant/ParticipantResult.java deleted file mode 100644 index 5030bc07b3..0000000000 --- a/src/main/java/domain/player/participant/ParticipantResult.java +++ /dev/null @@ -1,19 +0,0 @@ -package domain.player.participant; - -import domain.player.dealer.DealerResult; - -public enum ParticipantResult { - WINNER, - LOSER, - DRAWER; - - public DealerResult convertToDealerResult() { - if (this == WINNER) { - return DealerResult.LOSER; - } - if (this == LOSER) { - return DealerResult.WINNER; - } - return DealerResult.DRAWER; - } -} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/BetResult.java b/src/main/java/domain/player/participant/betresult/resultfinder/BetResult.java new file mode 100644 index 0000000000..fc81868f25 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/BetResult.java @@ -0,0 +1,12 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; + +public interface BetResult { + + Boolean canApply(Participant participant, Dealer dealer); + + BetResultState state(); +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/BetResultFinder.java b/src/main/java/domain/player/participant/betresult/resultfinder/BetResultFinder.java new file mode 100644 index 0000000000..c65e74f5ca --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/BetResultFinder.java @@ -0,0 +1,29 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.BreakEvenState; + +import java.util.List; + +public class BetResultFinder { + + private final List betResults + = List.of( + new DealerBlackjack(), + new DealerBust(), + new ParticipantBlackjack(), + new ParticipantBust(), + new ParticipantLose(), + new PlayerDraw() + ); + + public BetResultState findStateOf(Participant participant, Dealer dealer) { + return betResults.stream() + .filter(it -> it.canApply(participant, dealer)) + .map(BetResult::state) + .findFirst() + .orElse(new BreakEvenState()); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/DealerBlackjack.java b/src/main/java/domain/player/participant/betresult/resultfinder/DealerBlackjack.java new file mode 100644 index 0000000000..0ed4feb317 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/DealerBlackjack.java @@ -0,0 +1,19 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.LoseState; + +public class DealerBlackjack implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return !participant.isBlackjack() && dealer.isBlackjack(); + } + + @Override + public BetResultState state() { + return new LoseState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/DealerBust.java b/src/main/java/domain/player/participant/betresult/resultfinder/DealerBust.java new file mode 100644 index 0000000000..bdf7b203bb --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/DealerBust.java @@ -0,0 +1,19 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.BreakEvenState; + +public class DealerBust implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return dealer.isBust() && participant.isNotBust(); + } + + @Override + public BetResultState state() { + return new BreakEvenState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBlackjack.java b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBlackjack.java new file mode 100644 index 0000000000..4387db3a26 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBlackjack.java @@ -0,0 +1,19 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.WinState; + +public class ParticipantBlackjack implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return participant.isBlackjack() && !dealer.isBlackjack(); + } + + @Override + public BetResultState state() { + return new WinState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBust.java b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBust.java new file mode 100644 index 0000000000..c36cf1f2c2 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantBust.java @@ -0,0 +1,19 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.LoseState; + +public class ParticipantBust implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return participant.isBust(); + } + + @Override + public BetResultState state() { + return new LoseState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantLose.java b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantLose.java new file mode 100644 index 0000000000..5f44b440ed --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/ParticipantLose.java @@ -0,0 +1,19 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.LoseState; + +public class ParticipantLose implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return participant.score().isLessThan(dealer.score()); + } + + @Override + public BetResultState state() { + return new LoseState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultfinder/PlayerDraw.java b/src/main/java/domain/player/participant/betresult/resultfinder/PlayerDraw.java new file mode 100644 index 0000000000..375320fd5d --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultfinder/PlayerDraw.java @@ -0,0 +1,20 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.player.dealer.Dealer; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.BreakEvenState; + +public class PlayerDraw implements BetResult { + + @Override + public Boolean canApply(final Participant participant, final Dealer dealer) { + return (participant.isBlackjack() && dealer.isBlackjack()) || + participant.score().isSame(dealer.score()); + } + + @Override + public BetResultState state() { + return new BreakEvenState(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultstate/BetResultState.java b/src/main/java/domain/player/participant/betresult/resultstate/BetResultState.java new file mode 100644 index 0000000000..4d84f1320d --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultstate/BetResultState.java @@ -0,0 +1,9 @@ +package domain.player.participant.betresult.resultstate; + +import domain.player.participant.Money; + +@FunctionalInterface +public interface BetResultState { + + Money calculateBetOutcomeOf(final Money money); +} diff --git a/src/main/java/domain/player/participant/betresult/resultstate/BreakEvenState.java b/src/main/java/domain/player/participant/betresult/resultstate/BreakEvenState.java new file mode 100644 index 0000000000..282c00d5a3 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultstate/BreakEvenState.java @@ -0,0 +1,11 @@ +package domain.player.participant.betresult.resultstate; + +import domain.player.participant.Money; + +public class BreakEvenState implements BetResultState { + + @Override + public Money calculateBetOutcomeOf(final Money money) { + return money.breakEven(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultstate/LoseState.java b/src/main/java/domain/player/participant/betresult/resultstate/LoseState.java new file mode 100644 index 0000000000..69019614ef --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultstate/LoseState.java @@ -0,0 +1,11 @@ +package domain.player.participant.betresult.resultstate; + +import domain.player.participant.Money; + +public class LoseState implements BetResultState { + + @Override + public Money calculateBetOutcomeOf(final Money money) { + return money.lose(); + } +} diff --git a/src/main/java/domain/player/participant/betresult/resultstate/WinState.java b/src/main/java/domain/player/participant/betresult/resultstate/WinState.java new file mode 100644 index 0000000000..cf2352da13 --- /dev/null +++ b/src/main/java/domain/player/participant/betresult/resultstate/WinState.java @@ -0,0 +1,13 @@ +package domain.player.participant.betresult.resultstate; + +import domain.player.participant.Money; + +public class WinState implements BetResultState { + + private static final double WINNER_PERCENT = 1.5; + + @Override + public Money calculateBetOutcomeOf(final Money money) { + return money.times(WINNER_PERCENT); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 86a1f9e26f..09435a8527 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,5 +1,6 @@ package view; +import domain.player.Name; import domain.player.participant.Participant; import java.util.Arrays; @@ -24,7 +25,7 @@ public static List readParticipantsName() { .collect(Collectors.toList()); } - public static String readMoreCard(final Participant participant) { + public static boolean readMoreCard(final Participant participant) { System.out.println(participant.name().value() + "는 한장의 카드를 더 받으시겠습니다?(예는 y, 아니오는 n)"); final String input = scanner.nextLine(); @@ -33,7 +34,7 @@ public static String readMoreCard(final Participant participant) { return readMoreCard(participant); } - return input; + return input.equals(YES_COMMAND); } private static boolean validateIneligibleCommand(final String input) { @@ -50,4 +51,10 @@ private static boolean validateIneligibleCommand(final String input) { private static boolean ineligibleCommand(final String input) { return !input.equals(YES_COMMAND) && !input.equals(NO_COMMAND); } + + public static int readBettingMoney(final Name name) { + System.out.println(name.value() + "의 배팅 금액은?"); + + return Integer.parseInt(scanner.nextLine()); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 602bcf5bae..b2b4b8fad9 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,13 +1,11 @@ package view; -import domain.card.Card; import domain.card.CardShape; import domain.card.CardValue; import domain.player.Player; import domain.player.dealer.Dealer; -import domain.player.dealer.DealerResult; +import domain.player.participant.Money; import domain.player.participant.Participant; -import domain.player.participant.ParticipantResult; import java.util.EnumMap; import java.util.List; @@ -18,20 +16,15 @@ public class OutputView { private static final Map SHAPE_MESSAGE_MAP = new EnumMap<>(CardShape.class); private static final Map VALUE_MESSAGE_MAP = new EnumMap<>(CardValue.class); - private static final Map PARTICIPANT_RESULT_MAP = new EnumMap<>(ParticipantResult.class); - private static final Map DEALER_RESULT_MAP = new EnumMap<>(DealerResult.class); private static final String DELIM = ", "; private static final String CARD_INFORMATION_FORMAT = "카드: "; private static final String DEALER_INFORMATION_FORMAT = "딜러: "; - private static final String EMPTY_DELIM = " "; private static final String COLON = ": "; static { makeShapeMessage(); makeValueMessage(); - makeParticipantResultMessage(); - makeDealerResultMessage(); } private OutputView() { @@ -60,18 +53,6 @@ private static void makeValueMessage() { VALUE_MESSAGE_MAP.put(CardValue.ACE, "A"); } - private static void makeParticipantResultMessage() { - PARTICIPANT_RESULT_MAP.put(ParticipantResult.WINNER, "승"); - PARTICIPANT_RESULT_MAP.put(ParticipantResult.LOSER, "패"); - PARTICIPANT_RESULT_MAP.put(ParticipantResult.DRAWER, "무"); - } - - private static void makeDealerResultMessage() { - DEALER_RESULT_MAP.put(DealerResult.WINNER, "승"); - DEALER_RESULT_MAP.put(DealerResult.LOSER, "패"); - DEALER_RESULT_MAP.put(DealerResult.DRAWER, "무"); - } - public static void showDealtCardTo(final List participants) { System.out.println("딜러와 " + printDrawing(participants) + "에게 2장을 나누었습니다"); } @@ -83,13 +64,11 @@ private static String printDrawing(final List participants) { } public static void showStateOf(final Dealer dealer) { - final Card card = dealer.faceUpFirstCard(); - - System.out.println(getPlayerName(dealer) - + COLON - + VALUE_MESSAGE_MAP.get(card.cardValue()) - + SHAPE_MESSAGE_MAP.get(card.cardShape()) - ); + dealer.faceUpFirstDeal() + .forEach(card -> System.out.println(getPlayerName(dealer) + + COLON + + VALUE_MESSAGE_MAP.get(card.cardValue()) + + SHAPE_MESSAGE_MAP.get(card.cardShape()))); } public static void showStateOf(final List participants) { @@ -101,7 +80,7 @@ public static void showStateOf(final Player player) { } private static String makeStateMessage(final Player player) { - return player.cardArea() + return player.hand() .cards() .stream() .map(card -> String.format("%s %s", @@ -116,18 +95,26 @@ public static void showParticipantsStateResult(final List part } public static void showPlayerStateResult(final Player player) { - final String message = player.cardArea().cards().stream() + final String message = player.hand().cards().stream() .map(card -> String.format("%s %s", VALUE_MESSAGE_MAP.get(card.cardValue()), SHAPE_MESSAGE_MAP.get(card.cardShape()))) .collect(Collectors.joining(DELIM, getPlayerName(player) + CARD_INFORMATION_FORMAT, String.format(" - 결과: %d", - player.cardArea().calculate().value()))); + player.hand().calculate().value()))); System.out.println(message); } + public static void showBettingMoneyBoard(final Map bettingMoneyBoard) { + System.out.println("## 최종 수익"); + + for (final Participant participant : bettingMoneyBoard.keySet()) { + System.out.println(getPlayerName(participant) + COLON + bettingMoneyBoard.get(participant).value()); + } + } + private static String getPlayerName(final Player player) { return player.name().value(); } @@ -136,23 +123,7 @@ public static void dealerOneMoreCard() { System.out.println("딜러는 16 이하라 한장의 카드를 더 받았습니다."); } - public static void showDealerScoreBoard(final Map scoreBoard) { - - System.out.println(scoreBoard.keySet() - .stream() - .map(dealerResult -> scoreBoard.get(dealerResult) - + DEALER_RESULT_MAP.get(dealerResult)) - .collect(Collectors.joining(EMPTY_DELIM, DEALER_INFORMATION_FORMAT, ""))); - } - - public static void showParticipantsScoreBoard(final Map scoreBoard, - final List participants) { - - participants.stream() - .map(participant -> getPlayerName(participant) - + COLON - + PARTICIPANT_RESULT_MAP.get(scoreBoard.get(participant)) - ) - .forEach(System.out::println); + public static void showDealerMoneyBoard(final Money dealerMoney) { + System.out.println(DEALER_INFORMATION_FORMAT + dealerMoney.value()); } } diff --git a/src/test/java/domain/ScoreTest.java b/src/test/java/domain/ScoreTest.java index c20bdcac60..0c4cc7f358 100644 --- a/src/test/java/domain/ScoreTest.java +++ b/src/test/java/domain/ScoreTest.java @@ -152,6 +152,34 @@ void test_plusIfNotBurst(final int value, final int sum) throws Exception { final Score result = new Score(sum); //when & then - assertEquals(origin.plusTenIfNotBurst(), result); + assertEquals(origin.plusSoftHand(), result); + } + + @ParameterizedTest + @CsvSource(value = { + "21 -> true", + "20 -> false", + "0 -> false", + }, delimiterString = " -> ") + @DisplayName("isSumTwentyOne() : 점수가 21이다.") + void test_isBlackjack(final int value, final boolean isBlackjack) throws Exception { + //when & then + assertEquals(new Score(value).isSumTwentyOne(), isBlackjack); + } + + @ParameterizedTest + @CsvSource({ + "21,21,true", + "20,20,true", + "21,20,false" + }) + @DisplayName("isSame() : 같은 점수일 경우 true를 반환한다.") + void test_isSame(final int value1, final int value2, final boolean result) throws Exception { + //given + final Score score1 = new Score(value1); + final Score score2 = new Score(value2); + + //when & then + assertEquals(result, score1.isSame(score2)); } } diff --git a/src/test/java/domain/area/CardAreaTest.java b/src/test/java/domain/area/CardAreaTest.java deleted file mode 100644 index 87aa325cb1..0000000000 --- a/src/test/java/domain/area/CardAreaTest.java +++ /dev/null @@ -1,205 +0,0 @@ -package domain.area; - -import domain.Score; -import domain.card.Card; -import domain.card.CardShape; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -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.CsvSource; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.stream.Stream; - -import static domain.card.CardValue.ACE; -import static domain.card.CardValue.FOUR; -import static domain.card.CardValue.JACK; -import static domain.card.CardValue.NINE; -import static domain.card.CardValue.SEVEN; -import static domain.card.CardValue.SIX; -import static domain.card.CardValue.TEN; -import static domain.card.CardValue.THREE; -import static domain.card.CardValue.valueOf; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@SuppressWarnings("NonAsciiCharacters") -@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -@DisplayName("CardArea 은") -class CardAreaTest { - - @Test - void 카드를_추가할_수_있다() { - // given - final CardArea cardArea = new CardArea(); - - // when - final int beforeSize = cardArea.cards().size(); - cardArea.addCard(new Card(CardShape.CLOVER, FOUR)); - - // then - assertThat(cardArea.cards().size()).isEqualTo(beforeSize + 1); - } - - @ParameterizedTest(name = "카드 목록이 {0} 일 때, 총합은 {1}다.") - @CsvSource(value = { - "TWO+THREE = 5", - "FIVE+SIX = 11", - "TWO+TWO = 4", - "TEN+TEN = 20", - }, delimiterString = " = ") - void 자신이_가진_카드의_합을_구할_수_있다(final String values, final int totalScore) { - // given - final String[] split = values.split("\\+"); - - final CardArea cardArea = new CardArea(); - - // when - cardArea.addCard(new Card(CardShape.CLOVER, valueOf(split[0]))); - cardArea.addCard(new Card(CardShape.CLOVER, valueOf(split[1]))); - - // then - assertThat(cardArea.calculate()).isEqualTo(new Score(totalScore)); - } - - @ParameterizedTest(name = "킹, 퀸, 잭은 10으로 계산한다") - @CsvSource(value = { - "KING+QUEEN = 20", - "KING+JACK = 20", - "QUEEN+JACK = 20", - "KING+THREE = 13", - "QUEEN+THREE = 13", - "JACK+SIX = 16", - }, delimiterString = " = ") - void 킹_퀸_잭은_10으로_계산한다(final String values, final int totalScore) { - // given - final String[] split = values.split("\\+"); - final CardArea cardArea = new CardArea(); - - cardArea.addCard(new Card(CardShape.CLOVER, valueOf(split[0]))); - cardArea.addCard(new Card(CardShape.CLOVER, valueOf(split[1]))); - - // when & then - assertThat(cardArea.calculate()).isEqualTo(new Score(totalScore)); - } - - @ParameterizedTest(name = "[{index}] ACE 는 이전까지의 총합이 10 이하면 11로 계산한다") - @MethodSource("containsAceCardArea") - void ACE_는_이전까지의_총합이_10_이하면_11로_계산한다(final CardArea cardArea, final int totalScore) { - // then - assertThat(cardArea.calculate()).isEqualTo(new Score(totalScore)); - } - - static Stream containsAceCardArea() { - - // 10 + [11] = 21 - final CardArea cardArea1 = new CardArea(); - cardArea1.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea1.addCard(new Card(CardShape.CLOVER, ACE)); - - // 10 + 10 + [1] = 21 - final CardArea cardArea2 = new CardArea(); - cardArea2.addCard(new Card(CardShape.CLOVER, JACK)); - cardArea2.addCard(new Card(CardShape.CLOVER, TEN)); - - cardArea2.addCard(new Card(CardShape.CLOVER, ACE)); - - // [11] + 9 + [1] = 21 - final CardArea cardArea3 = new CardArea(); - cardArea3.addCard(new Card(CardShape.CLOVER, ACE)); - cardArea3.addCard(new Card(CardShape.CLOVER, NINE)); - - cardArea3.addCard(new Card(CardShape.CLOVER, ACE)); - - // [11] + 6 + 3 = 20 - final CardArea cardArea4 = new CardArea(); - cardArea4.addCard(new Card(CardShape.CLOVER, SIX)); - cardArea4.addCard(new Card(CardShape.CLOVER, THREE)); - - cardArea4.addCard(new Card(CardShape.CLOVER, ACE)); - - // [11] + 10 = 21 - final CardArea cardArea5 = new CardArea(); - cardArea5.addCard(new Card(CardShape.CLOVER, ACE)); - cardArea5.addCard(new Card(CardShape.CLOVER, TEN)); - - // 10 + [1] + 7 = 18 - final CardArea cardArea6 = new CardArea(); - cardArea6.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea6.addCard(new Card(CardShape.CLOVER, ACE)); - - cardArea6.addCard(new Card(CardShape.SPADE, SEVEN)); - - return Stream.of( - Arguments.of(cardArea1, 21), - Arguments.of(cardArea2, 21), - Arguments.of(cardArea3, 21), - Arguments.of(cardArea4, 20), - Arguments.of(cardArea5, 21), - Arguments.of(cardArea6, 18) - ); - } - - @Test - void 총합이_20_이하면_카드를_더_받을_수_있는_상태이다() { - // given - final CardArea cardArea = new CardArea(); - cardArea.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea.addCard(new Card(CardShape.CLOVER, TEN)); - - // when & then - assertTrue(cardArea.canMoreCard()); - } - - @Test - void 총합이_21_이상이면_카드를_더_받을_수_없는_상태이다() { - // given - final CardArea cardArea = new CardArea(); - cardArea.addCard(new Card(CardShape.CLOVER, ACE)); - cardArea.addCard(new Card(CardShape.SPADE, TEN)); - - // when & then - assertFalse(cardArea.canMoreCard()); - } - - @Test - void 총합이_21_초과이면_버스트_된다() { - // given - final CardArea cardArea = new CardArea(); - cardArea.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea.addCard(new Card(CardShape.SPADE, TEN)); - - cardArea.addCard(new Card(CardShape.DIAMOND, TEN)); - - // when & then - assertTrue(cardArea.isBust()); - } - - @Test - void 총합이_21_이하이면_버스트_아니다() { - // given - final CardArea cardArea = new CardArea(); - cardArea.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea.addCard(new Card(CardShape.CLOVER, ACE)); - - // when & then - assertFalse(cardArea.isBust()); - } - - @Test - void 딜러는_첫_장만_보여줄_수_있다() { - // given - final CardArea cardArea = new CardArea(); - - cardArea.addCard(new Card(CardShape.CLOVER, TEN)); - cardArea.addCard(new Card(CardShape.CLOVER, SEVEN)); - - // when & then - assertEquals(cardArea.firstCard(), new Card(CardShape.CLOVER, TEN)); - } -} diff --git a/src/test/java/domain/cardtable/CardTableTest.java b/src/test/java/domain/cardtable/CardTableTest.java index c1861c1824..8f69f2d496 100644 --- a/src/test/java/domain/cardtable/CardTableTest.java +++ b/src/test/java/domain/cardtable/CardTableTest.java @@ -1,12 +1,11 @@ package domain.cardtable; import domain.card.Card; -import domain.card.CardShape; import domain.deck.CardDeck; import domain.player.Name; import domain.player.dealer.Dealer; +import domain.player.participant.Money; import domain.player.participant.Participant; -import domain.player.participant.ParticipantResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,137 +21,217 @@ import static domain.card.CardShape.DIAMOND; import static domain.card.CardShape.HEART; import static domain.card.CardShape.SPADE; +import static domain.card.CardValue.ACE; +import static domain.card.CardValue.JACK; +import static domain.card.CardValue.KING; import static domain.card.CardValue.NINE; +import static domain.card.CardValue.QUEEN; import static domain.card.CardValue.TEN; -import static domain.player.participant.ParticipantResult.DRAWER; -import static domain.player.participant.ParticipantResult.LOSER; -import static domain.player.participant.ParticipantResult.WINNER; +import static domain.card.CardValue.TWO; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; class CardTableTest { - Participant participant; - - Dealer dealer; - CardDeck cardDeck; CardTable cardTable; @BeforeEach - void initCardArea() { + void initHand() { cardDeck = CardDeck.shuffledFullCardDeck(); cardTable = CardTable.readyToPlayBlackjack(cardDeck); - - participant = new Participant(new Name("name")); - participant.hit(new Card(CLOVER, TEN)); - participant.hit(new Card(CLOVER, NINE)); - - dealer = new Dealer(); - dealer.hit(new Card(DIAMOND, TEN)); - dealer.hit(new Card(DIAMOND, NINE)); } @Test - @DisplayName("matchBetween() : 참여자가 bust 일 경우에는 참여자가 무조건 게임에서 진다.") - void test_matchBetween_bust_participant_must_lose_participant() throws Exception { + @DisplayName("[final match] determineParticipantsBettingMoney() : 참여자가 bust 일 경우에는 참여자는 무조건 돈을 잃는다.") + void test_determineParticipantsBettingMoney_lose() throws Exception { //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(DIAMOND, KING)); + participant.hit(new Card(DIAMOND, JACK)); + + final Dealer dealer = new Dealer(); //when - final Map gameResult = - cardTable.determineWinner(List.of(participant), dealer); + final Map gameResultMoney = + cardTable.determineParticipantsBettingMoney(List.of(participant), dealer); //then assertAll( - () -> assertThat(gameResult).hasSize(1), - () -> assertThat(gameResult).containsValue(LOSER) + () -> assertThat(gameResultMoney).hasSize(1), + () -> assertThat(gameResultMoney).containsValue(Money.wons(-10000)) ); } @Test - @DisplayName("matchBetween() : 딜러는 bust 이면서 참여자가 bust 가 아니면 참여자가 무조건 게임에서 이긴다.") - void test_matchBetween_bust_dealer_must_lose_dealer() throws Exception { + @DisplayName("[final match] determineParticipantsBettingMoney() : 딜러가 bust 일 때, 참여자가 bust가 아니면 돈을 그대로 돌려받는다.") + void test_determineParticipantsBettingMoney_dealer_bust() throws Exception { //given - dealer.hit(new Card(SPADE, TEN)); + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(DIAMOND, KING)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(SPADE, KING)); + dealer.hit(new Card(SPADE, JACK)); + dealer.hit(new Card(SPADE, QUEEN)); //when - final Map gameResult = - cardTable.determineWinner(List.of(participant), dealer); + final Map gameResultMoney = + cardTable.determineParticipantsBettingMoney(List.of(participant), dealer); //then assertAll( - () -> assertThat(gameResult).hasSize(1), - () -> assertThat(gameResult).containsValue(WINNER) + () -> assertThat(gameResultMoney).hasSize(1), + () -> assertThat(gameResultMoney).containsValue(Money.wons(10000)) ); } @ParameterizedTest @MethodSource("makeBothNotBust") - @DisplayName("matchBetween() : 딜러, 참여자 모두 버스트가 아닐 때 점수가 높은 쪽이 이기고, 같으면 무승부이다.") - void test_matchBetween_not_bust_win_higher_score_or_draw_same_score( + @DisplayName("[final match] determineParticipantsBettingMoney() : 딜러, 참여자 모두 버스트가 아닐 때 참여자가 점수가 높거나 같으면 돈을 그대로 돌려받는다.") + void test_determineParticipantsBettingMoney_both_not_bust( final Participant participant, final Dealer dealer, - final ParticipantResult participantResult) throws Exception { + final Money resultBettingMoney) throws Exception { - //when & then - final Map gameResult = cardTable.determineWinner( - List.of(participant), dealer); + //when + final Map gameResultMoney = + cardTable.determineParticipantsBettingMoney(List.of(participant), dealer); //then assertAll( - () -> assertThat(gameResult).hasSize(1), - () -> assertThat(gameResult).containsValue(participantResult) + () -> assertThat(gameResultMoney).hasSize(1), + () -> assertThat(gameResultMoney).containsValue(resultBettingMoney) ); } static Stream makeBothNotBust() { //무승부 - final Participant participant1 = new Participant(new Name("name1")); - participant1.hit(new Card(CardShape.DIAMOND, TEN)); - participant1.hit(new Card(CardShape.SPADE, TEN)); + final Participant participant1 = new Participant(new Name("name1"), Money.wons(10000)); + participant1.hit(new Card(DIAMOND, TEN)); + participant1.hit(new Card(SPADE, TEN)); final Dealer dealer1 = new Dealer(); dealer1.hit(new Card(HEART, TEN)); dealer1.hit(new Card(CLOVER, TEN)); //참여자가 이길 경우 - final Participant participant2 = new Participant(new Name("name2")); - participant2.hit(new Card(CardShape.SPADE, TEN)); - participant2.hit(new Card(CardShape.DIAMOND, TEN)); + final Participant participant2 = new Participant(new Name("name2"), Money.wons(1000)); + participant2.hit(new Card(SPADE, TEN)); + participant2.hit(new Card(DIAMOND, TEN)); final Dealer dealer2 = new Dealer(); dealer2.hit(new Card(HEART, TEN)); dealer2.hit(new Card(CLOVER, NINE)); //딜러가 이길 경우 - final Participant participant3 = new Participant(new Name("name3")); - participant3.hit(new Card(CardShape.SPADE, TEN)); - participant3.hit(new Card(CardShape.DIAMOND, NINE)); + final Participant participant3 = new Participant(new Name("name3"), Money.wons(4000)); + participant3.hit(new Card(SPADE, TEN)); + participant3.hit(new Card(DIAMOND, NINE)); final Dealer dealer3 = new Dealer(); dealer3.hit(new Card(HEART, TEN)); dealer3.hit(new Card(CLOVER, TEN)); return Stream.of( - Arguments.of(participant1, dealer1, DRAWER), - Arguments.of(participant2, dealer2, WINNER), - Arguments.of(participant3, dealer3, LOSER) + Arguments.of(participant1, dealer1, Money.wons(10000)), + Arguments.of(participant2, dealer2, Money.wons(1000)), + Arguments.of(participant3, dealer3, Money.wons(-4000)) ); } + @ParameterizedTest + @MethodSource("determineFirstMatchResult") + @DisplayName("[first match] determineParticipantsBettingMoney() : 첫 두장에서 결과가 결정되면, 다시 계산하지 않고 그 결과 그대로 배당을 받는다.") + void test_determineParticipantsBettingMoney_finish_before_final_match(final List participants, + final Dealer dealer, + final Money resultMoney) throws Exception { + + //when + final Map gameResultMoney = + cardTable.determineParticipantsBettingMoney(participants, dealer); + + //then + assertAll( + () -> assertThat(gameResultMoney).hasSize(1), + () -> assertThat(gameResultMoney).containsValue(resultMoney) + ); + } + + static Stream determineFirstMatchResult() { + + // 딜러, 참여자 모두 블랙잭 O + final Participant participant1 = new Participant(new Name("name1"), Money.wons(10000)); + participant1.hit(new Card(DIAMOND, TEN)); + participant1.hit(new Card(SPADE, ACE)); + + final Dealer dealer1 = new Dealer(); + dealer1.hit(new Card(HEART, ACE)); + dealer1.hit(new Card(CLOVER, TEN)); + + // 참여자 블랙잭 O, 딜러 블랙잭 X + final Participant participant2 = new Participant(new Name("name2"), Money.wons(10000)); + participant2.hit(new Card(DIAMOND, TEN)); + participant2.hit(new Card(SPADE, ACE)); + + final Dealer dealer2 = new Dealer(); + dealer2.hit(new Card(HEART, ACE)); + dealer2.hit(new Card(CLOVER, ACE)); + + // 참여자 블랙잭 X, 딜러 블랙잭 O + final Participant participant3 = new Participant(new Name("name1"), Money.wons(10000)); + participant3.hit(new Card(DIAMOND, TEN)); + participant3.hit(new Card(SPADE, TEN)); + + final Dealer dealer3 = new Dealer(); + dealer3.hit(new Card(HEART, ACE)); + dealer3.hit(new Card(CLOVER, TEN)); + + return Stream.of( + Arguments.of(List.of(participant1), dealer1, Money.wons(10000)), + Arguments.of(List.of(participant2), dealer2, Money.wons(15000)), + Arguments.of(List.of(participant3), dealer3, Money.wons(-10000)) + ); + } + + @ParameterizedTest + @MethodSource("determineFirstMatchResult") + @DisplayName("determineDealerMoney() : 딜러가 얻은 금액은 참여자가 모두 잃은 금액과 같다.") + void test_determineDealerMoney(final List participants, + final Dealer dealer, + final Money resultMoney) throws Exception { + + //when + final Money dealerMoney = cardTable.determineDealerMoney(participants, dealer); + + //then + assertEquals(dealerMoney, resultMoney.lose()); + } + @Test @DisplayName("dealCardTo() : Player에게 카드를 나눠줄 수 있다.") void test_dealCardTo() throws Exception { - //when & then + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(0)); + participant.hit(new Card(SPADE, ACE)); + participant.hit(new Card(SPADE, TWO)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(DIAMOND, TEN)); + dealer.hit(new Card(DIAMOND, TEN)); + + //when + cardTable.dealCardTo(participant); + cardTable.dealCardTo(dealer); + + //then assertAll( - () -> assertTrue(cardTable.dealCardTo(participant)), - () -> assertFalse(cardTable.dealCardTo(dealer)), - () -> assertThat(participant.cardArea().cards()).hasSize(3), - () -> assertThat(dealer.cardArea().cards()).hasSize(2) + () -> assertThat(participant.hand().cards()).hasSize(3), + () -> assertThat(dealer.hand().cards()).hasSize(2) ); } } diff --git a/src/test/java/domain/hand/HandTest.java b/src/test/java/domain/hand/HandTest.java new file mode 100644 index 0000000000..d69b81a622 --- /dev/null +++ b/src/test/java/domain/hand/HandTest.java @@ -0,0 +1,250 @@ +package domain.hand; + +import domain.Score; +import domain.card.Card; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +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.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static domain.card.CardShape.CLOVER; +import static domain.card.CardShape.DIAMOND; +import static domain.card.CardShape.SPADE; +import static domain.card.CardValue.ACE; +import static domain.card.CardValue.FOUR; +import static domain.card.CardValue.JACK; +import static domain.card.CardValue.NINE; +import static domain.card.CardValue.SEVEN; +import static domain.card.CardValue.SIX; +import static domain.card.CardValue.TEN; +import static domain.card.CardValue.THREE; +import static domain.card.CardValue.valueOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SuppressWarnings("NonAsciiCharacters") +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@DisplayName("Hand 는") +class HandTest { + + @Test + void 카드를_추가할_수_있다() { + // given + final Hand hand = new Hand(); + + // when + final int beforeSize = hand.cards().size(); + hand.addCard(new Card(CLOVER, FOUR)); + + // then + assertThat(hand.cards().size()).isEqualTo(beforeSize + 1); + } + + @ParameterizedTest(name = "카드 목록이 {0} 일 때, 총합은 {1}다.") + @CsvSource(value = { + "TWO+THREE = 5", + "FIVE+SIX = 11", + "TWO+TWO = 4", + "TEN+TEN = 20", + }, delimiterString = " = ") + void 자신이_가진_카드의_합을_구할_수_있다(final String values, final int totalScore) { + // given + final String[] split = values.split("\\+"); + + final Hand hand = new Hand(); + + // when + hand.addCard(new Card(CLOVER, valueOf(split[0]))); + hand.addCard(new Card(CLOVER, valueOf(split[1]))); + + // then + assertThat(hand.calculate()).isEqualTo(new Score(totalScore)); + } + + @ParameterizedTest(name = "킹, 퀸, 잭은 10으로 계산한다") + @CsvSource(value = { + "KING+QUEEN = 20", + "KING+JACK = 20", + "QUEEN+JACK = 20", + "KING+THREE = 13", + "QUEEN+THREE = 13", + "JACK+SIX = 16", + }, delimiterString = " = ") + void 킹_퀸_잭은_10으로_계산한다(final String values, final int totalScore) { + // given + final String[] split = values.split("\\+"); + final Hand hand = new Hand(); + + hand.addCard(new Card(CLOVER, valueOf(split[0]))); + hand.addCard(new Card(CLOVER, valueOf(split[1]))); + + // when & then + assertThat(hand.calculate()).isEqualTo(new Score(totalScore)); + } + + @ParameterizedTest(name = "[{index}] ACE 는 이전까지의 총합이 10 이하면 11로 계산한다") + @MethodSource("isSoftHand") + void ACE_는_이전까지의_총합이_10_이하면_11로_계산한다(final Hand hand, final int totalScore) { + // then + assertThat(hand.calculate()).isEqualTo(new Score(totalScore)); + } + + static Stream isSoftHand() { + + // 10 + [11] = 21 + final Hand hand1 = new Hand(); + hand1.addCard(new Card(CLOVER, TEN)); + hand1.addCard(new Card(CLOVER, ACE)); + + // 10 + 10 + [1] = 21 + final Hand hand2 = new Hand(); + hand2.addCard(new Card(CLOVER, JACK)); + hand2.addCard(new Card(CLOVER, TEN)); + + hand2.addCard(new Card(CLOVER, ACE)); + + // [11] + 9 + [1] = 21 + final Hand hand3 = new Hand(); + hand3.addCard(new Card(CLOVER, ACE)); + hand3.addCard(new Card(CLOVER, NINE)); + + hand3.addCard(new Card(CLOVER, ACE)); + + // [11] + 6 + 3 = 20 + final Hand hand4 = new Hand(); + hand4.addCard(new Card(CLOVER, SIX)); + hand4.addCard(new Card(CLOVER, THREE)); + + hand4.addCard(new Card(CLOVER, ACE)); + + // [11] + 10 = 21 + final Hand hand5 = new Hand(); + hand5.addCard(new Card(CLOVER, ACE)); + hand5.addCard(new Card(CLOVER, TEN)); + + // 10 + [1] + 7 = 18 + final Hand hand6 = new Hand(); + hand6.addCard(new Card(CLOVER, TEN)); + hand6.addCard(new Card(CLOVER, ACE)); + + hand6.addCard(new Card(SPADE, SEVEN)); + + return Stream.of( + Arguments.of(hand1, 21), + Arguments.of(hand2, 21), + Arguments.of(hand3, 21), + Arguments.of(hand4, 20), + Arguments.of(hand5, 21), + Arguments.of(hand6, 18) + ); + } + + @Test + void 총합이_20_이하면_카드를_더_받을_수_있는_상태이다() { + // given + final Hand hand = new Hand(); + hand.addCard(new Card(CLOVER, TEN)); + hand.addCard(new Card(CLOVER, TEN)); + + // when & then + assertTrue(hand.canMoreCard()); + } + + @Test + void 총합이_21_이상이면_카드를_더_받을_수_없는_상태이다() { + // given + final Hand hand = new Hand(); + hand.addCard(new Card(CLOVER, ACE)); + hand.addCard(new Card(SPADE, TEN)); + + // when & then + assertFalse(hand.canMoreCard()); + } + + @Test + void 총합이_21_초과이면_버스트_된다() { + // given + final Hand hand = new Hand(); + hand.addCard(new Card(CLOVER, TEN)); + hand.addCard(new Card(SPADE, TEN)); + + hand.addCard(new Card(DIAMOND, TEN)); + + // when & then + assertTrue(hand.isBust()); + } + + @Test + void 총합이_21_이하이면_버스트_아니다() { + // given + final Hand hand = new Hand(); + hand.addCard(new Card(CLOVER, TEN)); + hand.addCard(new Card(CLOVER, ACE)); + + // when & then + assertFalse(hand.isBust()); + } + + @Test + @DisplayName("firstCard() : 처음 카드를 받을 때, 첫 번째 카드를 보여줄 수 있다.") + void test_firstCard() { + // given + final Hand hand = new Hand(); + + hand.addCard(new Card(CLOVER, TEN)); + hand.addCard(new Card(CLOVER, SEVEN)); + + // when & then + assertEquals(hand.firstCard(), new Card(CLOVER, TEN)); + } + + @Test + @DisplayName("secondCard() : 처음 카드를 받을 때, 두 번째 카드를 보여줄 수 있다.") + void test_secondCard() throws Exception { + // given + final Hand hand = new Hand(); + + hand.addCard(new Card(CLOVER, TEN)); + hand.addCard(new Card(CLOVER, SEVEN)); + + // when & then + assertEquals(hand.secondCard(), new Card(CLOVER, SEVEN)); + } + + @ParameterizedTest + @MethodSource("isBlackjack") + @DisplayName("isBlackjack() : 총합이 21이면 블랙잭이다.") + void test_isBlackjack(final Hand hand, + final boolean isBlackjack) throws Exception { + //when & then + assertEquals(hand.isBlackjack(), isBlackjack); + } + + static Stream isBlackjack() { + + // 21 + final Hand hand1 = new Hand(); + hand1.addCard(new Card(CLOVER, TEN)); + hand1.addCard(new Card(CLOVER, ACE)); + + // 21 + final Hand hand2 = new Hand(); + hand2.addCard(new Card(CLOVER, SIX)); + hand2.addCard(new Card(CLOVER, THREE)); + hand2.addCard(new Card(CLOVER, ACE)); + hand2.addCard(new Card(SPADE, ACE)); + + return Stream.of( + Arguments.of(hand1, true), + Arguments.of(hand2, false) + ); + } +} diff --git a/src/test/java/domain/player/PlayerTest.java b/src/test/java/domain/player/PlayerTest.java index 87e861044b..efea9183c6 100644 --- a/src/test/java/domain/player/PlayerTest.java +++ b/src/test/java/domain/player/PlayerTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; +import java.util.List; + import static domain.card.CardValue.TEN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -23,6 +25,11 @@ class PlayerTest { public boolean canHit() { return false; } + + @Override + public List faceUpFirstDeal() { + return null; + } }; @Test @@ -39,16 +46,21 @@ public boolean canHit() { public boolean canHit() { return false; } + + @Override + public List faceUpFirstDeal() { + return null; + } }); } @Test void 카드를_추가할_수_있다() { // when - final int beforeSize = player.cardArea().cards().size(); + final int beforeSize = player.hand().cards().size(); player.hit(new Card(CardShape.SPADE, TEN)); // then - assertThat(player.cardArea.cards()).hasSize(beforeSize + 1); + assertThat(player.hand.cards()).hasSize(beforeSize + 1); } } diff --git a/src/test/java/domain/player/dealer/DealerTest.java b/src/test/java/domain/player/dealer/DealerTest.java index c59bfe5ffd..bbf3c6fe7b 100644 --- a/src/test/java/domain/player/dealer/DealerTest.java +++ b/src/test/java/domain/player/dealer/DealerTest.java @@ -2,15 +2,17 @@ import domain.card.Card; import domain.card.CardShape; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; +import java.util.List; + import static domain.card.CardValue.SEVEN; import static domain.card.CardValue.SIX; import static domain.card.CardValue.TEN; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -44,15 +46,17 @@ class DealerTest { } @Test - @DisplayName("faceUpFirstCard() : 딜러는 첫 번째 카드만을 보여줍니다.") - void test_faceUpFirstCard() throws Exception { - //given + @DisplayName("faceUpFirstDeal() : 딜러는 처음 받은 카드 중 첫 번재 카드만 보여줘야한다.") + void test_faceUpFirstDeal() throws Exception { + // given final Dealer dealer = new Dealer(); - dealer.hit(new Card(CardShape.CLOVER, TEN)); dealer.hit(new Card(CardShape.CLOVER, SEVEN)); - // when & then - assertEquals(dealer.faceUpFirstCard(), new Card(CardShape.CLOVER, TEN)); + // when + final List cards = dealer.faceUpFirstDeal(); + + // then + Assertions.assertThat(cards).containsExactly(new Card(CardShape.CLOVER, TEN)); } } diff --git a/src/test/java/domain/player/participant/MoneyTest.java b/src/test/java/domain/player/participant/MoneyTest.java new file mode 100644 index 0000000000..9ff5a656f2 --- /dev/null +++ b/src/test/java/domain/player/participant/MoneyTest.java @@ -0,0 +1,75 @@ +package domain.player.participant; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MoneyTest { + + @ParameterizedTest + @CsvSource(value = { + "1000 -> 1000", + "1500 -> 1500", + "2000 -> 2000" + }, delimiterString = " -> ") + @DisplayName("breakEven() : 그대로 값을 돌려주다.") + void test_breakEven(final int bettingAmount, final int resultAmount) throws Exception { + //given + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(bettingMoney.breakEven(), resultMoney); + } + + @ParameterizedTest + @CsvSource(value = { + "1000,1.5,1500", + "1500,1.5,2250", + "1800,1.8,3240", + "2231,1.75,3904.25" + }) + @DisplayName("times() : 현재 돈에 주어진 percent 를 계산할 수 있다.") + void test_times(final int bettingAmount, final double percent, final double resultAmount) throws Exception { + //given + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(bettingMoney.times(percent), resultMoney); + } + + @ParameterizedTest + @CsvSource(value = { + "1000 -> -1000", + "1500 -> -1500", + "2000 -> -2000" + }, delimiterString = " -> ") + @DisplayName("lose() : 현재 가지고 있는 돈을 잃을 수 있다.") + void test_lose(final int bettingAmount, final int resultAmount) throws Exception { + //given + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(bettingMoney.lose(), resultMoney); + } + + @ParameterizedTest + @CsvSource(value = { + "1000,1000,2000", + "1500,1000,2500", + "2000,1028,3028" + }) + @DisplayName("plus() : 돈을 합할 수 있다.") + void test_plus(final int amount1, final int amount2, final int resultAmount) throws Exception { + //given + final Money origin = Money.wons(amount1); + final Money other = Money.wons(amount2); + + //when & then + assertEquals(origin.plus(other), Money.wons(resultAmount)); + } +} diff --git a/src/test/java/domain/player/participant/ParticipantResultTest.java b/src/test/java/domain/player/participant/ParticipantResultTest.java deleted file mode 100644 index 70dd85bae7..0000000000 --- a/src/test/java/domain/player/participant/ParticipantResultTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package domain.player.participant; - -import domain.player.dealer.DealerResult; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@DisplayName("ParticipantResult 의") -class ParticipantResultTest { - - @ParameterizedTest - @CsvSource(value = { - "WINNER -> LOSER", - "DRAWER -> DRAWER", - "LOSER -> WINNER" - }, delimiterString = " -> ") - @DisplayName("convertToDealerResult() : 무승부를 제외하고 딜러의 결과는 참여자의 결과에 대해 반대이다.") - void test_convertToDealerResult_opposite_DealerResult_And_ParticipantResult( - final ParticipantResult participantResult, final DealerResult dealerResult) throws Exception { - - //when & then - assertEquals(participantResult.convertToDealerResult(), dealerResult); - } -} diff --git a/src/test/java/domain/player/participant/ParticipantTest.java b/src/test/java/domain/player/participant/ParticipantTest.java index 6bee5e68f3..40bc67c4c2 100644 --- a/src/test/java/domain/player/participant/ParticipantTest.java +++ b/src/test/java/domain/player/participant/ParticipantTest.java @@ -1,14 +1,19 @@ package domain.player.participant; import domain.card.Card; +import domain.card.CardShape; import domain.player.Name; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.List; + import static domain.card.CardShape.CLOVER; import static domain.card.CardShape.SPADE; import static domain.card.CardValue.ACE; +import static domain.card.CardValue.SEVEN; import static domain.card.CardValue.TEN; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -16,7 +21,7 @@ @DisplayName("Participant 은") class ParticipantTest { - final Participant participant = new Participant(new Name("name")); + final Participant participant = new Participant(new Name("name"), Money.wons(0)); @BeforeEach void makeCardScoreTwenty() { @@ -40,4 +45,22 @@ void test_canHit_overScore21() { // then assertFalse(participant.canHit()); } + + @Test + @DisplayName("faceUpFirstDeal() : participant는 처음 받은 카드 두 장을 모두 보여줘야한다.") + void test_faceUpFirstDeal() throws Exception { + // given + final Participant participant = new Participant(new Name("name1"), Money.wons(0)); + participant.hit(new Card(CardShape.CLOVER, TEN)); + participant.hit(new Card(CardShape.CLOVER, SEVEN)); + + // when + final List cards = participant.faceUpFirstDeal(); + + // then + Assertions.assertThat(cards).containsExactly( + new Card(CardShape.CLOVER, TEN), + new Card(CardShape.CLOVER, SEVEN) + ); + } } diff --git a/src/test/java/domain/player/participant/betresult/BetResultStateTest.java b/src/test/java/domain/player/participant/betresult/BetResultStateTest.java new file mode 100644 index 0000000000..4fee182a22 --- /dev/null +++ b/src/test/java/domain/player/participant/betresult/BetResultStateTest.java @@ -0,0 +1,72 @@ +package domain.player.participant.betresult; + +import domain.player.participant.Money; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.BreakEvenState; +import domain.player.participant.betresult.resultstate.LoseState; +import domain.player.participant.betresult.resultstate.WinState; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BetResultStateTest { + + @ParameterizedTest + @CsvSource(value = { + "1000 -> 1500", + "1500 -> 2250", + "1800 -> 2700", + "2231 -> 3346.5", + "2249 -> 3373.5" + }, delimiterString = " -> ") + @DisplayName("calculateBetOutComeOf(WinState) : 게임에서 이길 경우 돈을 percent 만큼 더 얻는다.") + void test_calculateBetOutComeOf_WinState(final int bettingAmount, + final double resultAmount) throws Exception { + //given + BetResultState winState = new WinState(); + + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(winState.calculateBetOutcomeOf(bettingMoney), resultMoney); + } + + @ParameterizedTest + @CsvSource(value = { + "1000 -> -1000", + "1500 -> -1500", + "2000 -> -2000" + }, delimiterString = " -> ") + @DisplayName("calculateBetOutComeOf(LoseState) : 게임에서 질 경우 돈을 전부 잃는다.") + void test_lose(final int bettingAmount, final int resultAmount) throws Exception { + //given + BetResultState loseState = new LoseState(); + + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(loseState.calculateBetOutcomeOf(bettingMoney), resultMoney); + } + + @ParameterizedTest + @CsvSource(value = { + "1000 -> 1000", + "1500 -> 1500", + "2000 -> 2000" + }, delimiterString = " -> ") + @DisplayName("calculateBetOutComeOf(BreakEven) : 게임에서 무승부일 경우 본전이다.") + void test_breakEven(final int bettingAmount, final int resultAmount) throws Exception { + //given + BetResultState breakEvenState = new BreakEvenState(); + + final Money bettingMoney = Money.wons(bettingAmount); + final Money resultMoney = Money.wons(resultAmount); + + //when & then + assertEquals(breakEvenState.calculateBetOutcomeOf(bettingMoney), resultMoney); + } +} diff --git a/src/test/java/domain/player/participant/betresult/resultfinder/BetResultFinderTest.java b/src/test/java/domain/player/participant/betresult/resultfinder/BetResultFinderTest.java new file mode 100644 index 0000000000..2023ffd99c --- /dev/null +++ b/src/test/java/domain/player/participant/betresult/resultfinder/BetResultFinderTest.java @@ -0,0 +1,319 @@ +package domain.player.participant.betresult.resultfinder; + +import domain.card.Card; +import domain.player.Name; +import domain.player.dealer.Dealer; +import domain.player.participant.Money; +import domain.player.participant.Participant; +import domain.player.participant.betresult.resultstate.BetResultState; +import domain.player.participant.betresult.resultstate.BreakEvenState; +import domain.player.participant.betresult.resultstate.LoseState; +import domain.player.participant.betresult.resultstate.WinState; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static domain.card.CardShape.CLOVER; +import static domain.card.CardShape.DIAMOND; +import static domain.card.CardShape.HEART; +import static domain.card.CardShape.SPADE; +import static domain.card.CardValue.ACE; +import static domain.card.CardValue.KING; +import static domain.card.CardValue.NINE; +import static domain.card.CardValue.QUEEN; +import static domain.card.CardValue.TEN; +import static domain.card.CardValue.THREE; +import static domain.card.CardValue.TWO; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BetResultFinderTest { + + BetResultFinder betResultFinder = new BetResultFinder(); + + @Test + @DisplayName("[ParticipantLose] findStateOf() : 첫 두장 카드에서 딜러만 블랙잭일 경우 참여자는 진다") + void test_findStateOf_participantLose() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(DIAMOND, TEN)); + participant.hit(new Card(SPADE, TEN)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, ACE)); + dealer.hit(new Card(CLOVER, TEN)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(LoseState.class); + } + + @Test + @DisplayName("[PlayerDraw] findStateOf() : 첫 두장 카드에서 딜러, 참여자 모두 블랙잭이면 무승부다.") + void test_findStateOf_playerDraw() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(DIAMOND, ACE)); + participant.hit(new Card(SPADE, TEN)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, ACE)); + dealer.hit(new Card(CLOVER, TEN)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(BreakEvenState.class); + } + + @Test + @DisplayName("[PlayerDraw] findStateOf() : 마지막에 딜러와 참여자의 점수가 같으면 무승부다.") + void test_findStateOf_playerDraw_finalMatch() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(DIAMOND, TEN)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, ACE)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, TEN)); + dealer.hit(new Card(CLOVER, TEN)); + dealer.hit(new Card(CLOVER, ACE)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(BreakEvenState.class); + } + + @Test + @DisplayName("[ParticipantBust] findStateOf() : 참여자가 버스트면 무조건 진다.") + void test_findStateOf_participantBust() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(DIAMOND, NINE)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, NINE)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, ACE)); + dealer.hit(new Card(CLOVER, TWO)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(LoseState.class); + } + + @Test + @DisplayName("[ParticipantBlackjack] findStateOf() : 참여자만 블랙잭일 경우 참여자가 이긴다.") + void test_findStateOf_participantBlackjack() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, ACE)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, ACE)); + dealer.hit(new Card(CLOVER, TWO)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(WinState.class); + } + + @Test + @DisplayName("[DealerBust] findStateOf() : 딜러만 버스트일 경우 참여자가 이긴다.") + void test_findStateOf_dealerBust() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, NINE)); + participant.hit(new Card(SPADE, TWO)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, KING)); + dealer.hit(new Card(CLOVER, TWO)); + dealer.hit(new Card(CLOVER, QUEEN)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(BreakEvenState.class); + } + + @Test + @DisplayName("[ParticipantBust] findStateOf() : 딜러, 참여자가 버스트 일 경우에는 딜러가 이긴다.") + void test_findStateOf_both_bust() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, NINE)); + participant.hit(new Card(SPADE, TWO)); + participant.hit(new Card(CLOVER, TWO)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, KING)); + dealer.hit(new Card(CLOVER, TWO)); + dealer.hit(new Card(CLOVER, QUEEN)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(LoseState.class); + } + + @Test + @DisplayName("[DealerBlackjack] findStateOf() : 딜러만 블랙잭일 경우 딜러가 이긴다.") + void test_findStateOf_dealerBlackjack() throws Exception { + //given + final Participant participant = new Participant(new Name("name1"), Money.wons(10000)); + participant.hit(new Card(SPADE, TEN)); + participant.hit(new Card(SPADE, NINE)); + + final Dealer dealer = new Dealer(); + dealer.hit(new Card(HEART, KING)); + dealer.hit(new Card(CLOVER, ACE)); + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + Assertions.assertThat(betResultState).isInstanceOf(LoseState.class); + } + + @ParameterizedTest(name = "{2}") + @MethodSource("betBlackjack") + @DisplayName("findStateOf() : 첫 두장에서 승부가 날 수 있다.") + void test_findStateOf_blackjack(final Participant participant, + final Dealer dealer, + final BetResultState resultState) throws Exception { + + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + //then + assertEquals(resultState.getClass(), betResultState.getClass()); + } + + static Stream betBlackjack() { + + //첫 두장에서 참여자 블랙잭 O, 딜러 블랙잭 O + Participant participant1 = new Participant(new Name("name1"), Money.wons(10000)); + participant1.hit(new Card(DIAMOND, TEN)); + participant1.hit(new Card(DIAMOND, ACE)); + + final Dealer dealer1 = new Dealer(); + dealer1.hit(new Card(SPADE, TEN)); + dealer1.hit(new Card(SPADE, ACE)); + + //첫 두장에서 참여자 블랙잭 O, 딜러 블랙잭 X + Participant participant2 = new Participant(new Name("name2"), Money.wons(5000)); + participant2.hit(new Card(DIAMOND, TEN)); + participant2.hit(new Card(DIAMOND, ACE)); + + final Dealer dealer2 = new Dealer(); + dealer2.hit(new Card(SPADE, TEN)); + dealer2.hit(new Card(DIAMOND, TEN)); + + //첫 두장에서 참여자 블랙잭 X, 딜러 블랙잭 O + Participant participant3 = new Participant(new Name("name3"), Money.wons(1000)); + participant3.hit(new Card(DIAMOND, TEN)); + participant3.hit(new Card(SPADE, TEN)); + + final Dealer dealer3 = new Dealer(); + dealer3.hit(new Card(SPADE, TEN)); + dealer3.hit(new Card(DIAMOND, ACE)); + + return Stream.of( + Arguments.of(participant1, dealer1, new BreakEvenState()), + Arguments.of(participant2, dealer2, new WinState()), + Arguments.of(participant3, dealer3, new LoseState()) + ); + } + + @ParameterizedTest(name = "{2}") + @MethodSource("betNotBlackjack") + @DisplayName("findStateOf() : 첫 두장에서 승부가 결정되지 않고, 마지막에 승부 상태가 결정될 수 있다.") + void test_findStateOf_not_blackjack(final Participant participant, + final Dealer dealer, + final BetResultState resultState) throws Exception { + //when + final BetResultState betResultState = betResultFinder.findStateOf(participant, dealer); + + System.out.println("participant = " + participant.name().value()); + //then + assertEquals(resultState.getClass(), betResultState.getClass()); + } + + static Stream betNotBlackjack() { + + //참여자 승 + Participant participant1 = new Participant(new Name("name1"), Money.wons(10000)); + participant1.hit(new Card(DIAMOND, TEN)); + participant1.hit(new Card(DIAMOND, TEN)); + + final Dealer dealer1 = new Dealer(); + dealer1.hit(new Card(SPADE, TEN)); + dealer1.hit(new Card(SPADE, TWO)); + + //참여자 패 + Participant participant2 = new Participant(new Name("name2"), Money.wons(5000)); + participant2.hit(new Card(DIAMOND, THREE)); + participant2.hit(new Card(DIAMOND, ACE)); + + final Dealer dealer2 = new Dealer(); + dealer2.hit(new Card(SPADE, TEN)); + dealer2.hit(new Card(DIAMOND, TEN)); + + //무승부 + Participant participant3 = new Participant(new Name("name3"), Money.wons(1000)); + participant3.hit(new Card(DIAMOND, TEN)); + participant3.hit(new Card(SPADE, TEN)); + + final Dealer dealer3 = new Dealer(); + dealer3.hit(new Card(SPADE, TEN)); + dealer3.hit(new Card(DIAMOND, TEN)); + + //딜러 버스트, 참여자 버스트 X + Participant participant4 = new Participant(new Name("name4"), Money.wons(1000)); + participant4.hit(new Card(DIAMOND, TEN)); + participant4.hit(new Card(SPADE, TEN)); + + final Dealer dealer4 = new Dealer(); + dealer4.hit(new Card(SPADE, TEN)); + dealer4.hit(new Card(DIAMOND, TEN)); + dealer4.hit(new Card(DIAMOND, KING)); + + //참여자 버스트 + Participant participant5 = new Participant(new Name("name5"), Money.wons(5000)); + participant5.hit(new Card(DIAMOND, TEN)); + participant5.hit(new Card(SPADE, TEN)); + participant5.hit(new Card(SPADE, KING)); + + final Dealer dealer5 = new Dealer(); + dealer5.hit(new Card(DIAMOND, ACE)); + dealer5.hit(new Card(SPADE, TEN)); + + return Stream.of( + Arguments.of(participant1, dealer1, new BreakEvenState()), + Arguments.of(participant2, dealer2, new LoseState()), + Arguments.of(participant3, dealer3, new BreakEvenState()), + Arguments.of(participant4, dealer4, new BreakEvenState()), + Arguments.of(participant5, dealer5, new LoseState()) + ); + } +} diff --git a/src/test/java/minimission/SimpleLinkedList.java b/src/test/java/minimission/SimpleLinkedList.java index 7f1e884073..7a83c0550d 100644 --- a/src/test/java/minimission/SimpleLinkedList.java +++ b/src/test/java/minimission/SimpleLinkedList.java @@ -158,7 +158,7 @@ Node node(int index) { @Override public void clear() { - for (Node current = head; current != null;) { + for (Node current = head; current != null; ) { Node next = current.next; current.value = null; current.next = null;