From 4b5b9aaba43d0716631d33bf926f5f5f1fd0715d Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 14:26:18 +0900 Subject: [PATCH 01/24] =?UTF-8?q?feat:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EB=B2=A0=ED=8C=85=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackjackController.java | 23 ++++++- src/main/java/model/judgement/BetAmount.java | 27 ++++++++ src/main/java/model/judgement/GameStatus.java | 18 ----- src/main/java/model/judgement/Judgement.java | 18 ++--- .../java/model/judgement/PlayerResult.java | 24 +++++-- src/main/java/model/judgement/Profit.java | 14 ++++ .../java/model/judgement/ResultStatus.java | 35 ++++++++++ src/main/java/model/paticipant/Player.java | 11 ++- src/main/java/model/paticipant/Players.java | 7 -- src/main/java/view/InputView.java | 6 ++ src/main/java/view/OutputView.java | 23 ++++++- .../java/fixture/PlayerResultTestFixture.java | 12 ++-- .../java/fixture/ResultStatusTestFixture.java | 17 +++++ src/test/java/model/JudgementTest.java | 6 +- src/test/java/model/PlayerBustTest.java | 4 +- src/test/java/model/PlayerTest.java | 2 +- .../java/model/betting/BetAmountTest.java | 56 ++++++++++++++++ src/test/java/model/betting/ProfitTest.java | 40 +++++++++++ .../model/judgement/PlayerResultTest.java | 67 +++++++++++++++++++ .../model/judgement/ResultStatusTest.java | 23 +++++++ 20 files changed, 375 insertions(+), 58 deletions(-) create mode 100644 src/main/java/model/judgement/BetAmount.java delete mode 100644 src/main/java/model/judgement/GameStatus.java create mode 100644 src/main/java/model/judgement/Profit.java create mode 100644 src/main/java/model/judgement/ResultStatus.java create mode 100644 src/test/java/fixture/ResultStatusTestFixture.java create mode 100644 src/test/java/model/betting/BetAmountTest.java create mode 100644 src/test/java/model/betting/ProfitTest.java create mode 100644 src/test/java/model/judgement/PlayerResultTest.java create mode 100644 src/test/java/model/judgement/ResultStatusTest.java diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 7a084f07d7..6ee187f55d 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,10 +1,12 @@ package controller; +import java.util.ArrayList; import java.util.List; import model.BlackjackService; import model.judgement.DealerResult; import model.judgement.Judgement; import model.judgement.PlayerResult; +import model.judgement.Profit; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; @@ -16,7 +18,7 @@ public class BlackjackController { private final BlackjackService blackjackService; public BlackjackController(BlackjackService blackjackService) { - this.blackjackService = blackjackService;; + this.blackjackService = blackjackService; } public void run() { @@ -27,12 +29,18 @@ public void run() { drawMoreCardByPlayer(dealer, players); printFinalCards(dealer, players); - judgeGame(dealer, players); + //judgeGame(dealer, players); + printProfits(dealer, players); } private Players createPlayers() { List names = InputView.readPlayerNames(); - return Players.from(names); + List players = new ArrayList<>(); + for (String name : names) { + int betAmount = InputView.readBetAmount(name); + players.add(new Player(name, betAmount)); + } + return new Players(players); } private void drawMoreCardByPlayer(Dealer dealer, Players players) { @@ -86,4 +94,13 @@ private void judgeGame(Dealer dealer, Players players) { OutputView.printResultByDealer(dealerResult); OutputView.printResultByPlayers(playerResult); } + + private void printProfits(Dealer dealer, Players players) { + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); + Profit dealerProfit = playerResult.calculateDealerProfit(); + + OutputView.printFinalProfitHeader(); + OutputView.printProfitByDealer(dealerProfit); + OutputView.printProfitByPlayers(playerResult.calculateProfits()); + } } diff --git a/src/main/java/model/judgement/BetAmount.java b/src/main/java/model/judgement/BetAmount.java new file mode 100644 index 0000000000..a1cd55f0da --- /dev/null +++ b/src/main/java/model/judgement/BetAmount.java @@ -0,0 +1,27 @@ +package model.judgement; + +public record BetAmount(int amount) { + + private static final int MIN_BET_AMOUNT = 1; + private static final int MAX_BET_AMOUNT = 1_000_000; + + public BetAmount { + validate(amount); + } + + private static void validate(int amount) { + if (amount < MIN_BET_AMOUNT || amount > MAX_BET_AMOUNT) { + throw new IllegalArgumentException( + String.format("베팅 금액은 %d원 이상 %d원 이하여야 합니다.", MIN_BET_AMOUNT, MAX_BET_AMOUNT) + ); + } + } + + public Profit toProfit() { + return new Profit(amount); + } + + public Profit toNegativeProfit() { + return new Profit(-amount); + } +} diff --git a/src/main/java/model/judgement/GameStatus.java b/src/main/java/model/judgement/GameStatus.java deleted file mode 100644 index 7d65f7135c..0000000000 --- a/src/main/java/model/judgement/GameStatus.java +++ /dev/null @@ -1,18 +0,0 @@ -package model.judgement; - -public enum GameStatus { - - WIN("승"), - LOSE("패"), - DRAW("무"); - - private final String name; - - GameStatus(String name) { - this.name = name; - } - - public String getName() { - return name; - } -} diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index 7f6d9481a3..bd18447219 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -1,8 +1,8 @@ package model.judgement; -import static model.judgement.GameStatus.DRAW; -import static model.judgement.GameStatus.LOSE; -import static model.judgement.GameStatus.WIN; +import static model.judgement.ResultStatus.DRAW; +import static model.judgement.ResultStatus.LOSE; +import static model.judgement.ResultStatus.WIN; import java.util.LinkedHashMap; import java.util.Map; @@ -13,12 +13,12 @@ public class Judgement { public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { - Map result = new LinkedHashMap<>(); + Map result = new LinkedHashMap<>(); players.forEach(player -> result.put(player, decide(dealer, player))); return new PlayerResult(result); } - private static GameStatus decide(Dealer dealer, Player player) { + private static ResultStatus decide(Dealer dealer, Player player) { if (player.isBust()) { return LOSE; } @@ -29,7 +29,7 @@ private static GameStatus decide(Dealer dealer, Player player) { return decideByScore(dealer, player); } - private static GameStatus decideByScore(Dealer dealer, Player player) { + private static ResultStatus decideByScore(Dealer dealer, Player player) { int dealerScore = dealer.calculateTotalScore(); int playerScore = player.calculateTotalScore(); @@ -43,9 +43,9 @@ private static GameStatus decideByScore(Dealer dealer, Player player) { } public static DealerResult judgeByDealer(PlayerResult playerResult) { - int dealerWinCount = playerResult.countByStatus(GameStatus.LOSE); - int dealerLoseCount = playerResult.countByStatus(GameStatus.WIN); - int dealerDrawCount = playerResult.countByStatus(GameStatus.DRAW); + int dealerWinCount = playerResult.countByStatus(ResultStatus.LOSE); + int dealerLoseCount = playerResult.countByStatus(ResultStatus.WIN); + int dealerDrawCount = playerResult.countByStatus(ResultStatus.DRAW); return new DealerResult(dealerWinCount, dealerLoseCount, dealerDrawCount); } } diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index 4f3e7a11bf..7798f64267 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -7,20 +7,34 @@ public class PlayerResult { - private final Map result; + private final Map result; - public PlayerResult(Map result) { + public PlayerResult(Map result) { this.result = new LinkedHashMap<>(result); } - public int countByStatus(GameStatus gameStatus) { + public int countByStatus(ResultStatus resultStatus) { return (int) result.values() .stream() - .filter(status -> status == gameStatus) + .filter(status -> status == resultStatus) .count(); } - public Map getResult() { + public Map calculateProfits() { + Map profits = new LinkedHashMap<>(); + result.forEach((player, status) -> + profits.put(player, status.calculateProfit(player.getBetAmount())) + ); + return profits; + } + + public Profit calculateDealerProfit() { + return calculateProfits().values() + .stream() + .reduce(Profit.ZERO, (sum, profit) -> sum.add(profit.negate())); + } + + public Map getResult() { return Collections.unmodifiableMap(result); } } diff --git a/src/main/java/model/judgement/Profit.java b/src/main/java/model/judgement/Profit.java new file mode 100644 index 0000000000..6fd1228ac8 --- /dev/null +++ b/src/main/java/model/judgement/Profit.java @@ -0,0 +1,14 @@ +package model.judgement; + +public record Profit(int value) { + + public static final Profit ZERO = new Profit(0); + + public Profit add(Profit other) { + return new Profit(this.value + other.value); + } + + public Profit negate() { + return new Profit(-value); + } +} diff --git a/src/main/java/model/judgement/ResultStatus.java b/src/main/java/model/judgement/ResultStatus.java new file mode 100644 index 0000000000..b0e399ec19 --- /dev/null +++ b/src/main/java/model/judgement/ResultStatus.java @@ -0,0 +1,35 @@ +package model.judgement; + +public enum ResultStatus { + + WIN("승") { + @Override + public Profit calculateProfit(BetAmount betAmount) { + return betAmount.toProfit(); + } + }, + LOSE("패") { + @Override + public Profit calculateProfit(BetAmount betAmount) { + return betAmount.toNegativeProfit(); + } + }, + DRAW("무") { + @Override + public Profit calculateProfit(BetAmount betAmount) { + return Profit.ZERO; + } + }; + + private final String name; + + ResultStatus(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public abstract Profit calculateProfit(BetAmount betAmount); +} diff --git a/src/main/java/model/paticipant/Player.java b/src/main/java/model/paticipant/Player.java index 34eabb38b8..8672b49798 100644 --- a/src/main/java/model/paticipant/Player.java +++ b/src/main/java/model/paticipant/Player.java @@ -1,15 +1,24 @@ package model.paticipant; +import model.judgement.BetAmount; + public class Player extends Participant { private static final int PLAYER_HIT_THRESHOLD = 21; - public Player(String name) { + private final BetAmount betAmount; + + public Player(String name, int betAmount) { super(name); + this.betAmount = new BetAmount(betAmount); } @Override public boolean canHit() { return calculateTotalScore() < PLAYER_HIT_THRESHOLD; } + + public BetAmount getBetAmount() { + return betAmount; + } } diff --git a/src/main/java/model/paticipant/Players.java b/src/main/java/model/paticipant/Players.java index 501315cc77..019fd37eeb 100644 --- a/src/main/java/model/paticipant/Players.java +++ b/src/main/java/model/paticipant/Players.java @@ -13,13 +13,6 @@ public Players(List players) { this.players = new ArrayList<>(players); } - public static Players from(List playerNames) { - List players = playerNames.stream() - .map(Player::new) - .toList(); - return new Players(players); - } - public List getPlayers() { return Collections.unmodifiableList(players); } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 7d21549dd3..1814114eb0 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -17,6 +17,12 @@ public static List readPlayerNames() { .toList(); } + public static int readBetAmount(String playerName) { + System.out.println(); + System.out.printf("%s의 배팅 금액은?%n", playerName); + return Integer.parseInt(readLine()); + } + public static String readMoreCard(Player player) { System.out.println(player.getName() + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); return readLine(); diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index ac35e5aba0..2a68fecac4 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,9 +1,11 @@ package view; import java.util.List; +import java.util.Map; import model.card.Card; import model.judgement.DealerResult; import model.judgement.PlayerResult; +import model.judgement.Profit; import model.paticipant.Dealer; import model.paticipant.Participant; import model.paticipant.Player; @@ -32,7 +34,7 @@ public static void printCardByPlayers(Players players) { public static void printCardByDealer(Dealer dealer) { Card firstCard = dealer.getCards().getFirst(); String card = convert(firstCard); - System.out.println(dealer.getName() + "카드: " + card); + System.out.println(dealer.getName() + ": " + card); } public static void printCardByPlayer(Player player) { @@ -50,7 +52,7 @@ public static void printCardByPlayerWithScore(Participant participant) { .stream() .map(OutputView::convert) .toList(); - System.out.printf("%s카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); + System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); } private static String convert(Card card) { @@ -68,7 +70,7 @@ public static void printBlank() { public static void printFinalResultHeader() { System.out.println(); - System.out.println("##최종 승패"); + System.out.println("## 최종 승패"); } public static void printResultByDealer(DealerResult dealerResult) { @@ -90,4 +92,19 @@ public static void printResultByPlayers(PlayerResult playerResult) { playerResult.getResult() .forEach((player, status) -> System.out.printf("%s: %s%n", player.getName(), status.getName())); } + + public static void printFinalProfitHeader() { + System.out.println(); + System.out.println("## 최종 수익"); + } + + public static void printProfitByDealer(Profit profit) { + System.out.printf("딜러: %d%n", profit.value()); + } + + public static void printProfitByPlayers(Map profits) { + profits.forEach((player, profit) -> + System.out.printf("%s: %d%n", player.getName(), profit.value()) + ); + } } \ No newline at end of file diff --git a/src/test/java/fixture/PlayerResultTestFixture.java b/src/test/java/fixture/PlayerResultTestFixture.java index fadc81b3eb..c9879526e4 100644 --- a/src/test/java/fixture/PlayerResultTestFixture.java +++ b/src/test/java/fixture/PlayerResultTestFixture.java @@ -5,7 +5,7 @@ import model.card.Card; import model.card.CardShape; import model.card.CardValue; -import model.judgement.GameStatus; +import model.judgement.ResultStatus; import org.junit.jupiter.params.provider.Arguments; public class PlayerResultTestFixture { @@ -16,31 +16,31 @@ public class PlayerResultTestFixture { Arguments.of( List.of(card(CardValue.TEN), card(CardValue.JACK), card(CardValue.FIVE)), // 25점 List.of(card(CardValue.TWO), card(CardValue.THREE)), // 5점 - GameStatus.LOSE + ResultStatus.LOSE ), // 2. 딜러 버스트, 플레이어는 낫 버스트 (승리) Arguments.of( List.of(card(CardValue.TEN), card(CardValue.EIGHT)), // 18점 List.of(card(CardValue.TEN), card(CardValue.FIVE), card(CardValue.SEVEN)), // 22점 - GameStatus.WIN + ResultStatus.WIN ), // 3. 둘 다 버스트가 아닐 때 점수 비교 (플레이어가 높은 경우) Arguments.of( List.of(card(CardValue.ACE), card(CardValue.NINE)), // 20점 List.of(card(CardValue.TEN), card(CardValue.EIGHT)), // 18점 - GameStatus.WIN + ResultStatus.WIN ), // 4. 점수가 같은 경우 (무승부) Arguments.of( List.of(card(CardValue.TEN), card(CardValue.SEVEN)), // 17점 List.of(card(CardValue.EIGHT), card(CardValue.NINE)), // 17점 - GameStatus.DRAW + ResultStatus.DRAW ), // 5. 플레이어가 낮은 경우 (패배) Arguments.of( List.of(card(CardValue.FIVE), card(CardValue.SEVEN)), // 12점 List.of(card(CardValue.TEN), card(CardValue.SIX)), // 16점 - GameStatus.LOSE + ResultStatus.LOSE ) ); } diff --git a/src/test/java/fixture/ResultStatusTestFixture.java b/src/test/java/fixture/ResultStatusTestFixture.java new file mode 100644 index 0000000000..c9c8608e0f --- /dev/null +++ b/src/test/java/fixture/ResultStatusTestFixture.java @@ -0,0 +1,17 @@ +package fixture; + +import java.util.stream.Stream; +import model.judgement.ResultStatus; +import org.junit.jupiter.params.provider.Arguments; + +public class ResultStatusTestFixture { + + public static Stream 천_원_베팅에_따른_게임_결과별_수익_정보_제공() { + return Stream.of( + Arguments.of(ResultStatus.WIN, 1000), // 수익 금액 그대로 + Arguments.of(ResultStatus.LOSE, -1000), // 수익 금액 반대 - 손실 + Arguments.of(ResultStatus.DRAW, 0) // 무승부 시 수익 없음 + ); + } + +} diff --git a/src/test/java/model/JudgementTest.java b/src/test/java/model/JudgementTest.java index 42efcc2acc..926cb61ac7 100644 --- a/src/test/java/model/JudgementTest.java +++ b/src/test/java/model/JudgementTest.java @@ -5,9 +5,9 @@ import java.util.List; import model.card.Card; -import model.judgement.GameStatus; import model.judgement.Judgement; import model.judgement.PlayerResult; +import model.judgement.ResultStatus; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; @@ -21,13 +21,13 @@ public class JudgementTest { void 다양한_게임_상황에서_승패를_올바르게_판정한다( List playerCards, List dealerCards, - GameStatus status + ResultStatus status ) { // given Dealer dealer = createDealer(); dealerCards.forEach(dealer::addCard); - Player player = new Player("pobi"); + Player player = new Player("pobi", 10000); playerCards.forEach(player::addCard); // when diff --git a/src/test/java/model/PlayerBustTest.java b/src/test/java/model/PlayerBustTest.java index 22e5cc4be2..c3a827ef0d 100644 --- a/src/test/java/model/PlayerBustTest.java +++ b/src/test/java/model/PlayerBustTest.java @@ -13,7 +13,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_20_이하_일_때_카드를_더_받을_수_있다() { // given - Player pobi = new Player("pobi"); + Player pobi = new Player("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); @@ -24,7 +24,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_21_이상_일_때_카드를_더_받을_수_없다() { // given - Player pobi = new Player("pobi"); + Player pobi = new Player("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.ACE)); diff --git a/src/test/java/model/PlayerTest.java b/src/test/java/model/PlayerTest.java index d466413d3d..0f46227ef9 100644 --- a/src/test/java/model/PlayerTest.java +++ b/src/test/java/model/PlayerTest.java @@ -14,7 +14,7 @@ class PlayerTest { @MethodSource("fixture.PlayerTestFixture#플레이어별_카드목록_및_점수_제공") void 블랙잭_참여자는_자신의_카드_정보로_현재_점수를_계산할_수_있다(List cards, int expectedScore) { // given - Player pobi = new Player("pobi"); + Player pobi = new Player("pobi", 10000); cards.forEach(pobi::addCard); // when diff --git a/src/test/java/model/betting/BetAmountTest.java b/src/test/java/model/betting/BetAmountTest.java new file mode 100644 index 0000000000..adcbd47a8d --- /dev/null +++ b/src/test/java/model/betting/BetAmountTest.java @@ -0,0 +1,56 @@ +package model.betting; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import model.judgement.BetAmount; +import model.judgement.Profit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BetAmountTest { + + @ParameterizedTest + @ValueSource(ints = {0, 1000001}) + void 베팅_금액이_1원미만이거나_100만원을_초과한다면_예외가_발생한다(int invalidAmount) { + // when & then + assertThatThrownBy(() -> new BetAmount(invalidAmount)) + .isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest + @ValueSource(ints = {1, 1000000}) + void 베팅_금액이_1원부터_100만원이라면_올바른_베팅_금액이다(int validAmount) { + // when + BetAmount betAmount = new BetAmount(validAmount); + + // then + assertThat(betAmount.amount()).isEqualTo(validAmount); + } + + @Test + void 베팅_금액을_수익으로_변환할_수_있다() { + // given + BetAmount betAmount = new BetAmount(1000); + + // when + Profit profit = betAmount.toProfit(); + + // then + assertThat(profit).isEqualTo(new Profit(1000)); + } + + + @Test + void 베팅_금액을_손실로_변환할_수_있다() { + // given + BetAmount betAmount = new BetAmount(1000); + + // when + Profit profit = betAmount.toNegativeProfit(); + + // then + assertThat(profit).isEqualTo(new Profit(-1000)); + } +} \ No newline at end of file diff --git a/src/test/java/model/betting/ProfitTest.java b/src/test/java/model/betting/ProfitTest.java new file mode 100644 index 0000000000..dc36d54fe0 --- /dev/null +++ b/src/test/java/model/betting/ProfitTest.java @@ -0,0 +1,40 @@ +package model.betting; + +import static org.assertj.core.api.Assertions.assertThat; + +import model.judgement.Profit; +import org.junit.jupiter.api.Test; + +class ProfitTest { + + @Test + void 수익을_합산할_수_있다() { + // given + Profit profit1 = new Profit(1000); + Profit profit2 = new Profit(2000); + + // when + Profit total = profit1.add(profit2); + + // then + assertThat(total).isEqualTo(new Profit(3000)); + } + + @Test + void 수익의_부호를_반전할_수_있다() { + // given + Profit profit = new Profit(1000); + + // when + Profit negated = profit.negate(); + + // then + assertThat(negated).isEqualTo(new Profit(-1000)); + } + + @Test + void ZERO는_0원의_수익이다() { + // when & then + assertThat(Profit.ZERO).isEqualTo(new Profit(0)); + } +} diff --git a/src/test/java/model/judgement/PlayerResultTest.java b/src/test/java/model/judgement/PlayerResultTest.java new file mode 100644 index 0000000000..1c0e862c23 --- /dev/null +++ b/src/test/java/model/judgement/PlayerResultTest.java @@ -0,0 +1,67 @@ +package model.judgement; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.LinkedHashMap; +import java.util.Map; +import model.paticipant.Player; +import org.junit.jupiter.api.Test; + +class PlayerResultTest { + + @Test + void 플레이어별_수익을_계산한다() { + // given + Player pobi = new Player("pobi", 10000); + Player jason = new Player("jason", 20000); + + Map result = new LinkedHashMap<>(); + result.put(pobi, ResultStatus.WIN); + result.put(jason, ResultStatus.LOSE); + + PlayerResult playerResult = new PlayerResult(result); + + // when + Map profits = playerResult.calculateProfits(); + + // then + assertThat(profits.get(pobi)).isEqualTo(new Profit(10000)); + assertThat(profits.get(jason)).isEqualTo(new Profit(-20000)); + } + + @Test + void 딜러의_수익은_플레이어_수익의_합의_반대이다() { + // given + Player pobi = new Player("pobi", 10000); + Player jason = new Player("jason", 20000); + + Map result = new LinkedHashMap<>(); + result.put(pobi, ResultStatus.WIN); + result.put(jason, ResultStatus.LOSE); + + PlayerResult playerResult = new PlayerResult(result); + + // when + Profit dealerProfit = playerResult.calculateDealerProfit(); + + // then + assertThat(dealerProfit).isEqualTo(new Profit(10000)); + } + + @Test + void 무승부인_플레이어의_수익은_0이다() { + // given + Player pobi = new Player("pobi", 10000); + + Map result = new LinkedHashMap<>(); + result.put(pobi, ResultStatus.DRAW); + + PlayerResult playerResult = new PlayerResult(result); + + // when + Map profits = playerResult.calculateProfits(); + + // then + assertThat(profits.get(pobi)).isEqualTo(Profit.ZERO); + } +} diff --git a/src/test/java/model/judgement/ResultStatusTest.java b/src/test/java/model/judgement/ResultStatusTest.java new file mode 100644 index 0000000000..2fccf80f3c --- /dev/null +++ b/src/test/java/model/judgement/ResultStatusTest.java @@ -0,0 +1,23 @@ +package model.judgement; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class ResultStatusTest { + + @ParameterizedTest(name = "베팅 금액이 1000원 일 때 게임 결과가 {0}이라면, {1}원의 수익이 발생한다") + @MethodSource("fixture.ResultStatusTestFixture#천_원_베팅에_따른_게임_결과별_수익_정보_제공") + void 게임_결과에_따라_베팅_금액의_수익을_계산한다(ResultStatus resultStatus, int expectedProfit) { + // given + BetAmount betAmount = new BetAmount(1000); + + // when + Profit profit = resultStatus.calculateProfit(betAmount); + + // then + assertThat(profit.value()).isEqualTo(expectedProfit); + } + +} \ No newline at end of file From 460719b92b88f6bcf3ae5239f8c49f031a59ddda Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 14:29:13 +0900 Subject: [PATCH 02/24] =?UTF-8?q?refactor:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=88=98=EC=9D=B5=20=EA=B3=84=EC=82=B0=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20get?= =?UTF-8?q?ter=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/judgement/PlayerResult.java | 4 +--- src/main/java/model/paticipant/Player.java | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index 7798f64267..b36a5f3010 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -22,9 +22,7 @@ public int countByStatus(ResultStatus resultStatus) { public Map calculateProfits() { Map profits = new LinkedHashMap<>(); - result.forEach((player, status) -> - profits.put(player, status.calculateProfit(player.getBetAmount())) - ); + result.forEach((player, status) -> profits.put(player, player.calculateProfit(status))); return profits; } diff --git a/src/main/java/model/paticipant/Player.java b/src/main/java/model/paticipant/Player.java index 8672b49798..04650a8e8b 100644 --- a/src/main/java/model/paticipant/Player.java +++ b/src/main/java/model/paticipant/Player.java @@ -1,6 +1,8 @@ package model.paticipant; import model.judgement.BetAmount; +import model.judgement.Profit; +import model.judgement.ResultStatus; public class Player extends Participant { @@ -18,7 +20,7 @@ public boolean canHit() { return calculateTotalScore() < PLAYER_HIT_THRESHOLD; } - public BetAmount getBetAmount() { - return betAmount; + public Profit calculateProfit(ResultStatus resultStatus) { + return resultStatus.calculateProfit(betAmount); } } From e869c705daf53c19b15ac1a285963d631a17c578 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 14:49:35 +0900 Subject: [PATCH 03/24] =?UTF-8?q?refactor:=20=EB=B8=94=EB=9E=99=EC=9E=AD?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 베팅/미베팅 전환에 용이하도록 개선 --- src/main/java/BlackjackApplication.java | 5 +++- .../java/controller/BlackjackController.java | 27 +++++-------------- .../controller/result/ProfitReporter.java | 17 ++++++++++++ .../controller/result/ResultReporter.java | 8 ++++++ .../controller/result/WinLossReporter.java | 18 +++++++++++++ 5 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 src/main/java/controller/result/ProfitReporter.java create mode 100644 src/main/java/controller/result/ResultReporter.java create mode 100644 src/main/java/controller/result/WinLossReporter.java diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index 88cbe2052a..5ec43b04e3 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,4 +1,6 @@ import controller.BlackjackController; +import controller.result.ProfitReporter; +import controller.result.ResultReporter; import java.util.List; import model.BlackjackService; import model.card.Card; @@ -16,7 +18,8 @@ public static void main(String[] args) { Deck deck = new Deck(shuffledCards); BlackjackService blackjackService = new BlackjackService(deck); - BlackjackController controller = new BlackjackController(blackjackService); + ResultReporter resultReporter = new ProfitReporter(); + BlackjackController controller = new BlackjackController(blackjackService, resultReporter); controller.run(); } } diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 6ee187f55d..4d39b66791 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,12 +1,11 @@ package controller; +import controller.result.ResultReporter; import java.util.ArrayList; import java.util.List; import model.BlackjackService; -import model.judgement.DealerResult; import model.judgement.Judgement; import model.judgement.PlayerResult; -import model.judgement.Profit; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; @@ -16,9 +15,11 @@ public class BlackjackController { private final BlackjackService blackjackService; + private final ResultReporter resultReporter; - public BlackjackController(BlackjackService blackjackService) { + public BlackjackController(BlackjackService blackjackService, ResultReporter resultReporter) { this.blackjackService = blackjackService; + this.resultReporter = resultReporter; } public void run() { @@ -29,8 +30,7 @@ public void run() { drawMoreCardByPlayer(dealer, players); printFinalCards(dealer, players); - //judgeGame(dealer, players); - printProfits(dealer, players); + reportResult(dealer, players); } private Players createPlayers() { @@ -86,21 +86,8 @@ private void printFinalCards(Dealer dealer, Players players) { players.forEach(OutputView::printCardByPlayerWithScore); } - private void judgeGame(Dealer dealer, Players players) { + private void reportResult(Dealer dealer, Players players) { PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); - DealerResult dealerResult = Judgement.judgeByDealer(playerResult); - - OutputView.printFinalResultHeader(); - OutputView.printResultByDealer(dealerResult); - OutputView.printResultByPlayers(playerResult); - } - - private void printProfits(Dealer dealer, Players players) { - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); - Profit dealerProfit = playerResult.calculateDealerProfit(); - - OutputView.printFinalProfitHeader(); - OutputView.printProfitByDealer(dealerProfit); - OutputView.printProfitByPlayers(playerResult.calculateProfits()); + resultReporter.report(playerResult); } } diff --git a/src/main/java/controller/result/ProfitReporter.java b/src/main/java/controller/result/ProfitReporter.java new file mode 100644 index 0000000000..8501349806 --- /dev/null +++ b/src/main/java/controller/result/ProfitReporter.java @@ -0,0 +1,17 @@ +package controller.result; + +import model.judgement.PlayerResult; +import model.judgement.Profit; +import view.OutputView; + +public class ProfitReporter implements ResultReporter { + + @Override + public void report(PlayerResult playerResult) { + Profit dealerProfit = playerResult.calculateDealerProfit(); + + OutputView.printFinalProfitHeader(); + OutputView.printProfitByDealer(dealerProfit); + OutputView.printProfitByPlayers(playerResult.calculateProfits()); + } +} diff --git a/src/main/java/controller/result/ResultReporter.java b/src/main/java/controller/result/ResultReporter.java new file mode 100644 index 0000000000..f95b83a05b --- /dev/null +++ b/src/main/java/controller/result/ResultReporter.java @@ -0,0 +1,8 @@ +package controller.result; + +import model.judgement.PlayerResult; + +public interface ResultReporter { + + void report(PlayerResult playerResult); +} diff --git a/src/main/java/controller/result/WinLossReporter.java b/src/main/java/controller/result/WinLossReporter.java new file mode 100644 index 0000000000..b742918721 --- /dev/null +++ b/src/main/java/controller/result/WinLossReporter.java @@ -0,0 +1,18 @@ +package controller.result; + +import model.judgement.DealerResult; +import model.judgement.Judgement; +import model.judgement.PlayerResult; +import view.OutputView; + +public class WinLossReporter implements ResultReporter { + + @Override + public void report(PlayerResult playerResult) { + DealerResult dealerResult = Judgement.judgeByDealer(playerResult); + + OutputView.printFinalResultHeader(); + OutputView.printResultByDealer(dealerResult); + OutputView.printResultByPlayers(playerResult); + } +} From d81f8fb1d5aaf340eb5a5d2fefe4bf5ef60d140e Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 15:02:01 +0900 Subject: [PATCH 04/24] =?UTF-8?q?refactor:=20=EB=B8=94=EB=9E=99=EC=9E=AD?= =?UTF-8?q?=20=EB=B2=A0=ED=8C=85/=EB=AF=B8=EB=B2=A0=ED=8C=85=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=EC=97=90=20=EC=89=AC=EC=9A=B4=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/BlackjackApplication.java | 9 ++++--- .../java/controller/BlackjackController.java | 24 +++++------------ .../controller/input/BettingPlayerReader.java | 22 +++++++++++++++ .../input/NonBettingPlayerReader.java | 20 ++++++++++++++ .../java/controller/input/PlayerReader.java | 8 ++++++ .../java/controller/mode/BettingGameMode.java | 11 ++++++++ .../java/controller/mode/DefaultGameMode.java | 11 ++++++++ src/main/java/controller/mode/GameMode.java | 25 +++++++++++++++++ src/main/java/model/BlackjackService.java | 13 ++++++++- .../java/model/paticipant/BettingPlayer.java | 27 +++++++++++++++++++ .../model/paticipant/NonBettingPlayer.java | 15 +++++++++++ src/main/java/model/paticipant/Player.java | 25 ++++++++--------- src/main/java/view/OutputView.java | 9 +++++++ src/test/java/model/JudgementTest.java | 3 ++- src/test/java/model/PlayerBustTest.java | 5 ++-- src/test/java/model/PlayerTest.java | 3 ++- .../model/judgement/PlayerResultTest.java | 11 ++++---- 17 files changed, 195 insertions(+), 46 deletions(-) create mode 100644 src/main/java/controller/input/BettingPlayerReader.java create mode 100644 src/main/java/controller/input/NonBettingPlayerReader.java create mode 100644 src/main/java/controller/input/PlayerReader.java create mode 100644 src/main/java/controller/mode/BettingGameMode.java create mode 100644 src/main/java/controller/mode/DefaultGameMode.java create mode 100644 src/main/java/controller/mode/GameMode.java create mode 100644 src/main/java/model/paticipant/BettingPlayer.java create mode 100644 src/main/java/model/paticipant/NonBettingPlayer.java diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index 5ec43b04e3..e73068190d 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,6 +1,6 @@ import controller.BlackjackController; -import controller.result.ProfitReporter; -import controller.result.ResultReporter; +import controller.mode.BettingGameMode; +import controller.mode.GameMode; import java.util.List; import model.BlackjackService; import model.card.Card; @@ -18,8 +18,9 @@ public static void main(String[] args) { Deck deck = new Deck(shuffledCards); BlackjackService blackjackService = new BlackjackService(deck); - ResultReporter resultReporter = new ProfitReporter(); - BlackjackController controller = new BlackjackController(blackjackService, resultReporter); + GameMode gameMode = new BettingGameMode(); + + BlackjackController controller = new BlackjackController(blackjackService, gameMode); controller.run(); } } diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 4d39b66791..6fa4b15013 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,8 +1,6 @@ package controller; -import controller.result.ResultReporter; -import java.util.ArrayList; -import java.util.List; +import controller.mode.GameMode; import model.BlackjackService; import model.judgement.Judgement; import model.judgement.PlayerResult; @@ -15,16 +13,16 @@ public class BlackjackController { private final BlackjackService blackjackService; - private final ResultReporter resultReporter; + private final GameMode gameMode; - public BlackjackController(BlackjackService blackjackService, ResultReporter resultReporter) { + public BlackjackController(BlackjackService blackjackService, GameMode gameMode) { this.blackjackService = blackjackService; - this.resultReporter = resultReporter; + this.gameMode = gameMode; } public void run() { Dealer dealer = new Dealer(); - Players players = createPlayers(); + Players players = gameMode.createPlayers(); drawInitCards(dealer, players); drawMoreCardByPlayer(dealer, players); @@ -33,16 +31,6 @@ public void run() { reportResult(dealer, players); } - private Players createPlayers() { - List names = InputView.readPlayerNames(); - List players = new ArrayList<>(); - for (String name : names) { - int betAmount = InputView.readBetAmount(name); - players.add(new Player(name, betAmount)); - } - return new Players(players); - } - private void drawMoreCardByPlayer(Dealer dealer, Players players) { players.forEach(this::chooseHitOrStand); while (dealer.canHit()) { @@ -88,6 +76,6 @@ private void printFinalCards(Dealer dealer, Players players) { private void reportResult(Dealer dealer, Players players) { PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); - resultReporter.report(playerResult); + gameMode.reportResult(playerResult); } } diff --git a/src/main/java/controller/input/BettingPlayerReader.java b/src/main/java/controller/input/BettingPlayerReader.java new file mode 100644 index 0000000000..458deb21c1 --- /dev/null +++ b/src/main/java/controller/input/BettingPlayerReader.java @@ -0,0 +1,22 @@ +package controller.input; + +import java.util.ArrayList; +import java.util.List; +import model.paticipant.BettingPlayer; +import model.paticipant.Player; +import model.paticipant.Players; +import view.InputView; + +public class BettingPlayerReader implements PlayerReader { + + @Override + public Players readPlayers() { + List names = InputView.readPlayerNames(); + List players = new ArrayList<>(); + for (String name : names) { + int betAmount = InputView.readBetAmount(name); + players.add(new BettingPlayer(name, betAmount)); + } + return new Players(players); + } +} diff --git a/src/main/java/controller/input/NonBettingPlayerReader.java b/src/main/java/controller/input/NonBettingPlayerReader.java new file mode 100644 index 0000000000..9a8070380f --- /dev/null +++ b/src/main/java/controller/input/NonBettingPlayerReader.java @@ -0,0 +1,20 @@ +package controller.input; + +import java.util.List; +import java.util.stream.Collectors; +import model.paticipant.NonBettingPlayer; +import model.paticipant.Player; +import model.paticipant.Players; +import view.InputView; + +public class NonBettingPlayerReader implements PlayerReader { + + @Override + public Players readPlayers() { + List names = InputView.readPlayerNames(); + List players = names.stream() + .map(NonBettingPlayer::new) + .collect(Collectors.toList()); + return new Players(players); + } +} diff --git a/src/main/java/controller/input/PlayerReader.java b/src/main/java/controller/input/PlayerReader.java new file mode 100644 index 0000000000..36d5c19328 --- /dev/null +++ b/src/main/java/controller/input/PlayerReader.java @@ -0,0 +1,8 @@ +package controller.input; + +import model.paticipant.Players; + +public interface PlayerReader { + + Players readPlayers(); +} diff --git a/src/main/java/controller/mode/BettingGameMode.java b/src/main/java/controller/mode/BettingGameMode.java new file mode 100644 index 0000000000..a378f2acfc --- /dev/null +++ b/src/main/java/controller/mode/BettingGameMode.java @@ -0,0 +1,11 @@ +package controller.mode; + +import controller.input.BettingPlayerReader; +import controller.result.ProfitReporter; + +public class BettingGameMode extends GameMode { + + public BettingGameMode() { + super(new BettingPlayerReader(), new ProfitReporter()); + } +} diff --git a/src/main/java/controller/mode/DefaultGameMode.java b/src/main/java/controller/mode/DefaultGameMode.java new file mode 100644 index 0000000000..af267cd576 --- /dev/null +++ b/src/main/java/controller/mode/DefaultGameMode.java @@ -0,0 +1,11 @@ +package controller.mode; + +import controller.input.NonBettingPlayerReader; +import controller.result.WinLossReporter; + +public class DefaultGameMode extends GameMode { + + public DefaultGameMode() { + super(new NonBettingPlayerReader(), new WinLossReporter()); + } +} diff --git a/src/main/java/controller/mode/GameMode.java b/src/main/java/controller/mode/GameMode.java new file mode 100644 index 0000000000..4fb943099f --- /dev/null +++ b/src/main/java/controller/mode/GameMode.java @@ -0,0 +1,25 @@ +package controller.mode; + +import controller.input.PlayerReader; +import controller.result.ResultReporter; +import model.judgement.PlayerResult; +import model.paticipant.Players; + +public abstract class GameMode { + + private final PlayerReader playerReader; + private final ResultReporter resultReporter; + + protected GameMode(PlayerReader playerReader, ResultReporter resultReporter) { + this.playerReader = playerReader; + this.resultReporter = resultReporter; + } + + public Players createPlayers() { + return playerReader.readPlayers(); + } + + public void reportResult(PlayerResult playerResult) { + resultReporter.report(playerResult); + } +} diff --git a/src/main/java/model/BlackjackService.java b/src/main/java/model/BlackjackService.java index e0422c3073..2c6e2cd4ae 100644 --- a/src/main/java/model/BlackjackService.java +++ b/src/main/java/model/BlackjackService.java @@ -3,6 +3,7 @@ import model.card.Deck; import model.paticipant.Dealer; import model.paticipant.Participant; +import model.paticipant.Player; import model.paticipant.Players; public class BlackjackService { @@ -18,16 +19,26 @@ public BlackjackService(Deck deck) { public void drawTwoCards(Dealer dealer, Players players) { drawCardByParticipant(dealer, INITIAL_DISPENSE_COUNT); - players.forEach(player -> drawCardByParticipant(player, INITIAL_DISPENSE_COUNT)); + players.forEach(player -> drawCardByPlayer(player, INITIAL_DISPENSE_COUNT)); } public void drawOneCard(Participant participant) { drawCardByParticipant(participant, BASE_DISPENSE_COUNT); } + public void drawOneCard(Player player) { + drawCardByPlayer(player, BASE_DISPENSE_COUNT); + } + private void drawCardByParticipant(Participant participant, int count) { for (int i = 0; i < count; i++) { participant.addCard(deck.draw()); } } + + private void drawCardByPlayer(Player player, int count) { + for (int i = 0; i < count; i++) { + player.addCard(deck.draw()); + } + } } diff --git a/src/main/java/model/paticipant/BettingPlayer.java b/src/main/java/model/paticipant/BettingPlayer.java new file mode 100644 index 0000000000..8a20e3ab5e --- /dev/null +++ b/src/main/java/model/paticipant/BettingPlayer.java @@ -0,0 +1,27 @@ +package model.paticipant; + +import model.judgement.BetAmount; +import model.judgement.Profit; +import model.judgement.ResultStatus; + +public class BettingPlayer extends Participant implements Player { + + private static final int PLAYER_HIT_THRESHOLD = 21; + + private final BetAmount betAmount; + + public BettingPlayer(String name, int betAmount) { + super(name); + this.betAmount = new BetAmount(betAmount); + } + + @Override + public boolean canHit() { + return calculateTotalScore() < PLAYER_HIT_THRESHOLD; + } + + @Override + public Profit calculateProfit(ResultStatus resultStatus) { + return resultStatus.calculateProfit(betAmount); + } +} diff --git a/src/main/java/model/paticipant/NonBettingPlayer.java b/src/main/java/model/paticipant/NonBettingPlayer.java new file mode 100644 index 0000000000..db6856683b --- /dev/null +++ b/src/main/java/model/paticipant/NonBettingPlayer.java @@ -0,0 +1,15 @@ +package model.paticipant; + +public class NonBettingPlayer extends Participant implements Player { + + private static final int PLAYER_HIT_THRESHOLD = 21; + + public NonBettingPlayer(String name) { + super(name); + } + + @Override + public boolean canHit() { + return calculateTotalScore() < PLAYER_HIT_THRESHOLD; + } +} diff --git a/src/main/java/model/paticipant/Player.java b/src/main/java/model/paticipant/Player.java index 04650a8e8b..577a61c92a 100644 --- a/src/main/java/model/paticipant/Player.java +++ b/src/main/java/model/paticipant/Player.java @@ -1,26 +1,23 @@ package model.paticipant; -import model.judgement.BetAmount; import model.judgement.Profit; import model.judgement.ResultStatus; -public class Player extends Participant { +public interface Player { - private static final int PLAYER_HIT_THRESHOLD = 21; + String getName(); - private final BetAmount betAmount; + int calculateTotalScore(); - public Player(String name, int betAmount) { - super(name); - this.betAmount = new BetAmount(betAmount); - } + boolean canHit(); - @Override - public boolean canHit() { - return calculateTotalScore() < PLAYER_HIT_THRESHOLD; - } + void addCard(model.card.Card card); + + boolean isBust(); + + java.util.List getCards(); - public Profit calculateProfit(ResultStatus resultStatus) { - return resultStatus.calculateProfit(betAmount); + default Profit calculateProfit(ResultStatus resultStatus) { + return model.judgement.Profit.ZERO; } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 2a68fecac4..adde7fe6f1 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -55,6 +55,15 @@ public static void printCardByPlayerWithScore(Participant participant) { System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); } + public static void printCardByPlayerWithScore(Player player) { + int sum = player.calculateTotalScore(); + List cards = player.getCards() + .stream() + .map(OutputView::convert) + .toList(); + System.out.printf("%s 카드: %s - 결과: %d%n", player.getName(), String.join(", ", cards), sum); + } + private static String convert(Card card) { return card.value().getSymbol() + card.shape().getShape(); } diff --git a/src/test/java/model/JudgementTest.java b/src/test/java/model/JudgementTest.java index 926cb61ac7..17975119e7 100644 --- a/src/test/java/model/JudgementTest.java +++ b/src/test/java/model/JudgementTest.java @@ -9,6 +9,7 @@ import model.judgement.PlayerResult; import model.judgement.ResultStatus; import model.paticipant.Dealer; +import model.paticipant.BettingPlayer; import model.paticipant.Player; import model.paticipant.Players; import org.junit.jupiter.params.ParameterizedTest; @@ -27,7 +28,7 @@ public class JudgementTest { Dealer dealer = createDealer(); dealerCards.forEach(dealer::addCard); - Player player = new Player("pobi", 10000); + Player player = new BettingPlayer("pobi", 10000); playerCards.forEach(player::addCard); // when diff --git a/src/test/java/model/PlayerBustTest.java b/src/test/java/model/PlayerBustTest.java index c3a827ef0d..e53ae1f72a 100644 --- a/src/test/java/model/PlayerBustTest.java +++ b/src/test/java/model/PlayerBustTest.java @@ -5,6 +5,7 @@ import model.card.Card; import model.card.CardShape; import model.card.CardValue; +import model.paticipant.BettingPlayer; import model.paticipant.Player; import org.junit.jupiter.api.Test; @@ -13,7 +14,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_20_이하_일_때_카드를_더_받을_수_있다() { // given - Player pobi = new Player("pobi", 10000); + Player pobi = new BettingPlayer("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); @@ -24,7 +25,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_21_이상_일_때_카드를_더_받을_수_없다() { // given - Player pobi = new Player("pobi", 10000); + Player pobi = new BettingPlayer("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.ACE)); diff --git a/src/test/java/model/PlayerTest.java b/src/test/java/model/PlayerTest.java index 0f46227ef9..fb5a829539 100644 --- a/src/test/java/model/PlayerTest.java +++ b/src/test/java/model/PlayerTest.java @@ -4,6 +4,7 @@ import java.util.List; import model.card.Card; +import model.paticipant.BettingPlayer; import model.paticipant.Player; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -14,7 +15,7 @@ class PlayerTest { @MethodSource("fixture.PlayerTestFixture#플레이어별_카드목록_및_점수_제공") void 블랙잭_참여자는_자신의_카드_정보로_현재_점수를_계산할_수_있다(List cards, int expectedScore) { // given - Player pobi = new Player("pobi", 10000); + Player pobi = new BettingPlayer("pobi", 10000); cards.forEach(pobi::addCard); // when diff --git a/src/test/java/model/judgement/PlayerResultTest.java b/src/test/java/model/judgement/PlayerResultTest.java index 1c0e862c23..8bcb728d17 100644 --- a/src/test/java/model/judgement/PlayerResultTest.java +++ b/src/test/java/model/judgement/PlayerResultTest.java @@ -4,6 +4,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import model.paticipant.BettingPlayer; import model.paticipant.Player; import org.junit.jupiter.api.Test; @@ -12,8 +13,8 @@ class PlayerResultTest { @Test void 플레이어별_수익을_계산한다() { // given - Player pobi = new Player("pobi", 10000); - Player jason = new Player("jason", 20000); + Player pobi = new BettingPlayer("pobi", 10000); + Player jason = new BettingPlayer("jason", 20000); Map result = new LinkedHashMap<>(); result.put(pobi, ResultStatus.WIN); @@ -32,8 +33,8 @@ class PlayerResultTest { @Test void 딜러의_수익은_플레이어_수익의_합의_반대이다() { // given - Player pobi = new Player("pobi", 10000); - Player jason = new Player("jason", 20000); + Player pobi = new BettingPlayer("pobi", 10000); + Player jason = new BettingPlayer("jason", 20000); Map result = new LinkedHashMap<>(); result.put(pobi, ResultStatus.WIN); @@ -51,7 +52,7 @@ class PlayerResultTest { @Test void 무승부인_플레이어의_수익은_0이다() { // given - Player pobi = new Player("pobi", 10000); + Player pobi = new BettingPlayer("pobi", 10000); Map result = new LinkedHashMap<>(); result.put(pobi, ResultStatus.DRAW); From 967a9c2cddd0e5922743cbaabc4a405b981e9c80 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 15:04:40 +0900 Subject: [PATCH 05/24] =?UTF-8?q?refactor:=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=EC=9A=B0=20=EC=97=AC=EB=B6=80=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackjackController.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 6fa4b15013..15aab5e2b5 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -56,16 +56,20 @@ private Continuation readContinuation(Player player) { } private void chooseHitOrStand(Player player) { - boolean printed = false; - while (canHitMore(player)) { - blackjackService.drawOneCard(player); + boolean didDraw = drawMoreCard(player); + if (!didDraw) { OutputView.printCardByPlayer(player); - printed = true; } + } - if (!printed) { + private boolean drawMoreCard(Player player) { + boolean didDraw = false; + while (canHitMore(player)) { + blackjackService.drawOneCard(player); OutputView.printCardByPlayer(player); + didDraw = true; } + return didDraw; } private void printFinalCards(Dealer dealer, Players players) { From 8af38b2dd065ef145c02eaad3f294d3ad7a254ed Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 15:37:30 +0900 Subject: [PATCH 06/24] =?UTF-8?q?feat:=20=EB=B8=94=EB=9E=99=EC=9E=AD?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98=EC=9D=B5=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/card/Hand.java | 4 ++ src/main/java/model/judgement/BetAmount.java | 5 ++ src/main/java/model/judgement/Judgement.java | 18 +++++- .../java/model/judgement/ResultStatus.java | 6 ++ .../java/model/paticipant/Participant.java | 5 ++ src/main/java/model/paticipant/Player.java | 10 +++- .../java/fixture/ResultStatusTestFixture.java | 3 +- src/test/java/model/JudgementTest.java | 58 +++++++++++++++++++ .../java/model/betting/BetAmountTest.java | 12 ++++ .../model/paticipant/ParticipantTest.java | 54 +++++++++++++++++ 10 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 src/test/java/model/paticipant/ParticipantTest.java diff --git a/src/main/java/model/card/Hand.java b/src/main/java/model/card/Hand.java index 3e92b6074b..6e3a533279 100644 --- a/src/main/java/model/card/Hand.java +++ b/src/main/java/model/card/Hand.java @@ -28,6 +28,10 @@ public int countAce() { .count(); } + public int size() { + return cards.size(); + } + public List getCards() { return Collections.unmodifiableList(this.cards); } diff --git a/src/main/java/model/judgement/BetAmount.java b/src/main/java/model/judgement/BetAmount.java index a1cd55f0da..2b1f4b4774 100644 --- a/src/main/java/model/judgement/BetAmount.java +++ b/src/main/java/model/judgement/BetAmount.java @@ -4,6 +4,7 @@ public record BetAmount(int amount) { private static final int MIN_BET_AMOUNT = 1; private static final int MAX_BET_AMOUNT = 1_000_000; + private static final double BLACKJACK_MULTIPLIER = 1.5; public BetAmount { validate(amount); @@ -24,4 +25,8 @@ public Profit toProfit() { public Profit toNegativeProfit() { return new Profit(-amount); } + + public Profit toBlackjackProfit() { + return new Profit((int) (amount * BLACKJACK_MULTIPLIER)); + } } diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index bd18447219..a0c293f087 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -1,5 +1,6 @@ package model.judgement; +import static model.judgement.ResultStatus.BLACKJACK; import static model.judgement.ResultStatus.DRAW; import static model.judgement.ResultStatus.LOSE; import static model.judgement.ResultStatus.WIN; @@ -26,9 +27,24 @@ private static ResultStatus decide(Dealer dealer, Player player) { return WIN; } + if (dealer.isBlackjack()) { + return decideWhenDealerBlackjack(player); + } + + if (player.isBlackjack()) { + return BLACKJACK; + } + return decideByScore(dealer, player); } + private static ResultStatus decideWhenDealerBlackjack(Player player) { + if (player.isBlackjack()) { + return DRAW; + } + return LOSE; + } + private static ResultStatus decideByScore(Dealer dealer, Player player) { int dealerScore = dealer.calculateTotalScore(); int playerScore = player.calculateTotalScore(); @@ -44,7 +60,7 @@ private static ResultStatus decideByScore(Dealer dealer, Player player) { public static DealerResult judgeByDealer(PlayerResult playerResult) { int dealerWinCount = playerResult.countByStatus(ResultStatus.LOSE); - int dealerLoseCount = playerResult.countByStatus(ResultStatus.WIN); + int dealerLoseCount = playerResult.countByStatus(ResultStatus.WIN) + playerResult.countByStatus(ResultStatus.BLACKJACK); int dealerDrawCount = playerResult.countByStatus(ResultStatus.DRAW); return new DealerResult(dealerWinCount, dealerLoseCount, dealerDrawCount); } diff --git a/src/main/java/model/judgement/ResultStatus.java b/src/main/java/model/judgement/ResultStatus.java index b0e399ec19..cd8c4650b3 100644 --- a/src/main/java/model/judgement/ResultStatus.java +++ b/src/main/java/model/judgement/ResultStatus.java @@ -19,6 +19,12 @@ public Profit calculateProfit(BetAmount betAmount) { public Profit calculateProfit(BetAmount betAmount) { return Profit.ZERO; } + }, + BLACKJACK("승") { + @Override + public Profit calculateProfit(BetAmount betAmount) { + return betAmount.toBlackjackProfit(); + } }; private final String name; diff --git a/src/main/java/model/paticipant/Participant.java b/src/main/java/model/paticipant/Participant.java index e418b3ec99..85a3a4fccb 100644 --- a/src/main/java/model/paticipant/Participant.java +++ b/src/main/java/model/paticipant/Participant.java @@ -8,6 +8,7 @@ public abstract class Participant { private static final int BUST_LIMIT = 21; private static final int ACE_BONUS_SCORE = 10; + private static final int BLACKJACK_CARD_COUNT = 2; private final Name name; private final Hand hand; @@ -32,6 +33,10 @@ public boolean isBust() { return calculateTotalScore() > BUST_LIMIT; } + public boolean isBlackjack() { + return hand.size() == BLACKJACK_CARD_COUNT && calculateTotalScore() == BUST_LIMIT; + } + public void addCard(Card card) { this.hand.add(card); } diff --git a/src/main/java/model/paticipant/Player.java b/src/main/java/model/paticipant/Player.java index 577a61c92a..f55616070a 100644 --- a/src/main/java/model/paticipant/Player.java +++ b/src/main/java/model/paticipant/Player.java @@ -1,5 +1,9 @@ package model.paticipant; +import static model.judgement.Profit.ZERO; + +import java.util.List; +import model.card.Card; import model.judgement.Profit; import model.judgement.ResultStatus; @@ -15,9 +19,11 @@ public interface Player { boolean isBust(); - java.util.List getCards(); + boolean isBlackjack(); + + List getCards(); default Profit calculateProfit(ResultStatus resultStatus) { - return model.judgement.Profit.ZERO; + return ZERO; } } diff --git a/src/test/java/fixture/ResultStatusTestFixture.java b/src/test/java/fixture/ResultStatusTestFixture.java index c9c8608e0f..770a8312cf 100644 --- a/src/test/java/fixture/ResultStatusTestFixture.java +++ b/src/test/java/fixture/ResultStatusTestFixture.java @@ -10,7 +10,8 @@ public class ResultStatusTestFixture { return Stream.of( Arguments.of(ResultStatus.WIN, 1000), // 수익 금액 그대로 Arguments.of(ResultStatus.LOSE, -1000), // 수익 금액 반대 - 손실 - Arguments.of(ResultStatus.DRAW, 0) // 무승부 시 수익 없음 + Arguments.of(ResultStatus.DRAW, 0), // 무승부 시 수익 없음 + Arguments.of(ResultStatus.BLACKJACK, 1500) // 블랙잭 시 1.5배 수익 ); } diff --git a/src/test/java/model/JudgementTest.java b/src/test/java/model/JudgementTest.java index 17975119e7..dec959bfcf 100644 --- a/src/test/java/model/JudgementTest.java +++ b/src/test/java/model/JudgementTest.java @@ -5,6 +5,8 @@ import java.util.List; import model.card.Card; +import model.card.CardShape; +import model.card.CardValue; import model.judgement.Judgement; import model.judgement.PlayerResult; import model.judgement.ResultStatus; @@ -12,6 +14,7 @@ import model.paticipant.BettingPlayer; import model.paticipant.Player; import model.paticipant.Players; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -37,4 +40,59 @@ public class JudgementTest { // then assertThat(playerResult.countByStatus(status)).isEqualTo(1); } + + @Test + void 플레이어가_블랙잭이고_딜러가_블랙잭이_아니면_BLACKJACK_결과이다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.TEN)); + dealer.addCard(new Card(CardShape.HEART, CardValue.NINE)); + + Player player = new BettingPlayer("pobi", 10000); + player.addCard(new Card(CardShape.HEART, CardValue.ACE)); + player.addCard(new Card(CardShape.HEART, CardValue.KING)); + + // when + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); + + // then + assertThat(playerResult.countByStatus(ResultStatus.BLACKJACK)).isEqualTo(1); + } + + @Test + void 플레이어와_딜러_모두_블랙잭이면_DRAW_결과이다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.ACE)); + dealer.addCard(new Card(CardShape.HEART, CardValue.KING)); + + Player player = new BettingPlayer("pobi", 10000); + player.addCard(new Card(CardShape.DIAMOND, CardValue.ACE)); + player.addCard(new Card(CardShape.DIAMOND, CardValue.KING)); + + // when + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); + + // then + assertThat(playerResult.countByStatus(ResultStatus.DRAW)).isEqualTo(1); + } + + @Test + void 딜러가_블랙잭이고_플레이어가_블랙잭이_아니면_LOSE_결과이다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.ACE)); + dealer.addCard(new Card(CardShape.HEART, CardValue.KING)); + + Player player = new BettingPlayer("pobi", 10000); + player.addCard(new Card(CardShape.HEART, CardValue.TEN)); + player.addCard(new Card(CardShape.HEART, CardValue.FIVE)); + player.addCard(new Card(CardShape.HEART, CardValue.SIX)); + + // when + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); + + // then + assertThat(playerResult.countByStatus(ResultStatus.LOSE)).isEqualTo(1); + } } diff --git a/src/test/java/model/betting/BetAmountTest.java b/src/test/java/model/betting/BetAmountTest.java index adcbd47a8d..1312df3343 100644 --- a/src/test/java/model/betting/BetAmountTest.java +++ b/src/test/java/model/betting/BetAmountTest.java @@ -53,4 +53,16 @@ class BetAmountTest { // then assertThat(profit).isEqualTo(new Profit(-1000)); } + + @Test + void 블랙잭일_경우_베팅_금액의_1점_5배를_수익으로_변환한다() { + // given + BetAmount betAmount = new BetAmount(10000); + + // when + Profit profit = betAmount.toBlackjackProfit(); + + // then + assertThat(profit).isEqualTo(new Profit(15000)); + } } \ No newline at end of file diff --git a/src/test/java/model/paticipant/ParticipantTest.java b/src/test/java/model/paticipant/ParticipantTest.java new file mode 100644 index 0000000000..42b9cf4c55 --- /dev/null +++ b/src/test/java/model/paticipant/ParticipantTest.java @@ -0,0 +1,54 @@ +package model.paticipant; + +import static org.assertj.core.api.Assertions.assertThat; + +import model.card.Card; +import model.card.CardShape; +import model.card.CardValue; +import org.junit.jupiter.api.Test; + +class ParticipantTest { + + @Test + void 처음_2장의_카드_합이_21이면_블랙잭이다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.ACE)); + dealer.addCard(new Card(CardShape.HEART, CardValue.KING)); + + // when + boolean isBlackjack = dealer.isBlackjack(); + + // then + assertThat(isBlackjack).isTrue(); + } + + @Test + void 카드가_2장이상이면_블랙잭이_아니다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.TEN)); + dealer.addCard(new Card(CardShape.HEART, CardValue.FIVE)); + dealer.addCard(new Card(CardShape.HEART, CardValue.SIX)); + + // when + boolean isBlackjack = dealer.isBlackjack(); + + // then + assertThat(isBlackjack).isFalse(); + } + + @Test + void 카드_2장의_합이_21이_아니면_블랙잭이_아니다() { + // given + Dealer dealer = new Dealer(); + dealer.addCard(new Card(CardShape.HEART, CardValue.TEN)); + dealer.addCard(new Card(CardShape.HEART, CardValue.FIVE)); + + // when + boolean isBlackjack = dealer.isBlackjack(); + + // then + assertThat(isBlackjack).isFalse(); + } +} From ab14624b6aef18259fe469f840b03bb87fe62205 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 16:41:53 +0900 Subject: [PATCH 07/24] =?UTF-8?q?refactor:=20Enum=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=97=90=20=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/card/CardShape.java | 15 +------ src/main/java/model/card/CardValue.java | 34 +++++++-------- .../java/model/judgement/ResultStatus.java | 18 ++------ src/main/java/view/OutputView.java | 6 ++- src/main/java/view/mapper/EnumMapper.java | 41 +++++++++++++++++++ 5 files changed, 64 insertions(+), 50 deletions(-) create mode 100644 src/main/java/view/mapper/EnumMapper.java diff --git a/src/main/java/model/card/CardShape.java b/src/main/java/model/card/CardShape.java index c216538e63..358cd32906 100644 --- a/src/main/java/model/card/CardShape.java +++ b/src/main/java/model/card/CardShape.java @@ -1,18 +1,5 @@ package model.card; public enum CardShape { - DIAMOND("다이아몬드"), - HEART("하트"), - CLOVER("클로버"), - SPADE("스페이드"); - - private final String shape; - - CardShape(String shape) { - this.shape = shape; - } - - public String getShape() { - return shape; - } + DIAMOND, HEART, CLOVER, SPADE; } diff --git a/src/main/java/model/card/CardValue.java b/src/main/java/model/card/CardValue.java index 3a12e22c3e..62e2d7924f 100644 --- a/src/main/java/model/card/CardValue.java +++ b/src/main/java/model/card/CardValue.java @@ -1,33 +1,27 @@ package model.card; public enum CardValue { - ACE(1, "A"), - TWO(2, "2"), - THREE(3, "3"), - FOUR(4, "4"), - FIVE(5, "5"), - SIX(6, "6"), - SEVEN(7, "7"), - EIGHT(8, "8"), - NINE(9, "9"), - TEN(10, "10"), - JACK(10, "J"), - QUEEN(10, "Q"), - KING(10, "K"); + ACE(1), + TWO(2), + THREE(3), + FOUR(4), + FIVE(5), + SIX(6), + SEVEN(7), + EIGHT(8), + NINE(9), + TEN(10), + JACK(10), + QUEEN(10), + KING(10); private final int score; - private final String symbol; - CardValue(int score, String symbol) { + CardValue(int score) { this.score = score; - this.symbol = symbol; } public int getScore() { return score; } - - public String getSymbol() { - return symbol; - } } diff --git a/src/main/java/model/judgement/ResultStatus.java b/src/main/java/model/judgement/ResultStatus.java index cd8c4650b3..544612d6d2 100644 --- a/src/main/java/model/judgement/ResultStatus.java +++ b/src/main/java/model/judgement/ResultStatus.java @@ -2,40 +2,30 @@ public enum ResultStatus { - WIN("승") { + WIN { @Override public Profit calculateProfit(BetAmount betAmount) { return betAmount.toProfit(); } }, - LOSE("패") { + LOSE { @Override public Profit calculateProfit(BetAmount betAmount) { return betAmount.toNegativeProfit(); } }, - DRAW("무") { + DRAW { @Override public Profit calculateProfit(BetAmount betAmount) { return Profit.ZERO; } }, - BLACKJACK("승") { + BLACKJACK { @Override public Profit calculateProfit(BetAmount betAmount) { return betAmount.toBlackjackProfit(); } }; - private final String name; - - ResultStatus(String name) { - this.name = name; - } - - public String getName() { - return name; - } - public abstract Profit calculateProfit(BetAmount betAmount); } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index adde7fe6f1..3bd69b9f58 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -10,6 +10,7 @@ import model.paticipant.Participant; import model.paticipant.Player; import model.paticipant.Players; +import view.mapper.EnumMapper; public class OutputView { @@ -65,7 +66,7 @@ public static void printCardByPlayerWithScore(Player player) { } private static String convert(Card card) { - return card.value().getSymbol() + card.shape().getShape(); + return EnumMapper.CARD_VALUE_MAPPER.get(card.value()) + EnumMapper.CARD_SHAPE_MAPPER.get(card.shape()); } public static void printToOpenDealerNewCard(Dealer dealer) { @@ -99,7 +100,8 @@ public static void printResultByDealer(DealerResult dealerResult) { public static void printResultByPlayers(PlayerResult playerResult) { playerResult.getResult() - .forEach((player, status) -> System.out.printf("%s: %s%n", player.getName(), status.getName())); + .forEach((player, status) -> + System.out.printf("%s: %s%n", player.getName(), EnumMapper.RESULT_STATUS_MAPPER.get(status))); } public static void printFinalProfitHeader() { diff --git a/src/main/java/view/mapper/EnumMapper.java b/src/main/java/view/mapper/EnumMapper.java new file mode 100644 index 0000000000..e4907fa5ee --- /dev/null +++ b/src/main/java/view/mapper/EnumMapper.java @@ -0,0 +1,41 @@ +package view.mapper; + +import java.util.Map; +import model.card.CardShape; +import model.card.CardValue; +import model.judgement.ResultStatus; + +public class EnumMapper { + + public static final Map RESULT_STATUS_MAPPER = Map.of( + ResultStatus.WIN, "승", + ResultStatus.LOSE, "패", + ResultStatus.DRAW, "무", + ResultStatus.BLACKJACK, "블랙잭" + ); + + public static final Map CARD_VALUE_MAPPER = Map.ofEntries( + Map.entry(CardValue.ACE, "A"), + Map.entry(CardValue.TWO, "2"), + Map.entry(CardValue.THREE, "3"), + Map.entry(CardValue.FOUR, "4"), + Map.entry(CardValue.FIVE, "5"), + Map.entry(CardValue.SIX, "6"), + Map.entry(CardValue.SEVEN, "7"), + Map.entry(CardValue.EIGHT, "8"), + Map.entry(CardValue.NINE, "9"), + Map.entry(CardValue.TEN, "10"), + Map.entry(CardValue.JACK, "J"), + Map.entry(CardValue.QUEEN, "Q"), + Map.entry(CardValue.KING, "K") + ); + + public static final Map CARD_SHAPE_MAPPER = Map.of( + CardShape.HEART, "하트", + CardShape.SPADE, "스페이드", + CardShape.CLOVER, "클로버", + CardShape.DIAMOND, "다이아몬드" + ); + + public EnumMapper(){} +} From 9a45a99f7e5322e3f3ef2271b7f10e8b2a0061ee Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 16:49:20 +0900 Subject: [PATCH 08/24] =?UTF-8?q?refactor:=20OutputView=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/result/ProfitReporter.java | 8 +-- .../controller/result/WinLossReporter.java | 8 +-- src/main/java/view/OutputView.java | 45 ----------------- src/main/java/view/ProfitReportView.java | 25 ++++++++++ src/main/java/view/WinLossReportView.java | 50 +++++++++++++++++++ src/main/java/view/mapper/EnumMapper.java | 2 +- 6 files changed, 84 insertions(+), 54 deletions(-) create mode 100644 src/main/java/view/ProfitReportView.java create mode 100644 src/main/java/view/WinLossReportView.java diff --git a/src/main/java/controller/result/ProfitReporter.java b/src/main/java/controller/result/ProfitReporter.java index 8501349806..87df318b02 100644 --- a/src/main/java/controller/result/ProfitReporter.java +++ b/src/main/java/controller/result/ProfitReporter.java @@ -2,7 +2,7 @@ import model.judgement.PlayerResult; import model.judgement.Profit; -import view.OutputView; +import view.ProfitReportView; public class ProfitReporter implements ResultReporter { @@ -10,8 +10,8 @@ public class ProfitReporter implements ResultReporter { public void report(PlayerResult playerResult) { Profit dealerProfit = playerResult.calculateDealerProfit(); - OutputView.printFinalProfitHeader(); - OutputView.printProfitByDealer(dealerProfit); - OutputView.printProfitByPlayers(playerResult.calculateProfits()); + ProfitReportView.printFinalProfitHeader(); + ProfitReportView.printProfitByDealer(dealerProfit); + ProfitReportView.printProfitByPlayers(playerResult.calculateProfits()); } } diff --git a/src/main/java/controller/result/WinLossReporter.java b/src/main/java/controller/result/WinLossReporter.java index b742918721..71ed3a04b8 100644 --- a/src/main/java/controller/result/WinLossReporter.java +++ b/src/main/java/controller/result/WinLossReporter.java @@ -3,7 +3,7 @@ import model.judgement.DealerResult; import model.judgement.Judgement; import model.judgement.PlayerResult; -import view.OutputView; +import view.WinLossReportView; public class WinLossReporter implements ResultReporter { @@ -11,8 +11,8 @@ public class WinLossReporter implements ResultReporter { public void report(PlayerResult playerResult) { DealerResult dealerResult = Judgement.judgeByDealer(playerResult); - OutputView.printFinalResultHeader(); - OutputView.printResultByDealer(dealerResult); - OutputView.printResultByPlayers(playerResult); + WinLossReportView.printFinalResultHeader(); + WinLossReportView.printResultByDealer(dealerResult); + WinLossReportView.printResultByPlayers(playerResult); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 3bd69b9f58..93166cc7cf 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,11 +1,7 @@ package view; import java.util.List; -import java.util.Map; import model.card.Card; -import model.judgement.DealerResult; -import model.judgement.PlayerResult; -import model.judgement.Profit; import model.paticipant.Dealer; import model.paticipant.Participant; import model.paticipant.Player; @@ -77,45 +73,4 @@ public static void printToOpenDealerNewCard(Dealer dealer) { public static void printBlank() { System.out.println(); } - - public static void printFinalResultHeader() { - System.out.println(); - System.out.println("## 최종 승패"); - } - - public static void printResultByDealer(DealerResult dealerResult) { - System.out.print("딜러: "); - StringBuilder result = new StringBuilder(); - if (dealerResult.winCount() > 0) { - result.append(dealerResult.winCount()).append("승 "); - } - if (dealerResult.drawCount() > 0) { - result.append(dealerResult.drawCount()).append("무 "); - } - if (dealerResult.loseCount() > 0) { - result.append(dealerResult.loseCount()).append("패"); - } - System.out.println(result.toString().trim()); - } - - public static void printResultByPlayers(PlayerResult playerResult) { - playerResult.getResult() - .forEach((player, status) -> - System.out.printf("%s: %s%n", player.getName(), EnumMapper.RESULT_STATUS_MAPPER.get(status))); - } - - public static void printFinalProfitHeader() { - System.out.println(); - System.out.println("## 최종 수익"); - } - - public static void printProfitByDealer(Profit profit) { - System.out.printf("딜러: %d%n", profit.value()); - } - - public static void printProfitByPlayers(Map profits) { - profits.forEach((player, profit) -> - System.out.printf("%s: %d%n", player.getName(), profit.value()) - ); - } } \ No newline at end of file diff --git a/src/main/java/view/ProfitReportView.java b/src/main/java/view/ProfitReportView.java new file mode 100644 index 0000000000..dca7a0fe6b --- /dev/null +++ b/src/main/java/view/ProfitReportView.java @@ -0,0 +1,25 @@ +package view; + +import java.util.Map; +import model.judgement.Profit; +import model.paticipant.Player; + +public class ProfitReportView { + + private ProfitReportView() {} + + public static void printFinalProfitHeader() { + System.out.println(); + System.out.println("## 최종 수익"); + } + + public static void printProfitByDealer(Profit profit) { + System.out.printf("딜러: %d%n", profit.value()); + } + + public static void printProfitByPlayers(Map profits) { + profits.forEach((player, profit) -> + System.out.printf("%s: %d%n", player.getName(), profit.value()) + ); + } +} diff --git a/src/main/java/view/WinLossReportView.java b/src/main/java/view/WinLossReportView.java new file mode 100644 index 0000000000..1fb8d339b4 --- /dev/null +++ b/src/main/java/view/WinLossReportView.java @@ -0,0 +1,50 @@ +package view; + +import model.judgement.DealerResult; +import model.judgement.PlayerResult; +import view.mapper.EnumMapper; + +public class WinLossReportView { + + private WinLossReportView() {} + + public static void printFinalResultHeader() { + System.out.println(); + System.out.println("## 최종 승패"); + } + + public static void printResultByDealer(DealerResult dealerResult) { + System.out.print("딜러: "); + String result = extractWinMessage(dealerResult.winCount()) + + extractDrawMessage(dealerResult.drawCount()) + + extractLoseMessage(dealerResult.loseCount()); + System.out.println(result.trim()); + } + + private static String extractWinMessage(int winCount) { + if (winCount > 0) { + return "승 "; + } + return ""; + } + + private static String extractDrawMessage(int drawCount) { + if (drawCount > 0) { + return "무 "; + } + return ""; + } + + private static String extractLoseMessage(int loseCount) { + if (loseCount > 0) { + return "패 "; + } + return ""; + } + + public static void printResultByPlayers(PlayerResult playerResult) { + playerResult.getResult() + .forEach((player, status) -> + System.out.printf("%s: %s%n", player.getName(), EnumMapper.RESULT_STATUS_MAPPER.get(status))); + } +} diff --git a/src/main/java/view/mapper/EnumMapper.java b/src/main/java/view/mapper/EnumMapper.java index e4907fa5ee..6f19377688 100644 --- a/src/main/java/view/mapper/EnumMapper.java +++ b/src/main/java/view/mapper/EnumMapper.java @@ -37,5 +37,5 @@ public class EnumMapper { CardShape.DIAMOND, "다이아몬드" ); - public EnumMapper(){} + private EnumMapper(){} } From d287993f59434844715455b6661200ff5a7460f0 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 21:16:11 +0900 Subject: [PATCH 09/24] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=9E=84=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EC=83=81=ED=99=94=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=ED=9B=84=20=EC=A0=95=EC=A0=81=ED=8C=A9=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/BlackjackApplication.java | 5 +-- .../java/controller/BlackjackController.java | 1 - src/main/java/controller/GameMode.java | 37 +++++++++++++++++++ .../java/controller/mode/BettingGameMode.java | 11 ------ .../java/controller/mode/DefaultGameMode.java | 11 ------ src/main/java/controller/mode/GameMode.java | 25 ------------- ...porter.java => BettingResultReporter.java} | 2 +- ...ter.java => NonBettingResultReporter.java} | 2 +- 8 files changed, 41 insertions(+), 53 deletions(-) create mode 100644 src/main/java/controller/GameMode.java delete mode 100644 src/main/java/controller/mode/BettingGameMode.java delete mode 100644 src/main/java/controller/mode/DefaultGameMode.java delete mode 100644 src/main/java/controller/mode/GameMode.java rename src/main/java/controller/result/{ProfitReporter.java => BettingResultReporter.java} (88%) rename src/main/java/controller/result/{WinLossReporter.java => NonBettingResultReporter.java} (88%) diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index e73068190d..b2f70b7199 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,6 +1,5 @@ import controller.BlackjackController; -import controller.mode.BettingGameMode; -import controller.mode.GameMode; +import controller.GameMode; import java.util.List; import model.BlackjackService; import model.card.Card; @@ -18,7 +17,7 @@ public static void main(String[] args) { Deck deck = new Deck(shuffledCards); BlackjackService blackjackService = new BlackjackService(deck); - GameMode gameMode = new BettingGameMode(); + GameMode gameMode = GameMode.toBettingMode(); BlackjackController controller = new BlackjackController(blackjackService, gameMode); controller.run(); diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 15aab5e2b5..73905c4645 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,6 +1,5 @@ package controller; -import controller.mode.GameMode; import model.BlackjackService; import model.judgement.Judgement; import model.judgement.PlayerResult; diff --git a/src/main/java/controller/GameMode.java b/src/main/java/controller/GameMode.java new file mode 100644 index 0000000000..5952c35310 --- /dev/null +++ b/src/main/java/controller/GameMode.java @@ -0,0 +1,37 @@ +package controller; + +import controller.input.BettingPlayerReader; +import controller.input.NonBettingPlayerReader; +import controller.input.PlayerReader; +import controller.result.BettingResultReporter; +import controller.result.NonBettingResultReporter; +import controller.result.ResultReporter; +import model.judgement.PlayerResult; +import model.paticipant.Players; + +public class GameMode { + + private final PlayerReader playerReader; + private final ResultReporter resultReporter; + + private GameMode(PlayerReader playerReader, ResultReporter resultReporter) { + this.playerReader = playerReader; + this.resultReporter = resultReporter; + } + + public static GameMode toBettingMode() { + return new GameMode(new BettingPlayerReader(), new BettingResultReporter()); + } + + public static GameMode toNonBettingMode() { + return new GameMode(new NonBettingPlayerReader(), new NonBettingResultReporter()); + } + + public Players createPlayers() { + return playerReader.readPlayers(); + } + + public void reportResult(PlayerResult playerResult) { + resultReporter.report(playerResult); + } +} diff --git a/src/main/java/controller/mode/BettingGameMode.java b/src/main/java/controller/mode/BettingGameMode.java deleted file mode 100644 index a378f2acfc..0000000000 --- a/src/main/java/controller/mode/BettingGameMode.java +++ /dev/null @@ -1,11 +0,0 @@ -package controller.mode; - -import controller.input.BettingPlayerReader; -import controller.result.ProfitReporter; - -public class BettingGameMode extends GameMode { - - public BettingGameMode() { - super(new BettingPlayerReader(), new ProfitReporter()); - } -} diff --git a/src/main/java/controller/mode/DefaultGameMode.java b/src/main/java/controller/mode/DefaultGameMode.java deleted file mode 100644 index af267cd576..0000000000 --- a/src/main/java/controller/mode/DefaultGameMode.java +++ /dev/null @@ -1,11 +0,0 @@ -package controller.mode; - -import controller.input.NonBettingPlayerReader; -import controller.result.WinLossReporter; - -public class DefaultGameMode extends GameMode { - - public DefaultGameMode() { - super(new NonBettingPlayerReader(), new WinLossReporter()); - } -} diff --git a/src/main/java/controller/mode/GameMode.java b/src/main/java/controller/mode/GameMode.java deleted file mode 100644 index 4fb943099f..0000000000 --- a/src/main/java/controller/mode/GameMode.java +++ /dev/null @@ -1,25 +0,0 @@ -package controller.mode; - -import controller.input.PlayerReader; -import controller.result.ResultReporter; -import model.judgement.PlayerResult; -import model.paticipant.Players; - -public abstract class GameMode { - - private final PlayerReader playerReader; - private final ResultReporter resultReporter; - - protected GameMode(PlayerReader playerReader, ResultReporter resultReporter) { - this.playerReader = playerReader; - this.resultReporter = resultReporter; - } - - public Players createPlayers() { - return playerReader.readPlayers(); - } - - public void reportResult(PlayerResult playerResult) { - resultReporter.report(playerResult); - } -} diff --git a/src/main/java/controller/result/ProfitReporter.java b/src/main/java/controller/result/BettingResultReporter.java similarity index 88% rename from src/main/java/controller/result/ProfitReporter.java rename to src/main/java/controller/result/BettingResultReporter.java index 87df318b02..0cb5430ec3 100644 --- a/src/main/java/controller/result/ProfitReporter.java +++ b/src/main/java/controller/result/BettingResultReporter.java @@ -4,7 +4,7 @@ import model.judgement.Profit; import view.ProfitReportView; -public class ProfitReporter implements ResultReporter { +public class BettingResultReporter implements ResultReporter { @Override public void report(PlayerResult playerResult) { diff --git a/src/main/java/controller/result/WinLossReporter.java b/src/main/java/controller/result/NonBettingResultReporter.java similarity index 88% rename from src/main/java/controller/result/WinLossReporter.java rename to src/main/java/controller/result/NonBettingResultReporter.java index 71ed3a04b8..7e4f4c9ff2 100644 --- a/src/main/java/controller/result/WinLossReporter.java +++ b/src/main/java/controller/result/NonBettingResultReporter.java @@ -5,7 +5,7 @@ import model.judgement.PlayerResult; import view.WinLossReportView; -public class WinLossReporter implements ResultReporter { +public class NonBettingResultReporter implements ResultReporter { @Override public void report(PlayerResult playerResult) { From cf794795ef613870165dc4c26a580f83badc6a3e Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 21:42:06 +0900 Subject: [PATCH 10/24] =?UTF-8?q?refactor:=20BetAmount=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/judgement/ResultStatus.java | 2 ++ src/main/java/model/{judgement => paticipant}/BetAmount.java | 4 +++- src/main/java/model/paticipant/BettingPlayer.java | 1 - src/test/java/model/betting/BetAmountTest.java | 2 +- src/test/java/model/judgement/ResultStatusTest.java | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) rename src/main/java/model/{judgement => paticipant}/BetAmount.java (93%) diff --git a/src/main/java/model/judgement/ResultStatus.java b/src/main/java/model/judgement/ResultStatus.java index 544612d6d2..e11b0a3fc2 100644 --- a/src/main/java/model/judgement/ResultStatus.java +++ b/src/main/java/model/judgement/ResultStatus.java @@ -1,5 +1,7 @@ package model.judgement; +import model.paticipant.BetAmount; + public enum ResultStatus { WIN { diff --git a/src/main/java/model/judgement/BetAmount.java b/src/main/java/model/paticipant/BetAmount.java similarity index 93% rename from src/main/java/model/judgement/BetAmount.java rename to src/main/java/model/paticipant/BetAmount.java index 2b1f4b4774..aa86c17437 100644 --- a/src/main/java/model/judgement/BetAmount.java +++ b/src/main/java/model/paticipant/BetAmount.java @@ -1,4 +1,6 @@ -package model.judgement; +package model.paticipant; + +import model.judgement.Profit; public record BetAmount(int amount) { diff --git a/src/main/java/model/paticipant/BettingPlayer.java b/src/main/java/model/paticipant/BettingPlayer.java index 8a20e3ab5e..96c7e1a939 100644 --- a/src/main/java/model/paticipant/BettingPlayer.java +++ b/src/main/java/model/paticipant/BettingPlayer.java @@ -1,6 +1,5 @@ package model.paticipant; -import model.judgement.BetAmount; import model.judgement.Profit; import model.judgement.ResultStatus; diff --git a/src/test/java/model/betting/BetAmountTest.java b/src/test/java/model/betting/BetAmountTest.java index 1312df3343..71d4e8dfcb 100644 --- a/src/test/java/model/betting/BetAmountTest.java +++ b/src/test/java/model/betting/BetAmountTest.java @@ -3,8 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import model.judgement.BetAmount; import model.judgement.Profit; +import model.paticipant.BetAmount; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; diff --git a/src/test/java/model/judgement/ResultStatusTest.java b/src/test/java/model/judgement/ResultStatusTest.java index 2fccf80f3c..948d2549e7 100644 --- a/src/test/java/model/judgement/ResultStatusTest.java +++ b/src/test/java/model/judgement/ResultStatusTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import model.paticipant.BetAmount; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; From 9e660ae6179c74868e26a6379a0b356fd040cd5f Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 22:33:25 +0900 Subject: [PATCH 11/24] =?UTF-8?q?refactor:=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20GameMode=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackjackController.java | 11 ++--------- src/main/java/controller/GameMode.java | 5 ++++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 73905c4645..154731f0f6 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,8 +1,6 @@ package controller; import model.BlackjackService; -import model.judgement.Judgement; -import model.judgement.PlayerResult; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; @@ -25,9 +23,9 @@ public void run() { drawInitCards(dealer, players); drawMoreCardByPlayer(dealer, players); - printFinalCards(dealer, players); - reportResult(dealer, players); + + gameMode.reportResult(dealer, players); } private void drawMoreCardByPlayer(Dealer dealer, Players players) { @@ -76,9 +74,4 @@ private void printFinalCards(Dealer dealer, Players players) { OutputView.printCardByPlayerWithScore(dealer); players.forEach(OutputView::printCardByPlayerWithScore); } - - private void reportResult(Dealer dealer, Players players) { - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); - gameMode.reportResult(playerResult); - } } diff --git a/src/main/java/controller/GameMode.java b/src/main/java/controller/GameMode.java index 5952c35310..98c6d1cd0d 100644 --- a/src/main/java/controller/GameMode.java +++ b/src/main/java/controller/GameMode.java @@ -6,7 +6,9 @@ import controller.result.BettingResultReporter; import controller.result.NonBettingResultReporter; import controller.result.ResultReporter; +import model.judgement.Judgement; import model.judgement.PlayerResult; +import model.paticipant.Dealer; import model.paticipant.Players; public class GameMode { @@ -31,7 +33,8 @@ public Players createPlayers() { return playerReader.readPlayers(); } - public void reportResult(PlayerResult playerResult) { + public void reportResult(Dealer dealer, Players players) { + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); resultReporter.report(playerResult); } } From f0b4ae41a6c8426f34001ce5d8539ca1d4a0ba61 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 22:33:54 +0900 Subject: [PATCH 12/24] =?UTF-8?q?fix:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EA=B0=80=20=EB=B8=94=EB=9E=99=EC=9E=AD=20=EC=9D=BC=20?= =?UTF-8?q?=EB=95=8C=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B3=B4=EC=97=AC=EC=A3=BC=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackjackController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 154731f0f6..a447ec87ae 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -53,6 +53,10 @@ private Continuation readContinuation(Player player) { } private void chooseHitOrStand(Player player) { + if (player.isBlackjack()) { + return; + } + boolean didDraw = drawMoreCard(player); if (!didDraw) { OutputView.printCardByPlayer(player); From bd2c59e7f49d0176063e98ef8b93f7e71508809a Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 23:13:58 +0900 Subject: [PATCH 13/24] =?UTF-8?q?refactor:=20=EB=94=9C=EB=9F=AC=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EA=B3=84=EC=82=B0=EC=9D=98=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../result/NonBettingResultReporter.java | 3 +-- src/main/java/model/judgement/Judgement.java | 7 ------ .../java/model/judgement/PlayerResult.java | 24 +++++++++---------- src/main/java/view/WinLossReportView.java | 2 +- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/main/java/controller/result/NonBettingResultReporter.java b/src/main/java/controller/result/NonBettingResultReporter.java index 7e4f4c9ff2..61c9569d0d 100644 --- a/src/main/java/controller/result/NonBettingResultReporter.java +++ b/src/main/java/controller/result/NonBettingResultReporter.java @@ -1,7 +1,6 @@ package controller.result; import model.judgement.DealerResult; -import model.judgement.Judgement; import model.judgement.PlayerResult; import view.WinLossReportView; @@ -9,7 +8,7 @@ public class NonBettingResultReporter implements ResultReporter { @Override public void report(PlayerResult playerResult) { - DealerResult dealerResult = Judgement.judgeByDealer(playerResult); + DealerResult dealerResult = playerResult.calculateDealerResult(); WinLossReportView.printFinalResultHeader(); WinLossReportView.printResultByDealer(dealerResult); diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index a0c293f087..9f77ac8eea 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -57,11 +57,4 @@ private static ResultStatus decideByScore(Dealer dealer, Player player) { } return LOSE; } - - public static DealerResult judgeByDealer(PlayerResult playerResult) { - int dealerWinCount = playerResult.countByStatus(ResultStatus.LOSE); - int dealerLoseCount = playerResult.countByStatus(ResultStatus.WIN) + playerResult.countByStatus(ResultStatus.BLACKJACK); - int dealerDrawCount = playerResult.countByStatus(ResultStatus.DRAW); - return new DealerResult(dealerWinCount, dealerLoseCount, dealerDrawCount); - } } diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index b36a5f3010..4529ef8bd5 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -1,23 +1,20 @@ package model.judgement; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import model.paticipant.Player; -public class PlayerResult { - - private final Map result; +public record PlayerResult(Map result) { public PlayerResult(Map result) { - this.result = new LinkedHashMap<>(result); + this.result = Map.copyOf(result); } - public int countByStatus(ResultStatus resultStatus) { - return (int) result.values() - .stream() - .filter(status -> status == resultStatus) - .count(); + public DealerResult calculateDealerResult() { + int dealerWinCount = countByStatus(ResultStatus.LOSE); + int dealerLoseCount = countByStatus(ResultStatus.WIN) + countByStatus(ResultStatus.BLACKJACK); + int dealerDrawCount = countByStatus(ResultStatus.DRAW); + return new DealerResult(dealerWinCount, dealerLoseCount, dealerDrawCount); } public Map calculateProfits() { @@ -32,7 +29,10 @@ public Profit calculateDealerProfit() { .reduce(Profit.ZERO, (sum, profit) -> sum.add(profit.negate())); } - public Map getResult() { - return Collections.unmodifiableMap(result); + private int countByStatus(ResultStatus resultStatus) { + return (int) result.values() + .stream() + .filter(status -> status == resultStatus) + .count(); } } diff --git a/src/main/java/view/WinLossReportView.java b/src/main/java/view/WinLossReportView.java index 1fb8d339b4..e958daf1e3 100644 --- a/src/main/java/view/WinLossReportView.java +++ b/src/main/java/view/WinLossReportView.java @@ -43,7 +43,7 @@ private static String extractLoseMessage(int loseCount) { } public static void printResultByPlayers(PlayerResult playerResult) { - playerResult.getResult() + playerResult.result() .forEach((player, status) -> System.out.printf("%s: %s%n", player.getName(), EnumMapper.RESULT_STATUS_MAPPER.get(status))); } From e7bcfd276b99135e3a8ded7c04bb26e7ce847b55 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 23:46:51 +0900 Subject: [PATCH 14/24] =?UTF-8?q?refactor:=20=EB=B8=94=EB=9E=99=EC=9E=AD?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=A0=84=EB=9E=B5=20=ED=8C=A8=ED=84=B4=EC=9D=84=20=ED=86=B5?= =?UTF-8?q?=ED=95=B4=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/model/judgement/JudgeStrategy.java | 10 +++ src/main/java/model/judgement/Judgement.java | 56 ++++----------- .../judgement/strategy/BlackjackStrategy.java | 25 +++++++ .../judgement/strategy/BustStrategy.java | 22 ++++++ .../strategy/ScoreComparisonStrategy.java | 31 ++++++++ .../java/fixture/PlayerResultTestFixture.java | 71 ++++++++++++++----- src/test/java/model/JudgementTest.java | 62 +--------------- 7 files changed, 160 insertions(+), 117 deletions(-) create mode 100644 src/main/java/model/judgement/JudgeStrategy.java create mode 100644 src/main/java/model/judgement/strategy/BlackjackStrategy.java create mode 100644 src/main/java/model/judgement/strategy/BustStrategy.java create mode 100644 src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java diff --git a/src/main/java/model/judgement/JudgeStrategy.java b/src/main/java/model/judgement/JudgeStrategy.java new file mode 100644 index 0000000000..cbb02920eb --- /dev/null +++ b/src/main/java/model/judgement/JudgeStrategy.java @@ -0,0 +1,10 @@ +package model.judgement; + +import model.paticipant.Dealer; +import model.paticipant.Player; + +public interface JudgeStrategy { + + boolean isApplicable(Dealer dealer, Player player); + ResultStatus getResult(Dealer dealer, Player player); +} diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index 9f77ac8eea..defbcb5893 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -1,18 +1,23 @@ package model.judgement; -import static model.judgement.ResultStatus.BLACKJACK; -import static model.judgement.ResultStatus.DRAW; -import static model.judgement.ResultStatus.LOSE; -import static model.judgement.ResultStatus.WIN; - import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import model.judgement.strategy.BlackjackStrategy; +import model.judgement.strategy.BustStrategy; +import model.judgement.strategy.ScoreComparisonStrategy; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; public class Judgement { + private static final List STRATEGIES = List.of( + new BustStrategy(), + new BlackjackStrategy(), + new ScoreComparisonStrategy() + ); + public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { Map result = new LinkedHashMap<>(); players.forEach(player -> result.put(player, decide(dealer, player))); @@ -20,41 +25,10 @@ public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { } private static ResultStatus decide(Dealer dealer, Player player) { - if (player.isBust()) { - return LOSE; - } - if (dealer.isBust()) { - return WIN; - } - - if (dealer.isBlackjack()) { - return decideWhenDealerBlackjack(player); - } - - if (player.isBlackjack()) { - return BLACKJACK; - } - - return decideByScore(dealer, player); - } - - private static ResultStatus decideWhenDealerBlackjack(Player player) { - if (player.isBlackjack()) { - return DRAW; - } - return LOSE; - } - - private static ResultStatus decideByScore(Dealer dealer, Player player) { - int dealerScore = dealer.calculateTotalScore(); - int playerScore = player.calculateTotalScore(); - - if (playerScore > dealerScore) { - return WIN; - } - if (playerScore == dealerScore) { - return DRAW; - } - return LOSE; + return STRATEGIES.stream() + .filter(strategy -> strategy.isApplicable(dealer, player)) + .findFirst() + .map(strategy -> strategy.getResult(dealer, player)) + .orElse(ResultStatus.LOSE); } } diff --git a/src/main/java/model/judgement/strategy/BlackjackStrategy.java b/src/main/java/model/judgement/strategy/BlackjackStrategy.java new file mode 100644 index 0000000000..b356c10a07 --- /dev/null +++ b/src/main/java/model/judgement/strategy/BlackjackStrategy.java @@ -0,0 +1,25 @@ +package model.judgement.strategy; + +import model.judgement.JudgeStrategy; +import model.judgement.ResultStatus; +import model.paticipant.Dealer; +import model.paticipant.Player; + +public class BlackjackStrategy implements JudgeStrategy { + + @Override + public boolean isApplicable(Dealer dealer, Player player) { + return dealer.isBlackjack() || player.isBlackjack(); + } + + @Override + public ResultStatus getResult(Dealer dealer, Player player) { + if (dealer.isBlackjack() && player.isBlackjack()) { + return ResultStatus.DRAW; + } + if (player.isBlackjack()) { + return ResultStatus.BLACKJACK; + } + return ResultStatus.LOSE; + } +} \ No newline at end of file diff --git a/src/main/java/model/judgement/strategy/BustStrategy.java b/src/main/java/model/judgement/strategy/BustStrategy.java new file mode 100644 index 0000000000..e1e7964db2 --- /dev/null +++ b/src/main/java/model/judgement/strategy/BustStrategy.java @@ -0,0 +1,22 @@ +package model.judgement.strategy; + +import model.judgement.JudgeStrategy; +import model.judgement.ResultStatus; +import model.paticipant.Dealer; +import model.paticipant.Player; + +public class BustStrategy implements JudgeStrategy { + + @Override + public boolean isApplicable(Dealer dealer, Player player) { + return player.isBust() || dealer.isBust(); + } + + @Override + public ResultStatus getResult(Dealer dealer, Player player) { + if (player.isBust()) { + return ResultStatus.LOSE; + } + return ResultStatus.WIN; + } +} \ No newline at end of file diff --git a/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java b/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java new file mode 100644 index 0000000000..9a68b0f314 --- /dev/null +++ b/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java @@ -0,0 +1,31 @@ +package model.judgement.strategy; + +import model.judgement.JudgeStrategy; +import model.judgement.ResultStatus; +import model.paticipant.Dealer; +import model.paticipant.Player; + +public class ScoreComparisonStrategy implements JudgeStrategy { + + @Override + public boolean isApplicable(Dealer dealer, Player player) { + return true; + } + + @Override + public ResultStatus getResult(Dealer dealer, Player player) { + int dealerScore = dealer.calculateTotalScore(); + int playerScore = player.calculateTotalScore(); + return determineResult(playerScore, dealerScore); + } + + private ResultStatus determineResult(int playerScore, int dealerScore) { + if (playerScore > dealerScore) { + return ResultStatus.WIN; + } + if (playerScore == dealerScore) { + return ResultStatus.DRAW; + } + return ResultStatus.LOSE; + } +} \ No newline at end of file diff --git a/src/test/java/fixture/PlayerResultTestFixture.java b/src/test/java/fixture/PlayerResultTestFixture.java index c9879526e4..e84cccf13c 100644 --- a/src/test/java/fixture/PlayerResultTestFixture.java +++ b/src/test/java/fixture/PlayerResultTestFixture.java @@ -1,11 +1,26 @@ package fixture; +import static model.card.CardValue.ACE; +import static model.card.CardValue.EIGHT; +import static model.card.CardValue.FIVE; +import static model.card.CardValue.JACK; +import static model.card.CardValue.KING; +import static model.card.CardValue.NINE; +import static model.card.CardValue.SEVEN; +import static model.card.CardValue.SIX; +import static model.card.CardValue.TEN; +import static model.card.CardValue.THREE; +import static model.card.CardValue.TWO; +import static model.judgement.ResultStatus.BLACKJACK; +import static model.judgement.ResultStatus.DRAW; +import static model.judgement.ResultStatus.LOSE; +import static model.judgement.ResultStatus.WIN; + import java.util.List; import java.util.stream.Stream; import model.card.Card; import model.card.CardShape; import model.card.CardValue; -import model.judgement.ResultStatus; import org.junit.jupiter.params.provider.Arguments; public class PlayerResultTestFixture { @@ -14,33 +29,57 @@ public class PlayerResultTestFixture { return Stream.of( // 1. 플레이어 버스트 (딜러 점수 상관없이 패배) Arguments.of( - List.of(card(CardValue.TEN), card(CardValue.JACK), card(CardValue.FIVE)), // 25점 - List.of(card(CardValue.TWO), card(CardValue.THREE)), // 5점 - ResultStatus.LOSE + List.of(card(TEN), card(JACK), card(FIVE)), // 25점 + List.of(card(TWO), card(THREE)), // 5점 + LOSE ), // 2. 딜러 버스트, 플레이어는 낫 버스트 (승리) Arguments.of( - List.of(card(CardValue.TEN), card(CardValue.EIGHT)), // 18점 - List.of(card(CardValue.TEN), card(CardValue.FIVE), card(CardValue.SEVEN)), // 22점 - ResultStatus.WIN + List.of(card(TEN), card(EIGHT)), // 18점 + List.of(card(TEN), card(FIVE), card(SEVEN)), // 22점 + WIN ), // 3. 둘 다 버스트가 아닐 때 점수 비교 (플레이어가 높은 경우) Arguments.of( - List.of(card(CardValue.ACE), card(CardValue.NINE)), // 20점 - List.of(card(CardValue.TEN), card(CardValue.EIGHT)), // 18점 - ResultStatus.WIN + List.of(card(ACE), card(NINE)), // 20점 + List.of(card(TEN), card(EIGHT)), // 18점 + WIN ), // 4. 점수가 같은 경우 (무승부) Arguments.of( - List.of(card(CardValue.TEN), card(CardValue.SEVEN)), // 17점 - List.of(card(CardValue.EIGHT), card(CardValue.NINE)), // 17점 - ResultStatus.DRAW + List.of(card(TEN), card(SEVEN)), // 17점 + List.of(card(EIGHT), card(NINE)), // 17점 + DRAW ), // 5. 플레이어가 낮은 경우 (패배) Arguments.of( - List.of(card(CardValue.FIVE), card(CardValue.SEVEN)), // 12점 - List.of(card(CardValue.TEN), card(CardValue.SIX)), // 16점 - ResultStatus.LOSE + List.of(card(FIVE), card(SEVEN)), // 12점 + List.of(card(TEN), card(SIX)), // 16점 + LOSE + ), + // 6. 플레이어와 딜러 모두 버스트 (패배) + Arguments.of( + List.of(card(TEN), card(JACK), card(FIVE)), // 25점 + List.of(card(TEN), card(TEN), card(THREE)), // 23점 + LOSE + ), + // 7. 플레이어만 블랙잭인 경우 + Arguments.of( + List.of(card(ACE), card(KING)), // 블랙잭 + List.of(card(TEN), card(NINE)), // 19점 + BLACKJACK + ), + // 8. 플레이어와 딜러 모두 블랙잭인 경우 + Arguments.of( + List.of(card(ACE), card(KING)), // 블랙잭 + List.of(card(ACE), card(KING)), // 블랙잭 + DRAW + ), + // 9. 딜러만 블랙잭인 경우 + Arguments.of( + List.of(card(TEN), card(FIVE), card(SIX)), // 21점 (3장) + List.of(card(ACE), card(KING)), // 블랙잭 + LOSE ) ); } diff --git a/src/test/java/model/JudgementTest.java b/src/test/java/model/JudgementTest.java index dec959bfcf..c0b099c0ae 100644 --- a/src/test/java/model/JudgementTest.java +++ b/src/test/java/model/JudgementTest.java @@ -5,16 +5,13 @@ import java.util.List; import model.card.Card; -import model.card.CardShape; -import model.card.CardValue; import model.judgement.Judgement; import model.judgement.PlayerResult; import model.judgement.ResultStatus; -import model.paticipant.Dealer; import model.paticipant.BettingPlayer; +import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -38,61 +35,6 @@ public class JudgementTest { PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); // then - assertThat(playerResult.countByStatus(status)).isEqualTo(1); - } - - @Test - void 플레이어가_블랙잭이고_딜러가_블랙잭이_아니면_BLACKJACK_결과이다() { - // given - Dealer dealer = new Dealer(); - dealer.addCard(new Card(CardShape.HEART, CardValue.TEN)); - dealer.addCard(new Card(CardShape.HEART, CardValue.NINE)); - - Player player = new BettingPlayer("pobi", 10000); - player.addCard(new Card(CardShape.HEART, CardValue.ACE)); - player.addCard(new Card(CardShape.HEART, CardValue.KING)); - - // when - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); - - // then - assertThat(playerResult.countByStatus(ResultStatus.BLACKJACK)).isEqualTo(1); - } - - @Test - void 플레이어와_딜러_모두_블랙잭이면_DRAW_결과이다() { - // given - Dealer dealer = new Dealer(); - dealer.addCard(new Card(CardShape.HEART, CardValue.ACE)); - dealer.addCard(new Card(CardShape.HEART, CardValue.KING)); - - Player player = new BettingPlayer("pobi", 10000); - player.addCard(new Card(CardShape.DIAMOND, CardValue.ACE)); - player.addCard(new Card(CardShape.DIAMOND, CardValue.KING)); - - // when - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); - - // then - assertThat(playerResult.countByStatus(ResultStatus.DRAW)).isEqualTo(1); - } - - @Test - void 딜러가_블랙잭이고_플레이어가_블랙잭이_아니면_LOSE_결과이다() { - // given - Dealer dealer = new Dealer(); - dealer.addCard(new Card(CardShape.HEART, CardValue.ACE)); - dealer.addCard(new Card(CardShape.HEART, CardValue.KING)); - - Player player = new BettingPlayer("pobi", 10000); - player.addCard(new Card(CardShape.HEART, CardValue.TEN)); - player.addCard(new Card(CardShape.HEART, CardValue.FIVE)); - player.addCard(new Card(CardShape.HEART, CardValue.SIX)); - - // when - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); - - // then - assertThat(playerResult.countByStatus(ResultStatus.LOSE)).isEqualTo(1); + assertThat(playerResult.result()).containsEntry(player, status); } } From 7ff08abf44c057ff0da1f6104d6440ce86bf36a7 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 23:52:10 +0900 Subject: [PATCH 15/24] =?UTF-8?q?refactor:=20blackjackService=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=B1=85=EC=9E=84=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/BlackjackApplication.java | 10 +--------- src/main/java/model/BlackjackService.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index b2f70b7199..161f202746 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,22 +1,14 @@ import controller.BlackjackController; import controller.GameMode; -import java.util.List; import model.BlackjackService; -import model.card.Card; -import model.card.CardFactory; import model.card.CardShuffler; -import model.card.Deck; import model.card.SimpleCardShuffler; public class BlackjackApplication { public static void main(String[] args) { CardShuffler cardShuffler = new SimpleCardShuffler(); - List fullCards = CardFactory.createFullCards(); - List shuffledCards = cardShuffler.shuffle(fullCards); - Deck deck = new Deck(shuffledCards); - BlackjackService blackjackService = new BlackjackService(deck); - + BlackjackService blackjackService = BlackjackService.createDefaultService(cardShuffler); GameMode gameMode = GameMode.toBettingMode(); BlackjackController controller = new BlackjackController(blackjackService, gameMode); diff --git a/src/main/java/model/BlackjackService.java b/src/main/java/model/BlackjackService.java index 2c6e2cd4ae..1c2c37105b 100644 --- a/src/main/java/model/BlackjackService.java +++ b/src/main/java/model/BlackjackService.java @@ -1,5 +1,9 @@ package model; +import java.util.List; +import model.card.Card; +import model.card.CardFactory; +import model.card.CardShuffler; import model.card.Deck; import model.paticipant.Dealer; import model.paticipant.Participant; @@ -17,6 +21,13 @@ public BlackjackService(Deck deck) { this.deck = deck; } + public static BlackjackService createDefaultService(CardShuffler cardShuffler) { + List fullCards = CardFactory.createFullCards(); + List shuffledCards = cardShuffler.shuffle(fullCards); + Deck deck = new Deck(shuffledCards); + return new BlackjackService(deck); + } + public void drawTwoCards(Dealer dealer, Players players) { drawCardByParticipant(dealer, INITIAL_DISPENSE_COUNT); players.forEach(player -> drawCardByPlayer(player, INITIAL_DISPENSE_COUNT)); From 9fba90d857730104382afbaa961bdb83ffceb297 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Fri, 13 Mar 2026 23:59:36 +0900 Subject: [PATCH 16/24] =?UTF-8?q?refactor:=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=ED=9D=90=EB=A6=84=20report=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackjackController.java | 8 +------- src/main/java/controller/GameMode.java | 9 +++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index a447ec87ae..323f9d5e8c 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -23,13 +23,13 @@ public void run() { drawInitCards(dealer, players); drawMoreCardByPlayer(dealer, players); - printFinalCards(dealer, players); gameMode.reportResult(dealer, players); } private void drawMoreCardByPlayer(Dealer dealer, Players players) { players.forEach(this::chooseHitOrStand); + while (dealer.canHit()) { OutputView.printToOpenDealerNewCard(dealer); blackjackService.drawOneCard(dealer); @@ -72,10 +72,4 @@ private boolean drawMoreCard(Player player) { } return didDraw; } - - private void printFinalCards(Dealer dealer, Players players) { - OutputView.printBlank(); - OutputView.printCardByPlayerWithScore(dealer); - players.forEach(OutputView::printCardByPlayerWithScore); - } } diff --git a/src/main/java/controller/GameMode.java b/src/main/java/controller/GameMode.java index 98c6d1cd0d..d9a2a99f85 100644 --- a/src/main/java/controller/GameMode.java +++ b/src/main/java/controller/GameMode.java @@ -10,6 +10,7 @@ import model.judgement.PlayerResult; import model.paticipant.Dealer; import model.paticipant.Players; +import view.OutputView; public class GameMode { @@ -34,7 +35,15 @@ public Players createPlayers() { } public void reportResult(Dealer dealer, Players players) { + printFinalCards(dealer, players); + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); resultReporter.report(playerResult); } + + private void printFinalCards(Dealer dealer, Players players) { + OutputView.printBlank(); + OutputView.printCardByPlayerWithScore(dealer); + players.forEach(OutputView::printCardByPlayerWithScore); + } } From 30cde16686b92e248ca451684fb528f461cc73b2 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 17:13:49 +0900 Subject: [PATCH 17/24] =?UTF-8?q?fix:=20=EB=94=9C=EB=9F=AC=20=EC=A0=84?= =?UTF-8?q?=EC=A0=81=20=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=98=A4?= =?UTF-8?q?=ED=83=88=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/WinLossReportView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/WinLossReportView.java b/src/main/java/view/WinLossReportView.java index e958daf1e3..e368e22931 100644 --- a/src/main/java/view/WinLossReportView.java +++ b/src/main/java/view/WinLossReportView.java @@ -23,21 +23,21 @@ public static void printResultByDealer(DealerResult dealerResult) { private static String extractWinMessage(int winCount) { if (winCount > 0) { - return "승 "; + return winCount + "승 "; } return ""; } private static String extractDrawMessage(int drawCount) { if (drawCount > 0) { - return "무 "; + return drawCount + "무 "; } return ""; } private static String extractLoseMessage(int loseCount) { if (loseCount > 0) { - return "패 "; + return loseCount + "패 "; } return ""; } From cf82145057348ed95a7015f4fedf73aca646a191 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 18:01:56 +0900 Subject: [PATCH 18/24] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EC=8B=AC=ED=8C=90=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/judgement/Judgement.java | 19 +++++++----- .../strategy/ScoreComparisonStrategy.java | 31 ------------------- 2 files changed, 12 insertions(+), 38 deletions(-) delete mode 100644 src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index defbcb5893..23f55a77a9 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -5,18 +5,13 @@ import java.util.Map; import model.judgement.strategy.BlackjackStrategy; import model.judgement.strategy.BustStrategy; -import model.judgement.strategy.ScoreComparisonStrategy; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; public class Judgement { - private static final List STRATEGIES = List.of( - new BustStrategy(), - new BlackjackStrategy(), - new ScoreComparisonStrategy() - ); + private static final List STRATEGIES = List.of(new BustStrategy(), new BlackjackStrategy()); public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { Map result = new LinkedHashMap<>(); @@ -29,6 +24,16 @@ private static ResultStatus decide(Dealer dealer, Player player) { .filter(strategy -> strategy.isApplicable(dealer, player)) .findFirst() .map(strategy -> strategy.getResult(dealer, player)) - .orElse(ResultStatus.LOSE); + .orElseGet(() -> compareScore(dealer.calculateTotalScore(), player.calculateTotalScore())); + } + + private static ResultStatus compareScore(int playerScore, int dealerScore) { + if (playerScore > dealerScore) { + return ResultStatus.WIN; + } + if (playerScore == dealerScore) { + return ResultStatus.DRAW; + } + return ResultStatus.LOSE; } } diff --git a/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java b/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java deleted file mode 100644 index 9a68b0f314..0000000000 --- a/src/main/java/model/judgement/strategy/ScoreComparisonStrategy.java +++ /dev/null @@ -1,31 +0,0 @@ -package model.judgement.strategy; - -import model.judgement.JudgeStrategy; -import model.judgement.ResultStatus; -import model.paticipant.Dealer; -import model.paticipant.Player; - -public class ScoreComparisonStrategy implements JudgeStrategy { - - @Override - public boolean isApplicable(Dealer dealer, Player player) { - return true; - } - - @Override - public ResultStatus getResult(Dealer dealer, Player player) { - int dealerScore = dealer.calculateTotalScore(); - int playerScore = player.calculateTotalScore(); - return determineResult(playerScore, dealerScore); - } - - private ResultStatus determineResult(int playerScore, int dealerScore) { - if (playerScore > dealerScore) { - return ResultStatus.WIN; - } - if (playerScore == dealerScore) { - return ResultStatus.DRAW; - } - return ResultStatus.LOSE; - } -} \ No newline at end of file From 973843894f7124fc796a85e6a1b0613e32cf0dab Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 20:52:33 +0900 Subject: [PATCH 19/24] =?UTF-8?q?refactor:=20GameMode=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EA=B0=80=20=EA=B0=80=EC=A7=80=EA=B3=A0=20=EC=9E=88=EB=8D=98=20?= =?UTF-8?q?=EC=97=AC=EB=9F=AC=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/BlackjackApplication.java | 6 +- .../java/controller/BlackjackController.java | 73 ++++++++++--------- src/main/java/controller/GameMode.java | 14 +--- ...ackjackService.java => BlackjackGame.java} | 10 +-- src/main/java/model/paticipant/Players.java | 7 +- src/main/java/view/OutputView.java | 46 ++++++------ 6 files changed, 75 insertions(+), 81 deletions(-) rename src/main/java/model/{BlackjackService.java => BlackjackGame.java} (83%) diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index 161f202746..c93cbf8232 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,6 +1,6 @@ import controller.BlackjackController; import controller.GameMode; -import model.BlackjackService; +import model.BlackjackGame; import model.card.CardShuffler; import model.card.SimpleCardShuffler; @@ -8,10 +8,10 @@ public class BlackjackApplication { public static void main(String[] args) { CardShuffler cardShuffler = new SimpleCardShuffler(); - BlackjackService blackjackService = BlackjackService.createDefaultService(cardShuffler); + BlackjackGame blackjackGame = BlackjackGame.setup(cardShuffler); GameMode gameMode = GameMode.toBettingMode(); - BlackjackController controller = new BlackjackController(blackjackService, gameMode); + BlackjackController controller = new BlackjackController(blackjackGame, gameMode); controller.run(); } } diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index 323f9d5e8c..d8a5223c28 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -1,6 +1,8 @@ package controller; -import model.BlackjackService; +import model.BlackjackGame; +import model.judgement.Judgement; +import model.judgement.PlayerResult; import model.paticipant.Dealer; import model.paticipant.Player; import model.paticipant.Players; @@ -9,11 +11,11 @@ public class BlackjackController { - private final BlackjackService blackjackService; + private final BlackjackGame blackjackGame; private final GameMode gameMode; - public BlackjackController(BlackjackService blackjackService, GameMode gameMode) { - this.blackjackService = blackjackService; + public BlackjackController(BlackjackGame blackjackGame, GameMode gameMode) { + this.blackjackGame = blackjackGame; this.gameMode = gameMode; } @@ -21,55 +23,58 @@ public void run() { Dealer dealer = new Dealer(); Players players = gameMode.createPlayers(); - drawInitCards(dealer, players); - drawMoreCardByPlayer(dealer, players); + initialDeal(dealer, players); + proceedTurns(dealer, players); + finishGame(dealer, players); + } - gameMode.reportResult(dealer, players); + private void initialDeal(Dealer dealer, Players players) { + blackjackGame.drawInitCards(dealer, players); + OutputView.printCardOpen(dealer, players.players()); } - private void drawMoreCardByPlayer(Dealer dealer, Players players) { - players.forEach(this::chooseHitOrStand); + private void proceedTurns(Dealer dealer, Players players) { + players.forEach(this::processPlayerTurn); while (dealer.canHit()) { OutputView.printToOpenDealerNewCard(dealer); - blackjackService.drawOneCard(dealer); + blackjackGame.drawOneCard(dealer); } } - private void drawInitCards(Dealer dealer, Players players) { - blackjackService.drawTwoCards(dealer, players); - OutputView.printCardOpen(players); - OutputView.printCardByDealer(dealer); - OutputView.printCardByPlayers(players); - } - - private boolean canHitMore(Player player) { - return player.canHit() && readContinuation(player).isContinue(); - } - - private Continuation readContinuation(Player player) { - String inputCommand = InputView.readMoreCard(player); - return Continuation.from(inputCommand); - } - - private void chooseHitOrStand(Player player) { + private void processPlayerTurn(Player player) { if (player.isBlackjack()) { return; } - boolean didDraw = drawMoreCard(player); - if (!didDraw) { + boolean hasDrawn = hitUntilStand(player); + if (!hasDrawn) { OutputView.printCardByPlayer(player); } } - private boolean drawMoreCard(Player player) { - boolean didDraw = false; + private boolean hitUntilStand(Player player) { + boolean hasDrawn = false; while (canHitMore(player)) { - blackjackService.drawOneCard(player); + blackjackGame.drawOneCard(player); OutputView.printCardByPlayer(player); - didDraw = true; + hasDrawn = true; } - return didDraw; + return hasDrawn; + } + + private boolean canHitMore(Player player) { + return player.canHit() && readContinuation(player).isContinue(); + } + + private Continuation readContinuation(Player player) { + String inputCommand = InputView.readMoreCard(player); + return Continuation.from(inputCommand); + } + + private void finishGame(Dealer dealer, Players players) { + OutputView.printFinalCards(dealer, players.players()); + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); + gameMode.reportResult(playerResult); } } diff --git a/src/main/java/controller/GameMode.java b/src/main/java/controller/GameMode.java index d9a2a99f85..5952c35310 100644 --- a/src/main/java/controller/GameMode.java +++ b/src/main/java/controller/GameMode.java @@ -6,11 +6,8 @@ import controller.result.BettingResultReporter; import controller.result.NonBettingResultReporter; import controller.result.ResultReporter; -import model.judgement.Judgement; import model.judgement.PlayerResult; -import model.paticipant.Dealer; import model.paticipant.Players; -import view.OutputView; public class GameMode { @@ -34,16 +31,7 @@ public Players createPlayers() { return playerReader.readPlayers(); } - public void reportResult(Dealer dealer, Players players) { - printFinalCards(dealer, players); - - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); + public void reportResult(PlayerResult playerResult) { resultReporter.report(playerResult); } - - private void printFinalCards(Dealer dealer, Players players) { - OutputView.printBlank(); - OutputView.printCardByPlayerWithScore(dealer); - players.forEach(OutputView::printCardByPlayerWithScore); - } } diff --git a/src/main/java/model/BlackjackService.java b/src/main/java/model/BlackjackGame.java similarity index 83% rename from src/main/java/model/BlackjackService.java rename to src/main/java/model/BlackjackGame.java index 1c2c37105b..2c19d0ee03 100644 --- a/src/main/java/model/BlackjackService.java +++ b/src/main/java/model/BlackjackGame.java @@ -10,25 +10,25 @@ import model.paticipant.Player; import model.paticipant.Players; -public class BlackjackService { +public class BlackjackGame { private static final int INITIAL_DISPENSE_COUNT = 2; private static final int BASE_DISPENSE_COUNT = 1; private final Deck deck; - public BlackjackService(Deck deck) { + public BlackjackGame(Deck deck) { this.deck = deck; } - public static BlackjackService createDefaultService(CardShuffler cardShuffler) { + public static BlackjackGame setup(CardShuffler cardShuffler) { List fullCards = CardFactory.createFullCards(); List shuffledCards = cardShuffler.shuffle(fullCards); Deck deck = new Deck(shuffledCards); - return new BlackjackService(deck); + return new BlackjackGame(deck); } - public void drawTwoCards(Dealer dealer, Players players) { + public void drawInitCards(Dealer dealer, Players players) { drawCardByParticipant(dealer, INITIAL_DISPENSE_COUNT); players.forEach(player -> drawCardByPlayer(player, INITIAL_DISPENSE_COUNT)); } diff --git a/src/main/java/model/paticipant/Players.java b/src/main/java/model/paticipant/Players.java index 019fd37eeb..7d531ab0bd 100644 --- a/src/main/java/model/paticipant/Players.java +++ b/src/main/java/model/paticipant/Players.java @@ -5,15 +5,14 @@ import java.util.List; import java.util.function.Consumer; -public class Players { - - private final List players; +public record Players(List players) { public Players(List players) { this.players = new ArrayList<>(players); } - public List getPlayers() { + @Override + public List players() { return Collections.unmodifiableList(players); } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 93166cc7cf..b6b4a176e8 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -5,7 +5,6 @@ import model.paticipant.Dealer; import model.paticipant.Participant; import model.paticipant.Player; -import model.paticipant.Players; import view.mapper.EnumMapper; public class OutputView { @@ -13,25 +12,15 @@ public class OutputView { private OutputView() { } - public static void printCardOpen(Players players) { - List names = players.getPlayers() - .stream() + public static void printCardOpen(Dealer dealer, List players) { + List names = players.stream() .map(Player::getName) .toList(); - - System.out.println(); - System.out.printf("딜러와 %s에게 2장을 나누었습니다.%n", String.join(", ", names)); - } - - public static void printCardByPlayers(Players players) { - players.getPlayers().forEach(OutputView::printCardByPlayer); System.out.println(); - } + System.out.printf("%s와 %s에게 2장을 나누었습니다.%n", dealer.getName(), String.join(", ", names)); - public static void printCardByDealer(Dealer dealer) { - Card firstCard = dealer.getCards().getFirst(); - String card = convert(firstCard); - System.out.println(dealer.getName() + ": " + card); + printCardByDealer(dealer); + printCardByPlayers(players); } public static void printCardByPlayer(Player player) { @@ -43,7 +32,13 @@ public static void printCardByPlayer(Player player) { } - public static void printCardByPlayerWithScore(Participant participant) { + public static void printFinalCards(Participant dealer, List players) { + System.out.println(); + printCardByPlayerWithScore(dealer); + players.forEach(OutputView::printCardByPlayerWithScore); + } + + public static void printCardByPlayerWithScore(Player participant) { int sum = participant.calculateTotalScore(); List cards = participant.getCards() .stream() @@ -52,13 +47,13 @@ public static void printCardByPlayerWithScore(Participant participant) { System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); } - public static void printCardByPlayerWithScore(Player player) { - int sum = player.calculateTotalScore(); - List cards = player.getCards() + public static void printCardByPlayerWithScore(Participant participant) { + int sum = participant.calculateTotalScore(); + List cards = participant.getCards() .stream() .map(OutputView::convert) .toList(); - System.out.printf("%s 카드: %s - 결과: %d%n", player.getName(), String.join(", ", cards), sum); + System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); } private static String convert(Card card) { @@ -70,7 +65,14 @@ public static void printToOpenDealerNewCard(Dealer dealer) { System.out.printf("%s는 16 이하라 한장의 카드를 더 받았습니다.%n", dealer.getName()); } - public static void printBlank() { + private static void printCardByDealer(Dealer dealer) { + Card firstCard = dealer.getCards().getFirst(); + String card = convert(firstCard); + System.out.println(dealer.getName() + ": " + card); + } + + private static void printCardByPlayers(List players) { + players.forEach(OutputView::printCardByPlayer); System.out.println(); } } \ No newline at end of file From 4e3811f8a05f4a905ff4bab6ef77b1b1798b3507 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 23:01:57 +0900 Subject: [PATCH 20/24] =?UTF-8?q?refactor:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=ED=83=80=EC=9E=85=20=EA=B3=84=EC=B8=B5=20=EC=9E=AC?= =?UTF-8?q?=EC=84=A4=EA=B3=84=EB=A1=9C=20Participant/Player=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Participant(abstract) → Player(class) → BettingPlayer 계층으로 단순화 * Player 인터페이스와 Participant 간 중복 메서드 선언 제거 * calculateProfit을 BettingPlayer로 이동하여 ISP 위반 해소 --- .../input/NonBettingPlayerReader.java | 3 +- src/main/java/model/BlackjackGame.java | 13 +--- .../java/model/judgement/JudgeStrategy.java | 6 +- src/main/java/model/judgement/Judgement.java | 9 +-- .../java/model/judgement/PlayerResult.java | 7 ++- .../judgement/strategy/BlackjackStrategy.java | 12 ++-- .../judgement/strategy/BustStrategy.java | 10 ++-- .../java/model/paticipant/BettingPlayer.java | 10 +--- .../model/paticipant/NonBettingPlayer.java | 15 ----- .../java/model/paticipant/Participant.java | 4 +- src/main/java/model/paticipant/Player.java | 30 +++------- src/main/java/model/paticipant/Players.java | 9 +-- src/main/java/view/InputView.java | 6 +- src/main/java/view/OutputView.java | 60 +++++++------------ src/main/java/view/mapper/EnumMapper.java | 5 ++ src/test/java/model/JudgementTest.java | 8 +-- src/test/java/model/PlayerBustTest.java | 6 +- src/test/java/model/PlayerTest.java | 4 +- 18 files changed, 79 insertions(+), 138 deletions(-) delete mode 100644 src/main/java/model/paticipant/NonBettingPlayer.java diff --git a/src/main/java/controller/input/NonBettingPlayerReader.java b/src/main/java/controller/input/NonBettingPlayerReader.java index 9a8070380f..8f8c33dcae 100644 --- a/src/main/java/controller/input/NonBettingPlayerReader.java +++ b/src/main/java/controller/input/NonBettingPlayerReader.java @@ -2,7 +2,6 @@ import java.util.List; import java.util.stream.Collectors; -import model.paticipant.NonBettingPlayer; import model.paticipant.Player; import model.paticipant.Players; import view.InputView; @@ -13,7 +12,7 @@ public class NonBettingPlayerReader implements PlayerReader { public Players readPlayers() { List names = InputView.readPlayerNames(); List players = names.stream() - .map(NonBettingPlayer::new) + .map(Player::new) .collect(Collectors.toList()); return new Players(players); } diff --git a/src/main/java/model/BlackjackGame.java b/src/main/java/model/BlackjackGame.java index 2c19d0ee03..44aa768e90 100644 --- a/src/main/java/model/BlackjackGame.java +++ b/src/main/java/model/BlackjackGame.java @@ -7,7 +7,6 @@ import model.card.Deck; import model.paticipant.Dealer; import model.paticipant.Participant; -import model.paticipant.Player; import model.paticipant.Players; public class BlackjackGame { @@ -30,26 +29,16 @@ public static BlackjackGame setup(CardShuffler cardShuffler) { public void drawInitCards(Dealer dealer, Players players) { drawCardByParticipant(dealer, INITIAL_DISPENSE_COUNT); - players.forEach(player -> drawCardByPlayer(player, INITIAL_DISPENSE_COUNT)); + players.forEach(player -> drawCardByParticipant(player, INITIAL_DISPENSE_COUNT)); } public void drawOneCard(Participant participant) { drawCardByParticipant(participant, BASE_DISPENSE_COUNT); } - public void drawOneCard(Player player) { - drawCardByPlayer(player, BASE_DISPENSE_COUNT); - } - private void drawCardByParticipant(Participant participant, int count) { for (int i = 0; i < count; i++) { participant.addCard(deck.draw()); } } - - private void drawCardByPlayer(Player player, int count) { - for (int i = 0; i < count; i++) { - player.addCard(deck.draw()); - } - } } diff --git a/src/main/java/model/judgement/JudgeStrategy.java b/src/main/java/model/judgement/JudgeStrategy.java index cbb02920eb..3091309825 100644 --- a/src/main/java/model/judgement/JudgeStrategy.java +++ b/src/main/java/model/judgement/JudgeStrategy.java @@ -1,10 +1,10 @@ package model.judgement; import model.paticipant.Dealer; -import model.paticipant.Player; +import model.paticipant.Participant; public interface JudgeStrategy { - boolean isApplicable(Dealer dealer, Player player); - ResultStatus getResult(Dealer dealer, Player player); + boolean isApplicable(Dealer dealer, Participant participant); + ResultStatus getResult(Dealer dealer, Participant participant); } diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index 23f55a77a9..69c2546860 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -6,6 +6,7 @@ import model.judgement.strategy.BlackjackStrategy; import model.judgement.strategy.BustStrategy; import model.paticipant.Dealer; +import model.paticipant.Participant; import model.paticipant.Player; import model.paticipant.Players; @@ -19,12 +20,12 @@ public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { return new PlayerResult(result); } - private static ResultStatus decide(Dealer dealer, Player player) { + private static ResultStatus decide(Dealer dealer, Participant participant) { return STRATEGIES.stream() - .filter(strategy -> strategy.isApplicable(dealer, player)) + .filter(strategy -> strategy.isApplicable(dealer, participant)) .findFirst() - .map(strategy -> strategy.getResult(dealer, player)) - .orElseGet(() -> compareScore(dealer.calculateTotalScore(), player.calculateTotalScore())); + .map(strategy -> strategy.getResult(dealer, participant)) + .orElseGet(() -> compareScore(participant.calculateTotalScore(), dealer.calculateTotalScore())); } private static ResultStatus compareScore(int playerScore, int dealerScore) { diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index 4529ef8bd5..60acb92bc3 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -2,6 +2,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import model.paticipant.BettingPlayer; import model.paticipant.Player; public record PlayerResult(Map result) { @@ -19,7 +20,11 @@ public DealerResult calculateDealerResult() { public Map calculateProfits() { Map profits = new LinkedHashMap<>(); - result.forEach((player, status) -> profits.put(player, player.calculateProfit(status))); + result.forEach((player, status) -> { + if (player instanceof BettingPlayer bettingPlayer) { + profits.put(bettingPlayer, bettingPlayer.calculateProfit(status)); + } + }); return profits; } diff --git a/src/main/java/model/judgement/strategy/BlackjackStrategy.java b/src/main/java/model/judgement/strategy/BlackjackStrategy.java index b356c10a07..010ed0fdf1 100644 --- a/src/main/java/model/judgement/strategy/BlackjackStrategy.java +++ b/src/main/java/model/judgement/strategy/BlackjackStrategy.java @@ -3,21 +3,21 @@ import model.judgement.JudgeStrategy; import model.judgement.ResultStatus; import model.paticipant.Dealer; -import model.paticipant.Player; +import model.paticipant.Participant; public class BlackjackStrategy implements JudgeStrategy { @Override - public boolean isApplicable(Dealer dealer, Player player) { - return dealer.isBlackjack() || player.isBlackjack(); + public boolean isApplicable(Dealer dealer, Participant participant) { + return dealer.isBlackjack() || participant.isBlackjack(); } @Override - public ResultStatus getResult(Dealer dealer, Player player) { - if (dealer.isBlackjack() && player.isBlackjack()) { + public ResultStatus getResult(Dealer dealer, Participant participant) { + if (dealer.isBlackjack() && participant.isBlackjack()) { return ResultStatus.DRAW; } - if (player.isBlackjack()) { + if (participant.isBlackjack()) { return ResultStatus.BLACKJACK; } return ResultStatus.LOSE; diff --git a/src/main/java/model/judgement/strategy/BustStrategy.java b/src/main/java/model/judgement/strategy/BustStrategy.java index e1e7964db2..583128c943 100644 --- a/src/main/java/model/judgement/strategy/BustStrategy.java +++ b/src/main/java/model/judgement/strategy/BustStrategy.java @@ -3,18 +3,18 @@ import model.judgement.JudgeStrategy; import model.judgement.ResultStatus; import model.paticipant.Dealer; -import model.paticipant.Player; +import model.paticipant.Participant; public class BustStrategy implements JudgeStrategy { @Override - public boolean isApplicable(Dealer dealer, Player player) { - return player.isBust() || dealer.isBust(); + public boolean isApplicable(Dealer dealer, Participant participant) { + return participant.isBust() || dealer.isBust(); } @Override - public ResultStatus getResult(Dealer dealer, Player player) { - if (player.isBust()) { + public ResultStatus getResult(Dealer dealer, Participant participant) { + if (participant.isBust()) { return ResultStatus.LOSE; } return ResultStatus.WIN; diff --git a/src/main/java/model/paticipant/BettingPlayer.java b/src/main/java/model/paticipant/BettingPlayer.java index 96c7e1a939..500481a2b8 100644 --- a/src/main/java/model/paticipant/BettingPlayer.java +++ b/src/main/java/model/paticipant/BettingPlayer.java @@ -3,9 +3,7 @@ import model.judgement.Profit; import model.judgement.ResultStatus; -public class BettingPlayer extends Participant implements Player { - - private static final int PLAYER_HIT_THRESHOLD = 21; +public class BettingPlayer extends Player { private final BetAmount betAmount; @@ -14,12 +12,6 @@ public BettingPlayer(String name, int betAmount) { this.betAmount = new BetAmount(betAmount); } - @Override - public boolean canHit() { - return calculateTotalScore() < PLAYER_HIT_THRESHOLD; - } - - @Override public Profit calculateProfit(ResultStatus resultStatus) { return resultStatus.calculateProfit(betAmount); } diff --git a/src/main/java/model/paticipant/NonBettingPlayer.java b/src/main/java/model/paticipant/NonBettingPlayer.java deleted file mode 100644 index db6856683b..0000000000 --- a/src/main/java/model/paticipant/NonBettingPlayer.java +++ /dev/null @@ -1,15 +0,0 @@ -package model.paticipant; - -public class NonBettingPlayer extends Participant implements Player { - - private static final int PLAYER_HIT_THRESHOLD = 21; - - public NonBettingPlayer(String name) { - super(name); - } - - @Override - public boolean canHit() { - return calculateTotalScore() < PLAYER_HIT_THRESHOLD; - } -} diff --git a/src/main/java/model/paticipant/Participant.java b/src/main/java/model/paticipant/Participant.java index 85a3a4fccb..905d49a606 100644 --- a/src/main/java/model/paticipant/Participant.java +++ b/src/main/java/model/paticipant/Participant.java @@ -41,8 +41,6 @@ public void addCard(Card card) { this.hand.add(card); } - public abstract boolean canHit(); - public String getName() { return name.name(); } @@ -50,4 +48,6 @@ public String getName() { public List getCards() { return hand.getCards(); } + + public abstract boolean canHit(); } diff --git a/src/main/java/model/paticipant/Player.java b/src/main/java/model/paticipant/Player.java index f55616070a..34eabb38b8 100644 --- a/src/main/java/model/paticipant/Player.java +++ b/src/main/java/model/paticipant/Player.java @@ -1,29 +1,15 @@ package model.paticipant; -import static model.judgement.Profit.ZERO; +public class Player extends Participant { -import java.util.List; -import model.card.Card; -import model.judgement.Profit; -import model.judgement.ResultStatus; + private static final int PLAYER_HIT_THRESHOLD = 21; -public interface Player { - - String getName(); - - int calculateTotalScore(); - - boolean canHit(); - - void addCard(model.card.Card card); - - boolean isBust(); - - boolean isBlackjack(); - - List getCards(); + public Player(String name) { + super(name); + } - default Profit calculateProfit(ResultStatus resultStatus) { - return ZERO; + @Override + public boolean canHit() { + return calculateTotalScore() < PLAYER_HIT_THRESHOLD; } } diff --git a/src/main/java/model/paticipant/Players.java b/src/main/java/model/paticipant/Players.java index 7d531ab0bd..fc0988259c 100644 --- a/src/main/java/model/paticipant/Players.java +++ b/src/main/java/model/paticipant/Players.java @@ -1,19 +1,12 @@ package model.paticipant; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.function.Consumer; public record Players(List players) { public Players(List players) { - this.players = new ArrayList<>(players); - } - - @Override - public List players() { - return Collections.unmodifiableList(players); + this.players = List.copyOf(players); } public void forEach(Consumer action) { diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 1814114eb0..5a68ed0101 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -4,7 +4,7 @@ import java.util.Arrays; import java.util.List; -import model.paticipant.Player; +import model.paticipant.Participant; public class InputView { @@ -23,8 +23,8 @@ public static int readBetAmount(String playerName) { return Integer.parseInt(readLine()); } - public static String readMoreCard(Player player) { - System.out.println(player.getName() + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); + public static String readMoreCard(Participant participant) { + System.out.println(participant.getName() + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); return readLine(); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index b6b4a176e8..19ed7c1d1f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -12,52 +12,34 @@ public class OutputView { private OutputView() { } - public static void printCardOpen(Dealer dealer, List players) { - List names = players.stream() + public static void printCardOpen(Dealer dealer, List participants) { + List names = participants.stream() .map(Player::getName) .toList(); System.out.println(); System.out.printf("%s와 %s에게 2장을 나누었습니다.%n", dealer.getName(), String.join(", ", names)); printCardByDealer(dealer); - printCardByPlayers(players); + printCardByPlayers(participants); } - public static void printCardByPlayer(Player player) { - List cards = player.getCards() - .stream() - .map(OutputView::convert) - .toList(); - System.out.printf("%s카드: %s%n", player.getName(), String.join(", ", cards)); + private static void printCardByDealer(Dealer dealer) { + Card firstCard = dealer.getCards().getFirst(); + String card = EnumMapper.convert(firstCard); + System.out.println(dealer.getName() + ": " + card); } - - public static void printFinalCards(Participant dealer, List players) { + private static void printCardByPlayers(List participants) { + participants.forEach(OutputView::printCardByPlayer); System.out.println(); - printCardByPlayerWithScore(dealer); - players.forEach(OutputView::printCardByPlayerWithScore); } - public static void printCardByPlayerWithScore(Player participant) { - int sum = participant.calculateTotalScore(); + public static void printCardByPlayer(Participant participant) { List cards = participant.getCards() .stream() - .map(OutputView::convert) + .map(EnumMapper::convert) .toList(); - System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); - } - - public static void printCardByPlayerWithScore(Participant participant) { - int sum = participant.calculateTotalScore(); - List cards = participant.getCards() - .stream() - .map(OutputView::convert) - .toList(); - System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); - } - - private static String convert(Card card) { - return EnumMapper.CARD_VALUE_MAPPER.get(card.value()) + EnumMapper.CARD_SHAPE_MAPPER.get(card.shape()); + System.out.printf("%s카드: %s%n", participant.getName(), String.join(", ", cards)); } public static void printToOpenDealerNewCard(Dealer dealer) { @@ -65,14 +47,18 @@ public static void printToOpenDealerNewCard(Dealer dealer) { System.out.printf("%s는 16 이하라 한장의 카드를 더 받았습니다.%n", dealer.getName()); } - private static void printCardByDealer(Dealer dealer) { - Card firstCard = dealer.getCards().getFirst(); - String card = convert(firstCard); - System.out.println(dealer.getName() + ": " + card); + public static void printFinalCards(Dealer dealer, List participants) { + System.out.println(); + printCardByParticipantWithScore(dealer); + participants.forEach(OutputView::printCardByParticipantWithScore); } - private static void printCardByPlayers(List players) { - players.forEach(OutputView::printCardByPlayer); - System.out.println(); + public static void printCardByParticipantWithScore(Participant participant) { + int sum = participant.calculateTotalScore(); + List cards = participant.getCards() + .stream() + .map(EnumMapper::convert) + .toList(); + System.out.printf("%s 카드: %s - 결과: %d%n", participant.getName(), String.join(", ", cards), sum); } } \ No newline at end of file diff --git a/src/main/java/view/mapper/EnumMapper.java b/src/main/java/view/mapper/EnumMapper.java index 6f19377688..34c98a3017 100644 --- a/src/main/java/view/mapper/EnumMapper.java +++ b/src/main/java/view/mapper/EnumMapper.java @@ -1,6 +1,7 @@ package view.mapper; import java.util.Map; +import model.card.Card; import model.card.CardShape; import model.card.CardValue; import model.judgement.ResultStatus; @@ -38,4 +39,8 @@ public class EnumMapper { ); private EnumMapper(){} + + public static String convert(Card card) { + return CARD_VALUE_MAPPER.get(card.value()) + CARD_SHAPE_MAPPER.get(card.shape()); + } } diff --git a/src/test/java/model/JudgementTest.java b/src/test/java/model/JudgementTest.java index c0b099c0ae..fc5586233f 100644 --- a/src/test/java/model/JudgementTest.java +++ b/src/test/java/model/JudgementTest.java @@ -28,13 +28,13 @@ public class JudgementTest { Dealer dealer = createDealer(); dealerCards.forEach(dealer::addCard); - Player player = new BettingPlayer("pobi", 10000); - playerCards.forEach(player::addCard); + Player participant = new BettingPlayer("pobi", 10000); + playerCards.forEach(participant::addCard); // when - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(player))); + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, new Players(List.of(participant))); // then - assertThat(playerResult.result()).containsEntry(player, status); + assertThat(playerResult.result()).containsEntry(participant, status); } } diff --git a/src/test/java/model/PlayerBustTest.java b/src/test/java/model/PlayerBustTest.java index e53ae1f72a..b196c7b047 100644 --- a/src/test/java/model/PlayerBustTest.java +++ b/src/test/java/model/PlayerBustTest.java @@ -6,7 +6,7 @@ import model.card.CardShape; import model.card.CardValue; import model.paticipant.BettingPlayer; -import model.paticipant.Player; +import model.paticipant.Participant; import org.junit.jupiter.api.Test; public class PlayerBustTest { @@ -14,7 +14,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_20_이하_일_때_카드를_더_받을_수_있다() { // given - Player pobi = new BettingPlayer("pobi", 10000); + Participant pobi = new BettingPlayer("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); @@ -25,7 +25,7 @@ public class PlayerBustTest { @Test void 플레이어의_카드_점수_합이_21_이상_일_때_카드를_더_받을_수_없다() { // given - Player pobi = new BettingPlayer("pobi", 10000); + Participant pobi = new BettingPlayer("pobi", 10000); pobi.addCard(new Card(CardShape.HEART, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.TEN)); pobi.addCard(new Card(CardShape.DIAMOND, CardValue.ACE)); diff --git a/src/test/java/model/PlayerTest.java b/src/test/java/model/PlayerTest.java index fb5a829539..e54d2f023c 100644 --- a/src/test/java/model/PlayerTest.java +++ b/src/test/java/model/PlayerTest.java @@ -5,7 +5,7 @@ import java.util.List; import model.card.Card; import model.paticipant.BettingPlayer; -import model.paticipant.Player; +import model.paticipant.Participant; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -15,7 +15,7 @@ class PlayerTest { @MethodSource("fixture.PlayerTestFixture#플레이어별_카드목록_및_점수_제공") void 블랙잭_참여자는_자신의_카드_정보로_현재_점수를_계산할_수_있다(List cards, int expectedScore) { // given - Player pobi = new BettingPlayer("pobi", 10000); + Participant pobi = new BettingPlayer("pobi", 10000); cards.forEach(pobi::addCard); // when From 0c9b30a2bf91a5ec1bd1b9ea1f185fb0741a29dd Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 23:03:24 +0900 Subject: [PATCH 21/24] =?UTF-8?q?fix:=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=20=EA=B2=B0=EA=B3=BC=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=20=EC=B6=9C=EB=A0=A5=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EB=B6=88=EC=9D=BC=EC=B9=98=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/judgement/PlayerResult.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index 60acb92bc3..c87abe07e4 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -1,5 +1,6 @@ package model.judgement; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import model.paticipant.BettingPlayer; @@ -8,7 +9,7 @@ public record PlayerResult(Map result) { public PlayerResult(Map result) { - this.result = Map.copyOf(result); + this.result = Collections.unmodifiableMap(new LinkedHashMap<>(result)); } public DealerResult calculateDealerResult() { From d6d63e91cafca3d38248db6a1521d01cb80617f3 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 23:25:52 +0900 Subject: [PATCH 22/24] =?UTF-8?q?refactor:=20=EB=B2=A0=ED=8C=85=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20BettingCalculator=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../result/BettingResultReporter.java | 12 +++++++--- .../model/judgement/BettingCalculator.java | 23 +++++++++++++++++++ .../java/model/judgement/PlayerResult.java | 17 -------------- src/main/java/view/ProfitReportView.java | 4 ++-- ...ltTest.java => BettingCalculatorTest.java} | 13 +++++++---- 5 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 src/main/java/model/judgement/BettingCalculator.java rename src/test/java/model/judgement/{PlayerResultTest.java => BettingCalculatorTest.java} (78%) diff --git a/src/main/java/controller/result/BettingResultReporter.java b/src/main/java/controller/result/BettingResultReporter.java index 0cb5430ec3..594196930b 100644 --- a/src/main/java/controller/result/BettingResultReporter.java +++ b/src/main/java/controller/result/BettingResultReporter.java @@ -1,17 +1,23 @@ package controller.result; +import java.util.Map; +import model.judgement.BettingCalculator; import model.judgement.PlayerResult; import model.judgement.Profit; +import model.paticipant.BettingPlayer; import view.ProfitReportView; public class BettingResultReporter implements ResultReporter { + private final BettingCalculator calculator = new BettingCalculator(); + @Override public void report(PlayerResult playerResult) { - Profit dealerProfit = playerResult.calculateDealerProfit(); + Map profits = calculator.calculateProfits(playerResult); + Profit dealerProfit = calculator.calculateDealerProfit(profits); ProfitReportView.printFinalProfitHeader(); ProfitReportView.printProfitByDealer(dealerProfit); - ProfitReportView.printProfitByPlayers(playerResult.calculateProfits()); + ProfitReportView.printProfitByPlayers(profits); } -} +} \ No newline at end of file diff --git a/src/main/java/model/judgement/BettingCalculator.java b/src/main/java/model/judgement/BettingCalculator.java new file mode 100644 index 0000000000..0031dee6ee --- /dev/null +++ b/src/main/java/model/judgement/BettingCalculator.java @@ -0,0 +1,23 @@ +package model.judgement; + +import java.util.LinkedHashMap; +import java.util.Map; +import model.paticipant.BettingPlayer; + +public class BettingCalculator { + + public Map calculateProfits(PlayerResult playerResult) { + Map profits = new LinkedHashMap<>(); + playerResult.result().forEach((player, status) -> { + if (player instanceof BettingPlayer bettingPlayer) { + profits.put(bettingPlayer, bettingPlayer.calculateProfit(status)); + } + }); + return profits; + } + + public Profit calculateDealerProfit(Map profits) { + return profits.values().stream() + .reduce(Profit.ZERO, (sum, profit) -> sum.add(profit.negate())); + } +} diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index c87abe07e4..ee042f669e 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -3,7 +3,6 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import model.paticipant.BettingPlayer; import model.paticipant.Player; public record PlayerResult(Map result) { @@ -19,22 +18,6 @@ public DealerResult calculateDealerResult() { return new DealerResult(dealerWinCount, dealerLoseCount, dealerDrawCount); } - public Map calculateProfits() { - Map profits = new LinkedHashMap<>(); - result.forEach((player, status) -> { - if (player instanceof BettingPlayer bettingPlayer) { - profits.put(bettingPlayer, bettingPlayer.calculateProfit(status)); - } - }); - return profits; - } - - public Profit calculateDealerProfit() { - return calculateProfits().values() - .stream() - .reduce(Profit.ZERO, (sum, profit) -> sum.add(profit.negate())); - } - private int countByStatus(ResultStatus resultStatus) { return (int) result.values() .stream() diff --git a/src/main/java/view/ProfitReportView.java b/src/main/java/view/ProfitReportView.java index dca7a0fe6b..32b8555dc7 100644 --- a/src/main/java/view/ProfitReportView.java +++ b/src/main/java/view/ProfitReportView.java @@ -2,7 +2,7 @@ import java.util.Map; import model.judgement.Profit; -import model.paticipant.Player; +import model.paticipant.BettingPlayer; public class ProfitReportView { @@ -17,7 +17,7 @@ public static void printProfitByDealer(Profit profit) { System.out.printf("딜러: %d%n", profit.value()); } - public static void printProfitByPlayers(Map profits) { + public static void printProfitByPlayers(Map profits) { profits.forEach((player, profit) -> System.out.printf("%s: %d%n", player.getName(), profit.value()) ); diff --git a/src/test/java/model/judgement/PlayerResultTest.java b/src/test/java/model/judgement/BettingCalculatorTest.java similarity index 78% rename from src/test/java/model/judgement/PlayerResultTest.java rename to src/test/java/model/judgement/BettingCalculatorTest.java index 8bcb728d17..5cfc5568f0 100644 --- a/src/test/java/model/judgement/PlayerResultTest.java +++ b/src/test/java/model/judgement/BettingCalculatorTest.java @@ -8,7 +8,9 @@ import model.paticipant.Player; import org.junit.jupiter.api.Test; -class PlayerResultTest { +class BettingCalculatorTest { + + private BettingCalculator bettingCalculator = new BettingCalculator(); @Test void 플레이어별_수익을_계산한다() { @@ -23,7 +25,7 @@ class PlayerResultTest { PlayerResult playerResult = new PlayerResult(result); // when - Map profits = playerResult.calculateProfits(); + Map profits = bettingCalculator.calculateProfits(playerResult); // then assertThat(profits.get(pobi)).isEqualTo(new Profit(10000)); @@ -41,9 +43,10 @@ class PlayerResultTest { result.put(jason, ResultStatus.LOSE); PlayerResult playerResult = new PlayerResult(result); + Map profitByPlayer = bettingCalculator.calculateProfits(playerResult); // when - Profit dealerProfit = playerResult.calculateDealerProfit(); + Profit dealerProfit = bettingCalculator.calculateDealerProfit(profitByPlayer); // then assertThat(dealerProfit).isEqualTo(new Profit(10000)); @@ -60,9 +63,9 @@ class PlayerResultTest { PlayerResult playerResult = new PlayerResult(result); // when - Map profits = playerResult.calculateProfits(); + Map profits = bettingCalculator.calculateProfits(playerResult); // then assertThat(profits.get(pobi)).isEqualTo(Profit.ZERO); } -} +} \ No newline at end of file From 52fa0bdb9af6da66ea11769e8ce3bbf9d6fab1ff Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Sun, 15 Mar 2026 23:33:58 +0900 Subject: [PATCH 23/24] =?UTF-8?q?docs:=20readme=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 72 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 72abea04ba..f121f21edd 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,52 @@ # java-blackjack +## 게임 모드 + +### 베팅 모드 +플레이어가 베팅 금액을 걸고 게임 결과에 따라 수익/손실을 계산합니다. + +### 논베팅 모드 +베팅 없이 순수 승/무/패만 집계합니다. + +--- + ## 구현 기능 -- 게임에 참가할 사람 이름 입력 -- 카드 나눠주기 - - 카드 52장 생성 - - 정책: 사용하는 카드에 대해 정의 - - 카드의 종류: 하트, 다이아, 클로버, 스페이드 - - 카드의 숫자: A, 2 부터 10, J, Q, K - - 카드 뽑기 기능이 필요 - - 딜러는 자기 자신의 카드도 뽑는다. - - 딜러는 공개카드 1장과 비공개 카드 1장씩 받고, 공개 카드 출력 - - 참여자 별 카드 주기 - - 참여자들 카드 목록 출력 -- 플레이어 순서대로 카드를 더 받을 것인지 확인 - - 플레이어가 카드를 받았을 경우 현재 카드 목록 출력 -- 딜러의 Bust 판정 - - 카드 점수 계산 - - Ace 1/11 처리 필요 - - 딜러의 카드 합이 16이하면 카드 1장 받기 -- 딜러 카드와 플레이어 카드 출력하기 - - 카드 목록 출력 - - 카드 숫자 합 출력 -- 최종 승패여부 출력 - - 딜러의 승패 출력 - - 플레이어별 승패 출력 + +### 공통 +- 게임에 참가할 사람 이름 입력 +- 카드 52장 생성 + - 카드 종류: 하트, 다이아, 클로버, 스페이드 + - 카드 숫자: A, 2~10, J, Q, K +- 초기 카드 배분 + - 딜러: 공개 카드 1장, 비공개 카드 1장 + - 플레이어: 2장 +- 플레이어 순서대로 추가 카드 수령 여부 결정 + - 카드를 받을 경우 현재 카드 목록 출력 +- 카드 점수 계산 + - Ace: 1 또는 11로 계산 (버스트 방지 우선) +- 딜러 추가 카드 수령 + - 카드 합이 16 이하면 카드 1장 추가 +- 최종 카드 목록 및 점수 출력 + +### 베팅 모드 +- 플레이어별 베팅 금액 입력 + - 최소 1원, 최대 100만원 +- 게임 결과별 수익 계산 + - 승리: 베팅 금액만큼 수익 + - 패배: 베팅 금액만큼 손실 + - 무승부: 수익 없음 + - 블랙잭: 베팅 금액의 1.5배 수익 +- 딜러 및 플레이어별 최종 수익 출력 + +### 논베팅 모드 +- 딜러 및 플레이어별 최종 승/무/패 출력 + +--- + +## 판정 규칙 +- 버스트: 카드 합이 21 초과 시 즉시 패배 +- 블랙잭: 최초 2장으로 합이 21 + - 플레이어만 블랙잭: 1.5배 수익 + - 둘 다 블랙잭: 무승부 + - 딜러만 블랙잭: 플레이어 패배 +- 점수 비교: 버스트/블랙잭 외 경우 점수가 높은 쪽 승리 \ No newline at end of file From df7b53fa7ab2ff6a701a974a8ece1ea57842b926 Mon Sep 17 00:00:00 2001 From: jihwankim128 Date: Mon, 16 Mar 2026 01:00:03 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor:=20=EC=A0=9C=EB=84=88=EB=A6=AD?= =?UTF-8?q?=EC=9D=84=20=ED=99=9C=EC=9A=A9=ED=95=9C=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=EC=9E=AD=20=ED=83=80=EC=9E=85=20=EC=95=88=EC=A0=95=EC=84=B1=20?= =?UTF-8?q?=ED=99=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/BlackjackApplication.java | 11 ++++------ .../java/controller/BlackjackController.java | 16 +++++++------- src/main/java/controller/GameMode.java | 22 ++++++++++--------- .../controller/input/BettingPlayerReader.java | 9 ++++---- .../input/NonBettingPlayerReader.java | 6 ++--- .../java/controller/input/PlayerReader.java | 6 +++-- .../result/BettingResultReporter.java | 4 ++-- .../result/NonBettingResultReporter.java | 5 +++-- .../controller/result/ResultReporter.java | 5 +++-- src/main/java/model/BlackjackGame.java | 3 ++- .../model/judgement/BettingCalculator.java | 9 +++----- src/main/java/model/judgement/Judgement.java | 6 ++--- .../java/model/judgement/PlayerResult.java | 4 ++-- src/main/java/model/paticipant/Players.java | 6 ++--- src/main/java/view/OutputView.java | 8 +++---- src/main/java/view/WinLossReportView.java | 3 ++- 16 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/main/java/BlackjackApplication.java b/src/main/java/BlackjackApplication.java index c93cbf8232..44044d2208 100644 --- a/src/main/java/BlackjackApplication.java +++ b/src/main/java/BlackjackApplication.java @@ -1,17 +1,14 @@ import controller.BlackjackController; import controller.GameMode; import model.BlackjackGame; -import model.card.CardShuffler; import model.card.SimpleCardShuffler; public class BlackjackApplication { public static void main(String[] args) { - CardShuffler cardShuffler = new SimpleCardShuffler(); - BlackjackGame blackjackGame = BlackjackGame.setup(cardShuffler); - GameMode gameMode = GameMode.toBettingMode(); - - BlackjackController controller = new BlackjackController(blackjackGame, gameMode); - controller.run(); + new BlackjackController<>( + BlackjackGame.setup(new SimpleCardShuffler()), + GameMode.toBettingMode() + ).run(); } } diff --git a/src/main/java/controller/BlackjackController.java b/src/main/java/controller/BlackjackController.java index d8a5223c28..8dec13cc5a 100644 --- a/src/main/java/controller/BlackjackController.java +++ b/src/main/java/controller/BlackjackController.java @@ -9,31 +9,31 @@ import view.InputView; import view.OutputView; -public class BlackjackController { +public class BlackjackController { private final BlackjackGame blackjackGame; - private final GameMode gameMode; + private final GameMode gameMode; - public BlackjackController(BlackjackGame blackjackGame, GameMode gameMode) { + public BlackjackController(BlackjackGame blackjackGame, GameMode gameMode) { this.blackjackGame = blackjackGame; this.gameMode = gameMode; } public void run() { Dealer dealer = new Dealer(); - Players players = gameMode.createPlayers(); + Players players = gameMode.createPlayers(); initialDeal(dealer, players); proceedTurns(dealer, players); finishGame(dealer, players); } - private void initialDeal(Dealer dealer, Players players) { + private void initialDeal(Dealer dealer, Players players) { blackjackGame.drawInitCards(dealer, players); OutputView.printCardOpen(dealer, players.players()); } - private void proceedTurns(Dealer dealer, Players players) { + private void proceedTurns(Dealer dealer, Players players) { players.forEach(this::processPlayerTurn); while (dealer.canHit()) { @@ -72,9 +72,9 @@ private Continuation readContinuation(Player player) { return Continuation.from(inputCommand); } - private void finishGame(Dealer dealer, Players players) { + private void finishGame(Dealer dealer, Players players) { OutputView.printFinalCards(dealer, players.players()); - PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); + PlayerResult playerResult = Judgement.judgeByPlayer(dealer, players); gameMode.reportResult(playerResult); } } diff --git a/src/main/java/controller/GameMode.java b/src/main/java/controller/GameMode.java index 5952c35310..e6e76ca0c8 100644 --- a/src/main/java/controller/GameMode.java +++ b/src/main/java/controller/GameMode.java @@ -7,31 +7,33 @@ import controller.result.NonBettingResultReporter; import controller.result.ResultReporter; import model.judgement.PlayerResult; +import model.paticipant.BettingPlayer; +import model.paticipant.Player; import model.paticipant.Players; -public class GameMode { +public class GameMode { - private final PlayerReader playerReader; - private final ResultReporter resultReporter; + private final PlayerReader playerReader; + private final ResultReporter resultReporter; - private GameMode(PlayerReader playerReader, ResultReporter resultReporter) { + private GameMode(PlayerReader playerReader, ResultReporter resultReporter) { this.playerReader = playerReader; this.resultReporter = resultReporter; } - public static GameMode toBettingMode() { - return new GameMode(new BettingPlayerReader(), new BettingResultReporter()); + public static GameMode toBettingMode() { + return new GameMode<>(new BettingPlayerReader(), new BettingResultReporter()); } - public static GameMode toNonBettingMode() { - return new GameMode(new NonBettingPlayerReader(), new NonBettingResultReporter()); + public static GameMode toNonBettingMode() { + return new GameMode<>(new NonBettingPlayerReader(), new NonBettingResultReporter()); } - public Players createPlayers() { + public Players createPlayers() { return playerReader.readPlayers(); } - public void reportResult(PlayerResult playerResult) { + public void reportResult(PlayerResult playerResult) { resultReporter.report(playerResult); } } diff --git a/src/main/java/controller/input/BettingPlayerReader.java b/src/main/java/controller/input/BettingPlayerReader.java index 458deb21c1..937d9c22c7 100644 --- a/src/main/java/controller/input/BettingPlayerReader.java +++ b/src/main/java/controller/input/BettingPlayerReader.java @@ -3,20 +3,19 @@ import java.util.ArrayList; import java.util.List; import model.paticipant.BettingPlayer; -import model.paticipant.Player; import model.paticipant.Players; import view.InputView; -public class BettingPlayerReader implements PlayerReader { +public class BettingPlayerReader implements PlayerReader { @Override - public Players readPlayers() { + public Players readPlayers() { List names = InputView.readPlayerNames(); - List players = new ArrayList<>(); + List players = new ArrayList<>(); for (String name : names) { int betAmount = InputView.readBetAmount(name); players.add(new BettingPlayer(name, betAmount)); } - return new Players(players); + return new Players<>(players); } } diff --git a/src/main/java/controller/input/NonBettingPlayerReader.java b/src/main/java/controller/input/NonBettingPlayerReader.java index 8f8c33dcae..ac46b055a0 100644 --- a/src/main/java/controller/input/NonBettingPlayerReader.java +++ b/src/main/java/controller/input/NonBettingPlayerReader.java @@ -6,14 +6,14 @@ import model.paticipant.Players; import view.InputView; -public class NonBettingPlayerReader implements PlayerReader { +public class NonBettingPlayerReader implements PlayerReader { @Override - public Players readPlayers() { + public Players readPlayers() { List names = InputView.readPlayerNames(); List players = names.stream() .map(Player::new) .collect(Collectors.toList()); - return new Players(players); + return new Players<>(players); } } diff --git a/src/main/java/controller/input/PlayerReader.java b/src/main/java/controller/input/PlayerReader.java index 36d5c19328..424e4d835b 100644 --- a/src/main/java/controller/input/PlayerReader.java +++ b/src/main/java/controller/input/PlayerReader.java @@ -1,8 +1,10 @@ package controller.input; +import model.paticipant.Player; import model.paticipant.Players; -public interface PlayerReader { +public interface PlayerReader { + + Players readPlayers(); - Players readPlayers(); } diff --git a/src/main/java/controller/result/BettingResultReporter.java b/src/main/java/controller/result/BettingResultReporter.java index 594196930b..e5dfb02b38 100644 --- a/src/main/java/controller/result/BettingResultReporter.java +++ b/src/main/java/controller/result/BettingResultReporter.java @@ -7,12 +7,12 @@ import model.paticipant.BettingPlayer; import view.ProfitReportView; -public class BettingResultReporter implements ResultReporter { +public class BettingResultReporter implements ResultReporter { private final BettingCalculator calculator = new BettingCalculator(); @Override - public void report(PlayerResult playerResult) { + public void report(PlayerResult playerResult) { Map profits = calculator.calculateProfits(playerResult); Profit dealerProfit = calculator.calculateDealerProfit(profits); diff --git a/src/main/java/controller/result/NonBettingResultReporter.java b/src/main/java/controller/result/NonBettingResultReporter.java index 61c9569d0d..6d6e577f64 100644 --- a/src/main/java/controller/result/NonBettingResultReporter.java +++ b/src/main/java/controller/result/NonBettingResultReporter.java @@ -2,12 +2,13 @@ import model.judgement.DealerResult; import model.judgement.PlayerResult; +import model.paticipant.Player; import view.WinLossReportView; -public class NonBettingResultReporter implements ResultReporter { +public class NonBettingResultReporter implements ResultReporter { @Override - public void report(PlayerResult playerResult) { + public void report(PlayerResult playerResult) { DealerResult dealerResult = playerResult.calculateDealerResult(); WinLossReportView.printFinalResultHeader(); diff --git a/src/main/java/controller/result/ResultReporter.java b/src/main/java/controller/result/ResultReporter.java index f95b83a05b..cccacff1bd 100644 --- a/src/main/java/controller/result/ResultReporter.java +++ b/src/main/java/controller/result/ResultReporter.java @@ -1,8 +1,9 @@ package controller.result; import model.judgement.PlayerResult; +import model.paticipant.Player; -public interface ResultReporter { +public interface ResultReporter { - void report(PlayerResult playerResult); + void report(PlayerResult playerResult); } diff --git a/src/main/java/model/BlackjackGame.java b/src/main/java/model/BlackjackGame.java index 44aa768e90..98919b47a9 100644 --- a/src/main/java/model/BlackjackGame.java +++ b/src/main/java/model/BlackjackGame.java @@ -7,6 +7,7 @@ import model.card.Deck; import model.paticipant.Dealer; import model.paticipant.Participant; +import model.paticipant.Player; import model.paticipant.Players; public class BlackjackGame { @@ -27,7 +28,7 @@ public static BlackjackGame setup(CardShuffler cardShuffler) { return new BlackjackGame(deck); } - public void drawInitCards(Dealer dealer, Players players) { + public void drawInitCards(Dealer dealer, Players players) { drawCardByParticipant(dealer, INITIAL_DISPENSE_COUNT); players.forEach(player -> drawCardByParticipant(player, INITIAL_DISPENSE_COUNT)); } diff --git a/src/main/java/model/judgement/BettingCalculator.java b/src/main/java/model/judgement/BettingCalculator.java index 0031dee6ee..01f2916115 100644 --- a/src/main/java/model/judgement/BettingCalculator.java +++ b/src/main/java/model/judgement/BettingCalculator.java @@ -6,13 +6,10 @@ public class BettingCalculator { - public Map calculateProfits(PlayerResult playerResult) { + public Map calculateProfits(PlayerResult playerResult) { Map profits = new LinkedHashMap<>(); - playerResult.result().forEach((player, status) -> { - if (player instanceof BettingPlayer bettingPlayer) { - profits.put(bettingPlayer, bettingPlayer.calculateProfit(status)); - } - }); + playerResult.result() + .forEach((bettingPlayer, status) -> profits.put(bettingPlayer, bettingPlayer.calculateProfit(status))); return profits; } diff --git a/src/main/java/model/judgement/Judgement.java b/src/main/java/model/judgement/Judgement.java index 69c2546860..828a73c69d 100644 --- a/src/main/java/model/judgement/Judgement.java +++ b/src/main/java/model/judgement/Judgement.java @@ -14,10 +14,10 @@ public class Judgement { private static final List STRATEGIES = List.of(new BustStrategy(), new BlackjackStrategy()); - public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { - Map result = new LinkedHashMap<>(); + public static PlayerResult judgeByPlayer(Dealer dealer, Players players) { + Map result = new LinkedHashMap<>(); players.forEach(player -> result.put(player, decide(dealer, player))); - return new PlayerResult(result); + return new PlayerResult<>(result); } private static ResultStatus decide(Dealer dealer, Participant participant) { diff --git a/src/main/java/model/judgement/PlayerResult.java b/src/main/java/model/judgement/PlayerResult.java index ee042f669e..c6ff58db51 100644 --- a/src/main/java/model/judgement/PlayerResult.java +++ b/src/main/java/model/judgement/PlayerResult.java @@ -5,9 +5,9 @@ import java.util.Map; import model.paticipant.Player; -public record PlayerResult(Map result) { +public record PlayerResult(Map result) { - public PlayerResult(Map result) { + public PlayerResult(Map result) { this.result = Collections.unmodifiableMap(new LinkedHashMap<>(result)); } diff --git a/src/main/java/model/paticipant/Players.java b/src/main/java/model/paticipant/Players.java index fc0988259c..216b3e51fb 100644 --- a/src/main/java/model/paticipant/Players.java +++ b/src/main/java/model/paticipant/Players.java @@ -3,13 +3,13 @@ import java.util.List; import java.util.function.Consumer; -public record Players(List players) { +public record Players(List players) { - public Players(List players) { + public Players(List players) { this.players = List.copyOf(players); } - public void forEach(Consumer action) { + public void forEach(Consumer action) { players.forEach(action); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 19ed7c1d1f..b833d21431 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -12,7 +12,7 @@ public class OutputView { private OutputView() { } - public static void printCardOpen(Dealer dealer, List participants) { + public static void printCardOpen(Dealer dealer, List participants) { List names = participants.stream() .map(Player::getName) .toList(); @@ -29,8 +29,8 @@ private static void printCardByDealer(Dealer dealer) { System.out.println(dealer.getName() + ": " + card); } - private static void printCardByPlayers(List participants) { - participants.forEach(OutputView::printCardByPlayer); + private static void printCardByPlayers(List players) { + players.forEach(OutputView::printCardByPlayer); System.out.println(); } @@ -47,7 +47,7 @@ public static void printToOpenDealerNewCard(Dealer dealer) { System.out.printf("%s는 16 이하라 한장의 카드를 더 받았습니다.%n", dealer.getName()); } - public static void printFinalCards(Dealer dealer, List participants) { + public static void printFinalCards(Dealer dealer, List participants) { System.out.println(); printCardByParticipantWithScore(dealer); participants.forEach(OutputView::printCardByParticipantWithScore); diff --git a/src/main/java/view/WinLossReportView.java b/src/main/java/view/WinLossReportView.java index e368e22931..f35404428b 100644 --- a/src/main/java/view/WinLossReportView.java +++ b/src/main/java/view/WinLossReportView.java @@ -2,6 +2,7 @@ import model.judgement.DealerResult; import model.judgement.PlayerResult; +import model.paticipant.Player; import view.mapper.EnumMapper; public class WinLossReportView { @@ -42,7 +43,7 @@ private static String extractLoseMessage(int loseCount) { return ""; } - public static void printResultByPlayers(PlayerResult playerResult) { + public static void printResultByPlayers(PlayerResult playerResult) { playerResult.result() .forEach((player, status) -> System.out.printf("%s: %s%n", player.getName(), EnumMapper.RESULT_STATUS_MAPPER.get(status)));