From 4ac5d7ef076284d93af0924b130b9d0ca11ef09c Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sat, 14 Mar 2026 17:31:17 +0900 Subject: [PATCH 01/23] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=97=AC=ED=8D=BC=20=EB=8F=84=EC=9E=85=20=EB=B0=8F=20=EB=8F=85?= =?UTF-8?q?=EB=A6=BD=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dealerWith, handWith, card 헬퍼 메서드 추가 - BeforeEach 제거, 각 테스트가 독립적으로 상태 생성 - Hand isBust, cardNames 테스트 추가 - Players 검증 및 forEach 테스트 추가 - 테스트 이름과 검증 내용 불일치 수정 --- .../domain/{ => vo}/MatchResult.java | 0 .../java/blackjack/domain/DealerTest.java | 74 +++++-------- src/test/java/blackjack/domain/DeckTest.java | 72 +++++-------- src/test/java/blackjack/domain/HandTest.java | 86 +++++++++++---- .../blackjack/domain/MatchResultTest.java | 38 +++---- src/test/java/blackjack/domain/NameTest.java | 7 ++ .../java/blackjack/domain/PlayerTest.java | 102 ++++-------------- .../java/blackjack/domain/PlayersTest.java | 68 +++++------- 8 files changed, 187 insertions(+), 260 deletions(-) rename src/main/java/blackjack/domain/{ => vo}/MatchResult.java (100%) diff --git a/src/main/java/blackjack/domain/MatchResult.java b/src/main/java/blackjack/domain/vo/MatchResult.java similarity index 100% rename from src/main/java/blackjack/domain/MatchResult.java rename to src/main/java/blackjack/domain/vo/MatchResult.java diff --git a/src/test/java/blackjack/domain/DealerTest.java b/src/test/java/blackjack/domain/DealerTest.java index d65f6bd39e1..9893332beca 100644 --- a/src/test/java/blackjack/domain/DealerTest.java +++ b/src/test/java/blackjack/domain/DealerTest.java @@ -2,82 +2,58 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class DealerTest { - private Dealer dealer; + private Dealer dealerWith(TrumpCard... cards) { + Dealer dealer = Dealer.of(); + for (TrumpCard card : cards) { + dealer.hit(card); + } + return dealer; + } - @BeforeEach - void setUp() { - dealer = Dealer.of(); + private TrumpCard card(Suit suit, Rank rank) { + return TrumpCard.of(suit, rank); } @Test void 딜러를_생성한다() { + Dealer dealer = Dealer.of(); assertThat(dealer).isNotNull(); } @Test void 딜러가_카드_1장을_받는다() { - TrumpCard spadeAce = TrumpCard.of(Suit.SPADE, Rank.ACE); - dealer.receive(spadeAce); - assertThat(dealer.getCards()).hasSize(1); - } - - @Test - void 딜러가_여러_카드를_받는다() { - List cards = new ArrayList<>(); - cards.add(TrumpCard.of(Suit.SPADE, Rank.ACE)); - cards.add(TrumpCard.of(Suit.HEART, Rank.KING)); - - dealer.receiveCards(cards); - assertThat(dealer.getCards()).hasSize(2); + Dealer dealer = Dealer.of(); + dealer.hit(TrumpCard.of(Suit.SPADE, Rank.ACE)); + assertThat(dealer.countCards()).isEqualTo(1); } @Test void 딜러의_현재_점수를_계산한다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartFive = TrumpCard.of(Suit.HEART, Rank.FIVE); - - dealer.receive(spadeKing); - dealer.receive(heartFive); - + Dealer dealer = dealerWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.FIVE) + ); assertThat(dealer.score()).isEqualTo(15); } @Test void 딜러는_16이하면_카드를_더_받아야한다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartFive = TrumpCard.of(Suit.HEART, Rank.FIVE); - - dealer.receive(spadeKing); - dealer.receive(heartFive); - + Dealer dealer = dealerWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.FIVE) + ); assertThat(dealer.shouldHit()).isTrue(); } @Test void 딜러는_17이상이면_카드를_받지_않는다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartSeven = TrumpCard.of(Suit.HEART, Rank.SEVEN); - - dealer.receive(spadeKing); - dealer.receive(heartSeven); - + Dealer dealer = dealerWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.SEVEN) + ); assertThat(dealer.shouldHit()).isFalse(); } - - @Test - void 딜러의_첫_번째_카드를_조회한다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartFive = TrumpCard.of(Suit.HEART, Rank.FIVE); - - dealer.receive(spadeKing); - dealer.receive(heartFive); - - assertThat(dealer.getOpenCard()).isEqualTo(spadeKing); - } } diff --git a/src/test/java/blackjack/domain/DeckTest.java b/src/test/java/blackjack/domain/DeckTest.java index 1d3f028d7d1..07c174cab35 100644 --- a/src/test/java/blackjack/domain/DeckTest.java +++ b/src/test/java/blackjack/domain/DeckTest.java @@ -9,15 +9,26 @@ import org.junit.jupiter.api.Test; class DeckTest { + private Deck emptyDeck(){ + Deck deck = Deck.of(new ArrayList<>(TrumpCard.CARDS)); + for (int i = 0; i < 52; i++) { + deck.deal(); + } + return deck; + } @Test - void 전체_카드_수가_52장이_아니면_예외_발생한다() { + void 전체_카드_수가_52장보다_적으면_예외_발생한다() { List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } + cards.add(TrumpCard.of(Suit.SPADE, Rank.ACE)); + assertThatThrownBy(() -> Deck.of(cards)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("전체 카드 수는 52장이어야 합니다."); + } + + @Test + void 전체_카드_수가_52장보다_많으면_예외_발생한다() { + List cards = new ArrayList<>(TrumpCard.CARDS); cards.add(TrumpCard.of(Suit.SPADE, Rank.ACE)); assertThatThrownBy(() -> Deck.of(cards)) @@ -27,12 +38,7 @@ class DeckTest { @Test void 중복된_카드가_존재하면_예외_발생한다() { - List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } + List cards = new ArrayList<>(TrumpCard.CARDS); cards.removeFirst(); cards.add(TrumpCard.of(Suit.CLOVER, Rank.KING)); @@ -43,54 +49,26 @@ class DeckTest { @Test void 카드를_지급할_때_카드가_없으면_예외_발생한다() { - List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } - Deck deck = Deck.of(cards); - for (int i = 0; i < 52; i++) { - deck.draw(); - } + Deck deck = emptyDeck(); - assertThatThrownBy(deck::draw) + assertThatThrownBy(deck::deal) .isInstanceOf(IllegalArgumentException.class) .hasMessage("덱에 카드가 없습니다."); } @Test void 카드를_지급하면_전체_카드_수가_줄어든다() { - List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } - Deck deck = Deck.of(cards); - TrumpCard draw = deck.draw(); + Deck deck = Deck.of(new ArrayList<>(TrumpCard.CARDS)); + + deck.deal(); - assertThat(draw).isNotNull(); + assertThat(deck.countCards()).isNotNull(); } @Test void 게임을_시작하면_카드를_셔플한다() { Deck deck = Deck.create(Collections::reverse); - TrumpCard first = deck.draw(); + TrumpCard first = deck.deal(); assertThat(first).isEqualTo(TrumpCard.of(Suit.CLOVER, Rank.KING)); } - - @Test - void 카드_2장을_한번에_지급한다() { - List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } - Deck deck = Deck.of(cards); - List drawnCards = deck.drawSecondTimes(); - - assertThat(drawnCards).hasSize(2); - } } \ No newline at end of file diff --git a/src/test/java/blackjack/domain/HandTest.java b/src/test/java/blackjack/domain/HandTest.java index 95b3241db62..ccb6d8ba7c8 100644 --- a/src/test/java/blackjack/domain/HandTest.java +++ b/src/test/java/blackjack/domain/HandTest.java @@ -5,6 +5,17 @@ import org.junit.jupiter.api.Test; class HandTest { + private Hand handWith(TrumpCard... cards) { + Hand hand = Hand.init(); + for (TrumpCard card : cards) { + hand.add(card); + } + return hand; + } + + private TrumpCard card(Suit suit, Rank rank) { + return TrumpCard.of(suit, rank); + } @Test void 첫_카드는_비어있다() { @@ -16,34 +27,57 @@ class HandTest { void 카드를_받으면_카드가_늘어난다() { Hand hand = Hand.init(); TrumpCard newCard = TrumpCard.of(Suit.SPADE, Rank.ACE); - hand.receive(newCard); + + hand.add(newCard); + assertThat(hand.countCards()).isEqualTo(1); } @Test void 현재까지_확보한_카드_총_점수를_계산한다() { - Hand hand = Hand.init(); - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartFive = TrumpCard.of(Suit.HEART, Rank.FIVE); - - hand.receive(spadeKing); - hand.receive(heartFive); + Hand hand = handWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.FIVE) + ); int score = hand.calculateScore(); assertThat(score).isEqualTo(15); } + @Test + void 카드_총합이_21을_이하면_에이스는_11로_계산된다(){ + Hand hand = handWith( + card(Suit.HEART, Rank.ACE), + card(Suit.SPADE, Rank.NINE) + ); + + int score = hand.calculateScore(); + + assertThat(score).isEqualTo(20); + } @Test - void 카드_총합이_21을_넘으면_에이스_값이_1로_변환된다() { - Hand hand = Hand.init(); - TrumpCard heartAce = TrumpCard.of(Suit.HEART, Rank.ACE); - TrumpCard diamondNine = TrumpCard.of(Suit.DIAMOND, Rank.NINE); + void 카드_총합이_21을_넘으면_에이스_값이_1로_변환되어_계산된다() { + Hand hand = handWith( + card(Suit.HEART, Rank.ACE), + card(Suit.SPADE, Rank.KING), + card(Suit.DIAMOND, Rank.NINE) + ); - hand.receive(heartAce); - hand.receive(heartAce); - hand.receive(diamondNine); + int score = hand.calculateScore(); + + assertThat(score).isEqualTo(20); + } + + @Test + void 카드_총합이_21을_넘으면_에이스_값이_여러_개라도_각각의_에이스가_1로_변환되어_계산된다() { + Hand hand = handWith( + card(Suit.HEART, Rank.ACE), + card(Suit.SPADE, Rank.ACE), + card(Suit.DIAMOND, Rank.NINE), + card(Suit.DIAMOND, Rank.KING) + ); int score = hand.calculateScore(); @@ -51,15 +85,23 @@ class HandTest { } @Test - void 현재_보유한_카드_목록을_반환한다() { - Hand hand = Hand.init(); - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartFive = TrumpCard.of(Suit.HEART, Rank.FIVE); + void 카드_총합이_21_이하면_버스트가_아니다(){ + Hand hand = handWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.FIVE) + ); - hand.receive(spadeKing); - hand.receive(heartFive); + assertThat(hand.isBust()).isFalse(); + } - assertThat(hand.getCards()).hasSize(2); - assertThat(hand.getCards()).containsExactly(spadeKing, heartFive); + @Test + void 카드_총합이_21을_초과하면_버스트이다(){ + Hand hand = handWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.KING), + card(Suit.HEART, Rank.THREE) + ); + + assertThat(hand.isBust()).isTrue(); } } \ No newline at end of file diff --git a/src/test/java/blackjack/domain/MatchResultTest.java b/src/test/java/blackjack/domain/MatchResultTest.java index 0f1e7491481..3f4f6444c05 100644 --- a/src/test/java/blackjack/domain/MatchResultTest.java +++ b/src/test/java/blackjack/domain/MatchResultTest.java @@ -1,22 +1,22 @@ package blackjack.domain; +import blackjack.domain.vo.MatchResult; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; class MatchResultTest { @Test void 플레이어가_버스트라면_진다(){ Player player = Player.of(Name.of("pobi")); - player.receiveCard(TrumpCard.of(Suit.SPADE, Rank.TEN)); - player.receiveCard(TrumpCard.of(Suit.HEART, Rank.TEN)); - player.receiveCard(TrumpCard.of(Suit.DIAMOND, Rank.FIVE)); + player.hit(TrumpCard.of(Suit.SPADE, Rank.TEN)); + player.hit(TrumpCard.of(Suit.HEART, Rank.TEN)); + player.hit(TrumpCard.of(Suit.DIAMOND, Rank.FIVE)); Dealer dealer = Dealer.of(); - dealer.receive(TrumpCard.of(Suit.CLOVER, Rank.TEN)); - dealer.receive(TrumpCard.of(Suit.SPADE, Rank.SEVEN)); + dealer.hit(TrumpCard.of(Suit.CLOVER, Rank.TEN)); + dealer.hit(TrumpCard.of(Suit.SPADE, Rank.SEVEN)); assertThat(MatchResult.playerResult(player, dealer)).isEqualTo(MatchResult.LOSE); } @@ -24,13 +24,13 @@ class MatchResultTest { @Test void 플레이어가_버스트가_아니고_딜러가_버스트면_이긴다(){ Player player = Player.of(Name.of("pobi")); - player.receiveCard(TrumpCard.of(Suit.SPADE, Rank.TEN)); - player.receiveCard(TrumpCard.of(Suit.HEART, Rank.SEVEN)); + player.hit(TrumpCard.of(Suit.SPADE, Rank.TEN)); + player.hit(TrumpCard.of(Suit.HEART, Rank.SEVEN)); Dealer dealer = Dealer.of(); - dealer.receive(TrumpCard.of(Suit.CLOVER, Rank.TEN)); - dealer.receive(TrumpCard.of(Suit.DIAMOND, Rank.TEN)); - dealer.receive(TrumpCard.of(Suit.SPADE, Rank.FIVE)); + dealer.hit(TrumpCard.of(Suit.CLOVER, Rank.TEN)); + dealer.hit(TrumpCard.of(Suit.DIAMOND, Rank.TEN)); + dealer.hit(TrumpCard.of(Suit.SPADE, Rank.FIVE)); assertThat(MatchResult.playerResult(player, dealer)).isEqualTo(MatchResult.WIN); } @@ -38,12 +38,12 @@ class MatchResultTest { @Test void 둘_다_버스트가_아니면_더_큰_쪽이_이긴다(){ Player player = Player.of(Name.of("pobi")); - player.receiveCard(TrumpCard.of(Suit.SPADE, Rank.TEN)); - player.receiveCard(TrumpCard.of(Suit.HEART, Rank.TEN)); + player.hit(TrumpCard.of(Suit.SPADE, Rank.TEN)); + player.hit(TrumpCard.of(Suit.HEART, Rank.TEN)); Dealer dealer = Dealer.of(); - dealer.receive(TrumpCard.of(Suit.CLOVER, Rank.TEN)); - dealer.receive(TrumpCard.of(Suit.SPADE, Rank.SEVEN)); + dealer.hit(TrumpCard.of(Suit.CLOVER, Rank.TEN)); + dealer.hit(TrumpCard.of(Suit.SPADE, Rank.SEVEN)); assertThat(MatchResult.playerResult(player, dealer)).isEqualTo(MatchResult.WIN); } @@ -51,12 +51,12 @@ class MatchResultTest { @Test void 점수가_같으면_무승부() { Player player = Player.of(Name.of("pobi")); - player.receiveCard(TrumpCard.of(Suit.SPADE, Rank.TEN)); - player.receiveCard(TrumpCard.of(Suit.HEART, Rank.SEVEN)); + player.hit(TrumpCard.of(Suit.SPADE, Rank.TEN)); + player.hit(TrumpCard.of(Suit.HEART, Rank.SEVEN)); Dealer dealer = Dealer.of(); - dealer.receive(TrumpCard.of(Suit.CLOVER, Rank.TEN)); - dealer.receive(TrumpCard.of(Suit.DIAMOND, Rank.SEVEN)); + dealer.hit(TrumpCard.of(Suit.CLOVER, Rank.TEN)); + dealer.hit(TrumpCard.of(Suit.DIAMOND, Rank.SEVEN)); assertThat(MatchResult.playerResult(player, dealer)).isEqualTo(MatchResult.DRAW); } diff --git a/src/test/java/blackjack/domain/NameTest.java b/src/test/java/blackjack/domain/NameTest.java index 3f9725ca2aa..49b2baf59bb 100644 --- a/src/test/java/blackjack/domain/NameTest.java +++ b/src/test/java/blackjack/domain/NameTest.java @@ -16,6 +16,13 @@ class NameTest { .hasMessage("이름의 길이는 10이 넘을 수 없습니다."); } + @Test + void 이름의_길이가_10개이면_정상_생성된다(){ + String name = "일이삼사오육칠팔구십"; + Name playerName = Name.of(name); + assertThat(playerName).isNotNull(); + } + @Test void 이름이_비어있으면_예외_처리한다() { String name = ""; diff --git a/src/test/java/blackjack/domain/PlayerTest.java b/src/test/java/blackjack/domain/PlayerTest.java index 81018b07252..7a1beabc0b0 100644 --- a/src/test/java/blackjack/domain/PlayerTest.java +++ b/src/test/java/blackjack/domain/PlayerTest.java @@ -2,104 +2,42 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class PlayerTest { - private Player player; - - @BeforeEach - void setUp() { - Name newPlayerName = Name.of("한다"); - player = Player.of(newPlayerName); + private Player playerWith(TrumpCard... cards) { + Player player = Player.of(Name.of("한다")); + for (TrumpCard card : cards) { + player.hit(card); + } + return player; } - @Test - void 플레이어를_생성한다() { - assertThat(player).isNotNull(); + private TrumpCard card(Suit suit, Rank rank) { + return TrumpCard.of(suit, rank); } @Test - void 플레이어의_이름을_반환한다() { + void 플레이어는_이름을_가진다(){ + Player player = Player.of(Name.of("한다")); assertThat(player.name()).isEqualTo("한다"); } - - @Test - void 플레이어는_초기에_비어있는_핸드를_가진다() { - assertThat(player.countCards()).isEqualTo(0); - } - - @Test - void 플레이어가_카드1장_받는다() { - TrumpCard spaceAce = TrumpCard.of(Suit.SPADE, Rank.ACE); - player.receiveCard(spaceAce); - assertThat(player.countCards()).isEqualTo(1); - } - - @Test - void 플레이어가_여러_카드를_받는다() { - TrumpCard spaceAce = TrumpCard.of(Suit.SPADE, Rank.ACE); - TrumpCard heartKing = TrumpCard.of(Suit.HEART, Rank.KING); - - player.receiveCard(spaceAce); - player.receiveCard(heartKing); - assertThat(player.countCards()).isEqualTo(2); - } - - @Test - void 플레이어의_현재_점수를_계산한다() { - TrumpCard spaceAce = TrumpCard.of(Suit.SPADE, Rank.ACE); - TrumpCard heartKing = TrumpCard.of(Suit.HEART, Rank.KING); - - player.receiveCard(spaceAce); - player.receiveCard(heartKing); - - assertThat(player.score()).isEqualTo(21); - } - - @Test - void 플레이어가_여러_카드를_한번에_받는다() { - List cards = new ArrayList<>(); - cards.add(TrumpCard.of(Suit.SPADE, Rank.ACE)); - cards.add(TrumpCard.of(Suit.HEART, Rank.KING)); - - player.receiveCards(cards); - assertThat(player.countCards()).isEqualTo(2); - } - @Test - void 플레이어가_21이하면_카드를_더_받을_수_있다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - player.receiveCard(spadeKing); - + void 버스트가_아니면_카드를_더_받을_수_있다() { + Player player = playerWith( + card(Suit.SPADE, Rank.KING) + ); assertThat(player.canHit()).isTrue(); } @Test - void 플레이어가_21을_초과하면_카드를_받을_수_없다() { - TrumpCard spadeKing = TrumpCard.of(Suit.SPADE, Rank.KING); - TrumpCard heartQueen = TrumpCard.of(Suit.HEART, Rank.QUEEN); - TrumpCard diamondFive = TrumpCard.of(Suit.DIAMOND, Rank.FIVE); - - player.receiveCard(spadeKing); - player.receiveCard(heartQueen); - player.receiveCard(diamondFive); - + void 버스트이면_카드를_받을_수_없다() { + Player player = playerWith( + card(Suit.SPADE, Rank.KING), + card(Suit.HEART, Rank.QUEEN), + card(Suit.DIAMOND, Rank.FIVE) + ); assertThat(player.canHit()).isFalse(); } - - @Test - void 플레이어의_보유_카드_목록을_반환한다() { - TrumpCard spadeAce = TrumpCard.of(Suit.SPADE, Rank.ACE); - TrumpCard heartKing = TrumpCard.of(Suit.HEART, Rank.KING); - - player.receiveCard(spadeAce); - player.receiveCard(heartKing); - - assertThat(player.getCards()).hasSize(2); - assertThat(player.getCards()).containsExactly(spadeAce, heartKing); - } } diff --git a/src/test/java/blackjack/domain/PlayersTest.java b/src/test/java/blackjack/domain/PlayersTest.java index 6ad9d6b80a2..15ba6275873 100644 --- a/src/test/java/blackjack/domain/PlayersTest.java +++ b/src/test/java/blackjack/domain/PlayersTest.java @@ -4,60 +4,46 @@ import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.BeforeEach; + +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; public class PlayersTest { - private List playerList; - private Deck deck; - - @BeforeEach - void setUp() { - playerList = new ArrayList<>(); - playerList.add(Player.of(Name.of("handa"))); - playerList.add(Player.of(Name.of("dalsu"))); - - List cards = new ArrayList<>(); - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - cards.add(TrumpCard.of(suit, rank)); - } - } - deck = Deck.of(cards); + private Player player(String name){ + return Player.of(Name.of(name)); } @Test - void 게임에_참가한_플레이어의_명수를_반환한다() { - Players players = Players.of(playerList); - assertThat(players.count()).isEqualTo(2); + void 플레이어_목록이_비어있으면_예외_발생한다(){ + Assertions.assertThatThrownBy(() -> Players.of(List.of())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어는 1명 이상이어야 합니다."); } @Test - void 게임이_시작되면_모든_플레이어가_카드를_받는다() { - Players players = Players.of(playerList); - players.receiveCards(deck); - - List result = players.getPlayers(); - assertThat(result.get(0).countCards()).isEqualTo(2); - assertThat(result.get(1).countCards()).isEqualTo(2); + void 플레이어_목록이_null이면_예외_발생한다(){ + Assertions.assertThatThrownBy(() -> Players.of(null)) + .isInstanceOf(NullPointerException.class) + .hasMessage("플레이어 목록은 null일 수 없습니다."); } - @Test - void 특정_플레이어가_카드를_추가로_받는다() { - Players players = Players.of(playerList); - players.receiveCards(deck); - - TrumpCard newCard = deck.draw(); - players.hitPlayer(0, newCard); - - List result = players.getPlayers(); - assertThat(result.get(0).countCards()).isEqualTo(3); - assertThat(result.get(1).countCards()).isEqualTo(2); + void 게임에_참가한_플레이어의_명수를_반환한다() { + Players players = Players.of(List.of( + player("handa"), + player("dalsu") + )); + assertThat(players.count()).isEqualTo(2); } @Test - void 특정_플레이어가_카드를_더_받을_수_있는지_확인한다() { - Players players = Players.of(playerList); - assertThat(players.canHit(0)).isTrue(); + void 모든_플레이어에_대해_작업을_수행한다() { + Players players = Players.of(List.of( + player("handa"), + player("dalsu") + )); + List names = new ArrayList<>(); + players.forEach(p -> names.add(p.name())); + + assertThat(names).containsExactly("handa", "dalsu"); } } From 0892bb1fcbc0ec7b609c5a281701e80e356335b2 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sat, 14 Mar 2026 17:33:59 +0900 Subject: [PATCH 02/23] =?UTF-8?q?refactor:=20=EB=8F=84=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BA=A1=EC=8A=90=ED=99=94=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 도메인 용어 통일: pop→deal, draw→add, receive→hit - Deck deal(int count) 제거, 단일 deal()만 유지 - Hand에 isBust, cardNames 위임하여 책임 강화 - Player getCards() 제거로 내부 노출 방지 - Players 인덱스 기반 메서드 제거, forEach만 유지 --- src/main/java/blackjack/domain/Dealer.java | 18 +++++-------- src/main/java/blackjack/domain/Deck.java | 21 +++++---------- src/main/java/blackjack/domain/Hand.java | 18 ++++++++++--- src/main/java/blackjack/domain/Player.java | 26 ++++++------------ src/main/java/blackjack/domain/Players.java | 27 ++++--------------- src/main/java/blackjack/domain/TrumpCard.java | 7 +++++ 6 files changed, 47 insertions(+), 70 deletions(-) diff --git a/src/main/java/blackjack/domain/Dealer.java b/src/main/java/blackjack/domain/Dealer.java index 5a7bd327fdf..788f1a16b52 100644 --- a/src/main/java/blackjack/domain/Dealer.java +++ b/src/main/java/blackjack/domain/Dealer.java @@ -21,14 +21,8 @@ public static Dealer of() { return new Dealer(Hand.init()); } - public void receiveCards(List cards) { - for (TrumpCard card : cards) { - hand.receive(card); - } - } - - public void receive(TrumpCard card) { - hand.receive(card); + public void hit(TrumpCard card) { + hand.add(card); } public int score() { @@ -43,11 +37,11 @@ public boolean shouldHit() { return score() <= DEALER_HIT_THRESHOLD; } - public TrumpCard getOpenCard() { - return hand.getCards().getFirst(); - } - public boolean isBust() { return score() > 21; } + + public int countCards() { + return hand.countCards(); + } } diff --git a/src/main/java/blackjack/domain/Deck.java b/src/main/java/blackjack/domain/Deck.java index 316df52ca8c..b1b3c98e6a5 100644 --- a/src/main/java/blackjack/domain/Deck.java +++ b/src/main/java/blackjack/domain/Deck.java @@ -1,10 +1,8 @@ package blackjack.domain; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; public class Deck { private static final int CARDS_COUNT = 52; @@ -21,10 +19,7 @@ public static Deck of(List cards) { } public static Deck create(ShuffleStrategy strategy) { - List cards = Arrays.stream(Suit.values()) - .flatMap(suit -> Arrays.stream(Rank.values()) - .map(rank -> TrumpCard.of(suit, rank))) - .collect(Collectors.toList()); + List cards = new ArrayList<>(TrumpCard.CARDS); strategy.shuffle(cards); return new Deck(cards); } @@ -51,18 +46,14 @@ private void validateDuplicates(List cards) { } } - public List drawSecondTimes() { - List cards = new ArrayList<>(); - - cards.add(draw()); - cards.add(draw()); - return cards; - } - - public TrumpCard draw() { + public TrumpCard deal() { if (cards.isEmpty()) { throw new IllegalArgumentException("덱에 카드가 없습니다."); } return cards.removeFirst(); } + + public int countCards() { + return cards.size(); + } } diff --git a/src/main/java/blackjack/domain/Hand.java b/src/main/java/blackjack/domain/Hand.java index 2b531026aa8..50307630139 100644 --- a/src/main/java/blackjack/domain/Hand.java +++ b/src/main/java/blackjack/domain/Hand.java @@ -17,12 +17,13 @@ public static Hand init() { return new Hand(); } - public void receive(TrumpCard card) { + public void add(TrumpCard card) { cards.add(card); } - public int countCards() { - return cards.size(); + + public boolean isBust() { + return calculateScore() > BLACKJACK_THRESHOLD; } public int calculateScore() { @@ -51,6 +52,17 @@ private int countAces() { .count(); } + public List cardNames() { + return cards.stream() + .map(TrumpCard::koreanName) + .toList(); + } + + public int countCards() { + return cards.size(); + } + + public List getCards() { return List.copyOf(cards); } diff --git a/src/main/java/blackjack/domain/Player.java b/src/main/java/blackjack/domain/Player.java index ea91099dc7a..45584a56fcb 100644 --- a/src/main/java/blackjack/domain/Player.java +++ b/src/main/java/blackjack/domain/Player.java @@ -22,18 +22,16 @@ public static Player of(Name name) { return new Player(name, Hand.init()); } - public void receiveCards(List cards) { - for (TrumpCard card : cards) { - hand.receive(card); - } + public void hit(TrumpCard card) { + hand.add(card); } - public void receiveCard(TrumpCard card) { - hand.receive(card); + public boolean canHit() { + return !isBust(); } - public int countCards() { - return hand.countCards(); + public boolean isBust() { + return hand.isBust(); } public int score() { @@ -44,15 +42,7 @@ public String name() { return name.getName(); } - public boolean canHit() { - return score() <= 21; - } - - public boolean isBust() { - return score() > 21; - } - - public List getCards() { - return hand.getCards(); + public List cardNames() { + return hand.cardNames(); } } diff --git a/src/main/java/blackjack/domain/Players.java b/src/main/java/blackjack/domain/Players.java index af486c65118..ccca685359b 100644 --- a/src/main/java/blackjack/domain/Players.java +++ b/src/main/java/blackjack/domain/Players.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Objects; +import java.util.function.Consumer; public class Players { private final List players; @@ -22,29 +23,11 @@ public static Players of(List players) { return new Players(players); } - public void receiveCards(Deck deck) { - for (Player player : players) { - player.receiveCards(deck.drawSecondTimes()); - } - } + public void forEach(Consumer action){ + players.forEach(action); + } public int count() { - return this.players.size(); - } - - public boolean canHit(int playerIndex) { - return this.players.get(playerIndex).canHit(); - } - - public List getPlayers() { - return players; - } - - public void hitPlayer(int index, TrumpCard card) { - players.get(index).receiveCard(card); - } - - public Player playerAt(int index) { - return players.get(index); + return players.size(); } } diff --git a/src/main/java/blackjack/domain/TrumpCard.java b/src/main/java/blackjack/domain/TrumpCard.java index cdd99bcb350..2dae5729918 100644 --- a/src/main/java/blackjack/domain/TrumpCard.java +++ b/src/main/java/blackjack/domain/TrumpCard.java @@ -1,8 +1,15 @@ package blackjack.domain; +import java.util.Arrays; +import java.util.List; import java.util.Objects; public class TrumpCard { + public static final List CARDS = Arrays.stream(Suit.values()) + .flatMap(suit -> Arrays.stream(Rank.values()) + .map(rank -> TrumpCard.of(suit, rank))) + .toList(); + private final Suit suit; private final Rank rank; From dd583b791eaff095807212e8cd2f47cb9f239147 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sat, 14 Mar 2026 20:20:30 +0900 Subject: [PATCH 03/23] =?UTF-8?q?test:=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=20=EB=AA=85=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=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/blackjack/domain/DealerTest.java | 4 ++-- src/test/java/blackjack/domain/PlayerTest.java | 2 +- src/test/java/blackjack/domain/PlayersTest.java | 2 +- src/test/java/blackjack/domain/TrumpCardTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/blackjack/domain/DealerTest.java b/src/test/java/blackjack/domain/DealerTest.java index 9893332beca..8d2c188083e 100644 --- a/src/test/java/blackjack/domain/DealerTest.java +++ b/src/test/java/blackjack/domain/DealerTest.java @@ -45,7 +45,7 @@ private TrumpCard card(Suit suit, Rank rank) { card(Suit.SPADE, Rank.KING), card(Suit.HEART, Rank.FIVE) ); - assertThat(dealer.shouldHit()).isTrue(); + assertThat(dealer.canHit()).isTrue(); } @Test @@ -54,6 +54,6 @@ private TrumpCard card(Suit suit, Rank rank) { card(Suit.SPADE, Rank.KING), card(Suit.HEART, Rank.SEVEN) ); - assertThat(dealer.shouldHit()).isFalse(); + assertThat(dealer.canHit()).isFalse(); } } diff --git a/src/test/java/blackjack/domain/PlayerTest.java b/src/test/java/blackjack/domain/PlayerTest.java index 7a1beabc0b0..23638fac7f4 100644 --- a/src/test/java/blackjack/domain/PlayerTest.java +++ b/src/test/java/blackjack/domain/PlayerTest.java @@ -20,7 +20,7 @@ private TrumpCard card(Suit suit, Rank rank) { @Test void 플레이어는_이름을_가진다(){ Player player = Player.of(Name.of("한다")); - assertThat(player.name()).isEqualTo("한다"); + assertThat(player.getName()).isEqualTo("한다"); } @Test diff --git a/src/test/java/blackjack/domain/PlayersTest.java b/src/test/java/blackjack/domain/PlayersTest.java index 15ba6275873..0703df19847 100644 --- a/src/test/java/blackjack/domain/PlayersTest.java +++ b/src/test/java/blackjack/domain/PlayersTest.java @@ -42,7 +42,7 @@ private Player player(String name){ player("dalsu") )); List names = new ArrayList<>(); - players.forEach(p -> names.add(p.name())); + players.forEach(p -> names.add(p.getName())); assertThat(names).containsExactly("handa", "dalsu"); } diff --git a/src/test/java/blackjack/domain/TrumpCardTest.java b/src/test/java/blackjack/domain/TrumpCardTest.java index a6463875f51..a5018f24412 100644 --- a/src/test/java/blackjack/domain/TrumpCardTest.java +++ b/src/test/java/blackjack/domain/TrumpCardTest.java @@ -52,6 +52,6 @@ class TrumpCardTest { @Test void 카드의_랭크_이름을_반환한다() { TrumpCard trumpCard = TrumpCard.of(Suit.of("하트"), Rank.of("A")); - assertThat(trumpCard.symbol()).isEqualTo("A"); + assertThat(trumpCard.getSymbol()).isEqualTo("A"); } } \ No newline at end of file From cc021f7b7c2acba41df564c2360bc0d589443671 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sat, 14 Mar 2026 23:16:10 +0900 Subject: [PATCH 04/23] =?UTF-8?q?refactor:=20Dealer=EC=99=80=20Player=20?= =?UTF-8?q?=EA=B3=B5=EB=8F=99=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 - Participant 추상 클래스 추가 - 그 후 Dealer와 Player에 상속 추가 --- src/main/java/blackjack/domain/Dealer.java | 41 +++------------ .../java/blackjack/domain/Participant.java | 51 +++++++++++++++++++ src/main/java/blackjack/domain/Player.java | 39 ++------------ 3 files changed, 61 insertions(+), 70 deletions(-) create mode 100644 src/main/java/blackjack/domain/Participant.java diff --git a/src/main/java/blackjack/domain/Dealer.java b/src/main/java/blackjack/domain/Dealer.java index 788f1a16b52..484201c9047 100644 --- a/src/main/java/blackjack/domain/Dealer.java +++ b/src/main/java/blackjack/domain/Dealer.java @@ -1,47 +1,18 @@ package blackjack.domain; -import java.util.List; -import java.util.Objects; - -public class Dealer { +public class Dealer extends Participant{ private static final int DEALER_HIT_THRESHOLD = 16; - private final Hand hand; - - private Dealer(Hand hand) { - validate(hand); - this.hand = hand; - } - - private void validate(Hand hand) { - Objects.requireNonNull(hand, "딜러 덱(카드)는 null일 수 없습니다."); + private Dealer(Name name, Hand hand) { + super(name, hand); } public static Dealer of() { - return new Dealer(Hand.init()); - } - - public void hit(TrumpCard card) { - hand.add(card); - } - - public int score() { - return hand.calculateScore(); - } - - public List getCards() { - return hand.getCards(); + return new Dealer(Name.of("딜러"), Hand.init()); } - public boolean shouldHit() { + @Override + public boolean canHit() { return score() <= DEALER_HIT_THRESHOLD; } - - public boolean isBust() { - return score() > 21; - } - - public int countCards() { - return hand.countCards(); - } } diff --git a/src/main/java/blackjack/domain/Participant.java b/src/main/java/blackjack/domain/Participant.java new file mode 100644 index 00000000000..8cd882d874c --- /dev/null +++ b/src/main/java/blackjack/domain/Participant.java @@ -0,0 +1,51 @@ +package blackjack.domain; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +abstract class Participant { + protected final Name name; + protected final Hand hand; + + protected Participant(Name name, Hand hand) { + validate(name, hand); + this.name = name; + this.hand = hand; + } + + private void validate(Name name, Hand hand) { + Objects.requireNonNull(name, "참가자 이름은 null일 수 없습니다."); + Objects.requireNonNull(hand, "참자가 덱(카드)은 null일 수 없습니다."); + } + + public void hit(TrumpCard card) { + hand.add(card); + } + + public int score() { + return hand.calculateScore(); + } + + public boolean isBust() { + return hand.isBust(); + } + + public int countCards() { + return hand.countCards(); + } + + public List getCardNames() { + return hand.cardNames(); + } + + public String getName() { + return name.getName(); + } + + public abstract boolean canHit(); + + public List getCards() { + return hand.getCards(); + } +} diff --git a/src/main/java/blackjack/domain/Player.java b/src/main/java/blackjack/domain/Player.java index 45584a56fcb..2843af4a91b 100644 --- a/src/main/java/blackjack/domain/Player.java +++ b/src/main/java/blackjack/domain/Player.java @@ -1,48 +1,17 @@ package blackjack.domain; -import java.util.List; -import java.util.Objects; - -public class Player { - private final Name name; - private final Hand hand; - +public class Player extends Participant{ private Player(Name name, Hand hand) { - validate(name, hand); - this.name = name; - this.hand = hand; - } - - private void validate(Name name, Hand hand) { - Objects.requireNonNull(name, "플레이어 이름은 null일 수 없습니다."); - Objects.requireNonNull(hand, "플레이어 덱(카드)은 null일 수 없습니다."); + super(name, hand); } public static Player of(Name name) { return new Player(name, Hand.init()); } - public void hit(TrumpCard card) { - hand.add(card); - } - + @Override public boolean canHit() { return !isBust(); } - - public boolean isBust() { - return hand.isBust(); - } - - public int score() { - return hand.calculateScore(); - } - - public String name() { - return name.getName(); - } - - public List cardNames() { - return hand.cardNames(); - } } + From ee94a948c8d4e131136ed9004e48d26d89996cb4 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sat, 14 Mar 2026 23:19:14 +0900 Subject: [PATCH 05/23] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=EA=B3=BC=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B2=B0?= =?UTF-8?q?=ED=95=A9=EB=8F=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 컨트롤러가 인덱스로 Players를 조작하던 것 제거 - HitDecision 함수형 인터페이스 도입 - Players에서 Deck의 의존성 제거 --- .../controller/BlackjackController.java | 72 ++++-------------- .../java/blackjack/domain/BlackjackGame.java | 76 ++++++++----------- src/main/java/blackjack/domain/Hand.java | 5 +- .../java/blackjack/domain/HitDecision.java | 6 ++ src/main/java/blackjack/domain/Players.java | 5 ++ src/main/java/blackjack/domain/TrumpCard.java | 10 +-- .../java/blackjack/domain/TurnDisplay.java | 8 ++ .../java/blackjack/domain/vo/MatchResult.java | 5 +- src/main/java/blackjack/dto/CardDto.java | 2 +- .../java/blackjack/dto/DealResultDto.java | 11 ++- .../java/blackjack/dto/GameResultDto.java | 7 +- .../java/blackjack/dto/PlayerHandDto.java | 2 +- .../java/blackjack/dto/PlayerScoreDto.java | 2 +- src/main/java/blackjack/view/OutputView.java | 25 ++++-- 14 files changed, 105 insertions(+), 131 deletions(-) create mode 100644 src/main/java/blackjack/domain/HitDecision.java create mode 100644 src/main/java/blackjack/domain/TurnDisplay.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 9800f496143..480de2e10f8 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,12 +1,11 @@ package blackjack.controller; -import blackjack.domain.MatchResult; -import blackjack.domain.Player; +import blackjack.domain.BlackjackGame; +import blackjack.domain.vo.MatchResult; import blackjack.dto.DealResultDto; import blackjack.dto.GameResultDto; -import blackjack.dto.PlayerHandDto; -import blackjack.domain.BlackjackGame; import blackjack.util.Parser; +import blackjack.view.OutputView; import java.util.Collections; import java.util.List; @@ -15,30 +14,27 @@ import static blackjack.util.Parser.splitDelimiter; import static blackjack.view.InputView.readPlayNames; import static blackjack.view.InputView.readYesOrNo; -import static blackjack.view.OutputView.printCurrentPlayerHand; -import static blackjack.view.OutputView.printDealResult; -import static blackjack.view.OutputView.printDealerDrawMessage; -import static blackjack.view.OutputView.printEmptyLine; -import static blackjack.view.OutputView.printFinalResult; -import static blackjack.view.OutputView.printGameResult; public class BlackjackController { public void run() { List names = inputNames(); - BlackjackGame blackjackGame = BlackjackGame.create(names, Collections::shuffle); + BlackjackGame game = BlackjackGame.create(names, Collections::shuffle); - DealResultDto dealResultDto = deal(blackjackGame); - printDealResult(dealResultDto); + game.deal(); + OutputView.printDealResult(DealResultDto.from(game)); - playPlayerTurn(blackjackGame); - playDealerTurn(blackjackGame); + game.playPlayerTurns( + name -> Parser.parseDrawInput(readYesOrNo(name)).isHit(), + OutputView::printPlayerHand + ); - GameResultDto gameResultDto = blackjackGame.generateGameResult(); - printGameResult(gameResultDto); + game.playDealerTurn(); + OutputView.printDealerDrawMessage(); - Map playerFinalResult = blackjackGame.getPlayerFinalResult(); - Map dealerFinalResult = blackjackGame.getDealerFinalResult(playerFinalResult); - printFinalResult(playerFinalResult, dealerFinalResult); + OutputView.printGameResult(GameResultDto.from(game)); + + Map matchResults = game.matchResults(); + OutputView.printFinalResult(matchResults); } private List inputNames() { @@ -46,40 +42,4 @@ private List inputNames() { Parser.notEmpty(input); return splitDelimiter(input); } - - private DealResultDto deal(BlackjackGame blackjackGame) { - blackjackGame.deal(); - return DealResultDto.from(blackjackGame.getPlayers(), blackjackGame.getDealer()); - } - - private void playPlayerTurn(BlackjackGame blackjackGame) { - for (int i = 0; i < blackjackGame.playerCount(); i++) { - playTurn(blackjackGame, i); - } - } - - private void playTurn(BlackjackGame blackjackGame, int index) { - while (blackjackGame.canPlayerHit(index) && wantsToHit(blackjackGame, index)) { - hitAndPrintHand(blackjackGame, index); - } - printEmptyLine(); - } - - private boolean wantsToHit(BlackjackGame blackjackGame, int index) { - String answer = readYesOrNo(blackjackGame.playerNameByIndex(index)); - DrawCommand drawCommand = Parser.parseDrawInput(answer); - return drawCommand.isHit(); - } - - private void hitAndPrintHand(BlackjackGame blackjackGame, int index){ - PlayerHandDto playerHandDto = PlayerHandDto.from(blackjackGame.playerDraw(index)); - printCurrentPlayerHand(playerHandDto); - } - - private void playDealerTurn(BlackjackGame blackjackGame){ - while (blackjackGame.canDealerHit()) { - printDealerDrawMessage(); - blackjackGame.dealerDraw(); - } - } } \ No newline at end of file diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index 059e557f042..9984910de67 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -1,6 +1,6 @@ package blackjack.domain; -import blackjack.dto.GameResultDto; +import blackjack.domain.vo.MatchResult; import java.util.LinkedHashMap; import java.util.List; @@ -8,7 +8,6 @@ import java.util.Objects; import java.util.stream.Collectors; - public class BlackjackGame { private final Dealer dealer; private final Players players; @@ -41,51 +40,40 @@ private static Players generatePlayers(List names) { } public void deal() { - players.receiveCards(deck); - dealer.receiveCards(deck.drawSecondTimes()); - } - - public int playerCount() { - return players.count(); - } - - public boolean canPlayerHit(int index) { - return players.playerAt(index).canHit(); - } - - public String playerNameByIndex(int index) { - return players.playerAt(index).name(); - } - - public Player playerDraw(int index) { - TrumpCard drawn = deck.draw(); - players.playerAt(index).receiveCard(drawn); - return players.playerAt(index); - } - - public boolean canDealerHit() { - return dealer.shouldHit(); - } - - public void dealerDraw() { - TrumpCard drawn = deck.draw(); - dealer.receive(drawn); - } - - public GameResultDto generateGameResult() { - return GameResultDto.from(players, dealer); - } - - public Map getPlayerFinalResult() { - Map playerResult = new LinkedHashMap<>(); - for (Player player : players.getPlayers()) { - playerResult.put(player, MatchResult.playerResult(player, dealer)); + players.forEach( + player -> { + player.hit(deck.deal()); + player.hit(deck.deal()); + }); + dealer.hit(deck.deal()); + dealer.hit(deck.deal()); + } + + public void playPlayerTurns(HitDecision decision, TurnDisplay display) { + players.forEach(player -> { + while (player.canHit()) { + if (!decision.wantsHit(player.getName())) { + display.show(player.getName(), player.getCardNames()); + break; + } + player.hit(deck.deal()); + display.show(player.getName(), player.getCardNames()); + } + }); + } + + public void playDealerTurn() { + while (dealer.canHit()) { + dealer.hit(deck.deal()); } - return playerResult; } - public Map getDealerFinalResult(Map playerResult) { - return MatchResult.dealerResult(playerResult); + public Map matchResults() { + Map results = new LinkedHashMap<>(); + players.forEach(player -> + results.put(player.getName(), MatchResult.playerResult(player, dealer)) + ); + return results; } public Players getPlayers() { diff --git a/src/main/java/blackjack/domain/Hand.java b/src/main/java/blackjack/domain/Hand.java index 50307630139..8ce85f12ba6 100644 --- a/src/main/java/blackjack/domain/Hand.java +++ b/src/main/java/blackjack/domain/Hand.java @@ -33,7 +33,7 @@ public int calculateScore() { private int sumCardScores() { return cards.stream() - .mapToInt(TrumpCard::score) + .mapToInt(TrumpCard::getScore) .sum(); } @@ -54,7 +54,7 @@ private int countAces() { public List cardNames() { return cards.stream() - .map(TrumpCard::koreanName) + .map(TrumpCard::name) .toList(); } @@ -62,7 +62,6 @@ public int countCards() { return cards.size(); } - public List getCards() { return List.copyOf(cards); } diff --git a/src/main/java/blackjack/domain/HitDecision.java b/src/main/java/blackjack/domain/HitDecision.java new file mode 100644 index 00000000000..a439a00bf91 --- /dev/null +++ b/src/main/java/blackjack/domain/HitDecision.java @@ -0,0 +1,6 @@ +package blackjack.domain; + +@FunctionalInterface +public interface HitDecision { + boolean wantsHit(String name); +} diff --git a/src/main/java/blackjack/domain/Players.java b/src/main/java/blackjack/domain/Players.java index ccca685359b..231ff2dace0 100644 --- a/src/main/java/blackjack/domain/Players.java +++ b/src/main/java/blackjack/domain/Players.java @@ -1,5 +1,6 @@ package blackjack.domain; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Consumer; @@ -30,4 +31,8 @@ public void forEach(Consumer action){ public int count() { return players.size(); } + + public List getPlayers() { + return List.copyOf(players); + } } diff --git a/src/main/java/blackjack/domain/TrumpCard.java b/src/main/java/blackjack/domain/TrumpCard.java index 2dae5729918..bf725480e92 100644 --- a/src/main/java/blackjack/domain/TrumpCard.java +++ b/src/main/java/blackjack/domain/TrumpCard.java @@ -32,16 +32,12 @@ public boolean isAce() { return rank == Rank.ACE; } - public String koreanName() { - return suit.getKoreanName(); - } - - public int score() { + public int getScore() { return rank.getScore(); } - public String symbol() { - return rank.getSymbol(); + public String name() { + return rank.getSymbol() + suit.getKoreanName(); } @Override diff --git a/src/main/java/blackjack/domain/TurnDisplay.java b/src/main/java/blackjack/domain/TurnDisplay.java new file mode 100644 index 00000000000..321239a1cc6 --- /dev/null +++ b/src/main/java/blackjack/domain/TurnDisplay.java @@ -0,0 +1,8 @@ +package blackjack.domain; + +import java.util.List; + +@FunctionalInterface +public interface TurnDisplay { + void show(String name, List cardNames); +} diff --git a/src/main/java/blackjack/domain/vo/MatchResult.java b/src/main/java/blackjack/domain/vo/MatchResult.java index 563da76bc34..edb9ec3143f 100644 --- a/src/main/java/blackjack/domain/vo/MatchResult.java +++ b/src/main/java/blackjack/domain/vo/MatchResult.java @@ -1,4 +1,7 @@ -package blackjack.domain; +package blackjack.domain.vo; + +import blackjack.domain.Dealer; +import blackjack.domain.Player; import java.util.Map; diff --git a/src/main/java/blackjack/dto/CardDto.java b/src/main/java/blackjack/dto/CardDto.java index 2f638744520..01636beece8 100644 --- a/src/main/java/blackjack/dto/CardDto.java +++ b/src/main/java/blackjack/dto/CardDto.java @@ -6,6 +6,6 @@ public record CardDto( String display ) { public static CardDto from(TrumpCard card) { - return new CardDto(card.symbol() + card.koreanName()); + return new CardDto(card.name()); } } diff --git a/src/main/java/blackjack/dto/DealResultDto.java b/src/main/java/blackjack/dto/DealResultDto.java index f3d37eed668..009a18f107e 100644 --- a/src/main/java/blackjack/dto/DealResultDto.java +++ b/src/main/java/blackjack/dto/DealResultDto.java @@ -1,19 +1,18 @@ package blackjack.dto; -import blackjack.domain.Dealer; -import blackjack.domain.Players; - +import blackjack.domain.BlackjackGame; import java.util.List; public record DealResultDto( List playerHands, CardDto dealerOpenCard ) { - public static DealResultDto from(Players players, Dealer dealer) { - List playerHands = players.getPlayers().stream() + public static DealResultDto from(BlackjackGame game) { + List playerHands = game.getPlayers().getPlayers().stream() .map(PlayerHandDto::from) .toList(); - CardDto dealerCard = CardDto.from(dealer.getOpenCard()); + CardDto dealerCard = CardDto.from(game.getDealer().getCards().getFirst()); return new DealResultDto(playerHands, dealerCard); } } + diff --git a/src/main/java/blackjack/dto/GameResultDto.java b/src/main/java/blackjack/dto/GameResultDto.java index c31fd692a1c..5ceb6f62dac 100644 --- a/src/main/java/blackjack/dto/GameResultDto.java +++ b/src/main/java/blackjack/dto/GameResultDto.java @@ -1,5 +1,6 @@ package blackjack.dto; +import blackjack.domain.BlackjackGame; import blackjack.domain.Dealer; import blackjack.domain.Players; @@ -9,12 +10,12 @@ public record GameResultDto( List playerResults, DealerScoreDto dealerResult ) { - public static GameResultDto from(Players players, Dealer dealer) { - List playerResults = players.getPlayers().stream() + public static GameResultDto from(BlackjackGame game) { + List playerResults = game.getPlayers().getPlayers().stream() .map(PlayerScoreDto::from) .toList(); - DealerScoreDto dealerResult = DealerScoreDto.from(dealer); + DealerScoreDto dealerResult = DealerScoreDto.from(game.getDealer()); return new GameResultDto(playerResults, dealerResult); } } \ No newline at end of file diff --git a/src/main/java/blackjack/dto/PlayerHandDto.java b/src/main/java/blackjack/dto/PlayerHandDto.java index 20686addd17..0aaa2898db8 100644 --- a/src/main/java/blackjack/dto/PlayerHandDto.java +++ b/src/main/java/blackjack/dto/PlayerHandDto.java @@ -12,6 +12,6 @@ public static PlayerHandDto from(Player player) { List cardDtos = player.getCards().stream() .map(CardDto::from) .toList(); - return new PlayerHandDto(player.name(), cardDtos); + return new PlayerHandDto(player.getName(), cardDtos); } } diff --git a/src/main/java/blackjack/dto/PlayerScoreDto.java b/src/main/java/blackjack/dto/PlayerScoreDto.java index 410db8d084b..f38f90cb1ac 100644 --- a/src/main/java/blackjack/dto/PlayerScoreDto.java +++ b/src/main/java/blackjack/dto/PlayerScoreDto.java @@ -13,6 +13,6 @@ public static PlayerScoreDto from(Player player) { List cardDtos = player.getCards().stream() .map(CardDto::from) .toList(); - return new PlayerScoreDto(player.name(), cardDtos, player.score()); + return new PlayerScoreDto(player.getName(), cardDtos, player.score()); } } diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 5201baca2d5..162aa61375c 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -1,6 +1,6 @@ package blackjack.view; -import blackjack.domain.MatchResult; +import blackjack.domain.vo.MatchResult; import blackjack.domain.Player; import blackjack.dto.CardDto; import blackjack.dto.DealResultDto; @@ -30,6 +30,11 @@ public static void printCurrentPlayerHand(PlayerHandDto playerHand) { System.out.println(playerHand.name() + "카드: " + cards); } + public static void printPlayerHand(String name, List cards) { + String cardDisplay = String.join(", ", cards); + System.out.println(name + "카드: " + cardDisplay); + } + public static void printGameResult(GameResultDto gameResultDto) { DealerScoreDto dealer = gameResultDto.dealerResult(); System.out.println("딜러카드: " + formatCards(dealer.cards()) @@ -53,16 +58,20 @@ public static void printDealerDrawMessage() { System.out.println(); } - public static void printFinalResult(Map playerFinalResult, Map dealerFinalResult) { + public static void printFinalResult(Map matchResults) { System.out.println("## 최종 승패"); - printDealerFinalResult(dealerFinalResult.get("승"), dealerFinalResult.get("패")); - for (Player player : playerFinalResult.keySet()) { - printPlayerFinalResult(player.name(), playerFinalResult.get(player).getDisplay()); - } + printDealerFinalResult(matchResults); + matchResults.forEach((name, result) -> + System.out.println(name + ": " + result.getDisplay()) + ); } - private static void printDealerFinalResult(long dealerWinCount, long dealerLoseCount) { - System.out.println("딜러: " + dealerWinCount + "승 " + dealerLoseCount + "패"); + private static void printDealerFinalResult(Map matchResults) { + long winCount = matchResults.values().stream() + .filter(r -> r == MatchResult.LOSE).count(); + long loseCount = matchResults.values().stream() + .filter(r -> r == MatchResult.WIN).count(); + System.out.println("딜러: " + winCount + "승 " + loseCount + "패"); } private static void printPlayerFinalResult(String playerName, String result) { From af30a63d3e5269b1d553e2fd259a9dbd0b334f3b Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 03:08:08 +0900 Subject: [PATCH 06/23] =?UTF-8?q?feat:=20=EC=88=98=EC=9D=B5=20=EA=B8=B0?= =?UTF-8?q?=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 --- .../controller/BlackjackController.java | 11 ++-- src/main/java/blackjack/domain/Bet.java | 32 +++++++++++ .../java/blackjack/domain/BetDecision.java | 6 +++ .../java/blackjack/domain/BlackjackGame.java | 35 ++++++++++++ src/main/java/blackjack/domain/Hand.java | 4 +- src/main/java/blackjack/domain/Player.java | 17 ------ src/main/java/blackjack/domain/Players.java | 3 +- .../domain/{ => participant}/Dealer.java | 7 ++- .../domain/{ => participant}/Participant.java | 15 +++++- .../blackjack/domain/participant/Player.java | 32 +++++++++++ .../java/blackjack/domain/vo/GameResult.java | 12 +++++ .../java/blackjack/domain/vo/MatchResult.java | 6 +-- src/main/java/blackjack/domain/vo/Payoff.java | 53 +++++++++++++++++++ .../java/blackjack/dto/DealerScoreDto.java | 2 +- .../java/blackjack/dto/GameResultDto.java | 2 - .../java/blackjack/dto/PlayerHandDto.java | 2 +- .../java/blackjack/dto/PlayerScoreDto.java | 2 +- src/main/java/blackjack/view/InputView.java | 5 ++ src/main/java/blackjack/view/OutputView.java | 26 +++++---- .../java/blackjack/domain/TrumpCardTest.java | 8 +-- 20 files changed, 227 insertions(+), 53 deletions(-) create mode 100644 src/main/java/blackjack/domain/Bet.java create mode 100644 src/main/java/blackjack/domain/BetDecision.java delete mode 100644 src/main/java/blackjack/domain/Player.java rename src/main/java/blackjack/domain/{ => participant}/Dealer.java (70%) rename src/main/java/blackjack/domain/{ => participant}/Participant.java (75%) create mode 100644 src/main/java/blackjack/domain/participant/Player.java create mode 100644 src/main/java/blackjack/domain/vo/GameResult.java create mode 100644 src/main/java/blackjack/domain/vo/Payoff.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 480de2e10f8..bd2f78dcff5 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -1,15 +1,15 @@ package blackjack.controller; import blackjack.domain.BlackjackGame; -import blackjack.domain.vo.MatchResult; +import blackjack.domain.vo.GameResult; import blackjack.dto.DealResultDto; import blackjack.dto.GameResultDto; import blackjack.util.Parser; +import blackjack.view.InputView; import blackjack.view.OutputView; import java.util.Collections; import java.util.List; -import java.util.Map; import static blackjack.util.Parser.splitDelimiter; import static blackjack.view.InputView.readPlayNames; @@ -20,6 +20,8 @@ public void run() { List names = inputNames(); BlackjackGame game = BlackjackGame.create(names, Collections::shuffle); + game.betPlayers(name -> Integer.parseInt(InputView.readBetAmount(name))); + game.deal(); OutputView.printDealResult(DealResultDto.from(game)); @@ -33,8 +35,9 @@ public void run() { OutputView.printGameResult(GameResultDto.from(game)); - Map matchResults = game.matchResults(); - OutputView.printFinalResult(matchResults); + List gameResults = game.gameResults(); + int dealerProfit = game.getDealerProfit(gameResults); + OutputView.printFinalResult(gameResults, dealerProfit); } private List inputNames() { diff --git a/src/main/java/blackjack/domain/Bet.java b/src/main/java/blackjack/domain/Bet.java new file mode 100644 index 00000000000..be02fcf5321 --- /dev/null +++ b/src/main/java/blackjack/domain/Bet.java @@ -0,0 +1,32 @@ +package blackjack.domain; + +public class Bet { + private final int amount; + + private Bet(int amount) { + validate(amount); + this.amount = amount; + } + + public static Bet init(){ + return new Bet(0); + } + + public static Bet of(int amount){ + return new Bet(amount); + } + + public Bet add(int amount){ + return new Bet(this.amount + amount); + } + + private void validate(int amount) { + if (amount < 0) { + throw new IllegalArgumentException("배팅 금액은 음수가 나올 수 없습니다."); + } + } + + public int getAmount() { + return amount; + } +} diff --git a/src/main/java/blackjack/domain/BetDecision.java b/src/main/java/blackjack/domain/BetDecision.java new file mode 100644 index 00000000000..6e5f564b886 --- /dev/null +++ b/src/main/java/blackjack/domain/BetDecision.java @@ -0,0 +1,6 @@ +package blackjack.domain; + +@FunctionalInterface +public interface BetDecision { + int decideBet(String name); +} diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index 9984910de67..a467eb00e49 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -1,7 +1,12 @@ package blackjack.domain; +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Player; +import blackjack.domain.vo.GameResult; import blackjack.domain.vo.MatchResult; +import blackjack.domain.vo.Payoff; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -39,6 +44,13 @@ private static Players generatePlayers(List names) { .collect(Collectors.collectingAndThen(Collectors.toList(), Players::of)); } + public void betPlayers(BetDecision decision) { + players.forEach(player -> { + int amount = decision.decideBet(player.getName()); + player.placeBet(amount); + }); + } + public void deal() { players.forEach( player -> { @@ -68,6 +80,25 @@ public void playDealerTurn() { } } + public List gameResults(){ + List results = new ArrayList<>(); + players.forEach(player -> { + int profit = Payoff.playerResult(player, dealer) + .calculateProfit(player.getBet().getAmount()); + results.add(GameResult.from(player.getName(), profit)); + } + ); + return results; + } + + public int getDealerProfit(List gameResults){ + double profit = 0; + for (GameResult gameResult : gameResults) { + profit += gameResult.profit(); + } + return (int) Math.abs(profit); + } + public Map matchResults() { Map results = new LinkedHashMap<>(); players.forEach(player -> @@ -76,6 +107,10 @@ public Map matchResults() { return results; } + public Map getDealerFinalResult(Map playerResult) { + return MatchResult.dealerResult(playerResult); + } + public Players getPlayers() { return players; } diff --git a/src/main/java/blackjack/domain/Hand.java b/src/main/java/blackjack/domain/Hand.java index 8ce85f12ba6..644b25ea672 100644 --- a/src/main/java/blackjack/domain/Hand.java +++ b/src/main/java/blackjack/domain/Hand.java @@ -21,7 +21,9 @@ public void add(TrumpCard card) { cards.add(card); } - + public boolean isBlackjack(){ + return calculateScore() == BLACKJACK_THRESHOLD; + } public boolean isBust() { return calculateScore() > BLACKJACK_THRESHOLD; } diff --git a/src/main/java/blackjack/domain/Player.java b/src/main/java/blackjack/domain/Player.java deleted file mode 100644 index 2843af4a91b..00000000000 --- a/src/main/java/blackjack/domain/Player.java +++ /dev/null @@ -1,17 +0,0 @@ -package blackjack.domain; - -public class Player extends Participant{ - private Player(Name name, Hand hand) { - super(name, hand); - } - - public static Player of(Name name) { - return new Player(name, Hand.init()); - } - - @Override - public boolean canHit() { - return !isBust(); - } -} - diff --git a/src/main/java/blackjack/domain/Players.java b/src/main/java/blackjack/domain/Players.java index 231ff2dace0..30c7eedf37f 100644 --- a/src/main/java/blackjack/domain/Players.java +++ b/src/main/java/blackjack/domain/Players.java @@ -1,6 +1,7 @@ package blackjack.domain; -import java.util.Arrays; +import blackjack.domain.participant.Player; + import java.util.List; import java.util.Objects; import java.util.function.Consumer; diff --git a/src/main/java/blackjack/domain/Dealer.java b/src/main/java/blackjack/domain/participant/Dealer.java similarity index 70% rename from src/main/java/blackjack/domain/Dealer.java rename to src/main/java/blackjack/domain/participant/Dealer.java index 484201c9047..05e41800f36 100644 --- a/src/main/java/blackjack/domain/Dealer.java +++ b/src/main/java/blackjack/domain/participant/Dealer.java @@ -1,6 +1,9 @@ -package blackjack.domain; +package blackjack.domain.participant; -public class Dealer extends Participant{ +import blackjack.domain.Hand; +import blackjack.domain.Name; + +public class Dealer extends Participant { private static final int DEALER_HIT_THRESHOLD = 16; private Dealer(Name name, Hand hand) { diff --git a/src/main/java/blackjack/domain/Participant.java b/src/main/java/blackjack/domain/participant/Participant.java similarity index 75% rename from src/main/java/blackjack/domain/Participant.java rename to src/main/java/blackjack/domain/participant/Participant.java index 8cd882d874c..1aec0ac9710 100644 --- a/src/main/java/blackjack/domain/Participant.java +++ b/src/main/java/blackjack/domain/participant/Participant.java @@ -1,6 +1,9 @@ -package blackjack.domain; +package blackjack.domain.participant; + +import blackjack.domain.Hand; +import blackjack.domain.Name; +import blackjack.domain.TrumpCard; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -23,10 +26,18 @@ public void hit(TrumpCard card) { hand.add(card); } + public boolean hasHigherScoreThan(Participant other){ + return this.score() > other.score(); + } + public int score() { return hand.calculateScore(); } + public boolean isBlackjack() { + return hand.countCards() == 2 && hand.isBlackjack(); + } + public boolean isBust() { return hand.isBust(); } diff --git a/src/main/java/blackjack/domain/participant/Player.java b/src/main/java/blackjack/domain/participant/Player.java new file mode 100644 index 00000000000..51bd321ed24 --- /dev/null +++ b/src/main/java/blackjack/domain/participant/Player.java @@ -0,0 +1,32 @@ +package blackjack.domain.participant; + +import blackjack.domain.Bet; +import blackjack.domain.Hand; +import blackjack.domain.Name; + +public class Player extends Participant{ + private Bet bet; + + private Player(Name name, Hand hand, Bet bet) { + super(name, hand); + this.bet = bet; + } + + public static Player of(Name name) { + return new Player(name, Hand.init(), Bet.init()); + } + + public void placeBet(int amount) { + this.bet = bet.add(amount); + } + + public Bet getBet() { + return bet; + } + + @Override + public boolean canHit() { + return !isBust(); + } +} + diff --git a/src/main/java/blackjack/domain/vo/GameResult.java b/src/main/java/blackjack/domain/vo/GameResult.java new file mode 100644 index 00000000000..dd1dbcecda2 --- /dev/null +++ b/src/main/java/blackjack/domain/vo/GameResult.java @@ -0,0 +1,12 @@ +package blackjack.domain.vo; + +import blackjack.domain.Players; + +public record GameResult( + String name, + int profit +) { + public static GameResult from(String name, int profit) { + return new GameResult(name, profit); + } +} diff --git a/src/main/java/blackjack/domain/vo/MatchResult.java b/src/main/java/blackjack/domain/vo/MatchResult.java index edb9ec3143f..7e3cfb34eab 100644 --- a/src/main/java/blackjack/domain/vo/MatchResult.java +++ b/src/main/java/blackjack/domain/vo/MatchResult.java @@ -1,7 +1,7 @@ package blackjack.domain.vo; -import blackjack.domain.Dealer; -import blackjack.domain.Player; +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Player; import java.util.Map; @@ -36,7 +36,7 @@ public static MatchResult playerResult(Player player, Dealer dealer) { return DRAW; } - public static Map dealerResult(Map playerResults) { + public static Map dealerResult(Map playerResults) { return Map.of( "승", playerResults.values().stream().filter(r -> r == LOSE).count(), "패", playerResults.values().stream().filter(r -> r == WIN).count(), diff --git a/src/main/java/blackjack/domain/vo/Payoff.java b/src/main/java/blackjack/domain/vo/Payoff.java new file mode 100644 index 00000000000..0bef17ceb89 --- /dev/null +++ b/src/main/java/blackjack/domain/vo/Payoff.java @@ -0,0 +1,53 @@ +package blackjack.domain.vo; + +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Player; + +public enum Payoff { + BLACKJACK(1.5), + WIN(1.0), + DRAW(0.0), + LOSE(-1.0); + + private final double earningRate; + + Payoff(double earningRate) { + this.earningRate = earningRate; + } + + public static Payoff playerResult(Player player, Dealer dealer) { + if (player.isBust()) { + return LOSE; + } + + if (player.isBlackjack() && dealer.isBlackjack()) { + return DRAW; + } + + if (player.isBlackjack()) { + return BLACKJACK; + } + + if (dealer.isBlackjack()) { + return LOSE; + } + + if (dealer.isBust()) { + return WIN; + } + + if (player.hasHigherScoreThan(dealer)) { + return WIN; + } + + if (dealer.hasHigherScoreThan(player)) { + return LOSE; + } + + return DRAW; + } + + public int calculateProfit(int betAmount) { + return (int) (betAmount * earningRate); + } +} diff --git a/src/main/java/blackjack/dto/DealerScoreDto.java b/src/main/java/blackjack/dto/DealerScoreDto.java index 7c25f36dec9..c6c85b5cf8c 100644 --- a/src/main/java/blackjack/dto/DealerScoreDto.java +++ b/src/main/java/blackjack/dto/DealerScoreDto.java @@ -1,6 +1,6 @@ package blackjack.dto; -import blackjack.domain.Dealer; +import blackjack.domain.participant.Dealer; import java.util.List; diff --git a/src/main/java/blackjack/dto/GameResultDto.java b/src/main/java/blackjack/dto/GameResultDto.java index 5ceb6f62dac..04e8824e796 100644 --- a/src/main/java/blackjack/dto/GameResultDto.java +++ b/src/main/java/blackjack/dto/GameResultDto.java @@ -1,8 +1,6 @@ package blackjack.dto; import blackjack.domain.BlackjackGame; -import blackjack.domain.Dealer; -import blackjack.domain.Players; import java.util.List; diff --git a/src/main/java/blackjack/dto/PlayerHandDto.java b/src/main/java/blackjack/dto/PlayerHandDto.java index 0aaa2898db8..54cc7c6ea16 100644 --- a/src/main/java/blackjack/dto/PlayerHandDto.java +++ b/src/main/java/blackjack/dto/PlayerHandDto.java @@ -1,6 +1,6 @@ package blackjack.dto; -import blackjack.domain.Player; +import blackjack.domain.participant.Player; import java.util.List; diff --git a/src/main/java/blackjack/dto/PlayerScoreDto.java b/src/main/java/blackjack/dto/PlayerScoreDto.java index f38f90cb1ac..fa37d0172c5 100644 --- a/src/main/java/blackjack/dto/PlayerScoreDto.java +++ b/src/main/java/blackjack/dto/PlayerScoreDto.java @@ -1,6 +1,6 @@ package blackjack.dto; -import blackjack.domain.Player; +import blackjack.domain.participant.Player; import java.util.List; diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java index 3088b93e2dd..900ac37b4b3 100644 --- a/src/main/java/blackjack/view/InputView.java +++ b/src/main/java/blackjack/view/InputView.java @@ -17,4 +17,9 @@ public static String readYesOrNo(String playerName) { System.out.println(playerName + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); return SCANNER.nextLine(); } + + public static String readBetAmount(String playerName) { + System.out.println(playerName + "의 배팅 금액은?"); + return SCANNER.nextLine(); + } } diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 162aa61375c..2b637f107ea 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -1,7 +1,7 @@ package blackjack.view; +import blackjack.domain.vo.GameResult; import blackjack.domain.vo.MatchResult; -import blackjack.domain.Player; import blackjack.dto.CardDto; import blackjack.dto.DealResultDto; import blackjack.dto.DealerScoreDto; @@ -58,24 +58,28 @@ public static void printDealerDrawMessage() { System.out.println(); } - public static void printFinalResult(Map matchResults) { + public static void printFinalResult(Map matchResults, Map dealerResult) { System.out.println("## 최종 승패"); - printDealerFinalResult(matchResults); + printDealerFinalResult(dealerResult); matchResults.forEach((name, result) -> System.out.println(name + ": " + result.getDisplay()) ); } - private static void printDealerFinalResult(Map matchResults) { - long winCount = matchResults.values().stream() - .filter(r -> r == MatchResult.LOSE).count(); - long loseCount = matchResults.values().stream() - .filter(r -> r == MatchResult.WIN).count(); - System.out.println("딜러: " + winCount + "승 " + loseCount + "패"); + private static void printDealerFinalResult(Map dealerResult) { + System.out.println("딜러: " + dealerResult.get("승") + "승 " + + dealerResult.get("패") + "패"); } - private static void printPlayerFinalResult(String playerName, String result) { - System.out.println(playerName + ": " + result); + public static void printFinalResult(List gameResults, int dealerProfit) { + System.out.println("## 최종 승패"); + printDealerFinalResult(dealerProfit); + gameResults.forEach(result -> + System.out.println(result.name() + ": " + result.profit())); + } + + private static void printDealerFinalResult(int dealerProfit) { + System.out.println("딜러: " + dealerProfit); } public static void printEmptyLine(){ diff --git a/src/test/java/blackjack/domain/TrumpCardTest.java b/src/test/java/blackjack/domain/TrumpCardTest.java index a5018f24412..c103fefdfc1 100644 --- a/src/test/java/blackjack/domain/TrumpCardTest.java +++ b/src/test/java/blackjack/domain/TrumpCardTest.java @@ -46,12 +46,6 @@ class TrumpCardTest { @Test void 카드의_한글_이름을_반환한다() { TrumpCard trumpCard = TrumpCard.of(Suit.of("하트"), Rank.of("A")); - assertThat(trumpCard.koreanName()).isEqualTo("하트"); - } - - @Test - void 카드의_랭크_이름을_반환한다() { - TrumpCard trumpCard = TrumpCard.of(Suit.of("하트"), Rank.of("A")); - assertThat(trumpCard.getSymbol()).isEqualTo("A"); + assertThat(trumpCard.name()).isEqualTo("A하트"); } } \ No newline at end of file From 00cb413b5dc30926fd999bdabe03964a35a8070b Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 03:09:34 +0900 Subject: [PATCH 07/23] =?UTF-8?q?test:=20=EC=88=98=EC=9D=B5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/blackjack/domain/BetTest.java | 43 +++++++++++++++++++ .../java/blackjack/domain/DealerTest.java | 1 + .../blackjack/domain/MatchResultTest.java | 2 + .../java/blackjack/domain/PlayerTest.java | 1 + .../java/blackjack/domain/PlayersTest.java | 1 + 5 files changed, 48 insertions(+) create mode 100644 src/test/java/blackjack/domain/BetTest.java diff --git a/src/test/java/blackjack/domain/BetTest.java b/src/test/java/blackjack/domain/BetTest.java new file mode 100644 index 00000000000..588a0e79840 --- /dev/null +++ b/src/test/java/blackjack/domain/BetTest.java @@ -0,0 +1,43 @@ +package blackjack.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class BetTest { + + @Test + void 배팅_금액은_음수가_들어오면_예외처리한다(){ + Assertions.assertThatThrownBy(() -> Bet.of(-5000)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("배팅 금액은 음수가 나올 수 없습니다."); + } + + @Test + void 배팅_금액이_양수로_들어오면_정상입력된다(){ + //given + int amount = 5000; + + //when + Bet bet = Bet.of(amount); + //then + assertThat(bet).isNotNull(); + } + + @Test + void 배팅_금액은_초반에_0으로_초기화된다(){ + Bet bet = Bet.init(); + assertThat(bet.getAmount()).isEqualTo(0); + } + + @Test + void 배팅_금액이_추가되면_그_금액만큼_늘어난다(){ + Bet bet = Bet.init(); + int amount = 5000; + + Bet add = bet.add(amount); + + assertThat(add.getAmount()).isEqualTo(5000); + } +} \ No newline at end of file diff --git a/src/test/java/blackjack/domain/DealerTest.java b/src/test/java/blackjack/domain/DealerTest.java index 8d2c188083e..317e289065c 100644 --- a/src/test/java/blackjack/domain/DealerTest.java +++ b/src/test/java/blackjack/domain/DealerTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import blackjack.domain.participant.Dealer; import org.junit.jupiter.api.Test; class DealerTest { diff --git a/src/test/java/blackjack/domain/MatchResultTest.java b/src/test/java/blackjack/domain/MatchResultTest.java index 3f4f6444c05..d0eac1de1f1 100644 --- a/src/test/java/blackjack/domain/MatchResultTest.java +++ b/src/test/java/blackjack/domain/MatchResultTest.java @@ -1,5 +1,7 @@ package blackjack.domain; +import blackjack.domain.participant.Dealer; +import blackjack.domain.participant.Player; import blackjack.domain.vo.MatchResult; import org.junit.jupiter.api.Test; diff --git a/src/test/java/blackjack/domain/PlayerTest.java b/src/test/java/blackjack/domain/PlayerTest.java index 23638fac7f4..4bda75e1d3c 100644 --- a/src/test/java/blackjack/domain/PlayerTest.java +++ b/src/test/java/blackjack/domain/PlayerTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import blackjack.domain.participant.Player; import org.junit.jupiter.api.Test; public class PlayerTest { diff --git a/src/test/java/blackjack/domain/PlayersTest.java b/src/test/java/blackjack/domain/PlayersTest.java index 0703df19847..6eff8bdaf04 100644 --- a/src/test/java/blackjack/domain/PlayersTest.java +++ b/src/test/java/blackjack/domain/PlayersTest.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import blackjack.domain.participant.Player; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; From 0086a199483aef64d2a92de9b2431a824b66b2e7 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:02:34 +0900 Subject: [PATCH 08/23] =?UTF-8?q?refactor:=20BlackjackGame=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 플레이어 추가 드로우 턴 메소드 분리 - 딜러 수익 계산 메소드 에러 수정 --- .../java/blackjack/domain/BlackjackGame.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index a467eb00e49..6cdb708c789 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -63,17 +63,27 @@ public void deal() { public void playPlayerTurns(HitDecision decision, TurnDisplay display) { players.forEach(player -> { - while (player.canHit()) { - if (!decision.wantsHit(player.getName())) { - display.show(player.getName(), player.getCardNames()); - break; - } - player.hit(deck.deal()); - display.show(player.getName(), player.getCardNames()); - } + playerTurn(player, decision, display); }); } + private void playerTurn(Player player, HitDecision decision, TurnDisplay display) { + boolean playing = true; + while (player.canHit() && playing) { + playing = processHit(player, decision, display); + } + } + + private boolean processHit(Player player, HitDecision decision, TurnDisplay display) { + if (!decision.wantsHit(player.getName())) { + display.show(player.getName(), player.getCardNames()); + return false; + } + player.hit(deck.deal()); + display.show(player.getName(), player.getCardNames()); + return true; + } + public void playDealerTurn() { while (dealer.canHit()) { dealer.hit(deck.deal()); @@ -91,12 +101,10 @@ public List gameResults(){ return results; } - public int getDealerProfit(List gameResults){ - double profit = 0; - for (GameResult gameResult : gameResults) { - profit += gameResult.profit(); - } - return (int) Math.abs(profit); + public int getDealerProfit(List gameResults) { + return -gameResults.stream() + .mapToInt(GameResult::profit) + .sum(); } public Map matchResults() { From 551af634afb95bbc968e167bfc754fa4e42c47a6 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:03:20 +0900 Subject: [PATCH 09/23] =?UTF-8?q?test:=20BlackjackGame=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배팅 금액 입력 테스트 추가 - deal() 테스트 추가 - 플레이아 추가 수령 테스트 추가 - 딜러 추가 수령 테스트 추가 --- .../blackjack/domain/BlackjackGameTest.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/test/java/blackjack/domain/BlackjackGameTest.java diff --git a/src/test/java/blackjack/domain/BlackjackGameTest.java b/src/test/java/blackjack/domain/BlackjackGameTest.java new file mode 100644 index 00000000000..80a9296cbd4 --- /dev/null +++ b/src/test/java/blackjack/domain/BlackjackGameTest.java @@ -0,0 +1,79 @@ +package blackjack.domain; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class BlackjackGameTest { + private BlackjackGame createGame(String... names){ + return BlackjackGame.create(List.of(names), cards -> {}); + } + + @Test + void 모든_플레이어에게_배팅_금액을_입력받는다(){ + BlackjackGame game = createGame("pobi", "jason"); + + List askedPlayers = new ArrayList<>(); + game.betPlayers(name -> { + askedPlayers.add(name); + return 10000; + }); + + assertThat(askedPlayers).containsExactly("pobi", "jason"); + } + + @Test + void 모든_플레이어는_2장_딜러는_2장을_가진다(){ + BlackjackGame game = createGame("pobi", "jason"); + + game.deal(); + + assertThat(game.getDealer().countCards()).isEqualTo(2); + List cardCounts = new ArrayList<>(); + game.getPlayers().forEach(player -> { + cardCounts.add(player.countCards()); + } + ); + assertThat(cardCounts).containsOnly(2); + } + + @Test + void 플레이어가_hit을_선택하면_카드를_받는다(){ + BlackjackGame game = createGame("dalsoo"); + game.deal(); + List cardCounts = new ArrayList<>(); + + game.playPlayerTurns( + name -> true, + (name, cards) -> cardCounts.add(cards.size()) + ); + assertThat(cardCounts).isSorted(); + } + + @Test + void 플레이어가_stay를_선택하면_카드를_받지_않는다(){ + BlackjackGame game = createGame("dalsoo"); + game.deal(); + List cardCounts = new ArrayList<>(); + + game.playPlayerTurns( + name -> false, + (name, cards) -> cardCounts.add(cards.size()) + ); + + assertThat(cardCounts).containsExactly(2); + } + + @Test + void 딜러는_16이하면_카드를_더_받는다(){ + BlackjackGame game = createGame("dalsoo"); + game.deal(); + game.playPlayerTurns(name -> false, (name, cards) -> {}); + game.playDealerTurn(); + + assertThat(game.getDealer().canHit()).isFalse(); + } +} \ No newline at end of file From 85b49150c98b2121507aa9cf86c9b6082da72301 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:15:51 +0900 Subject: [PATCH 10/23] =?UTF-8?q?refactor:=20View=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=9D=98=20static=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B8=EC=8A=A4=ED=84=B4=EC=8A=A4=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존에는 유틸 클래스처럼 static으로 호출하고 있었는데, View는 유틸이 아니라 입출력이라는 역할을 가진 객체라고 판단 --- .../controller/BlackjackController.java | 27 ++++++++++++------- src/main/java/blackjack/view/InputView.java | 9 +++---- src/main/java/blackjack/view/OutputView.java | 24 ++++++++--------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index bd2f78dcff5..ea0ab72df00 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -12,36 +12,43 @@ import java.util.List; import static blackjack.util.Parser.splitDelimiter; -import static blackjack.view.InputView.readPlayNames; -import static blackjack.view.InputView.readYesOrNo; + public class BlackjackController { + private final InputView inputView; + private final OutputView outputView; + + public BlackjackController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + public void run() { List names = inputNames(); BlackjackGame game = BlackjackGame.create(names, Collections::shuffle); - game.betPlayers(name -> Integer.parseInt(InputView.readBetAmount(name))); + game.betPlayers(name -> Integer.parseInt(inputView.readBetAmount(name))); game.deal(); - OutputView.printDealResult(DealResultDto.from(game)); + outputView.printDealResult(DealResultDto.from(game)); game.playPlayerTurns( - name -> Parser.parseDrawInput(readYesOrNo(name)).isHit(), - OutputView::printPlayerHand + name -> Parser.parseDrawInput(inputView.readYesOrNo(name)).isHit(), + outputView::printPlayerHand ); game.playDealerTurn(); - OutputView.printDealerDrawMessage(); + outputView.printDealerDrawMessage(); - OutputView.printGameResult(GameResultDto.from(game)); + outputView.printGameResult(GameResultDto.from(game)); List gameResults = game.gameResults(); int dealerProfit = game.getDealerProfit(gameResults); - OutputView.printFinalResult(gameResults, dealerProfit); + outputView.printFinalResult(gameResults, dealerProfit); } private List inputNames() { - String input = readPlayNames(); + String input = inputView.readPlayNames(); Parser.notEmpty(input); return splitDelimiter(input); } diff --git a/src/main/java/blackjack/view/InputView.java b/src/main/java/blackjack/view/InputView.java index 900ac37b4b3..fee18684a6a 100644 --- a/src/main/java/blackjack/view/InputView.java +++ b/src/main/java/blackjack/view/InputView.java @@ -5,20 +5,17 @@ public class InputView { private static final Scanner SCANNER = new Scanner(System.in); - private InputView() { - } - - public static String readPlayNames() { + public String readPlayNames() { System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); return SCANNER.nextLine(); } - public static String readYesOrNo(String playerName) { + public String readYesOrNo(String playerName) { System.out.println(playerName + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); return SCANNER.nextLine(); } - public static String readBetAmount(String playerName) { + public String readBetAmount(String playerName) { System.out.println(playerName + "의 배팅 금액은?"); return SCANNER.nextLine(); } diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 2b637f107ea..1aa9f8cacb0 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -14,10 +14,8 @@ import java.util.stream.Collectors; public class OutputView { - private OutputView() { - } - public static void printDealResult(DealResultDto dealResultDto) { + public void printDealResult(DealResultDto dealResultDto) { System.out.println("딜러카드: " + dealResultDto.dealerOpenCard().display()); for (PlayerHandDto playerHand : dealResultDto.playerHands()) { printCurrentPlayerHand(playerHand); @@ -25,17 +23,17 @@ public static void printDealResult(DealResultDto dealResultDto) { System.out.println(); } - public static void printCurrentPlayerHand(PlayerHandDto playerHand) { + public void printCurrentPlayerHand(PlayerHandDto playerHand) { String cards = formatCards(playerHand.cards()); System.out.println(playerHand.name() + "카드: " + cards); } - public static void printPlayerHand(String name, List cards) { + public void printPlayerHand(String name, List cards) { String cardDisplay = String.join(", ", cards); System.out.println(name + "카드: " + cardDisplay); } - public static void printGameResult(GameResultDto gameResultDto) { + public void printGameResult(GameResultDto gameResultDto) { DealerScoreDto dealer = gameResultDto.dealerResult(); System.out.println("딜러카드: " + formatCards(dealer.cards()) + " - 결과: " + dealer.score()); @@ -47,18 +45,18 @@ public static void printGameResult(GameResultDto gameResultDto) { System.out.println(); } - private static String formatCards(List cards) { + private String formatCards(List cards) { return cards.stream() .map(CardDto::display) .collect(Collectors.joining(", ")); } - public static void printDealerDrawMessage() { + public void printDealerDrawMessage() { System.out.println("딜러는 16이하라 한장의 카드를 더 받았습니다."); System.out.println(); } - public static void printFinalResult(Map matchResults, Map dealerResult) { + public void printFinalResult(Map matchResults, Map dealerResult) { System.out.println("## 최종 승패"); printDealerFinalResult(dealerResult); matchResults.forEach((name, result) -> @@ -66,23 +64,23 @@ public static void printFinalResult(Map matchResults, Map dealerResult) { + private void printDealerFinalResult(Map dealerResult) { System.out.println("딜러: " + dealerResult.get("승") + "승 " + dealerResult.get("패") + "패"); } - public static void printFinalResult(List gameResults, int dealerProfit) { + public void printFinalResult(List gameResults, int dealerProfit) { System.out.println("## 최종 승패"); printDealerFinalResult(dealerProfit); gameResults.forEach(result -> System.out.println(result.name() + ": " + result.profit())); } - private static void printDealerFinalResult(int dealerProfit) { + private void printDealerFinalResult(int dealerProfit) { System.out.println("딜러: " + dealerProfit); } - public static void printEmptyLine(){ + public void printEmptyLine(){ System.out.println(); } } From c380883010005555ac903db3d5f85d6a805fe008 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:16:34 +0900 Subject: [PATCH 11/23] =?UTF-8?q?feat:=20AppConfig=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=EA=B3=BC=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A1=B0=EB=A6=BD=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/Application.java | 4 +++- src/main/java/blackjack/config/AppConfig.java | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/main/java/blackjack/config/AppConfig.java diff --git a/src/main/java/blackjack/Application.java b/src/main/java/blackjack/Application.java index f8d94ab2ca9..72011cb941d 100644 --- a/src/main/java/blackjack/Application.java +++ b/src/main/java/blackjack/Application.java @@ -1,10 +1,12 @@ package blackjack; +import blackjack.config.AppConfig; import blackjack.controller.BlackjackController; public class Application { public static void main(String[] args) { - BlackjackController blackjackController = new BlackjackController(); + AppConfig config = new AppConfig(); + BlackjackController blackjackController = config.blackjackController(); blackjackController.run(); } } diff --git a/src/main/java/blackjack/config/AppConfig.java b/src/main/java/blackjack/config/AppConfig.java new file mode 100644 index 00000000000..e3541eb7167 --- /dev/null +++ b/src/main/java/blackjack/config/AppConfig.java @@ -0,0 +1,19 @@ +package blackjack.config; + +import blackjack.controller.BlackjackController; +import blackjack.view.InputView; +import blackjack.view.OutputView; + +public class AppConfig { + public BlackjackController blackjackController(){ + return new BlackjackController(inputView(), outputView()); + } + + public InputView inputView() { + return new InputView(); + } + + public OutputView outputView() { + return new OutputView(); + } +} From 0fda59f712dff56090c73d5126d2497c6f80602b Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:30:21 +0900 Subject: [PATCH 12/23] =?UTF-8?q?feat:=20StringUtils=20=EC=9C=A0=ED=8B=B8?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parser에서 문자열까지 검증하고 있어 분리 - StringUtils에서 문자열 null, isBlank() 검증 --- .../blackjack/controller/BlackjackController.java | 1 - src/main/java/blackjack/util/Parser.java | 8 +++----- src/main/java/blackjack/util/StringUtils.java | 13 +++++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 src/main/java/blackjack/util/StringUtils.java diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index ea0ab72df00..2d4642d516e 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -49,7 +49,6 @@ public void run() { private List inputNames() { String input = inputView.readPlayNames(); - Parser.notEmpty(input); return splitDelimiter(input); } } \ No newline at end of file diff --git a/src/main/java/blackjack/util/Parser.java b/src/main/java/blackjack/util/Parser.java index 1b19adf2b26..370874fa3cb 100644 --- a/src/main/java/blackjack/util/Parser.java +++ b/src/main/java/blackjack/util/Parser.java @@ -5,11 +5,14 @@ import java.util.ArrayList; import java.util.List; +import static blackjack.util.StringUtils.notEmpty; + public class Parser { private Parser(){ } public static List splitDelimiter(String playerNames) { + notEmpty(playerNames); String[] values = playerNames.split(","); List splitResult = new ArrayList<>(); @@ -25,9 +28,4 @@ public static DrawCommand parseDrawInput(String input){ return DrawCommand.of(input); } - public static void notEmpty(String value) { - if (value == null || value.isBlank()) { - throw new IllegalArgumentException("입력이 비어있습니다."); - } - } } diff --git a/src/main/java/blackjack/util/StringUtils.java b/src/main/java/blackjack/util/StringUtils.java new file mode 100644 index 00000000000..cc9f9c8a133 --- /dev/null +++ b/src/main/java/blackjack/util/StringUtils.java @@ -0,0 +1,13 @@ +package blackjack.util; + +public class StringUtils { + private StringUtils(){ + } + + + public static void notEmpty(String value) { + if (value == null || value.isBlank()) { + throw new IllegalArgumentException("입력이 비어있습니다."); + } + } +} From a044615e1e347e06dae045beef346391a5b0761a Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 15:48:45 +0900 Subject: [PATCH 13/23] =?UTF-8?q?feat:=20=EC=B6=9C=EB=A0=A5=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/blackjack/controller/BlackjackController.java | 8 +++++++- src/main/java/blackjack/view/OutputView.java | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 2d4642d516e..09aa61c15ae 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -25,9 +25,14 @@ public BlackjackController(InputView inputView, OutputView outputView) { public void run() { List names = inputNames(); + outputView.printEmptyLine(); BlackjackGame game = BlackjackGame.create(names, Collections::shuffle); - game.betPlayers(name -> Integer.parseInt(inputView.readBetAmount(name))); + game.betPlayers(name -> { + String amount = inputView.readBetAmount(name); + outputView.printEmptyLine(); + return Integer.parseInt(amount); + }); game.deal(); outputView.printDealResult(DealResultDto.from(game)); @@ -36,6 +41,7 @@ public void run() { name -> Parser.parseDrawInput(inputView.readYesOrNo(name)).isHit(), outputView::printPlayerHand ); + outputView.printEmptyLine(); game.playDealerTurn(); outputView.printDealerDrawMessage(); diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 1aa9f8cacb0..86200837eef 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -16,6 +16,8 @@ public class OutputView { public void printDealResult(DealResultDto dealResultDto) { + String names = joinPlayerNames(dealResultDto); + System.out.println("딜러와 " + names + "에게 2장을 나누었습니다."); System.out.println("딜러카드: " + dealResultDto.dealerOpenCard().display()); for (PlayerHandDto playerHand : dealResultDto.playerHands()) { printCurrentPlayerHand(playerHand); @@ -23,6 +25,12 @@ public void printDealResult(DealResultDto dealResultDto) { System.out.println(); } + private String joinPlayerNames(DealResultDto dealResultDto) { + return dealResultDto.playerHands().stream() + .map(PlayerHandDto::name) + .collect(Collectors.joining(", ")); + } + public void printCurrentPlayerHand(PlayerHandDto playerHand) { String cards = formatCards(playerHand.cards()); System.out.println(playerHand.name() + "카드: " + cards); From afb261e5d8762d8d9bd7e49f6bbde423460e3522 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 21:42:27 +0900 Subject: [PATCH 14/23] =?UTF-8?q?refactor:=20AppConfig=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/config/AppConfig.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/blackjack/config/AppConfig.java b/src/main/java/blackjack/config/AppConfig.java index e3541eb7167..5bc162e909d 100644 --- a/src/main/java/blackjack/config/AppConfig.java +++ b/src/main/java/blackjack/config/AppConfig.java @@ -6,14 +6,6 @@ public class AppConfig { public BlackjackController blackjackController(){ - return new BlackjackController(inputView(), outputView()); - } - - public InputView inputView() { - return new InputView(); - } - - public OutputView outputView() { - return new OutputView(); + return new BlackjackController(new InputView(), new OutputView()); } } From a7f4d1708e729fc7f0f224c5300cec71f960b131 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 21:43:25 +0900 Subject: [PATCH 15/23] =?UTF-8?q?refactor:=20BlackjackGame=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/blackjack/domain/BlackjackGame.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index 6cdb708c789..3d648bf2304 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -107,18 +107,6 @@ public int getDealerProfit(List gameResults) { .sum(); } - public Map matchResults() { - Map results = new LinkedHashMap<>(); - players.forEach(player -> - results.put(player.getName(), MatchResult.playerResult(player, dealer)) - ); - return results; - } - - public Map getDealerFinalResult(Map playerResult) { - return MatchResult.dealerResult(playerResult); - } - public Players getPlayers() { return players; } From a2cd51d2ebea0d8a4152e849a1c825ec4ca8e94e Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 22:10:50 +0900 Subject: [PATCH 16/23] =?UTF-8?q?refactor:=20=EB=AF=B8=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - matchResults(), getDealerFinalResult() 삭제 - gameResults() → calculatePlayerProfits()로 변경 - getDealerProfit() → calculateDealerProfit()로 변경 --- .../blackjack/controller/BlackjackController.java | 4 ++-- src/main/java/blackjack/domain/BlackjackGame.java | 7 ++----- src/main/java/blackjack/domain/vo/GameResult.java | 2 -- src/main/java/blackjack/util/StringUtils.java | 1 - src/main/java/blackjack/view/OutputView.java | 15 --------------- 5 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index 09aa61c15ae..a477e412ec6 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -48,8 +48,8 @@ public void run() { outputView.printGameResult(GameResultDto.from(game)); - List gameResults = game.gameResults(); - int dealerProfit = game.getDealerProfit(gameResults); + List gameResults = game.calculatePlayerProfits(); + int dealerProfit = game.calculateDealerProfit(gameResults); outputView.printFinalResult(gameResults, dealerProfit); } diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index 3d648bf2304..7f2c3420838 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -3,13 +3,10 @@ import blackjack.domain.participant.Dealer; import blackjack.domain.participant.Player; import blackjack.domain.vo.GameResult; -import blackjack.domain.vo.MatchResult; import blackjack.domain.vo.Payoff; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -90,7 +87,7 @@ public void playDealerTurn() { } } - public List gameResults(){ + public List calculatePlayerProfits(){ List results = new ArrayList<>(); players.forEach(player -> { int profit = Payoff.playerResult(player, dealer) @@ -101,7 +98,7 @@ public List gameResults(){ return results; } - public int getDealerProfit(List gameResults) { + public int calculateDealerProfit(List gameResults) { return -gameResults.stream() .mapToInt(GameResult::profit) .sum(); diff --git a/src/main/java/blackjack/domain/vo/GameResult.java b/src/main/java/blackjack/domain/vo/GameResult.java index dd1dbcecda2..5776c127113 100644 --- a/src/main/java/blackjack/domain/vo/GameResult.java +++ b/src/main/java/blackjack/domain/vo/GameResult.java @@ -1,7 +1,5 @@ package blackjack.domain.vo; -import blackjack.domain.Players; - public record GameResult( String name, int profit diff --git a/src/main/java/blackjack/util/StringUtils.java b/src/main/java/blackjack/util/StringUtils.java index cc9f9c8a133..5c6e19e3319 100644 --- a/src/main/java/blackjack/util/StringUtils.java +++ b/src/main/java/blackjack/util/StringUtils.java @@ -4,7 +4,6 @@ public class StringUtils { private StringUtils(){ } - public static void notEmpty(String value) { if (value == null || value.isBlank()) { throw new IllegalArgumentException("입력이 비어있습니다."); diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index 86200837eef..d1d5f277849 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -1,7 +1,6 @@ package blackjack.view; import blackjack.domain.vo.GameResult; -import blackjack.domain.vo.MatchResult; import blackjack.dto.CardDto; import blackjack.dto.DealResultDto; import blackjack.dto.DealerScoreDto; @@ -10,7 +9,6 @@ import blackjack.dto.PlayerScoreDto; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; public class OutputView { @@ -64,19 +62,6 @@ public void printDealerDrawMessage() { System.out.println(); } - public void printFinalResult(Map matchResults, Map dealerResult) { - System.out.println("## 최종 승패"); - printDealerFinalResult(dealerResult); - matchResults.forEach((name, result) -> - System.out.println(name + ": " + result.getDisplay()) - ); - } - - private void printDealerFinalResult(Map dealerResult) { - System.out.println("딜러: " + dealerResult.get("승") + "승 " - + dealerResult.get("패") + "패"); - } - public void printFinalResult(List gameResults, int dealerProfit) { System.out.println("## 최종 승패"); printDealerFinalResult(dealerProfit); From 71e1006e1874e796a5d24515c2eec57220e4eb55 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 22:20:45 +0900 Subject: [PATCH 17/23] =?UTF-8?q?refactor:=20TrumpCard=20CARDS=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CARDS -> ALL_CARD 수정 --- src/main/java/blackjack/domain/Deck.java | 2 +- src/main/java/blackjack/domain/TrumpCard.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/blackjack/domain/Deck.java b/src/main/java/blackjack/domain/Deck.java index b1b3c98e6a5..9de7639c445 100644 --- a/src/main/java/blackjack/domain/Deck.java +++ b/src/main/java/blackjack/domain/Deck.java @@ -19,7 +19,7 @@ public static Deck of(List cards) { } public static Deck create(ShuffleStrategy strategy) { - List cards = new ArrayList<>(TrumpCard.CARDS); + List cards = new ArrayList<>(TrumpCard.ALL_CARD); strategy.shuffle(cards); return new Deck(cards); } diff --git a/src/main/java/blackjack/domain/TrumpCard.java b/src/main/java/blackjack/domain/TrumpCard.java index bf725480e92..e71d6aea3ff 100644 --- a/src/main/java/blackjack/domain/TrumpCard.java +++ b/src/main/java/blackjack/domain/TrumpCard.java @@ -5,7 +5,7 @@ import java.util.Objects; public class TrumpCard { - public static final List CARDS = Arrays.stream(Suit.values()) + public static final List ALL_CARD = Arrays.stream(Suit.values()) .flatMap(suit -> Arrays.stream(Rank.values()) .map(rank -> TrumpCard.of(suit, rank))) .toList(); From 1a064a02539f47d3aa29f84a2c2a46a8ed9cdbeb Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 22:40:29 +0900 Subject: [PATCH 18/23] =?UTF-8?q?refactor:=20=EB=94=9C=EB=9F=AC=20?= =?UTF-8?q?=EC=B2=AB=20=EC=B9=B4=EB=93=9C=20=EA=B3=B5=EA=B0=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20Dealer=20=EB=8F=84=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=EC=9C=BC=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 - Dealer에 openFirstCard() 추가 - DTO에서 직접 카드를 꺼내던 로직 제거 - "첫 패만 공개"는 도메인 규칙이므로 Dealer가 책임 --- src/main/java/blackjack/domain/Hand.java | 4 ++++ src/main/java/blackjack/domain/participant/Dealer.java | 5 +++++ src/main/java/blackjack/dto/DealResultDto.java | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/blackjack/domain/Hand.java b/src/main/java/blackjack/domain/Hand.java index 644b25ea672..176fc923723 100644 --- a/src/main/java/blackjack/domain/Hand.java +++ b/src/main/java/blackjack/domain/Hand.java @@ -64,6 +64,10 @@ public int countCards() { return cards.size(); } + public TrumpCard getFirstCard(){ + return cards.getFirst(); + } + public List getCards() { return List.copyOf(cards); } diff --git a/src/main/java/blackjack/domain/participant/Dealer.java b/src/main/java/blackjack/domain/participant/Dealer.java index 05e41800f36..2c290a3bb3d 100644 --- a/src/main/java/blackjack/domain/participant/Dealer.java +++ b/src/main/java/blackjack/domain/participant/Dealer.java @@ -2,6 +2,7 @@ import blackjack.domain.Hand; import blackjack.domain.Name; +import blackjack.domain.TrumpCard; public class Dealer extends Participant { private static final int DEALER_HIT_THRESHOLD = 16; @@ -18,4 +19,8 @@ public static Dealer of() { public boolean canHit() { return score() <= DEALER_HIT_THRESHOLD; } + + public TrumpCard openFirstCard(){ + return hand.getFirstCard(); + } } diff --git a/src/main/java/blackjack/dto/DealResultDto.java b/src/main/java/blackjack/dto/DealResultDto.java index 009a18f107e..b90917d53a4 100644 --- a/src/main/java/blackjack/dto/DealResultDto.java +++ b/src/main/java/blackjack/dto/DealResultDto.java @@ -11,7 +11,7 @@ public static DealResultDto from(BlackjackGame game) { List playerHands = game.getPlayers().getPlayers().stream() .map(PlayerHandDto::from) .toList(); - CardDto dealerCard = CardDto.from(game.getDealer().getCards().getFirst()); + CardDto dealerCard = CardDto.from(game.getDealer().openFirstCard()); return new DealResultDto(playerHands, dealerCard); } } From de1afb6613ee2b62c403c45a2cb10fa90ad61562 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 23:02:50 +0900 Subject: [PATCH 19/23] =?UTF-8?q?fix:=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=ED=8C=90=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 블랙잭 판단이 21로만 되었는데, 카드 수도 확인하는 로직 추가 --- src/main/java/blackjack/domain/Hand.java | 3 ++- src/main/java/blackjack/domain/participant/Participant.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/blackjack/domain/Hand.java b/src/main/java/blackjack/domain/Hand.java index 176fc923723..55406498180 100644 --- a/src/main/java/blackjack/domain/Hand.java +++ b/src/main/java/blackjack/domain/Hand.java @@ -6,6 +6,7 @@ public class Hand { private static final int ACE_DIFFERENCE = 10; private static final int BLACKJACK_THRESHOLD = 21; + private static final int BLACKJACK_CARD_COUNT = 2; private final List cards; @@ -22,7 +23,7 @@ public void add(TrumpCard card) { } public boolean isBlackjack(){ - return calculateScore() == BLACKJACK_THRESHOLD; + return countCards() == BLACKJACK_CARD_COUNT && calculateScore() == BLACKJACK_THRESHOLD; } public boolean isBust() { return calculateScore() > BLACKJACK_THRESHOLD; diff --git a/src/main/java/blackjack/domain/participant/Participant.java b/src/main/java/blackjack/domain/participant/Participant.java index 1aec0ac9710..748da17837b 100644 --- a/src/main/java/blackjack/domain/participant/Participant.java +++ b/src/main/java/blackjack/domain/participant/Participant.java @@ -35,7 +35,7 @@ public int score() { } public boolean isBlackjack() { - return hand.countCards() == 2 && hand.isBlackjack(); + return hand.isBlackjack(); } public boolean isBust() { From 2001f0e81e883e238d4b33ba8129e8cb0babfc92 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Sun, 15 Mar 2026 23:03:32 +0900 Subject: [PATCH 20/23] =?UTF-8?q?test:=20TrumpCard=20ALL=5FCARD=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=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/blackjack/domain/DeckTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/blackjack/domain/DeckTest.java b/src/test/java/blackjack/domain/DeckTest.java index 07c174cab35..11cb20d51b7 100644 --- a/src/test/java/blackjack/domain/DeckTest.java +++ b/src/test/java/blackjack/domain/DeckTest.java @@ -10,7 +10,7 @@ class DeckTest { private Deck emptyDeck(){ - Deck deck = Deck.of(new ArrayList<>(TrumpCard.CARDS)); + Deck deck = Deck.of(new ArrayList<>(TrumpCard.ALL_CARD)); for (int i = 0; i < 52; i++) { deck.deal(); } @@ -28,7 +28,7 @@ private Deck emptyDeck(){ @Test void 전체_카드_수가_52장보다_많으면_예외_발생한다() { - List cards = new ArrayList<>(TrumpCard.CARDS); + List cards = new ArrayList<>(TrumpCard.ALL_CARD); cards.add(TrumpCard.of(Suit.SPADE, Rank.ACE)); assertThatThrownBy(() -> Deck.of(cards)) @@ -38,7 +38,7 @@ private Deck emptyDeck(){ @Test void 중복된_카드가_존재하면_예외_발생한다() { - List cards = new ArrayList<>(TrumpCard.CARDS); + List cards = new ArrayList<>(TrumpCard.ALL_CARD); cards.removeFirst(); cards.add(TrumpCard.of(Suit.CLOVER, Rank.KING)); @@ -58,7 +58,7 @@ private Deck emptyDeck(){ @Test void 카드를_지급하면_전체_카드_수가_줄어든다() { - Deck deck = Deck.of(new ArrayList<>(TrumpCard.CARDS)); + Deck deck = Deck.of(new ArrayList<>(TrumpCard.ALL_CARD)); deck.deal(); From 1fda9e37752360e5b0482c85e2c212415afca8e2 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Mon, 16 Mar 2026 01:08:58 +0900 Subject: [PATCH 21/23] =?UTF-8?q?refactor:=20Bet=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EB=B3=80=EC=88=98=20int=20->=20BigDecimal?= =?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 --- .../controller/BlackjackController.java | 6 +-- src/main/java/blackjack/domain/Bet.java | 37 ++++++++++++------- .../java/blackjack/domain/BetDecision.java | 2 +- .../java/blackjack/domain/BlackjackGame.java | 14 ++++--- .../blackjack/domain/participant/Player.java | 4 +- .../java/blackjack/domain/vo/GameResult.java | 6 ++- src/main/java/blackjack/domain/vo/Payoff.java | 6 ++- src/main/java/blackjack/util/Parser.java | 1 - src/main/java/blackjack/view/OutputView.java | 5 ++- 9 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/main/java/blackjack/controller/BlackjackController.java b/src/main/java/blackjack/controller/BlackjackController.java index a477e412ec6..b23b1da7aa1 100644 --- a/src/main/java/blackjack/controller/BlackjackController.java +++ b/src/main/java/blackjack/controller/BlackjackController.java @@ -8,12 +8,12 @@ import blackjack.view.InputView; import blackjack.view.OutputView; +import java.math.BigDecimal; import java.util.Collections; import java.util.List; import static blackjack.util.Parser.splitDelimiter; - public class BlackjackController { private final InputView inputView; private final OutputView outputView; @@ -31,7 +31,7 @@ public void run() { game.betPlayers(name -> { String amount = inputView.readBetAmount(name); outputView.printEmptyLine(); - return Integer.parseInt(amount); + return amount; }); game.deal(); @@ -49,7 +49,7 @@ public void run() { outputView.printGameResult(GameResultDto.from(game)); List gameResults = game.calculatePlayerProfits(); - int dealerProfit = game.calculateDealerProfit(gameResults); + BigDecimal dealerProfit = game.calculateDealerProfit(gameResults); outputView.printFinalResult(gameResults, dealerProfit); } diff --git a/src/main/java/blackjack/domain/Bet.java b/src/main/java/blackjack/domain/Bet.java index be02fcf5321..7cb72bbd318 100644 --- a/src/main/java/blackjack/domain/Bet.java +++ b/src/main/java/blackjack/domain/Bet.java @@ -1,32 +1,43 @@ package blackjack.domain; +import java.math.BigDecimal; +import java.util.Objects; + public class Bet { - private final int amount; + private final BigDecimal amount; - private Bet(int amount) { + private Bet(BigDecimal amount) { validate(amount); this.amount = amount; } + private void validate(BigDecimal amount) { + Objects.requireNonNull(amount, "배팅 금액은 null일 수 없습니다."); + if (amount.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException("배팅 금액은 음수가 나올 수 없습니다."); + } + } + public static Bet init(){ - return new Bet(0); + return new Bet(BigDecimal.ZERO); } - public static Bet of(int amount){ - return new Bet(amount); + public static Bet of(String amount){ + return new Bet(new BigDecimal(amount)); } - public Bet add(int amount){ - return new Bet(this.amount + amount); + public BigDecimal getAmount() { + return amount; } - private void validate(int amount) { - if (amount < 0) { - throw new IllegalArgumentException("배팅 금액은 음수가 나올 수 없습니다."); - } + @Override + public final boolean equals(Object o) { + if (!(o instanceof Bet bet)) return false; + return Objects.equals(amount, bet.amount); } - public int getAmount() { - return amount; + @Override + public int hashCode() { + return Objects.hashCode(amount); } } diff --git a/src/main/java/blackjack/domain/BetDecision.java b/src/main/java/blackjack/domain/BetDecision.java index 6e5f564b886..5a4bfdbcbe1 100644 --- a/src/main/java/blackjack/domain/BetDecision.java +++ b/src/main/java/blackjack/domain/BetDecision.java @@ -2,5 +2,5 @@ @FunctionalInterface public interface BetDecision { - int decideBet(String name); + String decideBet(String name); } diff --git a/src/main/java/blackjack/domain/BlackjackGame.java b/src/main/java/blackjack/domain/BlackjackGame.java index 7f2c3420838..3db0b783362 100644 --- a/src/main/java/blackjack/domain/BlackjackGame.java +++ b/src/main/java/blackjack/domain/BlackjackGame.java @@ -5,6 +5,7 @@ import blackjack.domain.vo.GameResult; import blackjack.domain.vo.Payoff; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -43,7 +44,7 @@ private static Players generatePlayers(List names) { public void betPlayers(BetDecision decision) { players.forEach(player -> { - int amount = decision.decideBet(player.getName()); + String amount = decision.decideBet(player.getName()); player.placeBet(amount); }); } @@ -90,7 +91,7 @@ public void playDealerTurn() { public List calculatePlayerProfits(){ List results = new ArrayList<>(); players.forEach(player -> { - int profit = Payoff.playerResult(player, dealer) + BigDecimal profit = Payoff.playerResult(player, dealer) .calculateProfit(player.getBet().getAmount()); results.add(GameResult.from(player.getName(), profit)); } @@ -98,10 +99,11 @@ public List calculatePlayerProfits(){ return results; } - public int calculateDealerProfit(List gameResults) { - return -gameResults.stream() - .mapToInt(GameResult::profit) - .sum(); + public BigDecimal calculateDealerProfit(List gameResults) { + return gameResults.stream() + .map(GameResult::profit) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .negate(); } public Players getPlayers() { diff --git a/src/main/java/blackjack/domain/participant/Player.java b/src/main/java/blackjack/domain/participant/Player.java index 51bd321ed24..feb1b4fc301 100644 --- a/src/main/java/blackjack/domain/participant/Player.java +++ b/src/main/java/blackjack/domain/participant/Player.java @@ -16,8 +16,8 @@ public static Player of(Name name) { return new Player(name, Hand.init(), Bet.init()); } - public void placeBet(int amount) { - this.bet = bet.add(amount); + public void placeBet(String amount) { + this.bet = Bet.of(amount); } public Bet getBet() { diff --git a/src/main/java/blackjack/domain/vo/GameResult.java b/src/main/java/blackjack/domain/vo/GameResult.java index 5776c127113..2b43b9b6c71 100644 --- a/src/main/java/blackjack/domain/vo/GameResult.java +++ b/src/main/java/blackjack/domain/vo/GameResult.java @@ -1,10 +1,12 @@ package blackjack.domain.vo; +import java.math.BigDecimal; + public record GameResult( String name, - int profit + BigDecimal profit ) { - public static GameResult from(String name, int profit) { + public static GameResult from(String name, BigDecimal profit) { return new GameResult(name, profit); } } diff --git a/src/main/java/blackjack/domain/vo/Payoff.java b/src/main/java/blackjack/domain/vo/Payoff.java index 0bef17ceb89..72cf3d85d82 100644 --- a/src/main/java/blackjack/domain/vo/Payoff.java +++ b/src/main/java/blackjack/domain/vo/Payoff.java @@ -3,6 +3,8 @@ import blackjack.domain.participant.Dealer; import blackjack.domain.participant.Player; +import java.math.BigDecimal; + public enum Payoff { BLACKJACK(1.5), WIN(1.0), @@ -47,7 +49,7 @@ public static Payoff playerResult(Player player, Dealer dealer) { return DRAW; } - public int calculateProfit(int betAmount) { - return (int) (betAmount * earningRate); + public BigDecimal calculateProfit(BigDecimal betAmount) { + return betAmount.multiply(BigDecimal.valueOf(earningRate)); } } diff --git a/src/main/java/blackjack/util/Parser.java b/src/main/java/blackjack/util/Parser.java index 370874fa3cb..f7db8b491aa 100644 --- a/src/main/java/blackjack/util/Parser.java +++ b/src/main/java/blackjack/util/Parser.java @@ -27,5 +27,4 @@ public static DrawCommand parseDrawInput(String input){ notEmpty(input); return DrawCommand.of(input); } - } diff --git a/src/main/java/blackjack/view/OutputView.java b/src/main/java/blackjack/view/OutputView.java index d1d5f277849..b853d9805e4 100644 --- a/src/main/java/blackjack/view/OutputView.java +++ b/src/main/java/blackjack/view/OutputView.java @@ -8,6 +8,7 @@ import blackjack.dto.PlayerHandDto; import blackjack.dto.PlayerScoreDto; +import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; @@ -62,14 +63,14 @@ public void printDealerDrawMessage() { System.out.println(); } - public void printFinalResult(List gameResults, int dealerProfit) { + public void printFinalResult(List gameResults, BigDecimal dealerProfit) { System.out.println("## 최종 승패"); printDealerFinalResult(dealerProfit); gameResults.forEach(result -> System.out.println(result.name() + ": " + result.profit())); } - private void printDealerFinalResult(int dealerProfit) { + private void printDealerFinalResult(BigDecimal dealerProfit) { System.out.println("딜러: " + dealerProfit); } From 92e61ec0db19d84d24bff4021af4a7cbf1f978cc Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Mon, 16 Mar 2026 01:09:40 +0900 Subject: [PATCH 22/23] =?UTF-8?q?test:=20Bet=20=EC=9D=B8=EC=8A=A4=ED=84=B4?= =?UTF-8?q?=EC=88=98=20=EB=B3=80=EC=88=98=20=EC=88=98=EC=A0=95=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=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/test/java/blackjack/domain/BetTest.java | 16 ++++++++-------- .../java/blackjack/domain/BlackjackGameTest.java | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/java/blackjack/domain/BetTest.java b/src/test/java/blackjack/domain/BetTest.java index 588a0e79840..38be9dbbc24 100644 --- a/src/test/java/blackjack/domain/BetTest.java +++ b/src/test/java/blackjack/domain/BetTest.java @@ -3,13 +3,15 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import java.math.BigDecimal; + import static org.assertj.core.api.Assertions.assertThat; class BetTest { @Test void 배팅_금액은_음수가_들어오면_예외처리한다(){ - Assertions.assertThatThrownBy(() -> Bet.of(-5000)) + Assertions.assertThatThrownBy(() -> Bet.of("-5000")) .isInstanceOf(IllegalArgumentException.class) .hasMessage("배팅 금액은 음수가 나올 수 없습니다."); } @@ -17,7 +19,7 @@ class BetTest { @Test void 배팅_금액이_양수로_들어오면_정상입력된다(){ //given - int amount = 5000; + String amount = "5000"; //when Bet bet = Bet.of(amount); @@ -28,16 +30,14 @@ class BetTest { @Test void 배팅_금액은_초반에_0으로_초기화된다(){ Bet bet = Bet.init(); - assertThat(bet.getAmount()).isEqualTo(0); + assertThat(bet.getAmount()).isEqualByComparingTo(BigDecimal.ZERO); } @Test void 배팅_금액이_추가되면_그_금액만큼_늘어난다(){ - Bet bet = Bet.init(); - int amount = 5000; - - Bet add = bet.add(amount); + String amount = "5000"; + Bet bet = Bet.of(amount); - assertThat(add.getAmount()).isEqualTo(5000); + assertThat(bet.getAmount()).isEqualByComparingTo(new BigDecimal("5000")); } } \ No newline at end of file diff --git a/src/test/java/blackjack/domain/BlackjackGameTest.java b/src/test/java/blackjack/domain/BlackjackGameTest.java index 80a9296cbd4..ea0cf81994a 100644 --- a/src/test/java/blackjack/domain/BlackjackGameTest.java +++ b/src/test/java/blackjack/domain/BlackjackGameTest.java @@ -19,7 +19,7 @@ private BlackjackGame createGame(String... names){ List askedPlayers = new ArrayList<>(); game.betPlayers(name -> { askedPlayers.add(name); - return 10000; + return "10000"; }); assertThat(askedPlayers).containsExactly("pobi", "jason"); From 0049204c4c83cebf952005ca6e92fbbf0f157fe3 Mon Sep 17 00:00:00 2001 From: SooHyeon Lee Date: Mon, 16 Mar 2026 01:22:52 +0900 Subject: [PATCH 23/23] =?UTF-8?q?refactor:=20Deck=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EA=B0=80=20=EC=97=86=EC=9D=84=EB=95=8C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=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/blackjack/domain/Deck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/blackjack/domain/Deck.java b/src/main/java/blackjack/domain/Deck.java index 9de7639c445..2edc2734b13 100644 --- a/src/main/java/blackjack/domain/Deck.java +++ b/src/main/java/blackjack/domain/Deck.java @@ -48,7 +48,7 @@ private void validateDuplicates(List cards) { public TrumpCard deal() { if (cards.isEmpty()) { - throw new IllegalArgumentException("덱에 카드가 없습니다."); + throw new IllegalStateException("덱에 카드가 없습니다."); } return cards.removeFirst(); }