From 1da503b7447d68dcc7ae35d6bfb78affb250ffac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:37:22 +0900 Subject: [PATCH 01/30] =?UTF-8?q?refactor(domain):=20Card=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A5=BC=20record=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => card}/Card.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) rename src/main/java/domain/{ => card}/Card.java (72%) diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/card/Card.java similarity index 72% rename from src/main/java/domain/Card.java rename to src/main/java/domain/card/Card.java index 9dc0842b87e..f277187a607 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/card/Card.java @@ -1,12 +1,6 @@ -package domain; - -public class Card { - private final int card; - - public Card(int card) { - this.card = card; - } +package domain.card; +public record Card(int card) { public String getCardName() { int shape = card / 13; int number = card % 13; @@ -15,23 +9,16 @@ public String getCardName() { public int getScore() { int cardNumber = card % 13; - if (1 <= cardNumber && cardNumber <= 9) { return cardNumber + 1; } - if (cardNumber >= 10) { return 10; } - return 11; } public boolean isAce() { return card % 13 == 0; } - - public int getCard() { - return card; - } -} \ No newline at end of file +} From cc058b49ebc4fe2f810e705b4517593f2ccd7345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:39:51 +0900 Subject: [PATCH 02/30] =?UTF-8?q?feat(domain):=20=EB=B2=A0=ED=8C=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EA=B4=80=EB=A6=AC=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20Money=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/domain/participant/Money.java | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/java/domain/participant/Money.java diff --git a/src/main/java/domain/participant/Money.java b/src/main/java/domain/participant/Money.java new file mode 100644 index 00000000000..8a7068f44bb --- /dev/null +++ b/src/main/java/domain/participant/Money.java @@ -0,0 +1,36 @@ +package domain.participant; + +import java.util.regex.Pattern; + +public class Money { + private static final Pattern COUNT_PATTERN = Pattern.compile("\\d+"); + private final int amount; + + public Money(String input) { + validateNumeric(input); + this.amount = Integer.parseInt(input); + } + + private Money(int amount) { + this.amount = amount; + } + + public Money multiply(double rate) { + return new Money((int) (amount * rate)); + } + + public int getAmount() { + return amount; + } + + @Override + public String toString() { + return String.valueOf(amount); + } + + private void validateNumeric(String input) { + if (!COUNT_PATTERN.matcher(input).matches()) { + throw new IllegalArgumentException("숫자가 아닙니다."); + } + } +} From b85a8975bfd5fb913a64255cb7782dca80079aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:40:04 +0900 Subject: [PATCH 03/30] =?UTF-8?q?feat(dto):=20=EB=B2=A0=ED=8C=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EA=B4=80=EB=A6=AC=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20MoneyDTO=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/dto/MoneyDTO.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/dto/MoneyDTO.java diff --git a/src/main/java/dto/MoneyDTO.java b/src/main/java/dto/MoneyDTO.java new file mode 100644 index 00000000000..4605d60e81a --- /dev/null +++ b/src/main/java/dto/MoneyDTO.java @@ -0,0 +1,9 @@ +package dto; + +import java.util.List; + +public record MoneyDTO( + String dealerMoney, + List playerOutcomes +) { +} From 2bd3557b5e400bf7964ef05093ba6ad42896e262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:40:16 +0900 Subject: [PATCH 04/30] =?UTF-8?q?feat(domain):=20=EB=8D=B1=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=B1=85=EC=9E=84=EC=9D=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/domain/card/DeckFactory.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/domain/card/DeckFactory.java diff --git a/src/main/java/domain/card/DeckFactory.java b/src/main/java/domain/card/DeckFactory.java new file mode 100644 index 00000000000..1ddd0bdfa66 --- /dev/null +++ b/src/main/java/domain/card/DeckFactory.java @@ -0,0 +1,15 @@ +package domain.card; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +public class DeckFactory { + public static Deck create() { + List cards = IntStream.range(0, 52) + .mapToObj(Card::new) + .toList(); + + return new Deck(new ArrayList<>(cards)); + } +} From 904efb22015ea5a796cfb49f57e4dbac80a664ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:40:46 +0900 Subject: [PATCH 05/30] =?UTF-8?q?test(domain):=20=EC=8A=B9=ED=8C=A8=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=EC=99=80=20=EB=B2=A0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B2=80=EC=A6=9D=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=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 --- src/test/java/domain/OutcomeTest.java | 107 ++++++++++++++++++++------ 1 file changed, 82 insertions(+), 25 deletions(-) diff --git a/src/test/java/domain/OutcomeTest.java b/src/test/java/domain/OutcomeTest.java index b1e7bbf09a9..4e8e172b396 100644 --- a/src/test/java/domain/OutcomeTest.java +++ b/src/test/java/domain/OutcomeTest.java @@ -1,43 +1,100 @@ package domain; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; +import domain.card.Card; +import domain.participant.Dealer; +import domain.participant.Money; +import domain.participant.Player; +import domain.result.Outcome; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class OutcomeTest { + @Test - @DisplayName("점수가 같으면 무승부다") - void drawResult() { - Score dealerScore = new Score(20); - Score playerScore = new Score(20); - Outcome outcome = Outcome.decideWinner(playerScore, dealerScore); - assertEquals(Outcome.DRAW, outcome); + @DisplayName("1. 플레이어만 처음 2장으로 블랙잭일 경우") + void playerOnlyBlackJack() { + Player player = new Player("pobi", new Money("10000")); + Dealer dealer = new Dealer(); + + player.drawCard(new Card(0)); + player.drawCard(new Card(10)); + + dealer.drawCard(new Card(10)); + dealer.drawCard(new Card(8)); + + Outcome outcome = Outcome.decideWinner(player, dealer); + Money profit = player.getMoney().multiply(outcome.getRate()); + assertThat(outcome).isEqualTo(Outcome.BLACKJACK_WIN); + assertThat(profit.getAmount()).isEqualTo(15000); } @Test - @DisplayName("딜러 점수가 더 크면 플레이어는 패배한다") - void loseResult() { - Score dealerScore = new Score(20); - Score playerScore = new Score(18); - Outcome outcome = Outcome.decideWinner(playerScore, dealerScore); - assertEquals(Outcome.LOSE, outcome); + @DisplayName("2. 플레이어와 딜러 모두 처음 2장으로 블랙잭인 경우") + void bothBlackJack() { + Player player = new Player("pobi", new Money("10000")); + Dealer dealer = new Dealer(); + + player.drawCard(new Card(0)); + player.drawCard(new Card(10)); + + dealer.drawCard(new Card(0)); + dealer.drawCard(new Card(10)); + + Outcome outcome = Outcome.decideWinner(player, dealer); + Money profit = player.getMoney().multiply(outcome.getRate()); + assertThat(outcome).isEqualTo(Outcome.DRAW); + assertThat(profit.getAmount()).isEqualTo(10000); + } + + @Test + @DisplayName("3. 딜러만 처음 2장으로 블랙잭인 경우") + void dealerOnlyBlackJack() { + Player player = new Player("pobi", new Money("10000")); + Dealer dealer = new Dealer(); + + player.drawCard(new Card(10)); + player.drawCard(new Card(8)); + + dealer.drawCard(new Card(0)); + dealer.drawCard(new Card(10)); + + Outcome outcome = Outcome.decideWinner(player, dealer); + Money profit = player.getMoney().multiply(outcome.getRate()); + assertThat(outcome).isEqualTo(Outcome.LOSE); + assertThat(profit.getAmount()).isEqualTo(-10000); } @Test - @DisplayName("딜러가 버스트면 플레이어는 승리한다") - void winWhenDealerBust() { - Score dealerScore = new Score(22); - Score playerScore = new Score(18); - Outcome outcome = Outcome.decideWinner(playerScore, dealerScore); - assertEquals(Outcome.WIN, outcome); + @DisplayName("4. 플레이어가 카드를 추가로 뽑아 21을 초과할 경우") + void playerBust() { + Player player = new Player("pobi", new Money("10000")); + Dealer dealer = new Dealer(); + player.drawCard(new Card(10)); + player.drawCard(new Card(5)); + player.drawCard(new Card(10)); + dealer.drawCard(new Card(10)); + dealer.drawCard(new Card(8)); + Outcome outcome = Outcome.decideWinner(player, dealer); + Money profit = player.getMoney().multiply(outcome.getRate()); + assertThat(outcome).isEqualTo(Outcome.LOSE); + assertThat(profit.getAmount()).isEqualTo(-10000); } @Test - @DisplayName("플레이어와 딜러가 모두 버스트인 경우 플레이어는 패배한다") - void bothBust() { - Score dealerScore = new Score(22); - Score playerScore = new Score(23); - assertEquals(Outcome.LOSE, Outcome.decideWinner(playerScore, dealerScore)); + @DisplayName("5. 딜러가 21을 초과하고 플레이어는 21 이하일 경우") + void dealerBust_playerAlive() { + Player player = new Player("pobi", new Money("10000")); + Dealer dealer = new Dealer(); + player.drawCard(new Card(10)); + player.drawCard(new Card(5)); + dealer.drawCard(new Card(10)); + dealer.drawCard(new Card(5)); + dealer.drawCard(new Card(10)); + Outcome outcome = Outcome.decideWinner(player, dealer); + Money profit = player.getMoney().multiply(outcome.getRate()); + assertThat(outcome).isEqualTo(Outcome.WIN); + assertThat(profit.getAmount()).isEqualTo(10000); } -} \ No newline at end of file +} From ff51b03c81742c091d0480cb7033666693f5c393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:43:39 +0900 Subject: [PATCH 06/30] =?UTF-8?q?refactor(domain):=20CardSuitMap=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => card}/CardSuitMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/domain/{ => card}/CardSuitMap.java (97%) diff --git a/src/main/java/domain/CardSuitMap.java b/src/main/java/domain/card/CardSuitMap.java similarity index 97% rename from src/main/java/domain/CardSuitMap.java rename to src/main/java/domain/card/CardSuitMap.java index adb39f6e3f4..a5a7ec5e9cc 100644 --- a/src/main/java/domain/CardSuitMap.java +++ b/src/main/java/domain/card/CardSuitMap.java @@ -1,4 +1,4 @@ -package domain; +package domain.card; import java.util.Map; From 1c569c56926bcabefdf0cc34c1184d44437f3e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:43:55 +0900 Subject: [PATCH 07/30] =?UTF-8?q?refactor(domain):=20Dealer=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => participant}/Dealer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/java/domain/{ => participant}/Dealer.java (91%) diff --git a/src/main/java/domain/Dealer.java b/src/main/java/domain/participant/Dealer.java similarity index 91% rename from src/main/java/domain/Dealer.java rename to src/main/java/domain/participant/Dealer.java index d580dcd29ec..1396ccfe78e 100644 --- a/src/main/java/domain/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -1,4 +1,4 @@ -package domain; +package domain.participant; public class Dealer extends Participant { private static final int DEALER_DRAW_BOUND = 16; @@ -12,4 +12,4 @@ public Dealer() { public boolean canDraw() { return getScore().getGameScore() <= DEALER_DRAW_BOUND; } -} \ No newline at end of file +} From 75403732afebc151a61a75a18d5e57b433a02ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:45:42 +0900 Subject: [PATCH 08/30] =?UTF-8?q?refactor(domain):=20Hand=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20record=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/{ => participant}/Hand.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) rename src/main/java/domain/{ => participant}/Hand.java (62%) diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/participant/Hand.java similarity index 62% rename from src/main/java/domain/Hand.java rename to src/main/java/domain/participant/Hand.java index 15843f3caa6..edc05b4141c 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/participant/Hand.java @@ -1,14 +1,14 @@ -package domain; +package domain.participant; +import domain.card.Card; +import domain.result.Score; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class Hand { - private final List cards; - +public record Hand(List cards) { public Hand() { - this.cards = new ArrayList<>(); + this(new ArrayList<>()); } public Hand(List cards) { @@ -20,20 +20,16 @@ public void add(Card card) { } public Score calculateScore() { - int totalScore = 0; - int aceCount = 0; - for (Card card : cards) { - totalScore += card.getScore(); - if (card.isAce()) { - aceCount++; - } - } - + int totalScore = cards.stream() + .mapToInt(Card::getScore) + .sum(); + int aceCount = (int) cards.stream() + .filter(Card::isAce) + .count(); while (canLowerAceScore(totalScore, aceCount)) { totalScore -= 10; aceCount--; } - return new Score(totalScore); } @@ -45,7 +41,8 @@ private boolean canLowerAceScore(int score, int aceCount) { return score > 21 && aceCount > 0; } - public List getCards() { + @Override + public List cards() { return Collections.unmodifiableList(cards); } } From ac7eb2e9d2fc385e6a879d47864b1d50114da2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 16:46:21 +0900 Subject: [PATCH 09/30] =?UTF-8?q?refactor(domain):=20Name=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20record=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => participant}/Name.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) rename src/main/java/domain/{ => participant}/Name.java (66%) diff --git a/src/main/java/domain/Name.java b/src/main/java/domain/participant/Name.java similarity index 66% rename from src/main/java/domain/Name.java rename to src/main/java/domain/participant/Name.java index b30b7d24043..3da219af171 100644 --- a/src/main/java/domain/Name.java +++ b/src/main/java/domain/participant/Name.java @@ -1,25 +1,16 @@ -package domain; +package domain.participant; -public final class Name { - private final String name; - - public Name(String name) { +public record Name(String name) { + public Name { validate(name); - this.name = name; } private void validate(String name) { if (name == null) { throw new IllegalArgumentException("이름은 비어 있거나 공백만 있을 수 없습니다."); } - if (name.isBlank()) { throw new IllegalArgumentException("이름은 비어 있거나 공백만 있을 수 없습니다."); } } - - public String getName() { - return name; - } } - From d45e1dc1caff3d3ff12d009c970a0959f14b5979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:33:59 +0900 Subject: [PATCH 10/30] =?UTF-8?q?feat(domain):=20Outcome=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=EC=9E=AD=20=EC=8A=B9=ED=8C=A8=20=ED=8C=90=EB=B3=84=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B0=B0=EB=8B=B9=EB=A5=A0=20=EB=A1=9C=EC=A7=81=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 --- src/main/java/domain/Outcome.java | 44 ---------------- src/main/java/domain/result/Outcome.java | 67 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/domain/Outcome.java create mode 100644 src/main/java/domain/result/Outcome.java diff --git a/src/main/java/domain/Outcome.java b/src/main/java/domain/Outcome.java deleted file mode 100644 index 499846d5c28..00000000000 --- a/src/main/java/domain/Outcome.java +++ /dev/null @@ -1,44 +0,0 @@ -package domain; - -public enum Outcome { - WIN("승"), - LOSE("패"), - DRAW("무"); - - private final String name; - - Outcome(String name) { - this.name = name; - } - - public static Outcome decideWinner(Score playerScore, Score dealerScore) { - if (playerScore.isBust()) { - return LOSE; - } - if (dealerScore.isBust()) { - return WIN; - } - - if (playerScore.getGameScore() > dealerScore.getGameScore()) { - return WIN; - } - if (playerScore.getGameScore() < dealerScore.getGameScore()) { - return LOSE; - } - return DRAW; - } - - public String getName() { - return name; - } - - public Outcome opposite() { - if (this == WIN) { - return LOSE; - } - if (this == LOSE) { - return WIN; - } - return DRAW; - } -} \ No newline at end of file diff --git a/src/main/java/domain/result/Outcome.java b/src/main/java/domain/result/Outcome.java new file mode 100644 index 00000000000..9ab21491577 --- /dev/null +++ b/src/main/java/domain/result/Outcome.java @@ -0,0 +1,67 @@ +package domain.result; + +import domain.participant.Participant; + +public enum Outcome { + BLACKJACK_WIN("블랙잭 승", 1.5), + WIN("승", 1.0), + DRAW("무", 1.0), + LOSE("패", -1.0); + + private final String name; + private final double rate; + + Outcome(String name, double rate) { + this.name = name; + this.rate = rate; + } + + public static Outcome decideWinner(Participant player, Participant dealer) { + if (player.isFirstBlackJack() && dealer.isFirstBlackJack()) { + return DRAW; + } + if (player.isFirstBlackJack()) { + return BLACKJACK_WIN; + } + if (dealer.isFirstBlackJack()) { + return LOSE; + } + Score playerScore = player.getScore(); + Score dealerScore = dealer.getScore(); + return decideByScore(playerScore, dealerScore); + } + + private static Outcome decideByScore(Score playerScore, Score dealerScore) { + if (playerScore.isBust()) { + return LOSE; + } + if (dealerScore.isBust()) { + return WIN; + } + if (playerScore.getGameScore() > dealerScore.getGameScore()) { + return WIN; + } + if (playerScore.getGameScore() < dealerScore.getGameScore()) { + return LOSE; + } + return DRAW; + } + + public String getName() { + return name; + } + + public double getRate() { + return rate; + } + + public Outcome opposite() { + if (this == WIN) { + return LOSE; + } + if (this == LOSE) { + return WIN; + } + return DRAW; + } +} From c181ba755d403a0b8789f7ccd5e14c4dfab1ee81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:35:08 +0900 Subject: [PATCH 11/30] =?UTF-8?q?refactor(domain):=20Participant=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=EC=9E=AD=20=ED=99=95=EC=9D=B8,=20=EC=B9=B4=EB=93=9C?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EB=B0=98=ED=99=98=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{ => participant}/Participant.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) rename src/main/java/domain/{ => participant}/Participant.java (51%) diff --git a/src/main/java/domain/Participant.java b/src/main/java/domain/participant/Participant.java similarity index 51% rename from src/main/java/domain/Participant.java rename to src/main/java/domain/participant/Participant.java index b95bf7fb835..fc10566e0f9 100644 --- a/src/main/java/domain/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -1,4 +1,8 @@ -package domain; +package domain.participant; + +import domain.card.Card; +import domain.result.Score; +import java.util.List; public abstract class Participant { private final Hand hand; @@ -9,6 +13,10 @@ public Participant(String name) { this.hand = new Hand(); } + public boolean isFirstBlackJack() { + return hand.size() == 2 && hand.calculateScore().isBlackjack(); + } + public void drawCard(Card card) { hand.add(card); } @@ -18,12 +26,18 @@ public Score getScore() { } public String getName() { - return name.getName(); + return name.name(); } public Hand getHand() { - return new Hand(hand.getCards()); + return new Hand(hand.cards()); + } + + public List getCardNames() { + return hand.cards().stream() + .map(Card::getCardName) + .toList(); } public abstract boolean canDraw(); -} \ No newline at end of file +} From 268fe7b8ec4456f769f2aaf60ba4cd237e15adf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:36:15 +0900 Subject: [PATCH 12/30] =?UTF-8?q?refactor(dto):=20Outcome=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20import=20=EA=B2=BD=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/dto/AllOutcomeDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dto/AllOutcomeDto.java b/src/main/java/dto/AllOutcomeDto.java index 3fd4c2e7cc9..c7ae943d071 100644 --- a/src/main/java/dto/AllOutcomeDto.java +++ b/src/main/java/dto/AllOutcomeDto.java @@ -1,6 +1,6 @@ package dto; -import domain.Outcome; +import domain.result.Outcome; import java.util.List; import java.util.Map; From e0e7145ca3b77e826d3289ae7b7008d310620a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:37:25 +0900 Subject: [PATCH 13/30] =?UTF-8?q?refactor(message):=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=20=EB=A9=94=EC=84=B8=EC=A7=80=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/message/IOMessage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/message/IOMessage.java b/src/main/java/message/IOMessage.java index e09d449c142..064e7aef776 100644 --- a/src/main/java/message/IOMessage.java +++ b/src/main/java/message/IOMessage.java @@ -4,7 +4,9 @@ public enum IOMessage { ASK_GAME_PARTICIPANT("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"), ASK_MORE_CARD("는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"), DEALER_ONE_CARD("딜러는 16이하라 한장의 카드를 더 받았습니다."), - WINNING_STATISTICS("## 최종 승패"); + WINNING_STATISTICS("## 최종 승패"), + FINAL_MONEY_STATISTICS("## 최종 수익"), + ASK_MONEY("의 배팅 금액은?"); private final String message; From 569ebfc3c80229f04df406018b0f542aadbf36d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:38:13 +0900 Subject: [PATCH 14/30] =?UTF-8?q?feat(dto):=20=EB=8F=84=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=20=EB=B3=80=ED=99=98=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=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/dto/ParticipantDto.java | 7 +++++++ src/main/java/dto/ParticipantScoreDto.java | 10 +++++++++- src/main/java/dto/PlayerOutcomeDto.java | 11 ++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/dto/ParticipantDto.java b/src/main/java/dto/ParticipantDto.java index 655343f2a12..a60072813db 100644 --- a/src/main/java/dto/ParticipantDto.java +++ b/src/main/java/dto/ParticipantDto.java @@ -1,6 +1,13 @@ package dto; +import domain.participant.Participant; import java.util.List; public record ParticipantDto(String name, List cardNames) { + public static ParticipantDto from(Participant participant) { + return new ParticipantDto( + participant.getName(), + List.copyOf(participant.getCardNames()) + ); + } } diff --git a/src/main/java/dto/ParticipantScoreDto.java b/src/main/java/dto/ParticipantScoreDto.java index e2f707326d8..6e088dbbfed 100644 --- a/src/main/java/dto/ParticipantScoreDto.java +++ b/src/main/java/dto/ParticipantScoreDto.java @@ -1,6 +1,14 @@ package dto; +import domain.participant.Participant; import java.util.List; public record ParticipantScoreDto(String name, List cardNames, int score) { -} \ No newline at end of file + public static ParticipantScoreDto from(Participant participant) { + return new ParticipantScoreDto( + participant.getName(), + List.copyOf(participant.getCardNames()), + participant.getScore().getGameScore() + ); + } +} diff --git a/src/main/java/dto/PlayerOutcomeDto.java b/src/main/java/dto/PlayerOutcomeDto.java index 135a7cc4afa..df344b1b411 100644 --- a/src/main/java/dto/PlayerOutcomeDto.java +++ b/src/main/java/dto/PlayerOutcomeDto.java @@ -1,4 +1,13 @@ package dto; -public record PlayerOutcomeDto(String name, String outcome) { +import domain.participant.Money; +import domain.participant.Player; + +public record PlayerOutcomeDto(String name, String profit) { + public static PlayerOutcomeDto of(Player player, Money profit) { + return new PlayerOutcomeDto( + player.getName(), + String.valueOf(profit.getAmount()) + ); + } } From 9a30ff34a935d78e045205c3669d090e86214bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:39:36 +0900 Subject: [PATCH 15/30] =?UTF-8?q?feat(domain):=20Player=EC=97=90=20?= =?UTF-8?q?=EB=B0=B0=ED=8C=85=20=EA=B8=88=EC=95=A1=20=EC=86=8D=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=EC=8B=9C=20=EB=93=9C=EB=A1=9C=EC=9A=B0=20=EB=B0=A9=EC=A7=80=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=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/domain/Player.java | 12 ------------ src/main/java/domain/participant/Player.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/domain/Player.java create mode 100644 src/main/java/domain/participant/Player.java diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java deleted file mode 100644 index 47d62a53102..00000000000 --- a/src/main/java/domain/Player.java +++ /dev/null @@ -1,12 +0,0 @@ -package domain; - -public class Player extends Participant { - public Player(String name) { - super(name); - } - - @Override - public boolean canDraw() { - return !getScore().isBust(); - } -} \ No newline at end of file diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java new file mode 100644 index 00000000000..adbddc6413e --- /dev/null +++ b/src/main/java/domain/participant/Player.java @@ -0,0 +1,19 @@ +package domain.participant; + +public class Player extends Participant { + private final Money money; + + public Player(String name, Money money) { + super(name); + this.money = money; + } + + public Money getMoney() { + return money; + } + + @Override + public boolean canDraw() { + return !getScore().isBust() && !getScore().isBlackjack(); + } +} From 21d97c641967488f0fc83ccbf856eaa617f665d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:40:42 +0900 Subject: [PATCH 16/30] =?UTF-8?q?refactor(domain):=20Players=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A5=BC=20record=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=ED=95=98=EA=B3=A0=20=EC=9D=B4=EB=A6=84=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A1=9C=EC=A7=81=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/domain/Players.java | 24 ------------------- src/main/java/domain/participant/Players.java | 18 ++++++++++++++ 2 files changed, 18 insertions(+), 24 deletions(-) delete mode 100644 src/main/java/domain/Players.java create mode 100644 src/main/java/domain/participant/Players.java diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java deleted file mode 100644 index 3b2d3204ca0..00000000000 --- a/src/main/java/domain/Players.java +++ /dev/null @@ -1,24 +0,0 @@ -package domain; - -import java.util.ArrayList; -import java.util.List; - -public class Players { - private final List players; - - public Players(List players) { - this.players = players; - } - - public int getSize() { - return players.size(); - } - - public Player getPlayer(int index) { - return players.get(index); - } - - public List getPlayers() { - return new ArrayList<>(this.players); - } -} diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java new file mode 100644 index 00000000000..fc2b4b2b698 --- /dev/null +++ b/src/main/java/domain/participant/Players.java @@ -0,0 +1,18 @@ +package domain.participant; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public record Players(List players) { + public String getJoinedNames() { + return players.stream() + .map(Player::getName) + .collect(Collectors.joining(", ")); + } + + @Override + public List players() { + return new ArrayList<>(this.players); + } +} From d74b5896eb5ab188bdd95f730013b7b1e65776a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:41:01 +0900 Subject: [PATCH 17/30] =?UTF-8?q?refactor(controller):=20=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=20=EC=A7=84=ED=96=89=20=ED=9D=90=EB=A6=84=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=EB=B0=B0=ED=8C=85=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=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/controller/BlackJackGame.java | 119 ++++++++++---------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/main/java/controller/BlackJackGame.java b/src/main/java/controller/BlackJackGame.java index dad29ad70c3..de3ae5d7152 100644 --- a/src/main/java/controller/BlackJackGame.java +++ b/src/main/java/controller/BlackJackGame.java @@ -1,24 +1,20 @@ package controller; -import domain.Card; -import domain.Dealer; -import domain.Deck; -import domain.GameResult; -import domain.Outcome; -import domain.Participant; -import domain.Player; -import domain.Players; -import dto.AllOutcomeDto; +import domain.card.Deck; +import domain.card.DeckFactory; +import domain.participant.Dealer; +import domain.participant.Money; +import domain.participant.Player; +import domain.participant.Players; +import domain.result.Outcome; import dto.FinalScoreDto; import dto.InitialDto; +import dto.MoneyDTO; import dto.ParticipantDto; import dto.ParticipantScoreDto; import dto.PlayerOutcomeDto; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import java.util.stream.IntStream; import util.NameParser; import view.InputView; @@ -34,46 +30,61 @@ public BlackJackGame(InputView inputView, ResultView resultView) { } public void run() { - Deck deck = createDeck(); + Deck deck = DeckFactory.create(); Dealer dealer = new Dealer(); - Players players = NameParser.makeNameList(inputView.getParticipant()); + Players players = setupPlayers(); + playGame(deck, dealer, players); + } + + private void playGame(Deck deck, Dealer dealer, Players players) { initialDraw(deck, dealer, players); printInitialStatus(dealer, players); - players.getPlayers().forEach(player -> drawPlayerTurn(deck, player)); + if (dealer.isFirstBlackJack()) { + printResults(dealer, players); + return; + } + players.players().forEach(player -> drawPlayerTurn(deck, player)); drawDealerTurn(deck, dealer); + printResults(dealer, players); + } + + private void printResults(Dealer dealer, Players players) { printFinalScore(dealer, players); - printFinalWinner(dealer, players); + printFinalProfit(dealer, players); } - private Deck createDeck() { - List cards = IntStream.range(0, 52) - .mapToObj(Card::new) - .collect(Collectors.toList()); - return new Deck(cards); + private Players setupPlayers() { + List playerNames = NameParser.makeNameList(inputView.getParticipant()); + List players = new ArrayList<>(); + for (String name : playerNames) { + String money = inputView.getMoney(name); + players.add(new Player(name, new Money(money))); + } + return new Players(players); } private void initialDraw(Deck deck, Dealer dealer, Players players) { IntStream.range(0, 2).forEach(i -> { dealer.drawCard(deck.draw()); - players.getPlayers().forEach(player -> player.drawCard(deck.draw())); + players.players().forEach(player -> player.drawCard(deck.draw())); }); } private void printInitialStatus(Dealer dealer, Players players) { - ParticipantDto dealerDto = new ParticipantDto(dealer.getName(), getCardNames(dealer)); - List participantDtos = players.getPlayers().stream() - .map(player -> new ParticipantDto(player.getName(), getCardNames(player))) - .collect(Collectors.toList()); - String joinedNames = players.getPlayers().stream() - .map(Player::getName) - .collect(Collectors.joining(", ")); - resultView.printGameStart(new InitialDto(joinedNames, dealerDto, participantDtos)); + ParticipantDto dealerDto = ParticipantDto.from(dealer); + List participants = + players.players() + .stream() + .map(ParticipantDto::from) + .toList(); + String joinedNames = players.getJoinedNames(); + resultView.printGameStart(new InitialDto(joinedNames, dealerDto, participants)); } private void drawPlayerTurn(Deck deck, Player player) { while (player.canDraw() && inputView.getMoreCards(player.getName()).equals("y")) { player.drawCard(deck.draw()); - resultView.printParticipantMoreCard(new ParticipantDto(player.getName(), getCardNames(player))); + resultView.printParticipantMoreCard(ParticipantDto.from(player)); } } @@ -84,39 +95,25 @@ private void drawDealerTurn(Deck deck, Dealer dealer) { } } - private void printFinalWinner(Dealer dealer, Players players) { - Map playerResults = new LinkedHashMap<>(); - List outcomeDtos = new ArrayList<>(); - for (Player player : players.getPlayers()) { - Outcome outcome = Outcome.decideWinner(player.getScore(), dealer.getScore()); - playerResults.put(player, outcome); - outcomeDtos.add(new PlayerOutcomeDto(player.getName(), outcome.getName())); - } - GameResult gameResult = new GameResult(playerResults); - resultView.printWinner(new AllOutcomeDto(gameResult.getDealerResult(), outcomeDtos)); - } - private void printFinalScore(Dealer dealer, Players players) { - ParticipantScoreDto dealerScoreDto = createScoreDto(dealer); - List playerScoreDtos = players.getPlayers().stream() - .map(this::createScoreDto) - .collect(Collectors.toList()); + ParticipantScoreDto dealerScoreDto = ParticipantScoreDto.from(dealer); + List playerScoreDtos = + players.players() + .stream() + .map(ParticipantScoreDto::from) + .toList(); resultView.printResult(new FinalScoreDto(dealerScoreDto, playerScoreDtos)); } - private ParticipantScoreDto createScoreDto(Participant participant) { - return new ParticipantScoreDto( - participant.getName(), - getCardNames(participant), - participant.getScore().getGameScore() - ); - } - - private List getCardNames(Participant participant) { - List cardNames = new ArrayList<>(); - for (Card card : participant.getHand().getCards()) { - cardNames.add(card.getCardName()); + private void printFinalProfit(Dealer dealer, Players players) { + int dealerProfit = 0; + List outcomeDtos = new ArrayList<>(); + for (Player player : players.players()) { + Outcome outcome = Outcome.decideWinner(player, dealer); + Money playerProfit = player.getMoney().multiply(outcome.getRate()); + dealerProfit -= playerProfit.getAmount(); + outcomeDtos.add(PlayerOutcomeDto.of(player, playerProfit)); } - return cardNames; + resultView.printScore(new MoneyDTO(String.valueOf(dealerProfit), outcomeDtos)); } -} \ No newline at end of file +} From fa2598d0fac7ea101f36236ac5f595eb9831b266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:42:24 +0900 Subject: [PATCH 18/30] =?UTF-8?q?refactor(domain):=20Deck=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20record=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => card}/Deck.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) rename src/main/java/domain/{ => card}/Deck.java (84%) diff --git a/src/main/java/domain/Deck.java b/src/main/java/domain/card/Deck.java similarity index 84% rename from src/main/java/domain/Deck.java rename to src/main/java/domain/card/Deck.java index ee6a77ecccc..abdf138320f 100644 --- a/src/main/java/domain/Deck.java +++ b/src/main/java/domain/card/Deck.java @@ -1,11 +1,9 @@ -package domain; +package domain.card; import java.util.Collections; import java.util.List; -public class Deck { - private final List cards; - +public record Deck(List cards) { public Deck(List cards) { this.cards = cards; shuffle(); From 9dd0c9f247c93502cc7a1ee66a5c701dac557bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:42:43 +0900 Subject: [PATCH 19/30] =?UTF-8?q?refactor(domain):=20GameResult=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => result}/GameResult.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename src/main/java/domain/{ => result}/GameResult.java (92%) diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/result/GameResult.java similarity index 92% rename from src/main/java/domain/GameResult.java rename to src/main/java/domain/result/GameResult.java index 86b8ceed259..dd8f62fd6dc 100644 --- a/src/main/java/domain/GameResult.java +++ b/src/main/java/domain/result/GameResult.java @@ -1,5 +1,6 @@ -package domain; +package domain.result; +import domain.participant.Player; import java.util.EnumMap; import java.util.Map; @@ -21,4 +22,4 @@ public Map getDealerResult() { } return dealerResult; } -} \ No newline at end of file +} From e2c573f7d651d860d1b86a44b20e77679acadf05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:43:16 +0900 Subject: [PATCH 20/30] =?UTF-8?q?refactor(view):=20=EB=B2=A0=ED=8C=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EC=9E=85=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/InputView.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 5901c706b6d..5864e5e845b 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -15,4 +15,9 @@ public String getMoreCards(String name) { System.out.println(name + IOMessage.ASK_MORE_CARD.message()); return scanner.nextLine(); } + + public String getMoney(String name) { + System.out.println(name + IOMessage.ASK_MONEY.message()); + return scanner.nextLine(); + } } From 3e9e6c8b705dfe1686f67ac435b642f53881e8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:43:25 +0900 Subject: [PATCH 21/30] =?UTF-8?q?refactor(view):=20=EB=B2=A0=ED=8C=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/ResultView.java | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/view/ResultView.java b/src/main/java/view/ResultView.java index 76cb344e56a..e3c6bf9dd9c 100644 --- a/src/main/java/view/ResultView.java +++ b/src/main/java/view/ResultView.java @@ -1,14 +1,12 @@ package view; -import domain.Outcome; -import dto.AllOutcomeDto; import dto.FinalScoreDto; import dto.InitialDto; +import dto.MoneyDTO; import dto.ParticipantDto; import dto.ParticipantScoreDto; import dto.PlayerOutcomeDto; import java.util.List; -import java.util.Map; import message.IOMessage; public class ResultView { @@ -44,24 +42,21 @@ public void printResult(FinalScoreDto finalScoreDto) { } } - public void printWinner(AllOutcomeDto allOutcomeDto) { + public void printScore(MoneyDTO moneyDTO) { System.out.println(); - System.out.println(IOMessage.WINNING_STATISTICS.message()); - printDealerOutcome(allOutcomeDto.dealerResult()); - printPlayerOutcomes(allOutcomeDto.playerOutcomes()); + System.out.println(IOMessage.FINAL_MONEY_STATISTICS.message()); + printDealerOutcome(moneyDTO.dealerMoney()); + printPlayerOutcomes(moneyDTO.playerOutcomes()); } - private void printDealerOutcome(Map dealerOutcomes) { - System.out.print("딜러: "); - for (Outcome outcome : Outcome.values()) { - System.out.print(dealerOutcomes.get(outcome) + outcome.getName() + " "); - } + private void printDealerOutcome(String dealerOutcomes) { + System.out.print("딜러: " + dealerOutcomes); System.out.println(); } private void printPlayerOutcomes(List playerOutcomes) { for (PlayerOutcomeDto outcomeDto : playerOutcomes) { - System.out.println(outcomeDto.name() + ": " + outcomeDto.outcome()); + System.out.println(outcomeDto.name() + ": " + outcomeDto.profit()); } } } From fa98d95150cb2cc501f0372b7e9d966fefd17c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:44:31 +0900 Subject: [PATCH 22/30] =?UTF-8?q?refactor(util):=20NameParser=EC=9D=98=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=EC=9D=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/util/NameParser.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/util/NameParser.java b/src/main/java/util/NameParser.java index 31707b5ce1a..0701b2b142a 100644 --- a/src/main/java/util/NameParser.java +++ b/src/main/java/util/NameParser.java @@ -1,18 +1,13 @@ package util; -import domain.Player; -import domain.Players; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class NameParser { - public static Players makeNameList(String input) { - List playerList = Arrays.stream(input.split(",")) + public static List makeNameList(String input) { + return Arrays.stream(input.split(",")) .map(String::trim) - .map(Player::new) .collect(Collectors.toList()); - - return new Players(playerList); } } From a4266b0e6e854ef8396493785bb708aa111c5c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:44:51 +0900 Subject: [PATCH 23/30] =?UTF-8?q?refactor(domain):=20Score=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20record=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => result}/Score.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) rename src/main/java/domain/{ => result}/Score.java (66%) diff --git a/src/main/java/domain/Score.java b/src/main/java/domain/result/Score.java similarity index 66% rename from src/main/java/domain/Score.java rename to src/main/java/domain/result/Score.java index 0e629d278be..d4310d0ff41 100644 --- a/src/main/java/domain/Score.java +++ b/src/main/java/domain/result/Score.java @@ -1,14 +1,8 @@ -package domain; +package domain.result; -public final class Score { +public record Score(int score) { private static final int BLACKJACK_SCORE = 21; - private final int score; - - public Score(int score) { - this.score = score; - } - public int getGameScore() { return score; } @@ -20,4 +14,4 @@ public boolean isBust() { public boolean isBlackjack() { return score == BLACKJACK_SCORE; } -} \ No newline at end of file +} From 4ff24ce7a07f75f8e07643c7e65f8ede57704934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:46:13 +0900 Subject: [PATCH 24/30] =?UTF-8?q?test(util):=20NameParser=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/util/NameParserTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/util/NameParserTest.java b/src/test/java/util/NameParserTest.java index 589217713f2..b6d050f3c41 100644 --- a/src/test/java/util/NameParserTest.java +++ b/src/test/java/util/NameParserTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import domain.Players; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -10,16 +10,16 @@ class NameParserTest { @Test @DisplayName("이름 문자열을 쉼표로 분리해 플레이어 수를 만든다") void makePlayersSize() { - Players players = NameParser.makeNameList("pobi,jason"); + List names = NameParser.makeNameList("pobi,jason"); - assertEquals(2, players.getSize()); + assertEquals(2, names.size()); } @Test @DisplayName("쉼표 뒤 공백을 제거해 이름을 저장한다") void trimPlayerName() { - Players players = NameParser.makeNameList("pobi, jason"); + List names = NameParser.makeNameList("pobi, jason"); - assertEquals("jason", players.getPlayer(1).getName()); + assertEquals("jason", names.get(1)); } } From d7945e442685893b95b709cbd05dab16fc18ba86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:46:28 +0900 Subject: [PATCH 25/30] =?UTF-8?q?test(domain):=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20HandTest=20import=20=EA=B2=BD?= =?UTF-8?q?=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/test/java/domain/HandTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/domain/HandTest.java b/src/test/java/domain/HandTest.java index 76601d93716..3cfb7962043 100644 --- a/src/test/java/domain/HandTest.java +++ b/src/test/java/domain/HandTest.java @@ -3,6 +3,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import domain.card.Card; +import domain.participant.Hand; +import domain.result.Score; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -42,4 +45,4 @@ void calculateScoreExact21() { assertEquals(21, hand.calculateScore().getGameScore()); } -} \ No newline at end of file +} From 2e9fd10014b01deef37d6e57a0394b0c3ad16d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:47:33 +0900 Subject: [PATCH 26/30] =?UTF-8?q?test(domain):=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20ScoreTest=20import=20=EA=B2=BD?= =?UTF-8?q?=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/test/java/domain/ScoreTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/domain/ScoreTest.java b/src/test/java/domain/ScoreTest.java index e158a97cab1..1d9b1634386 100644 --- a/src/test/java/domain/ScoreTest.java +++ b/src/test/java/domain/ScoreTest.java @@ -2,6 +2,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import domain.card.Card; +import domain.result.Score; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From fcc7d80f3c454bb76909507d633123591de4e89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Fri, 13 Mar 2026 17:47:47 +0900 Subject: [PATCH 27/30] =?UTF-8?q?test(domain):=20Player=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EC=9E=90=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20Hand=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/PlayerTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java index ebde50d05fb..f80c5afe27d 100644 --- a/src/test/java/domain/PlayerTest.java +++ b/src/test/java/domain/PlayerTest.java @@ -2,6 +2,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import domain.card.Card; +import domain.participant.Dealer; +import domain.participant.Money; +import domain.participant.Player; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -9,9 +13,9 @@ class PlayerTest { @Test @DisplayName("플레이어가 카드를 받으면 핸드의 카드 개수가 증가한다") void drawCardByPlayer() { - Player player = new Player("pobi"); + Player player = new Player("pobi", new Money("0")); player.drawCard(new Card(1)); - assertEquals(1, player.getHand().getCards().size()); + assertEquals(1, player.getHand().cards().size()); } @Test @@ -19,6 +23,6 @@ void drawCardByPlayer() { void drawCardByDealer() { Dealer dealer = new Dealer(); dealer.drawCard(new Card(1)); - assertEquals(1, dealer.getHand().getCards().size()); + assertEquals(1, dealer.getHand().cards().size()); } } \ No newline at end of file From a4ed4b06371ba1e106ebd327ad5e3cbfe9134708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Sun, 15 Mar 2026 22:14:53 +0900 Subject: [PATCH 28/30] =?UTF-8?q?refactor(domain):=20CardSuitMap=EC=97=90?= =?UTF-8?q?=20private=20=EC=83=9D=EC=84=B1=EC=9E=90=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/domain/card/CardSuitMap.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/domain/card/CardSuitMap.java b/src/main/java/domain/card/CardSuitMap.java index a5a7ec5e9cc..00ed1db6d6e 100644 --- a/src/main/java/domain/card/CardSuitMap.java +++ b/src/main/java/domain/card/CardSuitMap.java @@ -26,6 +26,10 @@ public final class CardSuitMap { Map.entry(12, "K") ); + private CardSuitMap() { + + } + public static String getSuit(int shape) { return SUIT_MAP.get(shape); } @@ -34,3 +38,4 @@ public static String getRank(int number) { return RANK_MAP.get(number); } } + From 67adfabb3fbbce235e1a597e8ac7a80feefcfe7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Mon, 16 Mar 2026 11:15:32 +0900 Subject: [PATCH 29/30] =?UTF-8?q?refactor(domain):=20DeckFactory=EC=97=90?= =?UTF-8?q?=20private=20=EC=83=9D=EC=84=B1=EC=9E=90=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/domain/card/DeckFactory.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/domain/card/DeckFactory.java b/src/main/java/domain/card/DeckFactory.java index 1ddd0bdfa66..a97eb49aa6a 100644 --- a/src/main/java/domain/card/DeckFactory.java +++ b/src/main/java/domain/card/DeckFactory.java @@ -5,6 +5,10 @@ import java.util.stream.IntStream; public class DeckFactory { + + private DeckFactory() { + } + public static Deck create() { List cards = IntStream.range(0, 52) .mapToObj(Card::new) From c524a393dc561eb826536dc34795f719f8f2223d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B0=80=ED=98=84?= Date: Mon, 16 Mar 2026 11:16:29 +0900 Subject: [PATCH 30/30] =?UTF-8?q?docs:=20README.md=20=EC=88=98=EC=9D=B5=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=20=EB=B0=8F=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=83=81=EC=84=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c99e2c8de16..983ed1cf35c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ### 기능 요구사항 체크리스트 - [x] 게임에 참여할 사람의 이름을 쉼표(,) 기준으로 입력받아 분리한다. +- [x] 사용자로부터 베팅 금액을 입력받는다. - [x] 0부터 51 사이의 난수를 생성해 무늬와 숫자가 매핑된 중복 없는 카드를 발급한다. - [x] 게임 시작 시 딜러와 플레이어에게 각각 2장씩 카드를 분배한다. - [x] 딜러의 초기 카드는 1장만 보여주고, 플레이어는 보유한 모든 카드를 보여준다. @@ -12,23 +13,37 @@ - [x] 카드의 합을 계산할 때 K, Q, J는 10으로 계산하고, A는 11로 계산하고 21을 초과하면 1로 계산한다. - [x] 딜러는 처음에 받은 2장의 합계가 16 이하이면 무조건 1장의 카드를 추가로 받고, 17 이상이면 받지 않는다. - [x] 딜러와 플레이어의 턴이 모두 끝나면 각자의 최종 카드 목록과 점수를 출력한다. -- [x] 최종 점수를 비교해 딜러와 각 플레이어의 승/패/무 결과를 계산하고 출력한다. +- [x] 최종 점수와 딜러와 각 플레이어의 버스트/블랙잭/승패 결과를 통해 최종 수익을 계산해 출력한다. ### 주요 로직 요약 - **카드 생성** - - `Card`에서 `0~51` 범위의 난수를 뽑아 카드 번호를 만든다. + - `DeckFactory`에서 `0~51` 범위의 카드를 생성해 'Deck' 에서 shuffle 로 카드를 무작위로 섞는다. - **카드 이름/점수 매핑** - 카드 번호를 `shape(무늬)`와 `number(랭크)`로 분리해 문자열 카드명으로 변환한다. - 점수는 `A=11`, `2~10=숫자값`, `J/Q/K=10`으로 계산한다. - **중복 없는 카드 보장** - - `DuplicationSet`에 이미 나온 번호를 저장해, 중복 번호가 나오면 다시 뽑는다. + - `Deck`에서 카드를 뽑을 때마다 List의 첫 번째 요소를 제거하며 반환 - **버스트와 A 점수 보정** - 플레이어 점수가 21을 초과하면, 보유한 A 개수만큼 `11 -> 1` 보정(10점 차감)을 적용한다. - **게임 진행** - 시작 시 딜러/플레이어 모두 2장 배분 - 플레이어는 입력(`y/n`)으로 추가 카드 선택 - 딜러는 합계가 16 이하일 때 자동으로 추가 카드 드로우 -- **승패 계산** - - 버스트는 `-1` 처리 후 딜러와 각 플레이어 점수를 비교해 `승/패/무`를 기록한다. - \ No newline at end of file +- **수익 계산** + - 플레이어의 카드가 21을 초과할 경우 베팅 금액을 모두 잃게 된다 + - 처음 두 장의 카드 합이 21일 경우 블랙잭이 되면 베팅 금액의 1.5 배를 딜러에게 받는다. + - 딜러와 플레이어 모두 블랙잭인 경우 베팅 금액을 돌려받는다. + - 딜러가 21을 초과하면 남아 있던 플레이어들은 패에 상관 없이 베팅 금액을 받는다. + +### 최종 수익 계산 + +| 상황 | 결과 | 수익 배율 | 비고 | +|:-----------------------------|:----|:-----:|:------------------| +| **플레이어 버스트(Bust)** | 패배 | -1.0 | 베팅 금액 상실 | +| **플레이어 블랙잭 & 딜러 블랙잭 아님** | 승리 | +1.5 | 베팅 금액의 1.5배 수익 발생 | +| **플레이어 & 딜러 모두 블랙잭** | 무승부 | 0 | 베팅 금액 돌려받음 | +| **플레이어 21 이하 & 딜러 버스트** | 승리 | +1.0 | 베팅 금액만큼 수익 발생 | +| **둘 다 21 이하 (플레이어 점수 > 딜러)** | 승리 | +1.0 | 베팅 금액만큼 수익 발생 | +| **둘 다 21 이하 (플레이어 점수 < 딜러)** | 패배 | -1.0 | 베팅 금액 상실 | +| **둘 다 21 이하 (플레이어 점수 = 딜러)** | 무승부 | 0 | 베팅 금액 돌려받음 |