From 4f3dfba1959da55db1d7fca37d970557286b493c Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 16:49:18 +0900 Subject: [PATCH 01/88] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index 1ff5f7b6790..f3b9049043c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,36 @@ # java-blackjack 블랙잭 미션 저장소 + +## 구현할 기능 목록 + +### 카드 덱 생성 + 셔플 +- [ ] 52장의 카드를 생성한다. +- [ ] 카드를 셔플한다. + +### 플레이어/딜러 관리 +- [ ] 플레이어를 등록한다. +- [ ] 딜러를 등록한다. +- [ ] 카드를 돌린다. + +### 카드 점수 계산 +- [ ] J,Q,K는 10으로 처리한다. +- [ ] Ace는 1점으로 처리한다. +- [ ] 카드 점수를 합산한다. + +### Ace 1/11 처리 +- [ ] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. + +### 버스트 판정 +- [ ] 21점이 넘으면 버스트 + +### 히트/스탠드 입력 +- [ ] 버스트가 아니면 히트/스탠드를 입력받는다. +- [ ] 히트면 카드를 한 장 더 받는다. +- [ ] 스탠드면 턴을 종료한다. + +### 승패 판정 +- [ ] 딜러와 점수를 비교한다. +- [ ] 결과를 생성한다. + +### 결과 출력 \ No newline at end of file From 3bbf6544cb1359975fef85b05e83a5638ff18655 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 17:53:36 +0900 Subject: [PATCH 02/88] =?UTF-8?q?feat:=20=EB=8D=B1=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- src/test/java/Card.java | 15 +++++++++++++ src/test/java/Deck.java | 22 +++++++++++++++++++ src/test/java/DeckTest.java | 42 +++++++++++++++++++++++++++++++++++++ src/test/java/Rank.java | 15 +++++++++++++ src/test/java/Suit.java | 3 +++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/test/java/Card.java create mode 100644 src/test/java/Deck.java create mode 100644 src/test/java/DeckTest.java create mode 100644 src/test/java/Rank.java create mode 100644 src/test/java/Suit.java diff --git a/README.md b/README.md index f3b9049043c..83077515f4d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ ## 구현할 기능 목록 ### 카드 덱 생성 + 셔플 -- [ ] 52장의 카드를 생성한다. +- [x] 52장의 카드를 생성한다. + - [x] 카드는 무늬별 숫자순으로 생성된다. - [ ] 카드를 셔플한다. ### 플레이어/딜러 관리 diff --git a/src/test/java/Card.java b/src/test/java/Card.java new file mode 100644 index 00000000000..c443a9a9723 --- /dev/null +++ b/src/test/java/Card.java @@ -0,0 +1,15 @@ +public class Card { + + private Rank rank; + private Suit suit; + + public Card(Rank rank, Suit suit) { + this.rank = rank; + this.suit = suit; + } + + @Override + public String toString() { + return "" + rank + suit; + } +} diff --git a/src/test/java/Deck.java b/src/test/java/Deck.java new file mode 100644 index 00000000000..f2053146e00 --- /dev/null +++ b/src/test/java/Deck.java @@ -0,0 +1,22 @@ +import java.util.ArrayList; +import java.util.List; + +public class Deck { + List cards = new ArrayList<>(); + + public void init() { + for (Suit suit : Suit.values()) { + for (Rank rank : Rank.values()) { + cards.add(new Card(rank, suit)); + } + } + } + + public int size() { + return cards.size(); + } + + public Card draw() { + return cards.removeFirst(); + } +} diff --git a/src/test/java/DeckTest.java b/src/test/java/DeckTest.java new file mode 100644 index 00000000000..9dd4d4cdbb2 --- /dev/null +++ b/src/test/java/DeckTest.java @@ -0,0 +1,42 @@ +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DeckTest { + + @Test + void 카드를_52장_생성한다() { + Deck deck = new Deck(); + deck.init(); + + int deckSize = deck.size(); + + assertThat(deckSize).isEqualTo(52); + } + + @Test + void 카드는_숫자순에서_무늬순으로_생성된다() { + Deck deck = new Deck(); + deck.init(); + int deckSize = deck.size(); + + List result = new ArrayList<>(); + for (int i = 0; i < deckSize; i++) { + Card card = deck.draw(); + result.add(card); + } + + assertThat(result.toString()).contains( + "[ACESPADE, TWOSPADE, THREESPADE, FOURSPADE, FIVESPADE, SIXSPADE, SEVENSPADE, EIGHTSPADE, " + + "NINESPADE, TENSPADE, JACKSPADE, QUEENSPADE, KINGSPADE, ACEHEART, TWOHEART, THREEHEART, " + + "FOURHEART, FIVEHEART, SIXHEART, SEVENHEART, EIGHTHEART, NINEHEART, TENHEART, JACKHEART," + + " QUEENHEART, KINGHEART, ACEDIAMOND, TWODIAMOND, THREEDIAMOND, FOURDIAMOND, FIVEDIAMOND," + + " SIXDIAMOND, SEVENDIAMOND, EIGHTDIAMOND, NINEDIAMOND, TENDIAMOND, JACKDIAMOND," + + " QUEENDIAMOND, KINGDIAMOND, ACECLUB, TWOCLUB, THREECLUB, FOURCLUB, FIVECLUB, SIXCLUB," + + " SEVENCLUB, EIGHTCLUB, NINECLUB, TENCLUB, JACKCLUB, QUEENCLUB, KINGCLUB]" + ); + } +} diff --git a/src/test/java/Rank.java b/src/test/java/Rank.java new file mode 100644 index 00000000000..9b794290661 --- /dev/null +++ b/src/test/java/Rank.java @@ -0,0 +1,15 @@ +public enum Rank { + ACE, + TWO, + THREE, + FOUR, + FIVE, + SIX, + SEVEN, + EIGHT, + NINE, + TEN, + JACK, + QUEEN, + KING +} diff --git a/src/test/java/Suit.java b/src/test/java/Suit.java new file mode 100644 index 00000000000..6ce8999293e --- /dev/null +++ b/src/test/java/Suit.java @@ -0,0 +1,3 @@ +public enum Suit { + SPADE, HEART, DIAMOND, CLUB +} From 63f556a288271637257bd5bc9e85b26931778500 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 18:19:53 +0900 Subject: [PATCH 03/88] =?UTF-8?q?feat:=20=EB=8D=B1=20=EC=85=94=ED=94=8C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/Card.java | 14 ++++++++++++++ src/test/java/Deck.java | 6 ++++++ src/test/java/DeckTest.java | 28 ++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 83077515f4d..c4656c10e0b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ### 카드 덱 생성 + 셔플 - [x] 52장의 카드를 생성한다. - [x] 카드는 무늬별 숫자순으로 생성된다. -- [ ] 카드를 셔플한다. +- [x] 카드를 셔플한다. ### 플레이어/딜러 관리 - [ ] 플레이어를 등록한다. diff --git a/src/test/java/Card.java b/src/test/java/Card.java index c443a9a9723..a6725627808 100644 --- a/src/test/java/Card.java +++ b/src/test/java/Card.java @@ -1,3 +1,5 @@ +import java.util.Objects; + public class Card { private Rank rank; @@ -8,6 +10,18 @@ public Card(Rank rank, Suit suit) { this.suit = suit; } + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Card card = (Card) o; + return rank == card.rank && suit == card.suit; + } + + @Override + public int hashCode() { + return Objects.hash(rank, suit); + } + @Override public String toString() { return "" + rank + suit; diff --git a/src/test/java/Deck.java b/src/test/java/Deck.java index f2053146e00..ffbd601b0ca 100644 --- a/src/test/java/Deck.java +++ b/src/test/java/Deck.java @@ -1,4 +1,5 @@ import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class Deck { @@ -19,4 +20,9 @@ public int size() { public Card draw() { return cards.removeFirst(); } + + public void shuffle() { + Collections.shuffle(cards); + System.out.println("cards = " + cards); + } } diff --git a/src/test/java/DeckTest.java b/src/test/java/DeckTest.java index 9dd4d4cdbb2..145edfbad18 100644 --- a/src/test/java/DeckTest.java +++ b/src/test/java/DeckTest.java @@ -1,3 +1,4 @@ +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -39,4 +40,31 @@ public class DeckTest { " SEVENCLUB, EIGHTCLUB, NINECLUB, TENCLUB, JACKCLUB, QUEENCLUB, KINGCLUB]" ); } + + @Test + void 카드_셔플_테스트() { + Deck deck1 = new Deck(); + deck1.init(); + deck1.shuffle(); + int deckSize = deck1.size(); + + List result1 = new ArrayList<>(); + for (int i = 0; i < deckSize; i++) { + Card card = deck1.draw(); + result1.add(card); + } + + Deck deck2 = new Deck(); + deck2.init(); + + List result2 = new ArrayList<>(); + for (int i = 0; i < deckSize; i++) { + Card card = deck2.draw(); + result2.add(card); + } + + assertThat(result1.size()).isEqualTo(result2.size()); + assertThat(result1).containsExactlyInAnyOrderElementsOf(result2); + + } } From 33badfd3b216eb0c5e3ec689f2040291cf8ed3b7 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 19:20:49 +0900 Subject: [PATCH 04/88] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/{test => main}/java/Card.java | 0 src/{test => main}/java/Deck.java | 0 src/{test => main}/java/Rank.java | 0 src/{test => main}/java/Suit.java | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename src/{test => main}/java/Card.java (100%) rename src/{test => main}/java/Deck.java (100%) rename src/{test => main}/java/Rank.java (100%) rename src/{test => main}/java/Suit.java (100%) diff --git a/README.md b/README.md index c4656c10e0b..05b662589a0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [x] 카드를 셔플한다. ### 플레이어/딜러 관리 -- [ ] 플레이어를 등록한다. +- [ ] 플레이어를 플레이어 목록에 등록한다. - [ ] 딜러를 등록한다. - [ ] 카드를 돌린다. diff --git a/src/test/java/Card.java b/src/main/java/Card.java similarity index 100% rename from src/test/java/Card.java rename to src/main/java/Card.java diff --git a/src/test/java/Deck.java b/src/main/java/Deck.java similarity index 100% rename from src/test/java/Deck.java rename to src/main/java/Deck.java diff --git a/src/test/java/Rank.java b/src/main/java/Rank.java similarity index 100% rename from src/test/java/Rank.java rename to src/main/java/Rank.java diff --git a/src/test/java/Suit.java b/src/main/java/Suit.java similarity index 100% rename from src/test/java/Suit.java rename to src/main/java/Suit.java From e3e2962456d7f71f4d773d869d0219e70fd79d89 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 19:44:13 +0900 Subject: [PATCH 05/88] =?UTF-8?q?test:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EB=93=B1=EB=A1=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/PlayersTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/java/PlayersTest.java diff --git a/src/test/java/PlayersTest.java b/src/test/java/PlayersTest.java new file mode 100644 index 00000000000..7375841a58a --- /dev/null +++ b/src/test/java/PlayersTest.java @@ -0,0 +1,18 @@ +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PlayersTest { + + @Test + void 플레이어를_등록한다() { + Players players = new Players(); + players.add(new Player("pobi")); + + List records = players.getPlayers(); + + assertThat(records).anyMatch(player -> player.getName().equals("pobi")); + } +} From c885805711b3673a4f8965c9d68cb73d9a4c7c9b Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 19:50:19 +0900 Subject: [PATCH 06/88] =?UTF-8?q?feat:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/Player.java | 11 +++++++++++ src/test/java/Players.java | 15 +++++++++++++++ src/test/java/PlayersTest.java | 3 ++- 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/test/java/Player.java create mode 100644 src/test/java/Players.java diff --git a/README.md b/README.md index 05b662589a0..a94f4c4d467 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [x] 카드를 셔플한다. ### 플레이어/딜러 관리 -- [ ] 플레이어를 플레이어 목록에 등록한다. +- [x] 플레이어를 플레이어 목록에 등록한다. - [ ] 딜러를 등록한다. - [ ] 카드를 돌린다. diff --git a/src/test/java/Player.java b/src/test/java/Player.java new file mode 100644 index 00000000000..318fc222333 --- /dev/null +++ b/src/test/java/Player.java @@ -0,0 +1,11 @@ +public class Player { + private String name; + + public Player(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/test/java/Players.java b/src/test/java/Players.java new file mode 100644 index 00000000000..1c6ede940b4 --- /dev/null +++ b/src/test/java/Players.java @@ -0,0 +1,15 @@ +import java.util.ArrayList; +import java.util.List; + +public class Players { + List players = new ArrayList<>(); + + + public void add(Player player) { + players.add(player); + } + + public List getPlayers() { + return List.copyOf(players); + } +} diff --git a/src/test/java/PlayersTest.java b/src/test/java/PlayersTest.java index 7375841a58a..5ae81c1fe63 100644 --- a/src/test/java/PlayersTest.java +++ b/src/test/java/PlayersTest.java @@ -10,9 +10,10 @@ public class PlayersTest { void 플레이어를_등록한다() { Players players = new Players(); players.add(new Player("pobi")); + players.add(new Player("abc")); List records = players.getPlayers(); - assertThat(records).anyMatch(player -> player.getName().equals("pobi")); + assertThat(records).anyMatch(player -> player.getName().equals("abc")); } } From 0a84a824c3e8c346743490fcea6c997ec3df4290 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 19:57:22 +0900 Subject: [PATCH 07/88] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/Dealer.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 src/test/java/Dealer.java diff --git a/README.md b/README.md index a94f4c4d467..9b35e284ea2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ### 플레이어/딜러 관리 - [x] 플레이어를 플레이어 목록에 등록한다. -- [ ] 딜러를 등록한다. +- [x] 딜러를 만든다. - [ ] 카드를 돌린다. ### 카드 점수 계산 diff --git a/src/test/java/Dealer.java b/src/test/java/Dealer.java new file mode 100644 index 00000000000..05c4102ceed --- /dev/null +++ b/src/test/java/Dealer.java @@ -0,0 +1,6 @@ +public class Dealer extends Player { + + public Dealer(String name) { + super(name); + } +} From 47dd596fbd219263421188bd68762288c99e57c0 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:31:56 +0900 Subject: [PATCH 08/88] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=20=EB=8F=8C?= =?UTF-8?q?=EB=A6=AC=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/Dealer.java | 4 ++-- src/test/java/DeckTest.java | 18 ++++++++++++++++++ src/test/java/GameManager.java | 19 +++++++++++++++++++ src/test/java/Player.java | 12 ++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/test/java/GameManager.java diff --git a/README.md b/README.md index 9b35e284ea2..bb8515c5e4e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ### 플레이어/딜러 관리 - [x] 플레이어를 플레이어 목록에 등록한다. - [x] 딜러를 만든다. -- [ ] 카드를 돌린다. +- [x] 카드를 돌린다. ### 카드 점수 계산 - [ ] J,Q,K는 10으로 처리한다. diff --git a/src/test/java/Dealer.java b/src/test/java/Dealer.java index 05c4102ceed..bf3d97aa3d4 100644 --- a/src/test/java/Dealer.java +++ b/src/test/java/Dealer.java @@ -1,6 +1,6 @@ public class Dealer extends Player { - public Dealer(String name) { - super(name); + public Dealer() { + super("딜러"); } } diff --git a/src/test/java/DeckTest.java b/src/test/java/DeckTest.java index 145edfbad18..83404952939 100644 --- a/src/test/java/DeckTest.java +++ b/src/test/java/DeckTest.java @@ -65,6 +65,24 @@ public class DeckTest { assertThat(result1.size()).isEqualTo(result2.size()); assertThat(result1).containsExactlyInAnyOrderElementsOf(result2); + } + + @Test + void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { + Player player1 = new Player("pobi"); + Player player2 = new Player("cary"); + + Players players = new Players(); + players.add(player1); + players.add(player2); + List records = players.getPlayers(); + Dealer dealer = new Dealer(); + GameManager manager = new GameManager(); + + manager.dealCards(records, dealer); + assertThat(player1.getHand().size()).isEqualTo(2); + assertThat(player2.getHand().size()).isEqualTo(2); + assertThat(dealer.getHand().size()).isEqualTo(2); } } diff --git a/src/test/java/GameManager.java b/src/test/java/GameManager.java new file mode 100644 index 00000000000..53414520364 --- /dev/null +++ b/src/test/java/GameManager.java @@ -0,0 +1,19 @@ +import java.util.List; + +public class GameManager { + private Deck deck = new Deck(); + + public GameManager() { + deck.init(); + deck.shuffle(); + } + + public void dealCards(List records, Dealer dealer) { + for (int i = 0; i < 2; i++) { + for (Player player : records) { + player.addCard(deck.draw()); + } + dealer.addCard(deck.draw()); + } + } +} diff --git a/src/test/java/Player.java b/src/test/java/Player.java index 318fc222333..163b94d876f 100644 --- a/src/test/java/Player.java +++ b/src/test/java/Player.java @@ -1,5 +1,9 @@ +import java.util.ArrayList; +import java.util.List; + public class Player { private String name; + private List hand = new ArrayList<>(); public Player(String name) { this.name = name; @@ -8,4 +12,12 @@ public Player(String name) { public String getName() { return name; } + + public void addCard(Card card) { + hand.add(card); + } + + public List getHand() { + return List.copyOf(hand); + } } From 6975c3f8efcc2ea4c69871336a3a2e6e32752ea0 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:37:00 +0900 Subject: [PATCH 09/88] =?UTF-8?q?feat:=20J,=20Q,=20K,=20A=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=EC=B2=98=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/java/Rank.java | 37 +++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index bb8515c5e4e..bf1534c75fa 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ - [x] 카드를 돌린다. ### 카드 점수 계산 -- [ ] J,Q,K는 10으로 처리한다. -- [ ] Ace는 1점으로 처리한다. +- [x] J,Q,K는 10으로 처리한다. +- [x] Ace는 1점으로 처리한다. - [ ] 카드 점수를 합산한다. ### Ace 1/11 처리 diff --git a/src/main/java/Rank.java b/src/main/java/Rank.java index 9b794290661..4f7290da0f6 100644 --- a/src/main/java/Rank.java +++ b/src/main/java/Rank.java @@ -1,15 +1,24 @@ public enum Rank { - ACE, - TWO, - THREE, - FOUR, - FIVE, - SIX, - SEVEN, - EIGHT, - NINE, - TEN, - JACK, - QUEEN, - KING -} + ACE(1), + TWO(2), + THREE(3), + FOUR(4), + FIVE(5), + SIX(6), + SEVEN(7), + EIGHT(8), + NINE(9), + TEN(10), + JACK(10), + QUEEN(10), + KING(10); + + private final int value; + + Rank(int value) { + this.value = value; + } + + public int getValue() { + return value; +}} From a80668010452735d6e7c6efa6ba35108e0d382b8 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:43:26 +0900 Subject: [PATCH 10/88] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/DeckTest.java | 19 ------------------- src/test/java/GameManagerTest.java | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 src/test/java/GameManagerTest.java diff --git a/src/test/java/DeckTest.java b/src/test/java/DeckTest.java index 83404952939..19a70915e11 100644 --- a/src/test/java/DeckTest.java +++ b/src/test/java/DeckTest.java @@ -66,23 +66,4 @@ public class DeckTest { assertThat(result1.size()).isEqualTo(result2.size()); assertThat(result1).containsExactlyInAnyOrderElementsOf(result2); } - - @Test - void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { - Player player1 = new Player("pobi"); - Player player2 = new Player("cary"); - - Players players = new Players(); - players.add(player1); - players.add(player2); - List records = players.getPlayers(); - Dealer dealer = new Dealer(); - GameManager manager = new GameManager(); - - manager.dealCards(records, dealer); - - assertThat(player1.getHand().size()).isEqualTo(2); - assertThat(player2.getHand().size()).isEqualTo(2); - assertThat(dealer.getHand().size()).isEqualTo(2); - } } diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java new file mode 100644 index 00000000000..b8ae95731c1 --- /dev/null +++ b/src/test/java/GameManagerTest.java @@ -0,0 +1,27 @@ +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GameManagerTest { + + @Test + void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { + Player player1 = new Player("pobi"); + Player player2 = new Player("cary"); + + Players players = new Players(); + players.add(player1); + players.add(player2); + List records = players.getPlayers(); + Dealer dealer = new Dealer(); + GameManager manager = new GameManager(); + + manager.dealCards(records, dealer); + + assertThat(player1.getHand().size()).isEqualTo(2); + assertThat(player2.getHand().size()).isEqualTo(2); + assertThat(dealer.getHand().size()).isEqualTo(2); + } +} \ No newline at end of file From 426d150e3e857e306f872ddb1be4254d02a7e376 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:49:51 +0900 Subject: [PATCH 11/88] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/{test => main}/java/Dealer.java | 0 src/{test => main}/java/GameManager.java | 0 src/{test => main}/java/Player.java | 0 src/{test => main}/java/Players.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/{test => main}/java/Dealer.java (100%) rename src/{test => main}/java/GameManager.java (100%) rename src/{test => main}/java/Player.java (100%) rename src/{test => main}/java/Players.java (100%) diff --git a/src/test/java/Dealer.java b/src/main/java/Dealer.java similarity index 100% rename from src/test/java/Dealer.java rename to src/main/java/Dealer.java diff --git a/src/test/java/GameManager.java b/src/main/java/GameManager.java similarity index 100% rename from src/test/java/GameManager.java rename to src/main/java/GameManager.java diff --git a/src/test/java/Player.java b/src/main/java/Player.java similarity index 100% rename from src/test/java/Player.java rename to src/main/java/Player.java diff --git a/src/test/java/Players.java b/src/main/java/Players.java similarity index 100% rename from src/test/java/Players.java rename to src/main/java/Players.java From cb3496316d68a1eb50905211ca991d01327e4b1c Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:50:03 +0900 Subject: [PATCH 12/88] =?UTF-8?q?test:=20=EC=B9=B4=EB=93=9C=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=ED=95=A9=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/ScoreCalculator.java | 2 ++ src/test/java/ScoreCalculatorTest.java | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/test/java/ScoreCalculator.java create mode 100644 src/test/java/ScoreCalculatorTest.java diff --git a/README.md b/README.md index bf1534c75fa..9132c4fdd40 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ### 카드 덱 생성 + 셔플 - [x] 52장의 카드를 생성한다. - - [x] 카드는 무늬별 숫자순으로 생성된다. +- [x] 카드는 무늬별 숫자순으로 생성된다. - [x] 카드를 셔플한다. ### 플레이어/딜러 관리 diff --git a/src/test/java/ScoreCalculator.java b/src/test/java/ScoreCalculator.java new file mode 100644 index 00000000000..390f227156e --- /dev/null +++ b/src/test/java/ScoreCalculator.java @@ -0,0 +1,2 @@ +public class ScoreCalculator { +} diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/ScoreCalculatorTest.java new file mode 100644 index 00000000000..4302b2ec1fe --- /dev/null +++ b/src/test/java/ScoreCalculatorTest.java @@ -0,0 +1,18 @@ +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScoreCalculatorTest { + + @Test + void 카드_점수를_합산한다() { + ScoreCalculator calculator = new ScoreCalculator(); + List hand = List.of(new Card(Rank.JACK, Suit.SPADE), new Card(Rank.TEN, Suit.SPADE)); + + int currentScore = calculator.sumScore(hand); + + assertThat(currentScore).isEqualTo(20); + } +} From fddb58f0baad4c158a4594a11998672ff47a3c3f Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 20:53:09 +0900 Subject: [PATCH 13/88] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=ED=95=A9=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Card.java | 4 ++++ src/test/java/ScoreCalculator.java | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/Card.java b/src/main/java/Card.java index a6725627808..67c41194935 100644 --- a/src/main/java/Card.java +++ b/src/main/java/Card.java @@ -10,6 +10,10 @@ public Card(Rank rank, Suit suit) { this.suit = suit; } + public int getRank() { + return this.rank.getValue(); + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/src/test/java/ScoreCalculator.java b/src/test/java/ScoreCalculator.java index 390f227156e..96590d9f000 100644 --- a/src/test/java/ScoreCalculator.java +++ b/src/test/java/ScoreCalculator.java @@ -1,2 +1,11 @@ +import java.util.List; + public class ScoreCalculator { + public int sumScore(List hand) { + int score = 0; + for (Card card : hand) { + score += card.getRank(); + } + return score; + } } From 969d642a437c1fde2e52c5798491a2019144c4a0 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 21:02:34 +0900 Subject: [PATCH 14/88] =?UTF-8?q?test:=20Ace=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/ScoreCalculatorTest.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9132c4fdd40..0d2d185777f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ### 카드 점수 계산 - [x] J,Q,K는 10으로 처리한다. - [x] Ace는 1점으로 처리한다. -- [ ] 카드 점수를 합산한다. +- [x] 카드 점수를 합산한다. ### Ace 1/11 처리 - [ ] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/ScoreCalculatorTest.java index 4302b2ec1fe..97f0f7d9d7a 100644 --- a/src/test/java/ScoreCalculatorTest.java +++ b/src/test/java/ScoreCalculatorTest.java @@ -15,4 +15,15 @@ public class ScoreCalculatorTest { assertThat(currentScore).isEqualTo(20); } + + @Test + void 핸드에_A가_있고_합산점수가_11점_이하면_10점을_추가한다() { + ScoreCalculator calculator = new ScoreCalculator(); + List hand = List.of(new Card(Rank.ACE, Suit.SPADE), new Card(Rank.KING, Suit.SPADE)); + + int currentScore = calculator.sumScore(hand); + int finalScore = calculator.checkAce(currentScore, hand); + + assertThat(currentScore).isEqualTo(21); + } } From 2039b007a817ca10df6d4a3f935632f684eb9207 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 21:10:03 +0900 Subject: [PATCH 15/88] =?UTF-8?q?feat:=20Ace=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/test/java/ScoreCalculator.java | 15 +++++++++++++++ src/test/java/ScoreCalculatorTest.java | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d2d185777f..16a42dbab73 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ - [x] 카드 점수를 합산한다. ### Ace 1/11 처리 -- [ ] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. +- [x] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. ### 버스트 판정 - [ ] 21점이 넘으면 버스트 diff --git a/src/test/java/ScoreCalculator.java b/src/test/java/ScoreCalculator.java index 96590d9f000..9ceed9158f1 100644 --- a/src/test/java/ScoreCalculator.java +++ b/src/test/java/ScoreCalculator.java @@ -8,4 +8,19 @@ public int sumScore(List hand) { } return score; } + + public int checkAce(int currentScore, List hand) { + Card findCard + = hand.stream().filter(c -> c.getRank() == 1).findAny().orElse(null); + + if (findCard == null) { + return currentScore; + } + + if (currentScore + 10 > 21) { + return currentScore; + } + + return currentScore + 10; + } } diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/ScoreCalculatorTest.java index 97f0f7d9d7a..f136adec910 100644 --- a/src/test/java/ScoreCalculatorTest.java +++ b/src/test/java/ScoreCalculatorTest.java @@ -24,6 +24,20 @@ public class ScoreCalculatorTest { int currentScore = calculator.sumScore(hand); int finalScore = calculator.checkAce(currentScore, hand); - assertThat(currentScore).isEqualTo(21); + assertThat(finalScore).isEqualTo(21); + } + + @Test + void 핸드에_A가_있고_합산점수가_11점_초과이면_원래점수를_사용한다() { + ScoreCalculator calculator = new ScoreCalculator(); + List hand = List.of( + new Card(Rank.ACE, Suit.SPADE), + new Card(Rank.ACE, Suit.HEART), + new Card(Rank.KING, Suit.HEART)); + + int currentScore = calculator.sumScore(hand); + int finalScore = calculator.checkAce(currentScore, hand); + + assertThat(finalScore).isEqualTo(12); } } From 2892a54ef92ab0930c640fad66ec5d494e48807e Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 21:15:20 +0900 Subject: [PATCH 16/88] =?UTF-8?q?refactor:=20=EC=A0=90=EC=88=98=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/ScoreCalculator.java | 6 ++++-- src/test/java/ScoreCalculatorTest.java | 14 ++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/java/ScoreCalculator.java b/src/test/java/ScoreCalculator.java index 9ceed9158f1..a588e9aedb9 100644 --- a/src/test/java/ScoreCalculator.java +++ b/src/test/java/ScoreCalculator.java @@ -1,7 +1,7 @@ import java.util.List; public class ScoreCalculator { - public int sumScore(List hand) { + private int sumScore(List hand) { int score = 0; for (Card card : hand) { score += card.getRank(); @@ -9,7 +9,9 @@ public int sumScore(List hand) { return score; } - public int checkAce(int currentScore, List hand) { + public int calculateScore(List hand) { + int currentScore = sumScore(hand); + Card findCard = hand.stream().filter(c -> c.getRank() == 1).findAny().orElse(null); diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/ScoreCalculatorTest.java index f136adec910..bcccbc75f0c 100644 --- a/src/test/java/ScoreCalculatorTest.java +++ b/src/test/java/ScoreCalculatorTest.java @@ -11,9 +11,9 @@ public class ScoreCalculatorTest { ScoreCalculator calculator = new ScoreCalculator(); List hand = List.of(new Card(Rank.JACK, Suit.SPADE), new Card(Rank.TEN, Suit.SPADE)); - int currentScore = calculator.sumScore(hand); + int score = calculator.calculateScore(hand); - assertThat(currentScore).isEqualTo(20); + assertThat(score).isEqualTo(20); } @Test @@ -21,10 +21,9 @@ public class ScoreCalculatorTest { ScoreCalculator calculator = new ScoreCalculator(); List hand = List.of(new Card(Rank.ACE, Suit.SPADE), new Card(Rank.KING, Suit.SPADE)); - int currentScore = calculator.sumScore(hand); - int finalScore = calculator.checkAce(currentScore, hand); + int score = calculator.calculateScore(hand); - assertThat(finalScore).isEqualTo(21); + assertThat(score).isEqualTo(21); } @Test @@ -35,9 +34,8 @@ public class ScoreCalculatorTest { new Card(Rank.ACE, Suit.HEART), new Card(Rank.KING, Suit.HEART)); - int currentScore = calculator.sumScore(hand); - int finalScore = calculator.checkAce(currentScore, hand); + int score = calculator.calculateScore(hand); - assertThat(finalScore).isEqualTo(12); + assertThat(score).isEqualTo(12); } } From 1a8250b974f568cad26d347f1de2ded85f1bf187 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 21:36:05 +0900 Subject: [PATCH 17/88] =?UTF-8?q?feat:=20=EB=B2=84=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/GameManager.java | 7 +++++++ src/main/java/Player.java | 9 +++++++++ src/{test => main}/java/ScoreCalculator.java | 4 ++++ src/test/java/ScoreCalculatorTest.java | 8 ++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) rename src/{test => main}/java/ScoreCalculator.java (89%) diff --git a/README.md b/README.md index 16a42dbab73..74fa52bdad0 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ - [x] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. ### 버스트 판정 -- [ ] 21점이 넘으면 버스트 +- [x] 21점이 넘으면 버스트 ### 히트/스탠드 입력 - [ ] 버스트가 아니면 히트/스탠드를 입력받는다. diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 53414520364..79c5312b3c8 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -2,6 +2,7 @@ public class GameManager { private Deck deck = new Deck(); + private ScoreCalculator scoreCalculator = new ScoreCalculator(); public GameManager() { deck.init(); @@ -16,4 +17,10 @@ public void dealCards(List records, Dealer dealer) { dealer.addCard(deck.draw()); } } + + public void judgeBust(int score, Player currentPlayer) { + if (scoreCalculator.isBust(score)) { + currentPlayer.setBust(); + } + } } diff --git a/src/main/java/Player.java b/src/main/java/Player.java index 163b94d876f..20314871cf5 100644 --- a/src/main/java/Player.java +++ b/src/main/java/Player.java @@ -4,6 +4,15 @@ public class Player { private String name; private List hand = new ArrayList<>(); + private boolean isBust = false; + + public boolean isBust() { + return isBust; + } + + public void setBust() { + isBust = true; + } public Player(String name) { this.name = name; diff --git a/src/test/java/ScoreCalculator.java b/src/main/java/ScoreCalculator.java similarity index 89% rename from src/test/java/ScoreCalculator.java rename to src/main/java/ScoreCalculator.java index a588e9aedb9..feb03123201 100644 --- a/src/test/java/ScoreCalculator.java +++ b/src/main/java/ScoreCalculator.java @@ -25,4 +25,8 @@ public int calculateScore(List hand) { return currentScore + 10; } + + public boolean isBust(int score) { + return score > 21; + } } diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/ScoreCalculatorTest.java index bcccbc75f0c..3201dcbf3d2 100644 --- a/src/test/java/ScoreCalculatorTest.java +++ b/src/test/java/ScoreCalculatorTest.java @@ -38,4 +38,12 @@ public class ScoreCalculatorTest { assertThat(score).isEqualTo(12); } + + @Test + void 핸드가_21점이_넘으면_버스트다() { + ScoreCalculator calculator = new ScoreCalculator(); + boolean result = calculator.isBust(22); + + assertThat(result).isTrue(); + } } From 0610c2633a55df14e95622f31ea675c3e057cc46 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Wed, 4 Mar 2026 22:02:16 +0900 Subject: [PATCH 18/88] =?UTF-8?q?feat:=20=EC=8B=A4=ED=96=89=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 10 +++++++++ src/main/java/Deck.java | 1 - src/main/java/GameController.java | 37 +++++++++++++++++++++++++++++++ src/main/java/GameManager.java | 8 +++++++ src/main/java/Player.java | 9 +++++++- src/main/java/Players.java | 2 +- 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/GameController.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000000..beb2a78f3c6 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,10 @@ +public class Application { + + public static void main(String[] args) { + + GameManager manager = new GameManager(); + + GameController controller = new GameController(manager); + controller.run(); + } +} diff --git a/src/main/java/Deck.java b/src/main/java/Deck.java index ffbd601b0ca..268b0abccdc 100644 --- a/src/main/java/Deck.java +++ b/src/main/java/Deck.java @@ -23,6 +23,5 @@ public Card draw() { public void shuffle() { Collections.shuffle(cards); - System.out.println("cards = " + cards); } } diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java new file mode 100644 index 00000000000..f494ba2692b --- /dev/null +++ b/src/main/java/GameController.java @@ -0,0 +1,37 @@ +public class GameController { + + private GameManager manager; + + public GameController(GameManager manager) { + this.manager = manager; + } + + public void run() { + + // 플레이어 등록 + Players players = new Players(); + players.add(new Player("pobi")); + players.add(new Player("cary")); + + // 카드 뿌리기 + Dealer dealer = new Dealer(); + manager.dealCards(players.getPlayers(), dealer); + + for (Player player : players.getPlayers()) { + while (!player.isBust()) { + int score = manager.calculateScore(player.getHand()); + manager.judgeBust(score, player); + if (player.isBust()) { + continue; + } + manager.drawCard(player); + } + } + + for (Player player : players.getPlayers()) { + System.out.println("player = " + player); + } + + + } +} diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 79c5312b3c8..47151832bcb 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -23,4 +23,12 @@ public void judgeBust(int score, Player currentPlayer) { currentPlayer.setBust(); } } + + public int calculateScore(List hand) { + return scoreCalculator.calculateScore(hand); + } + + public void drawCard(Player player) { + player.addCard(deck.draw()); + } } diff --git a/src/main/java/Player.java b/src/main/java/Player.java index 20314871cf5..9389dd5406e 100644 --- a/src/main/java/Player.java +++ b/src/main/java/Player.java @@ -29,4 +29,11 @@ public void addCard(Card card) { public List getHand() { return List.copyOf(hand); } -} + +@Override public String toString() { + return "Player{" + + "name='" + name + '\'' + + ", hand=" + hand + + ", isBust=" + isBust + + '}'; +}} diff --git a/src/main/java/Players.java b/src/main/java/Players.java index 1c6ede940b4..71ef2919ce5 100644 --- a/src/main/java/Players.java +++ b/src/main/java/Players.java @@ -2,7 +2,7 @@ import java.util.List; public class Players { - List players = new ArrayList<>(); + private List players = new ArrayList<>(); public void add(Player player) { From d9861e25de8fb286e1079c4a92799d5da4e990b2 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 16:54:36 +0900 Subject: [PATCH 19/88] =?UTF-8?q?refactor:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EB=93=B1=EB=A1=9D=20=EB=B0=8F=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=20=EC=A4=80=EB=B9=84=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 2 +- src/main/java/GameManager.java | 35 ++++++++++++++++- src/main/java/GameScoreResultDto.java | 37 ++++++++++++++++++ src/main/java/Player.java | 19 ++++++---- src/test/java/GameManagerTest.java | 54 ++++++++++++++++++++++----- 5 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 src/main/java/GameScoreResultDto.java diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index f494ba2692b..df490e44083 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -15,7 +15,7 @@ public void run() { // 카드 뿌리기 Dealer dealer = new Dealer(); - manager.dealCards(players.getPlayers(), dealer); + manager.startGame(); for (Player player : players.getPlayers()) { while (!player.isBust()) { diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 47151832bcb..11dd5d1b436 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -1,17 +1,20 @@ +import java.util.ArrayList; import java.util.List; public class GameManager { private Deck deck = new Deck(); private ScoreCalculator scoreCalculator = new ScoreCalculator(); + private Players players = new Players(); + private Dealer dealer = new Dealer(); public GameManager() { deck.init(); deck.shuffle(); } - public void dealCards(List records, Dealer dealer) { + public void startGame() { for (int i = 0; i < 2; i++) { - for (Player player : records) { + for (Player player : players.getPlayers()) { player.addCard(deck.draw()); } dealer.addCard(deck.draw()); @@ -31,4 +34,32 @@ public int calculateScore(List hand) { public void drawCard(Player player) { player.addCard(deck.draw()); } + + public void addPlayer(String name) { + players.add(new Player(name)); + } + + public List getPlayerSequence() { + return players.getPlayers(); + } + + public List getScoreResults(){ + List results = new ArrayList<>(); + // dealer + results.add(new GameScoreResultDto( + dealer.getName(), + dealer.getHandToString(), + scoreCalculator.calculateScore(dealer.getHand()) + )); + //players + for (Player player : players.getPlayers()) { + results.add(new GameScoreResultDto( + player.getName(), + player.getHandToString(), + scoreCalculator.calculateScore(dealer.getHand()) + )); + } + + return results; + } } diff --git a/src/main/java/GameScoreResultDto.java b/src/main/java/GameScoreResultDto.java new file mode 100644 index 00000000000..1078a314e41 --- /dev/null +++ b/src/main/java/GameScoreResultDto.java @@ -0,0 +1,37 @@ +import java.util.List; + +public class GameScoreResultDto { + String playerName; + List hand; + int result; + + public GameScoreResultDto(String playerName, List hand, int result) { + this.playerName = playerName; + this.hand = hand; + this.result = result; + } + + public String getPlayerName() { + return playerName; + } + + public void setPlayerName(String playerName) { + this.playerName = playerName; + } + + public List getHand() { + return hand; + } + + public void setHand(List hand) { + this.hand = hand; + } + + public int getResult() { + return result; + } + + public void setResult(int result) { + this.result = result; + } +} diff --git a/src/main/java/Player.java b/src/main/java/Player.java index 9389dd5406e..57a01bed0b6 100644 --- a/src/main/java/Player.java +++ b/src/main/java/Player.java @@ -30,10 +30,15 @@ public List getHand() { return List.copyOf(hand); } -@Override public String toString() { - return "Player{" + - "name='" + name + '\'' + - ", hand=" + hand + - ", isBust=" + isBust + - '}'; -}} + public List getHandToString() { + return hand.stream().map(Card::toString).toList(); + } + + @Override + public String toString() { + return "Player{" + + "name='" + name + '\'' + + ", hand=" + hand + + ", isBust=" + isBust + + '}'; + }} diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index b8ae95731c1..a1336a95aa3 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -1,5 +1,6 @@ import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -8,20 +9,53 @@ class GameManagerTest { @Test void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { - Player player1 = new Player("pobi"); - Player player2 = new Player("cary"); + GameManager manager = new GameManager(); + + manager.addPlayer("pobi"); + manager.addPlayer("cary"); + + manager.startGame(); + List scoreResults = manager.getScoreResults(); - Players players = new Players(); - players.add(player1); - players.add(player2); - List records = players.getPlayers(); + List records = manager.getPlayerSequence(); Dealer dealer = new Dealer(); + + assertThat(scoreResults.get(0).getHand().size()).isEqualTo(2); + assertThat(scoreResults.get(0).getPlayerName()).isEqualTo("딜러"); + assertThat(scoreResults.get(1).getHand().size()).isEqualTo(2); + assertThat(scoreResults.get(1).getPlayerName()).isEqualTo("pobi"); + assertThat(scoreResults.get(2).getHand().size()).isEqualTo(2); + assertThat(scoreResults.get(2).getPlayerName()).isEqualTo("cary"); + } + + @Test + void 플레이어를_한명_등록한다() { GameManager manager = new GameManager(); + manager.addPlayer("pobi"); - manager.dealCards(records, dealer); + List result = manager.getPlayerSequence(); - assertThat(player1.getHand().size()).isEqualTo(2); - assertThat(player2.getHand().size()).isEqualTo(2); - assertThat(dealer.getHand().size()).isEqualTo(2); + assertThat(result.size()).isEqualTo(1); + assertThat(result.getFirst().getName()).isEqualTo("pobi"); } + + @Test + void 플레이어를_세명_등록한다() { + GameManager manager = new GameManager(); + List playerNames = List.of("pobi", "cary", "rudy"); + + for (String playerName : playerNames) { + manager.addPlayer(playerName); + } + + List result = manager.getPlayerSequence(); + + assertThat(result.size()).isEqualTo(3); + } + + @Test + void 게임을_시작하면_카드를_2장씩_나눠준다() { + GameManager manager = new GameManager(); + } + } \ No newline at end of file From c8768681f555f0b9492a6476da8dce336ea6e28b Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 17:16:52 +0900 Subject: [PATCH 20/88] =?UTF-8?q?test:=20=EA=B2=8C=EC=9E=84=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=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/main/java/GameController.java | 18 ++++++++----- src/main/java/GameInitialInfoDto.java | 38 +++++++++++++++++++++++++++ src/main/java/GameManager.java | 4 +++ src/test/java/GameManagerTest.java | 27 ++++++++++++++++--- 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 src/main/java/GameInitialInfoDto.java diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index df490e44083..e257ed1fb9a 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -1,3 +1,5 @@ +import java.util.List; + public class GameController { private GameManager manager; @@ -8,15 +10,16 @@ public GameController(GameManager manager) { public void run() { - // 플레이어 등록 - Players players = new Players(); - players.add(new Player("pobi")); - players.add(new Player("cary")); - - // 카드 뿌리기 - Dealer dealer = new Dealer(); + List playerName = List.of("pobi", "cary"); + // 카드를 2장씩 세팅 manager.startGame(); + + + + + + /* for (Player player : players.getPlayers()) { while (!player.isBust()) { int score = manager.calculateScore(player.getHand()); @@ -31,6 +34,7 @@ public void run() { for (Player player : players.getPlayers()) { System.out.println("player = " + player); } + */ } diff --git a/src/main/java/GameInitialInfoDto.java b/src/main/java/GameInitialInfoDto.java new file mode 100644 index 00000000000..ee391d09ae9 --- /dev/null +++ b/src/main/java/GameInitialInfoDto.java @@ -0,0 +1,38 @@ +import java.util.List; + +public class GameInitialInfoDto { + + private String playerName; + private int initialHandSize; + private List hand; + + public GameInitialInfoDto(String playerName, int initialHandSize, List hand) { + this.playerName = playerName; + this.initialHandSize = initialHandSize; + this.hand = hand; + } + + public String getPlayerName() { + return playerName; + } + + public void setPlayerName(String playerName) { + this.playerName = playerName; + } + + public int getInitialHandSize() { + return initialHandSize; + } + + public void setInitialHandSize(int initialHandSize) { + this.initialHandSize = initialHandSize; + } + + public List getHand() { + return hand; + } + + public void setHand(List hand) { + this.hand = hand; + } +} diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 11dd5d1b436..0db8f17ce85 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -62,4 +62,8 @@ public List getScoreResults(){ return results; } + + public List getInitialInfo() { + return null; + } } diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index a1336a95aa3..f1cf0233c7e 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -17,9 +17,6 @@ class GameManagerTest { manager.startGame(); List scoreResults = manager.getScoreResults(); - List records = manager.getPlayerSequence(); - Dealer dealer = new Dealer(); - assertThat(scoreResults.get(0).getHand().size()).isEqualTo(2); assertThat(scoreResults.get(0).getPlayerName()).isEqualTo("딜러"); assertThat(scoreResults.get(1).getHand().size()).isEqualTo(2); @@ -28,6 +25,30 @@ class GameManagerTest { assertThat(scoreResults.get(2).getPlayerName()).isEqualTo("cary"); } + @Test + void 딜러의_카드는_한_장만_공개한다() { + GameManager manager = new GameManager(); + + manager.addPlayer("pobi"); + + manager.startGame(); + List initialInfo = manager.getInitialInfo(); + + assertThat(initialInfo.getFirst().getHand().size()).isEqualTo(1); + } + + @Test + void 플레이어의_카드는_두_장_공개한다() { + GameManager manager = new GameManager(); + + manager.addPlayer("pobi"); + + manager.startGame(); + List initialInfo = manager.getInitialInfo(); + + assertThat(initialInfo.get(1).getHand().size()).isEqualTo(2); + } + @Test void 플레이어를_한명_등록한다() { GameManager manager = new GameManager(); From e4516edc614ad487a1e53de573df56bcc6cc8b5f Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 17:24:29 +0900 Subject: [PATCH 21/88] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=84=EB=8B=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameManager.java | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 0db8f17ce85..736b824d234 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -64,6 +64,27 @@ public List getScoreResults(){ } public List getInitialInfo() { - return null; + List results = new ArrayList<>(); + + // 딜러 첫 카드 공개 + List dealerOpenCard = new ArrayList<>(); + dealerOpenCard.add(dealer.getHandToString().getFirst()); + + // dealer + results.add(new GameInitialInfoDto( + dealer.getName(), + 2, + dealerOpenCard + )); + //players + for (Player player : players.getPlayers()) { + results.add(new GameInitialInfoDto( + player.getName(), + 2, + player.getHandToString() + )); + } + + return results; } } From 5984dcf25716a69a73da81862ec197f613c2a643 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 17:56:05 +0900 Subject: [PATCH 22/88] =?UTF-8?q?test:=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 20 +++++++++++++++++++- src/main/java/GameManager.java | 8 +++++++- src/main/java/Player.java | 20 ++++++++++---------- src/test/java/GameManagerTest.java | 10 ++++++++++ 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index e257ed1fb9a..c92690366df 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -9,12 +9,30 @@ public GameController(GameManager manager) { } public void run() { - + // 플레이어 입력 List playerName = List.of("pobi", "cary"); + // 카드를 2장씩 세팅 manager.startGame(); + // 초기 정보 표출 + List initialInfo = manager.getInitialInfo(); + + for (Player player : manager.getPlayerSequence()) { + while (true) { + if (!player.isBust()) { + break; + } + +// if (view.isYes().equals("n")) { +// break; +// } + List playerHand = manager.drawCard(player); + + + } + } diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 736b824d234..45dec0dbe3d 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -31,8 +31,10 @@ public int calculateScore(List hand) { return scoreCalculator.calculateScore(hand); } - public void drawCard(Player player) { + public List drawCard(Player player) { player.addCard(deck.draw()); + judgeBust(calculateScore(player.getHand()), player); + return player.getHandToString(); } public void addPlayer(String name) { @@ -87,4 +89,8 @@ public List getInitialInfo() { return results; } + + public boolean isBlackjack(Player player) { + return false; + } } diff --git a/src/main/java/Player.java b/src/main/java/Player.java index 57a01bed0b6..cd0d77a67d4 100644 --- a/src/main/java/Player.java +++ b/src/main/java/Player.java @@ -6,26 +6,22 @@ public class Player { private List hand = new ArrayList<>(); private boolean isBust = false; - public boolean isBust() { - return isBust; - } - - public void setBust() { - isBust = true; - } - public Player(String name) { this.name = name; } - public String getName() { - return name; + public boolean isBust() { + return isBust; } public void addCard(Card card) { hand.add(card); } + public String getName() { + return name; + } + public List getHand() { return List.copyOf(hand); } @@ -34,6 +30,10 @@ public List getHandToString() { return hand.stream().map(Card::toString).toList(); } + public void setBust() { + isBust = true; + } + @Override public String toString() { return "Player{" + diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index f1cf0233c7e..cc1d7df0607 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -79,4 +79,14 @@ class GameManagerTest { GameManager manager = new GameManager(); } + @Test + void 합계가_21점이면_블랙잭이다() { + GameManager manager = new GameManager(); + Player player = new Player("pobi"); + player.addCard(new Card(Rank.ACE, Suit.SPADE)); + player.addCard(new Card(Rank.KING, Suit.SPADE)); + + assertThat(manager.isBlackjack(player)).isTrue(); + } + } \ No newline at end of file From 86e65eab92846f331ce651f34d696c8a1cb15854 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 17:57:26 +0900 Subject: [PATCH 23/88] =?UTF-8?q?feat:=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 45dec0dbe3d..adbb30998ad 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -91,6 +91,6 @@ public List getInitialInfo() { } public boolean isBlackjack(Player player) { - return false; + return calculateScore(player.getHand()) == 21; } } From 87d0052901821a0891615730438ed9bb3bbeeb00 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 17:59:13 +0900 Subject: [PATCH 24/88] =?UTF-8?q?test:=20=EB=B8=94=EB=9E=99=EC=9E=AD=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BC=80=EC=9D=B4=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 --- src/test/java/GameManagerTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index cc1d7df0607..e3cf6b704e5 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -89,4 +89,14 @@ class GameManagerTest { assertThat(manager.isBlackjack(player)).isTrue(); } + @Test + void 합계가_21점이_아니면_블랙잭이_아니다() { + GameManager manager = new GameManager(); + Player player = new Player("pobi"); + player.addCard(new Card(Rank.TEN, Suit.SPADE)); + player.addCard(new Card(Rank.KING, Suit.SPADE)); + + assertThat(manager.isBlackjack(player)).isFalse(); + } + } \ No newline at end of file From 00142ff2125bb4b09cd34eaf64ffa54c3352eed6 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 18:06:55 +0900 Subject: [PATCH 25/88] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 37 +++++++------------------------ 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index c92690366df..2138b569b21 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -1,4 +1,5 @@ import java.util.List; +import java.util.Scanner; public class GameController { @@ -10,7 +11,8 @@ public GameController(GameManager manager) { public void run() { // 플레이어 입력 - List playerName = List.of("pobi", "cary"); + manager.addPlayer("pobi"); + manager.addPlayer("cary"); // 카드를 2장씩 세팅 manager.startGame(); @@ -20,40 +22,17 @@ public void run() { for (Player player : manager.getPlayerSequence()) { while (true) { - if (!player.isBust()) { + if (player.isBust() || manager.isBlackjack(player)) { break; } -// if (view.isYes().equals("n")) { -// break; -// } + if (new Scanner(System.in).nextLine().equals("n")) { + break; + } List playerHand = manager.drawCard(player); - - + System.out.println("playerHand = " + playerHand); } } - - - - - /* - for (Player player : players.getPlayers()) { - while (!player.isBust()) { - int score = manager.calculateScore(player.getHand()); - manager.judgeBust(score, player); - if (player.isBust()) { - continue; - } - manager.drawCard(player); - } - } - - for (Player player : players.getPlayers()) { - System.out.println("player = " + player); - } - */ - - } } From 7c6c131fffb8462e3ce0f53d7593191fd3ddfaaa Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 18:14:57 +0900 Subject: [PATCH 26/88] =?UTF-8?q?test:=20=EB=94=9C=EB=9F=AC=EA=B0=80=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EB=A5=BC=20=EB=B0=9B=EC=9D=84=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=EC=A7=80=20=ED=99=95=EC=9D=B8=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 --- src/main/java/GameController.java | 3 +++ src/test/java/GameManagerTest.java | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index 2138b569b21..b949b8d8683 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -20,6 +20,7 @@ public void run() { // 초기 정보 표출 List initialInfo = manager.getInitialInfo(); + // 플레이어 턴 실행 for (Player player : manager.getPlayerSequence()) { while (true) { if (player.isBust() || manager.isBlackjack(player)) { @@ -34,5 +35,7 @@ public void run() { System.out.println("playerHand = " + playerHand); } } + + } } diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index e3cf6b704e5..75025b147cf 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -99,4 +99,11 @@ class GameManagerTest { assertThat(manager.isBlackjack(player)).isFalse(); } + @Test + void 딜러가_17점_이상인지_확인한다() { + GameManager manager = new GameManager(); + + assertThat(manager.isDealerTurn()).isTrue(); + } + } \ No newline at end of file From f4ff0ab2f0698e329ad2fd87716022120a161731 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 18:17:44 +0900 Subject: [PATCH 27/88] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=EA=B0=80=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EB=A5=BC=20=EB=B0=9B=EC=9D=84=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=EC=A7=80=20=ED=99=95=EC=9D=B8=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 --- src/main/java/GameManager.java | 4 ++++ src/test/java/GameManagerTest.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index adbb30998ad..1479bd4cb66 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -93,4 +93,8 @@ public List getInitialInfo() { public boolean isBlackjack(Player player) { return calculateScore(player.getHand()) == 21; } + + public boolean isDealerTurn() { + return calculateScore(dealer.getHand()) <= 16; + } } diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index 75025b147cf..6db69008884 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -100,7 +100,7 @@ class GameManagerTest { } @Test - void 딜러가_17점_이상인지_확인한다() { + void 딜러가_16점_이하인지_확인한다() { GameManager manager = new GameManager(); assertThat(manager.isDealerTurn()).isTrue(); From 034a4da6f617325d3f811751a13f05a84f2747b7 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 18:28:50 +0900 Subject: [PATCH 28/88] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=20=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=EC=9A=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 5 ++++- src/main/java/GameManager.java | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index b949b8d8683..1eb2c5485af 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -31,11 +31,14 @@ public void run() { break; } - List playerHand = manager.drawCard(player); + List playerHand = manager.drawPlayerCard(player); System.out.println("playerHand = " + playerHand); } } + while (manager.isDealerTurn()) { + manager.drawDealerCard(); + } } } diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 1479bd4cb66..6dcfd944ec7 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -31,12 +31,18 @@ public int calculateScore(List hand) { return scoreCalculator.calculateScore(hand); } - public List drawCard(Player player) { + public List drawPlayerCard(Player player) { player.addCard(deck.draw()); judgeBust(calculateScore(player.getHand()), player); return player.getHandToString(); } + public List drawDealerCard() { + dealer.addCard(deck.draw()); + judgeBust(calculateScore(dealer.getHand()), dealer); + return dealer.getHandToString(); + } + public void addPlayer(String name) { players.add(new Player(name)); } From e28165f7a02be456c859742720570a9dd3e2eb19 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 19:08:12 +0900 Subject: [PATCH 29/88] =?UTF-8?q?feat:=20=EC=B5=9C=EC=A2=85=20=EC=8A=B9?= =?UTF-8?q?=ED=8C=A8=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 6 +++++ src/main/java/GameFinalResultDto.java | 29 ++++++++++++++++++++++++ src/main/java/GameManager.java | 32 ++++++++++++++++++++++++--- src/main/java/GameScoreResultDto.java | 9 ++++++++ src/main/java/Result.java | 3 +++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/main/java/GameFinalResultDto.java create mode 100644 src/main/java/Result.java diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index 1eb2c5485af..d4e8d01e94a 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -36,9 +36,15 @@ public void run() { } } + // 딜러 턴 실행 while (manager.isDealerTurn()) { manager.drawDealerCard(); } + // 점수 결과 출력 + System.out.println(manager.getScoreResults()); + + // 최종 승패 출력 + System.out.println(manager.getFinalResult()); } } diff --git a/src/main/java/GameFinalResultDto.java b/src/main/java/GameFinalResultDto.java new file mode 100644 index 00000000000..8ef58aff453 --- /dev/null +++ b/src/main/java/GameFinalResultDto.java @@ -0,0 +1,29 @@ +public class GameFinalResultDto { + String name; + Result result; + + public GameFinalResultDto(String name) { + this(name, null); + } + + public GameFinalResultDto(String name, Result result) { + this.name = name; + this.result = result; + } + + public String getName() { + return name; + } + + public Result getResult() { + return result; + } + + @Override + public String toString() { + return "GameFinalResultDto{" + + "name='" + name + '\'' + + ", result=" + result + + '}'; + } +} diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 6dcfd944ec7..d5fd38b1f66 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -51,20 +51,20 @@ public List getPlayerSequence() { return players.getPlayers(); } - public List getScoreResults(){ + public List getScoreResults() { List results = new ArrayList<>(); // dealer results.add(new GameScoreResultDto( dealer.getName(), dealer.getHandToString(), scoreCalculator.calculateScore(dealer.getHand()) - )); + )); //players for (Player player : players.getPlayers()) { results.add(new GameScoreResultDto( player.getName(), player.getHandToString(), - scoreCalculator.calculateScore(dealer.getHand()) + scoreCalculator.calculateScore(player.getHand()) )); } @@ -103,4 +103,30 @@ public boolean isBlackjack(Player player) { public boolean isDealerTurn() { return calculateScore(dealer.getHand()) <= 16; } + + public List getFinalResult() { + List results = new ArrayList<>(); + // 딜러 추가 + results.add(new GameFinalResultDto(dealer.getName())); + + // 플레이어 추가 + for (Player player : players.getPlayers()) { + int playerScore = calculateScore(player.getHand()); + int dealerScore = calculateScore(dealer.getHand()); + + if (playerScore > dealerScore) { + results.add(new GameFinalResultDto(player.getName(), Result.WIN)); + } + + if (playerScore == dealerScore) { + results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); + } + + if (playerScore < dealerScore) { + results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); + } + } + + return results; + } } diff --git a/src/main/java/GameScoreResultDto.java b/src/main/java/GameScoreResultDto.java index 1078a314e41..5a0231e3725 100644 --- a/src/main/java/GameScoreResultDto.java +++ b/src/main/java/GameScoreResultDto.java @@ -34,4 +34,13 @@ public int getResult() { public void setResult(int result) { this.result = result; } + + @Override + public String toString() { + return "GameScoreResultDto{" + + "playerName='" + playerName + '\'' + + ", hand=" + hand + + ", result=" + result + + '}'; + } } diff --git a/src/main/java/Result.java b/src/main/java/Result.java new file mode 100644 index 00000000000..8094857b95f --- /dev/null +++ b/src/main/java/Result.java @@ -0,0 +1,3 @@ +public enum Result { + WIN, DRAW, LOSE +} From 50b2d81b534ad562fbed912dd9c7697e14ce8336 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 19:49:01 +0900 Subject: [PATCH 30/88] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EC=A0=95=EB=B3=B4=20=EC=9E=85=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 4 +--- src/main/java/GameController.java | 13 ++++++++++--- src/main/java/InputView.java | 24 +++++++++++++++++++++++ src/main/java/OutputView.java | 32 +++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 src/main/java/InputView.java create mode 100644 src/main/java/OutputView.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java index beb2a78f3c6..858cfd03460 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -2,9 +2,7 @@ public class Application { public static void main(String[] args) { - GameManager manager = new GameManager(); - - GameController controller = new GameController(manager); + GameController controller = new GameController(new GameManager(), new InputView(), new OutputView()); controller.run(); } } diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index d4e8d01e94a..849c40835b1 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -4,21 +4,28 @@ public class GameController { private GameManager manager; + private InputView inputView; + private OutputView outputView; - public GameController(GameManager manager) { + public GameController(GameManager manager, InputView inputView, OutputView outputView) { this.manager = manager; + this.inputView = inputView; + this.outputView = outputView; } public void run() { // 플레이어 입력 - manager.addPlayer("pobi"); - manager.addPlayer("cary"); + List playerNames = inputView.readPlayerName(); + for (String playerName : playerNames) { + manager.addPlayer(playerName); + } // 카드를 2장씩 세팅 manager.startGame(); // 초기 정보 표출 List initialInfo = manager.getInitialInfo(); + outputView.printInitialInfo(initialInfo); // 플레이어 턴 실행 for (Player player : manager.getPlayerSequence()) { diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java new file mode 100644 index 00000000000..444abafd54e --- /dev/null +++ b/src/main/java/InputView.java @@ -0,0 +1,24 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + public List readPlayerName() { + Scanner scanner = new Scanner(System.in); + List playerNames = new ArrayList<>(); + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + String s = scanner.nextLine(); + System.out.println(); + + if (s == null || s.trim().isEmpty()) { + return new ArrayList<>(); + } + + return Arrays.stream(s.split(",")) + .map(String::trim) // split된 항목 앞 뒤 공백 제거 + .filter(c -> !c.isEmpty()) // 콤마가 두번 겹치는 경우 필터링 + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java new file mode 100644 index 00000000000..655a7c6956a --- /dev/null +++ b/src/main/java/OutputView.java @@ -0,0 +1,32 @@ +import java.text.MessageFormat; +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + private static final String DEAL_MESSAGE = "딜러와 {0}에게 {1}장을 나누었습니다."; + private static final String SHOW_HAND_MESSAGE = "{0}카드: {1}"; + + public void printInitialInfo(List initialInfo) { + String playerNames = initialInfo.stream() + .skip(1) // 0번은 딜러 + .map(GameInitialInfoDto::getPlayerName) + .collect(Collectors.joining(", ")); + + System.out.println(MessageFormat.format( + DEAL_MESSAGE, + playerNames, + initialInfo.getFirst().getInitialHandSize() + )); + + for (GameInitialInfoDto info : initialInfo) { + System.out.println(MessageFormat.format( + SHOW_HAND_MESSAGE, + info.getPlayerName(), + String.join(", ", info.getHand()) + )); + } + System.out.println(); + } + + +} From 681e322957b9628921cb377a8c435e1b0c3c383f Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 20:46:43 +0900 Subject: [PATCH 31/88] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameController.java | 9 ++-- src/main/java/InputView.java | 12 +++++ src/main/java/OutputView.java | 73 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index 849c40835b1..afe90ac37e2 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -34,24 +34,25 @@ public void run() { break; } - if (new Scanner(System.in).nextLine().equals("n")) { + if (inputView.readCommand(player.getName()).equals("n")) { break; } List playerHand = manager.drawPlayerCard(player); - System.out.println("playerHand = " + playerHand); + outputView.printHand(playerHand, player.getName()); } } // 딜러 턴 실행 while (manager.isDealerTurn()) { manager.drawDealerCard(); + outputView.printDealerTurn(); } // 점수 결과 출력 - System.out.println(manager.getScoreResults()); + outputView.printScoreResults(manager.getScoreResults()); // 최종 승패 출력 - System.out.println(manager.getFinalResult()); + outputView.printFinalResult(manager.getFinalResult()); } } diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java index 444abafd54e..06b58829108 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/InputView.java @@ -21,4 +21,16 @@ public List readPlayerName() { .filter(c -> !c.isEmpty()) // 콤마가 두번 겹치는 경우 필터링 .collect(Collectors.toList()); } + + public String readCommand(String playerName) { + Scanner sc = new Scanner(System.in); + while (true) { + System.out.println(playerName + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); + String input = sc.nextLine(); + if (input.equals("y") || input.equals("n")) { + return input; + } + System.out.println("y 혹은 n만 입력할 수 있습니다."); + } + } } diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java index 655a7c6956a..123a1041138 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/OutputView.java @@ -5,6 +5,7 @@ public class OutputView { private static final String DEAL_MESSAGE = "딜러와 {0}에게 {1}장을 나누었습니다."; private static final String SHOW_HAND_MESSAGE = "{0}카드: {1}"; + private static final String FINAL_RESULT_MESSAGE = "{0}: {1}"; public void printInitialInfo(List initialInfo) { String playerNames = initialInfo.stream() @@ -28,5 +29,77 @@ public void printInitialInfo(List initialInfo) { System.out.println(); } + public void printHand(List hand, String name) { + System.out.println(MessageFormat.format( + SHOW_HAND_MESSAGE, + name, + String.join(", ", hand) + )); + } + + public void printDealerTurn() { + System.out.println(); + System.out.println("딜러는 16이하라 한장의 카드를 더 받았습니다."); + } + + public void printScoreResults(List scoreResults) { + System.out.println(); + for (GameScoreResultDto scoreResult : scoreResults) { + System.out.println(MessageFormat.format( + SHOW_HAND_MESSAGE, + scoreResult.getPlayerName(), + String.join(", ", scoreResult.getHand()) + + " - 결과: " + scoreResult.getResult() + )); + } + System.out.println(); + } + + public void printFinalResult(List finalResult) { + System.out.println("## 최종 승패"); + + int winCount = 0; + int drawCount = 0; + int loseCount = 0; + GameFinalResultDto firstPlayer = finalResult.removeFirst(); + + for (GameFinalResultDto result : finalResult) { + if (result.getResult() == Result.LOSE) { + loseCount++; + continue; + } + + if (result.getResult() == Result.DRAW) { + drawCount++; + continue; + } + + winCount++; + } + + StringBuilder sb = new StringBuilder(); + sb.append(firstPlayer.getName()); + sb.append(": "); + if (winCount != 0) { + sb.append(winCount).append("승 "); + } + + if (drawCount != 0) { + sb.append(winCount).append("무 "); + } + + if (loseCount != 0) { + sb.append(winCount).append("패 "); + } + System.out.println(sb); + + for (GameFinalResultDto result : finalResult) { + System.out.println(MessageFormat.format( + FINAL_RESULT_MESSAGE, + result.getName(), + result.getResult() + )); + } + } } From c5be281059b68778422081c4f48402a7c11a4bba Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 21:08:59 +0900 Subject: [PATCH 32/88] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=9E=85=EC=B6=9C=EB=A0=A5=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 5 ++- src/main/java/GameController.java | 63 ++++++++++++++++--------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 858cfd03460..32f012ac091 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,8 +1,11 @@ public class Application { public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + GameManager manager = new GameManager(); - GameController controller = new GameController(new GameManager(), new InputView(), new OutputView()); + GameController controller = new GameController(manager, inputView, outputView); controller.run(); } } diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index afe90ac37e2..b7e4fbbac17 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -1,5 +1,4 @@ import java.util.List; -import java.util.Scanner; public class GameController { @@ -14,45 +13,49 @@ public GameController(GameManager manager, InputView inputView, OutputView outpu } public void run() { - // 플레이어 입력 - List playerNames = inputView.readPlayerName(); - for (String playerName : playerNames) { - manager.addPlayer(playerName); - } - - // 카드를 2장씩 세팅 - manager.startGame(); + registerPlayer(); + initGame(); + playPlayerTurn(); + playDealerTurn(); + outputView.printScoreResults(manager.getScoreResults()); + outputView.printFinalResult(manager.getFinalResult()); + } - // 초기 정보 표출 - List initialInfo = manager.getInitialInfo(); - outputView.printInitialInfo(initialInfo); + private void playDealerTurn() { + while (manager.isDealerTurn()) { + manager.drawDealerCard(); + outputView.printDealerTurn(); + } + } - // 플레이어 턴 실행 + private void playPlayerTurn() { for (Player player : manager.getPlayerSequence()) { - while (true) { - if (player.isBust() || manager.isBlackjack(player)) { - break; - } - - if (inputView.readCommand(player.getName()).equals("n")) { - break; - } - + while (isPlayerTurn(player) && isStand(player)) { List playerHand = manager.drawPlayerCard(player); outputView.printHand(playerHand, player.getName()); } } + } - // 딜러 턴 실행 - while (manager.isDealerTurn()) { - manager.drawDealerCard(); - outputView.printDealerTurn(); + private void registerPlayer() { + List playerNames = inputView.readPlayerName(); + for (String playerName : playerNames) { + manager.addPlayer(playerName); } + } - // 점수 결과 출력 - outputView.printScoreResults(manager.getScoreResults()); + private void initGame() { + manager.startGame(); - // 최종 승패 출력 - outputView.printFinalResult(manager.getFinalResult()); + List initialInfo = manager.getInitialInfo(); + outputView.printInitialInfo(initialInfo); + } + + private boolean isStand(Player player) { + return !inputView.readCommand(player.getName()).equals("n"); + } + + private boolean isPlayerTurn(Player player) { + return !(player.isBust() && manager.isBlackjack(player)); } } From 28b911a9f166c0ab44d58f58d690ed537b2a1837 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 21:13:22 +0900 Subject: [PATCH 33/88] =?UTF-8?q?refactor:=20InputView=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/InputView.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java index 06b58829108..30460590b65 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/InputView.java @@ -5,13 +5,21 @@ import java.util.stream.Collectors; public class InputView { + private static final String COMMAND_REINPUT_MESSAGE = "y 혹은 n만 입력할 수 있습니다."; + private static final String COMMAND_INPUT_MESSAGE = "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"; + private static final String PLAYER_NAMES_INPUT_MESSAGE = "게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"; + private static final List CORRECT_COMMAND_INPUT = List.of("y", "n"); + public List readPlayerName() { Scanner scanner = new Scanner(System.in); - List playerNames = new ArrayList<>(); - System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); - String s = scanner.nextLine(); + System.out.println(PLAYER_NAMES_INPUT_MESSAGE); + String input = scanner.nextLine(); System.out.println(); + return splitPlayerNameInput(input); + } + + private static List splitPlayerNameInput(String s) { if (s == null || s.trim().isEmpty()) { return new ArrayList<>(); } @@ -25,12 +33,12 @@ public List readPlayerName() { public String readCommand(String playerName) { Scanner sc = new Scanner(System.in); while (true) { - System.out.println(playerName + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"); + System.out.println(playerName + COMMAND_INPUT_MESSAGE); String input = sc.nextLine(); - if (input.equals("y") || input.equals("n")) { + if (CORRECT_COMMAND_INPUT.contains(input)) { return input; } - System.out.println("y 혹은 n만 입력할 수 있습니다."); + System.out.println(COMMAND_REINPUT_MESSAGE); } } } From fb32a2342877b2e0f02c6e8c1910a52b15c3fb45 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 21:47:52 +0900 Subject: [PATCH 34/88] =?UTF-8?q?refactor:=20OutputView=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=81=EC=88=98=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/OutputView.java | 95 +++++++++++++++++------------------ src/main/java/Result.java | 12 ++++- 2 files changed, 57 insertions(+), 50 deletions(-) diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java index 123a1041138..7437e456eb1 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/OutputView.java @@ -1,32 +1,18 @@ import java.text.MessageFormat; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class OutputView { private static final String DEAL_MESSAGE = "딜러와 {0}에게 {1}장을 나누었습니다."; private static final String SHOW_HAND_MESSAGE = "{0}카드: {1}"; private static final String FINAL_RESULT_MESSAGE = "{0}: {1}"; + private static final String DEALER_DRAW_MESSAGE = "딜러는 16이하라 한장의 카드를 더 받았습니다."; public void printInitialInfo(List initialInfo) { - String playerNames = initialInfo.stream() - .skip(1) // 0번은 딜러 - .map(GameInitialInfoDto::getPlayerName) - .collect(Collectors.joining(", ")); - - System.out.println(MessageFormat.format( - DEAL_MESSAGE, - playerNames, - initialInfo.getFirst().getInitialHandSize() - )); - - for (GameInitialInfoDto info : initialInfo) { - System.out.println(MessageFormat.format( - SHOW_HAND_MESSAGE, - info.getPlayerName(), - String.join(", ", info.getHand()) - )); - } - System.out.println(); + printHandOutNotice(initialInfo); + printInitialHands(initialInfo); } public void printHand(List hand, String name) { @@ -39,7 +25,7 @@ public void printHand(List hand, String name) { public void printDealerTurn() { System.out.println(); - System.out.println("딜러는 16이하라 한장의 카드를 더 받았습니다."); + System.out.println(DEALER_DRAW_MESSAGE); } public void printScoreResults(List scoreResults) { @@ -49,7 +35,7 @@ public void printScoreResults(List scoreResults) { SHOW_HAND_MESSAGE, scoreResult.getPlayerName(), String.join(", ", scoreResult.getHand()) - + " - 결과: " + scoreResult.getResult() + + " - 결과: " + scoreResult.getResult() )); } System.out.println(); @@ -57,43 +43,30 @@ public void printScoreResults(List scoreResults) { public void printFinalResult(List finalResult) { System.out.println("## 최종 승패"); - - int winCount = 0; - int drawCount = 0; - int loseCount = 0; - GameFinalResultDto firstPlayer = finalResult.removeFirst(); + Map resultCounts = new HashMap<>(); + countDealerResult(finalResult, resultCounts); + printDealerResult(firstPlayer, resultCounts); + printPlayerResult(finalResult); + } + private void countDealerResult(List finalResult, Map resultCounts) { for (GameFinalResultDto result : finalResult) { - if (result.getResult() == Result.LOSE) { - loseCount++; - continue; - } - - if (result.getResult() == Result.DRAW) { - drawCount++; - continue; - } - - winCount++; + Integer beforeCount = resultCounts.getOrDefault(result.result, 0); + resultCounts.put(result.result, ++beforeCount); } + } + private void printDealerResult(GameFinalResultDto firstPlayer, Map resultCounts) { StringBuilder sb = new StringBuilder(); - sb.append(firstPlayer.getName()); - sb.append(": "); - if (winCount != 0) { - sb.append(winCount).append("승 "); - } - - if (drawCount != 0) { - sb.append(winCount).append("무 "); - } - - if (loseCount != 0) { - sb.append(winCount).append("패 "); + sb.append(firstPlayer.getName()).append(": "); + for (Result result : resultCounts.keySet()) { + sb.append(resultCounts.get(result)).append(result.getName()); } System.out.println(sb); + } + private void printPlayerResult(List finalResult) { for (GameFinalResultDto result : finalResult) { System.out.println(MessageFormat.format( FINAL_RESULT_MESSAGE, @@ -102,4 +75,28 @@ public void printFinalResult(List finalResult) { )); } } + + private void printHandOutNotice(List initialInfo) { + String playerNames = initialInfo.stream() + .skip(1) // 0번은 딜러 + .map(GameInitialInfoDto::getPlayerName) + .collect(Collectors.joining(", ")); + + System.out.println(MessageFormat.format( + DEAL_MESSAGE, + playerNames, + initialInfo.getFirst().getInitialHandSize() + )); + } + + private void printInitialHands(List initialInfo) { + for (GameInitialInfoDto info : initialInfo) { + System.out.println(MessageFormat.format( + SHOW_HAND_MESSAGE, + info.getPlayerName(), + String.join(", ", info.getHand()) + )); + } + System.out.println(); + } } diff --git a/src/main/java/Result.java b/src/main/java/Result.java index 8094857b95f..9a37d5e46bb 100644 --- a/src/main/java/Result.java +++ b/src/main/java/Result.java @@ -1,3 +1,13 @@ public enum Result { - WIN, DRAW, LOSE + WIN("승"), DRAW("무"), LOSE("패"); + + private String name; + + Result(String name) { + this.name = name; + } + + public String getName() { + return name; + } } From 959f02e1c0416b2a965a1898a56bef46b6e2a421 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 21:55:16 +0900 Subject: [PATCH 35/88] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=A7=81=20?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=83=81=EC=88=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ScoreCalculator.java | 14 ++++++++------ src/test/java/DeckTest.java | 1 - src/test/java/GameManagerTest.java | 1 - 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/ScoreCalculator.java b/src/main/java/ScoreCalculator.java index feb03123201..ee3c3f27b20 100644 --- a/src/main/java/ScoreCalculator.java +++ b/src/main/java/ScoreCalculator.java @@ -1,6 +1,11 @@ import java.util.List; public class ScoreCalculator { + + + public static final int BLACKJACK_SCORE = 21; + public static final int ACE_BONUS_SCORE = 10; + private int sumScore(List hand) { int score = 0; for (Card card : hand) { @@ -11,19 +16,16 @@ private int sumScore(List hand) { public int calculateScore(List hand) { int currentScore = sumScore(hand); - - Card findCard - = hand.stream().filter(c -> c.getRank() == 1).findAny().orElse(null); - + Card findCard = hand.stream().filter(c -> c.getRank() == 1).findAny().orElse(null); if (findCard == null) { return currentScore; } - if (currentScore + 10 > 21) { + if (currentScore + ACE_BONUS_SCORE > BLACKJACK_SCORE) { return currentScore; } - return currentScore + 10; + return currentScore + ACE_BONUS_SCORE; } public boolean isBust(int score) { diff --git a/src/test/java/DeckTest.java b/src/test/java/DeckTest.java index 19a70915e11..78d178d1ba5 100644 --- a/src/test/java/DeckTest.java +++ b/src/test/java/DeckTest.java @@ -1,4 +1,3 @@ -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/GameManagerTest.java b/src/test/java/GameManagerTest.java index 6db69008884..44000129630 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/GameManagerTest.java @@ -1,6 +1,5 @@ import org.junit.jupiter.api.Test; -import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; From ef3b0a2736bad335ea1f5dd3ee67051513050225 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Thu, 5 Mar 2026 21:58:39 +0900 Subject: [PATCH 36/88] docs: Todo List Update --- README.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 74fa52bdad0..88627736014 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,19 @@ - [x] 21점이 넘으면 버스트 ### 히트/스탠드 입력 -- [ ] 버스트가 아니면 히트/스탠드를 입력받는다. -- [ ] 히트면 카드를 한 장 더 받는다. -- [ ] 스탠드면 턴을 종료한다. +- [x] 버스트가 아니면 히트/스탠드를 입력받는다. +- [x] 히트면 카드를 한 장 더 받는다. +- [x] 스탠드면 턴을 종료한다. ### 승패 판정 -- [ ] 딜러와 점수를 비교한다. -- [ ] 결과를 생성한다. +- [x] 딜러와 점수를 비교한다. +- [x] 결과를 생성한다. -### 결과 출력 \ No newline at end of file +### 결과 출력 + +--- + +### TO-DO +- [ ] GameManager 리팩터링 +- [ ] Enum 출력값 변경 +- [ ] 테스트 케이스 추가 \ No newline at end of file From 0776dfb23eacffad8732a671cb7ab6c033bacc1c Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 10:55:56 +0900 Subject: [PATCH 37/88] =?UTF-8?q?refactor:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EC=B6=9C=EB=A0=A5=20=ED=98=95=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++++- src/main/java/Card.java | 2 +- src/main/java/GameFinalResultDto.java | 4 ++-- src/main/java/Rank.java | 5 +++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 88627736014..1134d5fe135 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,8 @@ ### TO-DO - [ ] GameManager 리팩터링 - [ ] Enum 출력값 변경 -- [ ] 테스트 케이스 추가 \ No newline at end of file + - [x] 승패 출력값 변경 + - [x] Rank 출력값 변경 + - [ ] Suit 출력값 변경 +- [ ] 테스트 케이스 추가 +- [ ] 패키지 정리 \ No newline at end of file diff --git a/src/main/java/Card.java b/src/main/java/Card.java index 67c41194935..787d2e30a49 100644 --- a/src/main/java/Card.java +++ b/src/main/java/Card.java @@ -28,6 +28,6 @@ public int hashCode() { @Override public String toString() { - return "" + rank + suit; + return "" + rank.getValue() + suit; } } diff --git a/src/main/java/GameFinalResultDto.java b/src/main/java/GameFinalResultDto.java index 8ef58aff453..f431dbce675 100644 --- a/src/main/java/GameFinalResultDto.java +++ b/src/main/java/GameFinalResultDto.java @@ -15,8 +15,8 @@ public String getName() { return name; } - public Result getResult() { - return result; + public String getResult() { + return result.getName(); } @Override diff --git a/src/main/java/Rank.java b/src/main/java/Rank.java index 4f7290da0f6..344d2c91f7d 100644 --- a/src/main/java/Rank.java +++ b/src/main/java/Rank.java @@ -20,5 +20,6 @@ public enum Rank { } public int getValue() { - return value; -}} + return value; + } +} From 7b13d009e3a93eb21fcbac709854c577e49e9a16 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 10:56:48 +0900 Subject: [PATCH 38/88] docs: README Update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1134d5fe135..b7b9a2776f6 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,11 @@ --- ### TO-DO -- [ ] GameManager 리팩터링 - [ ] Enum 출력값 변경 - [x] 승패 출력값 변경 - [x] Rank 출력값 변경 - [ ] Suit 출력값 변경 +- [x] 딜러 승패 판정 오류 수정 +- [ ] GameManager 리팩터링 - [ ] 테스트 케이스 추가 - [ ] 패키지 정리 \ No newline at end of file From 35ba56a62babff5c6d356142c6edaff9ab75c97e Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 11:38:02 +0900 Subject: [PATCH 39/88] =?UTF-8?q?fix:=20=EB=94=9C=EB=9F=AC=20=EC=8A=B9?= =?UTF-8?q?=ED=8C=A8=20=ED=8C=90=EC=A0=95=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- src/main/java/GameFinalResultDto.java | 4 ++-- src/main/java/OutputView.java | 20 +++++++++++++++----- src/main/java/Result.java | 2 +- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b7b9a2776f6..cf33cd74250 100644 --- a/README.md +++ b/README.md @@ -46,4 +46,6 @@ - [x] 딜러 승패 판정 오류 수정 - [ ] GameManager 리팩터링 - [ ] 테스트 케이스 추가 -- [ ] 패키지 정리 \ No newline at end of file +- [ ] 패키지 정리 +- [ ] 버스트인데 카드 받을거냐고 물어봄 +- [ ] Ace 출력 표시 문제 \ No newline at end of file diff --git a/src/main/java/GameFinalResultDto.java b/src/main/java/GameFinalResultDto.java index f431dbce675..8ef58aff453 100644 --- a/src/main/java/GameFinalResultDto.java +++ b/src/main/java/GameFinalResultDto.java @@ -15,8 +15,8 @@ public String getName() { return name; } - public String getResult() { - return result.getName(); + public Result getResult() { + return result; } @Override diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java index 7437e456eb1..72571200022 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/OutputView.java @@ -1,5 +1,5 @@ import java.text.MessageFormat; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -44,7 +44,8 @@ public void printScoreResults(List scoreResults) { public void printFinalResult(List finalResult) { System.out.println("## 최종 승패"); GameFinalResultDto firstPlayer = finalResult.removeFirst(); - Map resultCounts = new HashMap<>(); + Map resultCounts = new EnumMap<>(Result.class); + countDealerResult(finalResult, resultCounts); printDealerResult(firstPlayer, resultCounts); printPlayerResult(finalResult); @@ -52,8 +53,17 @@ public void printFinalResult(List finalResult) { private void countDealerResult(List finalResult, Map resultCounts) { for (GameFinalResultDto result : finalResult) { - Integer beforeCount = resultCounts.getOrDefault(result.result, 0); - resultCounts.put(result.result, ++beforeCount); + if (result.getResult() == Result.WIN) { + resultCounts.put(Result.LOSE, resultCounts.getOrDefault(Result.LOSE, 0) + 1); + continue; + } + + if (result.getResult() == Result.LOSE) { + resultCounts.put(Result.WIN, resultCounts.getOrDefault(Result.WIN, 0) + 1); + continue; + } + + resultCounts.put(result.getResult(), resultCounts.getOrDefault(result.getResult(), 0) + 1); } } @@ -71,7 +81,7 @@ private void printPlayerResult(List finalResult) { System.out.println(MessageFormat.format( FINAL_RESULT_MESSAGE, result.getName(), - result.getResult() + result.getResult().getName() )); } } diff --git a/src/main/java/Result.java b/src/main/java/Result.java index 9a37d5e46bb..3c363a53a1a 100644 --- a/src/main/java/Result.java +++ b/src/main/java/Result.java @@ -8,6 +8,6 @@ public enum Result { } public String getName() { - return name; + return name + " "; } } From d29c5a033afc3585c6263b122033ac0d0f70b6e4 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 11:41:43 +0900 Subject: [PATCH 40/88] =?UTF-8?q?refactor:=20=EB=AC=B4=EB=8A=AC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=ED=91=9C=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/java/Card.java | 2 +- src/main/java/Suit.java | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf33cd74250..82d16e71b60 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ --- ### TO-DO -- [ ] Enum 출력값 변경 +- [x] Enum 출력값 변경 - [x] 승패 출력값 변경 - [x] Rank 출력값 변경 - - [ ] Suit 출력값 변경 + - [x] Suit 출력값 변경 - [x] 딜러 승패 판정 오류 수정 - [ ] GameManager 리팩터링 - [ ] 테스트 케이스 추가 diff --git a/src/main/java/Card.java b/src/main/java/Card.java index 787d2e30a49..567b3c18176 100644 --- a/src/main/java/Card.java +++ b/src/main/java/Card.java @@ -28,6 +28,6 @@ public int hashCode() { @Override public String toString() { - return "" + rank.getValue() + suit; + return "" + rank.getValue() + suit.getName(); } } diff --git a/src/main/java/Suit.java b/src/main/java/Suit.java index 6ce8999293e..8d10ab08083 100644 --- a/src/main/java/Suit.java +++ b/src/main/java/Suit.java @@ -1,3 +1,16 @@ public enum Suit { - SPADE, HEART, DIAMOND, CLUB + SPADE("스페이드"), + HEART("하트"), + DIAMOND("다이아몬드"), + CLUB("클로버"); + + private final String name; + + Suit(String name) { + this.name = name; + } + + public String getName() { + return name; + } } From 096c2d5644398f7df850a3bf40d6075d842732ab Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 11:44:25 +0900 Subject: [PATCH 41/88] =?UTF-8?q?fix:=20=EB=B2=84=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=98=A4=EB=A5=98=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 --- README.md | 2 +- src/main/java/GameController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 82d16e71b60..011a4c01547 100644 --- a/README.md +++ b/README.md @@ -47,5 +47,5 @@ - [ ] GameManager 리팩터링 - [ ] 테스트 케이스 추가 - [ ] 패키지 정리 -- [ ] 버스트인데 카드 받을거냐고 물어봄 +- [x] 버스트인데 hit/stand 질문 - [ ] Ace 출력 표시 문제 \ No newline at end of file diff --git a/src/main/java/GameController.java b/src/main/java/GameController.java index b7e4fbbac17..56144ebd1bc 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/GameController.java @@ -56,6 +56,6 @@ private boolean isStand(Player player) { } private boolean isPlayerTurn(Player player) { - return !(player.isBust() && manager.isBlackjack(player)); + return !(player.isBust() || manager.isBlackjack(player)); } } From 73d806bbf2b24ecef4b906ef87e62f4b98d6151a Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 11:49:04 +0900 Subject: [PATCH 42/88] =?UTF-8?q?fix:=20Ace,=20Face=20Card=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=B4=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/Card.java | 2 +- src/main/java/Rank.java | 34 ++++++++++++++++++++-------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 011a4c01547..bf7540d06a8 100644 --- a/README.md +++ b/README.md @@ -48,4 +48,4 @@ - [ ] 테스트 케이스 추가 - [ ] 패키지 정리 - [x] 버스트인데 hit/stand 질문 -- [ ] Ace 출력 표시 문제 \ No newline at end of file +- [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 \ No newline at end of file diff --git a/src/main/java/Card.java b/src/main/java/Card.java index 567b3c18176..4d556d01cf8 100644 --- a/src/main/java/Card.java +++ b/src/main/java/Card.java @@ -28,6 +28,6 @@ public int hashCode() { @Override public String toString() { - return "" + rank.getValue() + suit.getName(); + return rank.getName() + suit.getName(); } } diff --git a/src/main/java/Rank.java b/src/main/java/Rank.java index 344d2c91f7d..7f44ef0360c 100644 --- a/src/main/java/Rank.java +++ b/src/main/java/Rank.java @@ -1,25 +1,31 @@ public enum Rank { - ACE(1), - TWO(2), - THREE(3), - FOUR(4), - FIVE(5), - SIX(6), - SEVEN(7), - EIGHT(8), - NINE(9), - TEN(10), - JACK(10), - QUEEN(10), - KING(10); + ACE(1, "A"), + TWO(2, "2"), + THREE(3, "3"), + FOUR(4, "4"), + FIVE(5, "5"), + SIX(6, "6"), + SEVEN(7, "7"), + EIGHT(8, "8"), + NINE(9, "9"), + TEN(10, "10"), + JACK(10, "J"), + QUEEN(10, "Q"), + KING(10, "K"); private final int value; + private final String name; - Rank(int value) { + Rank(int value, String name) { this.value = value; + this.name = name; } public int getValue() { return value; } + + public String getName() { + return name; + } } From 468fecdceeb39718737936f99b90295923b77805 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 14:26:33 +0900 Subject: [PATCH 43/88] =?UTF-8?q?refactor:=20GameManager=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/GameManager.java | 42 +++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index d5fd38b1f66..7bea022f52d 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -54,12 +54,22 @@ public List getPlayerSequence() { public List getScoreResults() { List results = new ArrayList<>(); // dealer + aggregateDealerResult(results); + //players + aggregatePlayerResult(results); + + return results; + } + + private void aggregateDealerResult(List results) { results.add(new GameScoreResultDto( dealer.getName(), dealer.getHandToString(), scoreCalculator.calculateScore(dealer.getHand()) )); - //players + } + + private void aggregatePlayerResult(List results) { for (Player player : players.getPlayers()) { results.add(new GameScoreResultDto( player.getName(), @@ -67,8 +77,6 @@ public List getScoreResults() { scoreCalculator.calculateScore(player.getHand()) )); } - - return results; } public List getInitialInfo() { @@ -79,12 +87,14 @@ public List getInitialInfo() { dealerOpenCard.add(dealer.getHandToString().getFirst()); // dealer - results.add(new GameInitialInfoDto( - dealer.getName(), - 2, - dealerOpenCard - )); + addDealerInfo(results, dealerOpenCard); //players + addPlayersInfo(results); + + return results; + } + + private void addPlayersInfo(List results) { for (Player player : players.getPlayers()) { results.add(new GameInitialInfoDto( player.getName(), @@ -92,8 +102,14 @@ public List getInitialInfo() { player.getHandToString() )); } + } - return results; + private void addDealerInfo(List results, List dealerOpenCard) { + results.add(new GameInitialInfoDto( + dealer.getName(), + 2, + dealerOpenCard + )); } public boolean isBlackjack(Player player) { @@ -110,6 +126,12 @@ public List getFinalResult() { results.add(new GameFinalResultDto(dealer.getName())); // 플레이어 추가 + determineWinLose(results); + + return results; + } + + private void determineWinLose(List results) { for (Player player : players.getPlayers()) { int playerScore = calculateScore(player.getHand()); int dealerScore = calculateScore(dealer.getHand()); @@ -126,7 +148,5 @@ public List getFinalResult() { results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); } } - - return results; } } From 26555f9039b06c28d66a2a0e6da87b7fd4286ad3 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 14:39:07 +0900 Subject: [PATCH 44/88] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++------ src/main/java/Application.java | 5 +++++ src/main/java/{ => controller}/GameController.java | 8 ++++++++ src/main/java/{ => domain}/Card.java | 5 +++++ src/main/java/{ => domain}/Dealer.java | 2 ++ src/main/java/{ => domain}/Deck.java | 5 +++++ src/main/java/{ => domain}/GameManager.java | 7 +++++++ src/main/java/{ => domain}/Player.java | 4 +++- src/main/java/{ => domain}/Players.java | 2 ++ src/main/java/{ => domain}/ScoreCalculator.java | 3 ++- src/main/java/{ => domain/constant}/Rank.java | 2 ++ src/main/java/{ => domain/constant}/Result.java | 2 ++ src/main/java/{ => domain/constant}/Suit.java | 2 ++ .../java/{ => domain/dto}/GameFinalResultDto.java | 6 +++++- .../java/{ => domain/dto}/GameInitialInfoDto.java | 14 ++------------ .../java/{ => domain/dto}/GameScoreResultDto.java | 4 +++- src/main/java/{ => view}/InputView.java | 2 ++ src/main/java/{ => view}/OutputView.java | 7 +++++++ src/test/java/{ => domain}/DeckTest.java | 14 +++++++------- src/test/java/{ => domain}/GameManagerTest.java | 6 ++++++ src/test/java/{ => domain}/PlayersTest.java | 2 ++ .../java/{ => domain}/ScoreCalculatorTest.java | 4 ++++ 22 files changed, 89 insertions(+), 29 deletions(-) rename src/main/java/{ => controller}/GameController.java (91%) rename src/main/java/{ => domain}/Card.java (89%) rename src/main/java/{ => domain}/Dealer.java (84%) rename src/main/java/{ => domain}/Deck.java (87%) rename src/main/java/{ => domain}/GameManager.java (96%) rename src/main/java/{ => domain}/Player.java (94%) rename src/main/java/{ => domain}/Players.java (94%) rename src/main/java/{ => domain}/ScoreCalculator.java (98%) rename src/main/java/{ => domain/constant}/Rank.java (95%) rename src/main/java/{ => domain/constant}/Result.java (89%) rename src/main/java/{ => domain/constant}/Suit.java (91%) rename src/main/java/{ => domain/dto}/GameFinalResultDto.java (84%) rename src/main/java/{ => domain/dto}/GameInitialInfoDto.java (66%) rename src/main/java/{ => domain/dto}/GameScoreResultDto.java (93%) rename src/main/java/{ => view}/InputView.java (99%) rename src/main/java/{ => view}/OutputView.java (96%) rename src/test/java/{ => domain}/DeckTest.java (63%) rename src/test/java/{ => domain}/GameManagerTest.java (95%) rename src/test/java/{ => domain}/PlayersTest.java (96%) rename src/test/java/{ => domain}/ScoreCalculatorTest.java (95%) diff --git a/README.md b/README.md index bf7540d06a8..18b9e7a1079 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,11 @@ ### TO-DO - [x] Enum 출력값 변경 - [x] 승패 출력값 변경 - - [x] Rank 출력값 변경 - - [x] Suit 출력값 변경 + - [x] domain.constant.Suit 출력값 변경 - [x] 딜러 승패 판정 오류 수정 -- [ ] GameManager 리팩터링 -- [ ] 테스트 케이스 추가 -- [ ] 패키지 정리 - [x] 버스트인데 hit/stand 질문 -- [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 \ No newline at end of file +- [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 +- [x] domain.GameManager 리팩터링 +- [ ] 패키지 정리 +- [ ] 규칙 적용 +- [ ] 테스트 케이스 추가 diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 32f012ac091..100c5ed7785 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,3 +1,8 @@ +import controller.GameController; +import domain.GameManager; +import view.InputView; +import view.OutputView; + public class Application { public static void main(String[] args) { diff --git a/src/main/java/GameController.java b/src/main/java/controller/GameController.java similarity index 91% rename from src/main/java/GameController.java rename to src/main/java/controller/GameController.java index 56144ebd1bc..4d29c090f1b 100644 --- a/src/main/java/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,3 +1,11 @@ +package controller; + +import domain.GameManager; +import domain.Player; +import domain.dto.GameInitialInfoDto; +import view.InputView; +import view.OutputView; + import java.util.List; public class GameController { diff --git a/src/main/java/Card.java b/src/main/java/domain/Card.java similarity index 89% rename from src/main/java/Card.java rename to src/main/java/domain/Card.java index 4d556d01cf8..a0e8eeda769 100644 --- a/src/main/java/Card.java +++ b/src/main/java/domain/Card.java @@ -1,3 +1,8 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; + import java.util.Objects; public class Card { diff --git a/src/main/java/Dealer.java b/src/main/java/domain/Dealer.java similarity index 84% rename from src/main/java/Dealer.java rename to src/main/java/domain/Dealer.java index bf3d97aa3d4..06245fe081d 100644 --- a/src/main/java/Dealer.java +++ b/src/main/java/domain/Dealer.java @@ -1,3 +1,5 @@ +package domain; + public class Dealer extends Player { public Dealer() { diff --git a/src/main/java/Deck.java b/src/main/java/domain/Deck.java similarity index 87% rename from src/main/java/Deck.java rename to src/main/java/domain/Deck.java index 268b0abccdc..7530b431638 100644 --- a/src/main/java/Deck.java +++ b/src/main/java/domain/Deck.java @@ -1,3 +1,8 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; + import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/main/java/GameManager.java b/src/main/java/domain/GameManager.java similarity index 96% rename from src/main/java/GameManager.java rename to src/main/java/domain/GameManager.java index 7bea022f52d..e795ffb2f39 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -1,3 +1,10 @@ +package domain; + +import domain.constant.Result; +import domain.dto.GameFinalResultDto; +import domain.dto.GameInitialInfoDto; +import domain.dto.GameScoreResultDto; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/Player.java b/src/main/java/domain/Player.java similarity index 94% rename from src/main/java/Player.java rename to src/main/java/domain/Player.java index cd0d77a67d4..e13d27c825e 100644 --- a/src/main/java/Player.java +++ b/src/main/java/domain/Player.java @@ -1,3 +1,5 @@ +package domain; + import java.util.ArrayList; import java.util.List; @@ -36,7 +38,7 @@ public void setBust() { @Override public String toString() { - return "Player{" + + return "domain.Player{" + "name='" + name + '\'' + ", hand=" + hand + ", isBust=" + isBust + diff --git a/src/main/java/Players.java b/src/main/java/domain/Players.java similarity index 94% rename from src/main/java/Players.java rename to src/main/java/domain/Players.java index 71ef2919ce5..2434d206135 100644 --- a/src/main/java/Players.java +++ b/src/main/java/domain/Players.java @@ -1,3 +1,5 @@ +package domain; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/ScoreCalculator.java b/src/main/java/domain/ScoreCalculator.java similarity index 98% rename from src/main/java/ScoreCalculator.java rename to src/main/java/domain/ScoreCalculator.java index ee3c3f27b20..6ef2cfeb8be 100644 --- a/src/main/java/ScoreCalculator.java +++ b/src/main/java/domain/ScoreCalculator.java @@ -1,8 +1,9 @@ +package domain; + import java.util.List; public class ScoreCalculator { - public static final int BLACKJACK_SCORE = 21; public static final int ACE_BONUS_SCORE = 10; diff --git a/src/main/java/Rank.java b/src/main/java/domain/constant/Rank.java similarity index 95% rename from src/main/java/Rank.java rename to src/main/java/domain/constant/Rank.java index 7f44ef0360c..e73d863337d 100644 --- a/src/main/java/Rank.java +++ b/src/main/java/domain/constant/Rank.java @@ -1,3 +1,5 @@ +package domain.constant; + public enum Rank { ACE(1, "A"), TWO(2, "2"), diff --git a/src/main/java/Result.java b/src/main/java/domain/constant/Result.java similarity index 89% rename from src/main/java/Result.java rename to src/main/java/domain/constant/Result.java index 3c363a53a1a..7f4455cfb9e 100644 --- a/src/main/java/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -1,3 +1,5 @@ +package domain.constant; + public enum Result { WIN("승"), DRAW("무"), LOSE("패"); diff --git a/src/main/java/Suit.java b/src/main/java/domain/constant/Suit.java similarity index 91% rename from src/main/java/Suit.java rename to src/main/java/domain/constant/Suit.java index 8d10ab08083..7e5b7a28243 100644 --- a/src/main/java/Suit.java +++ b/src/main/java/domain/constant/Suit.java @@ -1,3 +1,5 @@ +package domain.constant; + public enum Suit { SPADE("스페이드"), HEART("하트"), diff --git a/src/main/java/GameFinalResultDto.java b/src/main/java/domain/dto/GameFinalResultDto.java similarity index 84% rename from src/main/java/GameFinalResultDto.java rename to src/main/java/domain/dto/GameFinalResultDto.java index 8ef58aff453..f61a9a581da 100644 --- a/src/main/java/GameFinalResultDto.java +++ b/src/main/java/domain/dto/GameFinalResultDto.java @@ -1,3 +1,7 @@ +package domain.dto; + +import domain.constant.Result; + public class GameFinalResultDto { String name; Result result; @@ -21,7 +25,7 @@ public Result getResult() { @Override public String toString() { - return "GameFinalResultDto{" + + return "domain.dto.GameFinalResultDto{" + "name='" + name + '\'' + ", result=" + result + '}'; diff --git a/src/main/java/GameInitialInfoDto.java b/src/main/java/domain/dto/GameInitialInfoDto.java similarity index 66% rename from src/main/java/GameInitialInfoDto.java rename to src/main/java/domain/dto/GameInitialInfoDto.java index ee391d09ae9..ecef57c2caa 100644 --- a/src/main/java/GameInitialInfoDto.java +++ b/src/main/java/domain/dto/GameInitialInfoDto.java @@ -1,3 +1,5 @@ +package domain.dto; + import java.util.List; public class GameInitialInfoDto { @@ -16,23 +18,11 @@ public String getPlayerName() { return playerName; } - public void setPlayerName(String playerName) { - this.playerName = playerName; - } - public int getInitialHandSize() { return initialHandSize; } - public void setInitialHandSize(int initialHandSize) { - this.initialHandSize = initialHandSize; - } - public List getHand() { return hand; } - - public void setHand(List hand) { - this.hand = hand; - } } diff --git a/src/main/java/GameScoreResultDto.java b/src/main/java/domain/dto/GameScoreResultDto.java similarity index 93% rename from src/main/java/GameScoreResultDto.java rename to src/main/java/domain/dto/GameScoreResultDto.java index 5a0231e3725..3cc84efa21b 100644 --- a/src/main/java/GameScoreResultDto.java +++ b/src/main/java/domain/dto/GameScoreResultDto.java @@ -1,3 +1,5 @@ +package domain.dto; + import java.util.List; public class GameScoreResultDto { @@ -37,7 +39,7 @@ public void setResult(int result) { @Override public String toString() { - return "GameScoreResultDto{" + + return "domain.dto.GameScoreResultDto{" + "playerName='" + playerName + '\'' + ", hand=" + hand + ", result=" + result + diff --git a/src/main/java/InputView.java b/src/main/java/view/InputView.java similarity index 99% rename from src/main/java/InputView.java rename to src/main/java/view/InputView.java index 30460590b65..40fbc931af7 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,3 +1,5 @@ +package view; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/OutputView.java b/src/main/java/view/OutputView.java similarity index 96% rename from src/main/java/OutputView.java rename to src/main/java/view/OutputView.java index 72571200022..7383cf017f9 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,3 +1,10 @@ +package view; + +import domain.constant.Result; +import domain.dto.GameFinalResultDto; +import domain.dto.GameInitialInfoDto; +import domain.dto.GameScoreResultDto; + import java.text.MessageFormat; import java.util.EnumMap; import java.util.List; diff --git a/src/test/java/DeckTest.java b/src/test/java/domain/DeckTest.java similarity index 63% rename from src/test/java/DeckTest.java rename to src/test/java/domain/DeckTest.java index 78d178d1ba5..340f8e4f4ab 100644 --- a/src/test/java/DeckTest.java +++ b/src/test/java/domain/DeckTest.java @@ -1,3 +1,5 @@ +package domain; + import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -30,13 +32,11 @@ public class DeckTest { } assertThat(result.toString()).contains( - "[ACESPADE, TWOSPADE, THREESPADE, FOURSPADE, FIVESPADE, SIXSPADE, SEVENSPADE, EIGHTSPADE, " + - "NINESPADE, TENSPADE, JACKSPADE, QUEENSPADE, KINGSPADE, ACEHEART, TWOHEART, THREEHEART, " + - "FOURHEART, FIVEHEART, SIXHEART, SEVENHEART, EIGHTHEART, NINEHEART, TENHEART, JACKHEART," + - " QUEENHEART, KINGHEART, ACEDIAMOND, TWODIAMOND, THREEDIAMOND, FOURDIAMOND, FIVEDIAMOND," + - " SIXDIAMOND, SEVENDIAMOND, EIGHTDIAMOND, NINEDIAMOND, TENDIAMOND, JACKDIAMOND," + - " QUEENDIAMOND, KINGDIAMOND, ACECLUB, TWOCLUB, THREECLUB, FOURCLUB, FIVECLUB, SIXCLUB," + - " SEVENCLUB, EIGHTCLUB, NINECLUB, TENCLUB, JACKCLUB, QUEENCLUB, KINGCLUB]" + "[A스페이드, 2스페이드, 3스페이드, 4스페이드, 5스페이드, 6스페이드, 7스페이드, 8스페이드, 9스페이드, 10스페이드, " + + "J스페이드, Q스페이드, K스페이드, A하트, 2하트, 3하트, 4하트, 5하트, 6하트, 7하트, 8하트, 9하트, 10하트," + + " J하트, Q하트, K하트, A다이아몬드, 2다이아몬드, 3다이아몬드, 4다이아몬드, 5다이아몬드, 6다이아몬드, 7다이아몬드," + + " 8다이아몬드, 9다이아몬드, 10다이아몬드, J다이아몬드, Q다이아몬드, K다이아몬드, A클로버, 2클로버, 3클로버, 4클로버," + + " 5클로버, 6클로버, 7클로버, 8클로버, 9클로버, 10클로버, J클로버, Q클로버, K클로버]" ); } diff --git a/src/test/java/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java similarity index 95% rename from src/test/java/GameManagerTest.java rename to src/test/java/domain/GameManagerTest.java index 44000129630..f8d7afe5e56 100644 --- a/src/test/java/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -1,3 +1,9 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; +import domain.dto.GameInitialInfoDto; +import domain.dto.GameScoreResultDto; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/PlayersTest.java b/src/test/java/domain/PlayersTest.java similarity index 96% rename from src/test/java/PlayersTest.java rename to src/test/java/domain/PlayersTest.java index 5ae81c1fe63..c24a27c8719 100644 --- a/src/test/java/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -1,3 +1,5 @@ +package domain; + import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/ScoreCalculatorTest.java b/src/test/java/domain/ScoreCalculatorTest.java similarity index 95% rename from src/test/java/ScoreCalculatorTest.java rename to src/test/java/domain/ScoreCalculatorTest.java index 3201dcbf3d2..07bae63cb1b 100644 --- a/src/test/java/ScoreCalculatorTest.java +++ b/src/test/java/domain/ScoreCalculatorTest.java @@ -1,3 +1,7 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; import org.junit.jupiter.api.Test; import java.util.List; From ad1fc70e74ee5d3513dd4aabf744db0d81a56a85 Mon Sep 17 00:00:00 2001 From: tjdakf Date: Fri, 6 Mar 2026 14:57:12 +0900 Subject: [PATCH 45/88] =?UTF-8?q?fix:=20=EB=B2=84=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EC=98=A4=EB=A5=98=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 --- README.md | 2 +- src/main/java/domain/GameManager.java | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 18b9e7a1079..c9ffcd157b9 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,6 @@ - [x] 버스트인데 hit/stand 질문 - [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 - [x] domain.GameManager 리팩터링 -- [ ] 패키지 정리 +- [x] 패키지 정리 - [ ] 규칙 적용 - [ ] 테스트 케이스 추가 diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index e795ffb2f39..85b7acb3d30 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -142,18 +142,17 @@ private void determineWinLose(List results) { for (Player player : players.getPlayers()) { int playerScore = calculateScore(player.getHand()); int dealerScore = calculateScore(dealer.getHand()); + if (player.isBust() || playerScore < dealerScore) { + results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); + continue; + } if (playerScore > dealerScore) { results.add(new GameFinalResultDto(player.getName(), Result.WIN)); + continue; } - if (playerScore == dealerScore) { - results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); - } - - if (playerScore < dealerScore) { - results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); - } + results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); } } } From 4cbbeb2d80f3b8c2973490fb231efdb75bf3c9c1 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 2 Mar 2026 19:00:41 +0900 Subject: [PATCH 46/88] =?UTF-8?q?test:=20=EC=8B=A4=ED=97=982=20ace=201/11?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/ApplicationTest.java | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/java/ApplicationTest.java diff --git a/src/test/java/ApplicationTest.java b/src/test/java/ApplicationTest.java new file mode 100644 index 00000000000..47f1135d09c --- /dev/null +++ b/src/test/java/ApplicationTest.java @@ -0,0 +1,32 @@ +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class ApplicationTest { + @DisplayName("Ace 1/11 규칙 테스트") + @ParameterizedTest(name = "[{index}] {0} -> ace={1}") + @MethodSource("cases") + void drawAceTest(List cards, int expectedAce) { + List result = Application.drawAce(new ArrayList<>(cards)); + int actualAce = result.get(result.size() - 1); + assertThat(actualAce).isEqualTo(expectedAce); + } + + static Stream cases() { + return Stream.of( + Arguments.of(List.of(2, 4, 7), 1), + Arguments.of(List.of(3, 6), 11), + Arguments.of(List.of(10), 11), + Arguments.of(List.of(10,10), 1), + Arguments.of(List.of(8,2,4), 1), + Arguments.of(List.of(4,5,7), 1), + Arguments.of(List.of(), 11) + ); + } +} From b9026da1771408cb57f44f59ed7d3d6ae3cd72c9 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 8 Mar 2026 01:23:19 +0900 Subject: [PATCH 47/88] =?UTF-8?q?refactor:=20drawDealerCard=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=ED=83=80=EC=9E=85=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/domain/GameManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index 85b7acb3d30..aca86935361 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -44,10 +44,9 @@ public List drawPlayerCard(Player player) { return player.getHandToString(); } - public List drawDealerCard() { + public void drawDealerCard() { dealer.addCard(deck.draw()); judgeBust(calculateScore(dealer.getHand()), dealer); - return dealer.getHandToString(); } public void addPlayer(String name) { From a1246bfe5eab5178974d7b403e15c4cec25397f4 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 8 Mar 2026 01:28:20 +0900 Subject: [PATCH 48/88] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=EC=99=80=20=EB=8F=84=EB=A9=94=EC=9D=B8=EB=93=A4?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B8=EC=8A=A4=ED=84=B4=EC=8A=A4=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20final=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 6 +++--- src/main/java/domain/Card.java | 4 ++-- src/main/java/domain/GameManager.java | 8 ++++---- src/main/java/domain/Player.java | 8 +++++--- src/main/java/domain/Players.java | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 4d29c090f1b..28c2f4634b4 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -10,9 +10,9 @@ public class GameController { - private GameManager manager; - private InputView inputView; - private OutputView outputView; + private final GameManager manager; + private final InputView inputView; + private final OutputView outputView; public GameController(GameManager manager, InputView inputView, OutputView outputView) { this.manager = manager; diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/Card.java index a0e8eeda769..8b36a808069 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/Card.java @@ -7,8 +7,8 @@ public class Card { - private Rank rank; - private Suit suit; + private final Rank rank; + private final Suit suit; public Card(Rank rank, Suit suit) { this.rank = rank; diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index aca86935361..7a956a2c566 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -9,10 +9,10 @@ import java.util.List; public class GameManager { - private Deck deck = new Deck(); - private ScoreCalculator scoreCalculator = new ScoreCalculator(); - private Players players = new Players(); - private Dealer dealer = new Dealer(); + private final Deck deck = new Deck(); + private final ScoreCalculator scoreCalculator = new ScoreCalculator(); + private final Players players = new Players(); + private final Dealer dealer = new Dealer(); public GameManager() { deck.init(); diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index e13d27c825e..5a177ee4291 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -4,8 +4,8 @@ import java.util.List; public class Player { - private String name; - private List hand = new ArrayList<>(); + private final String name; + private final List hand = new ArrayList<>(); private boolean isBust = false; public Player(String name) { @@ -29,7 +29,9 @@ public List getHand() { } public List getHandToString() { - return hand.stream().map(Card::toString).toList(); + return hand.stream() + .map(Card::toString) + .toList(); } public void setBust() { diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java index 2434d206135..e0d1a7f4aba 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/Players.java @@ -4,7 +4,7 @@ import java.util.List; public class Players { - private List players = new ArrayList<>(); + private final List players = new ArrayList<>(); public void add(Player player) { From f4edc4a6ef4eb743de9966f5ecdb7c16d4899eea Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 8 Mar 2026 01:29:14 +0900 Subject: [PATCH 49/88] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8=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/test/java/domain/GameManagerTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index f8d7afe5e56..c1372adb87d 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -79,11 +79,6 @@ class GameManagerTest { assertThat(result.size()).isEqualTo(3); } - @Test - void 게임을_시작하면_카드를_2장씩_나눠준다() { - GameManager manager = new GameManager(); - } - @Test void 합계가_21점이면_블랙잭이다() { GameManager manager = new GameManager(); From 86cf9e30f4470b7ff88e60bcc5aeaa30b78f1555 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 08:30:39 +0900 Subject: [PATCH 50/88] =?UTF-8?q?refactor:=20rank=20=EA=B0=92=20=EB=B9=84?= =?UTF-8?q?=EA=B5=90=20=EB=B0=A9=EC=8B=9D=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/domain/Card.java | 7 ++++++- src/main/java/domain/ScoreCalculator.java | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/Card.java index 8b36a808069..d883947cb5e 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/Card.java @@ -15,10 +15,15 @@ public Card(Rank rank, Suit suit) { this.suit = suit; } - public int getRank() { + public Rank getRank() { + return this.rank; + } + + public int getRankValue() { return this.rank.getValue(); } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/src/main/java/domain/ScoreCalculator.java b/src/main/java/domain/ScoreCalculator.java index 6ef2cfeb8be..5c6f7fa9c89 100644 --- a/src/main/java/domain/ScoreCalculator.java +++ b/src/main/java/domain/ScoreCalculator.java @@ -1,5 +1,6 @@ package domain; +import domain.constant.Rank; import java.util.List; public class ScoreCalculator { @@ -10,15 +11,17 @@ public class ScoreCalculator { private int sumScore(List hand) { int score = 0; for (Card card : hand) { - score += card.getRank(); + score += card.getRankValue(); } return score; } public int calculateScore(List hand) { int currentScore = sumScore(hand); - Card findCard = hand.stream().filter(c -> c.getRank() == 1).findAny().orElse(null); - if (findCard == null) { + boolean hasACE = hand.stream() + .anyMatch(c -> c.getRank() == Rank.ACE); + + if (!hasACE) { return currentScore; } From 7ba0758d165d08b1e967ecbcd705602653356369 Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Mon, 9 Mar 2026 15:34:48 +0900 Subject: [PATCH 51/88] docs: to-do update --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index c9ffcd157b9..de4226174c6 100644 --- a/README.md +++ b/README.md @@ -47,5 +47,16 @@ - [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 - [x] domain.GameManager 리팩터링 - [x] 패키지 정리 +- [x] drawDealerCard() 메서드의 응답값 미사용 +- [ ] GameManager의 책임 재분배 (Deck 초기화, 셔플) +- [ ] GameController 구조 수정 +- [ ] 디미터의 법칙 - 스트림 체이닝은 줄바꿈해서 작성 +- [x] rank 1 보다는 의미있는 값 (`ACE`)가 이해하기 쉽다 +- [x] 주석이 정말 필요한지, 이름이나 구조로 충분하지 않은지 +- [ ] primitive 타입과 wrapper 타입의 차이 +- [ ] 일급 컬렉션, Cards를 만들게 되면 어떤 장점이 있는가? +- [ ] Controller가 필요할까? 필요한 이유는 무엇일까? +- [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 +- [ ] 플레이어가 입력되지 않는 경우에 대한 예외처리 - [ ] 규칙 적용 - [ ] 테스트 케이스 추가 From 1eabd39578dd3468399cc4c1d4318dcbd1d096ca Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Mon, 9 Mar 2026 17:51:54 +0900 Subject: [PATCH 52/88] =?UTF-8?q?refactor:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=ED=95=B8=EB=93=9C=20=ED=95=84=EB=93=9C=20=EC=9D=BC?= =?UTF-8?q?=EA=B8=89=20=EC=BB=AC=EB=A0=89=EC=85=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++--- src/main/java/domain/Hand.java | 27 +++++++++++++++++++++++++++ src/main/java/domain/Player.java | 18 ++++-------------- 3 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 src/main/java/domain/Hand.java diff --git a/README.md b/README.md index de4226174c6..9e858a08f87 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,13 @@ - [x] drawDealerCard() 메서드의 응답값 미사용 - [ ] GameManager의 책임 재분배 (Deck 초기화, 셔플) - [ ] GameController 구조 수정 -- [ ] 디미터의 법칙 - 스트림 체이닝은 줄바꿈해서 작성 +- [ ] 디미터의 법칙 - 스트림 체이닝은 줄바꿈해서 작성, 체이닝 메서드 안생기도록 구조 수정 - [x] rank 1 보다는 의미있는 값 (`ACE`)가 이해하기 쉽다 - [x] 주석이 정말 필요한지, 이름이나 구조로 충분하지 않은지 - [ ] primitive 타입과 wrapper 타입의 차이 -- [ ] 일급 컬렉션, Cards를 만들게 되면 어떤 장점이 있는가? -- [ ] Controller가 필요할까? 필요한 이유는 무엇일까? +- [X] 일급 컬렉션 -> Hand로 수정 + - [ ] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 +- [ ] Controller 구조 수정 - [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 - [ ] 플레이어가 입력되지 않는 경우에 대한 예외처리 - [ ] 규칙 적용 diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java new file mode 100644 index 00000000000..62f5c1f92be --- /dev/null +++ b/src/main/java/domain/Hand.java @@ -0,0 +1,27 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class Hand { + private final List hand; + + public Hand() { + hand = new ArrayList<>(); + } + + public void add(Card card) { + hand.add(card); + } + + public List getHand() { + return List.copyOf(hand); + } + + public List toStringList() { + return hand.stream() + .map(Card::toString) + .toList(); + } + +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 5a177ee4291..0d88fa778a9 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -5,7 +5,7 @@ public class Player { private final String name; - private final List hand = new ArrayList<>(); + private final Hand hand = new Hand(); private boolean isBust = false; public Player(String name) { @@ -25,24 +25,14 @@ public String getName() { } public List getHand() { - return List.copyOf(hand); + return hand.getHand(); } public List getHandToString() { - return hand.stream() - .map(Card::toString) - .toList(); + return hand.toStringList(); } public void setBust() { isBust = true; } - - @Override - public String toString() { - return "domain.Player{" + - "name='" + name + '\'' + - ", hand=" + hand + - ", isBust=" + isBust + - '}'; - }} +} \ No newline at end of file From e6a31cc81145ac0d6f6baebcb76998c4950f3ecd Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 21:10:17 +0900 Subject: [PATCH 53/88] =?UTF-8?q?refactor:=20GameManager=EC=9D=98=20Deck?= =?UTF-8?q?=20=EC=9D=98=EC=A1=B4=EB=8F=84=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/domain/Deck.java | 15 ++++++++++----- src/main/java/domain/GameManager.java | 5 +---- src/test/java/domain/DeckTest.java | 15 +++------------ 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/main/java/domain/Deck.java b/src/main/java/domain/Deck.java index 7530b431638..cdf0b52d458 100644 --- a/src/main/java/domain/Deck.java +++ b/src/main/java/domain/Deck.java @@ -10,7 +10,12 @@ public class Deck { List cards = new ArrayList<>(); - public void init() { + public Deck () { + init(); + shuffle(); + } + + private void init() { for (Suit suit : Suit.values()) { for (Rank rank : Rank.values()) { cards.add(new Card(rank, suit)); @@ -18,6 +23,10 @@ public void init() { } } + private void shuffle() { + Collections.shuffle(cards); + } + public int size() { return cards.size(); } @@ -25,8 +34,4 @@ public int size() { public Card draw() { return cards.removeFirst(); } - - public void shuffle() { - Collections.shuffle(cards); - } } diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index 7a956a2c566..14561c6487d 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -14,10 +14,7 @@ public class GameManager { private final Players players = new Players(); private final Dealer dealer = new Dealer(); - public GameManager() { - deck.init(); - deck.shuffle(); - } + public GameManager() {} public void startGame() { for (int i = 0; i < 2; i++) { diff --git a/src/test/java/domain/DeckTest.java b/src/test/java/domain/DeckTest.java index 340f8e4f4ab..795d10dcbeb 100644 --- a/src/test/java/domain/DeckTest.java +++ b/src/test/java/domain/DeckTest.java @@ -12,7 +12,6 @@ public class DeckTest { @Test void 카드를_52장_생성한다() { Deck deck = new Deck(); - deck.init(); int deckSize = deck.size(); @@ -22,7 +21,7 @@ public class DeckTest { @Test void 카드는_숫자순에서_무늬순으로_생성된다() { Deck deck = new Deck(); - deck.init(); + int deckSize = deck.size(); List result = new ArrayList<>(); @@ -31,20 +30,13 @@ public class DeckTest { result.add(card); } - assertThat(result.toString()).contains( - "[A스페이드, 2스페이드, 3스페이드, 4스페이드, 5스페이드, 6스페이드, 7스페이드, 8스페이드, 9스페이드, 10스페이드, " + - "J스페이드, Q스페이드, K스페이드, A하트, 2하트, 3하트, 4하트, 5하트, 6하트, 7하트, 8하트, 9하트, 10하트," + - " J하트, Q하트, K하트, A다이아몬드, 2다이아몬드, 3다이아몬드, 4다이아몬드, 5다이아몬드, 6다이아몬드, 7다이아몬드," + - " 8다이아몬드, 9다이아몬드, 10다이아몬드, J다이아몬드, Q다이아몬드, K다이아몬드, A클로버, 2클로버, 3클로버, 4클로버," + - " 5클로버, 6클로버, 7클로버, 8클로버, 9클로버, 10클로버, J클로버, Q클로버, K클로버]" - ); + assertThat(result.size()).isEqualTo(52); } @Test void 카드_셔플_테스트() { Deck deck1 = new Deck(); - deck1.init(); - deck1.shuffle(); + int deckSize = deck1.size(); List result1 = new ArrayList<>(); @@ -54,7 +46,6 @@ public class DeckTest { } Deck deck2 = new Deck(); - deck2.init(); List result2 = new ArrayList<>(); for (int i = 0; i < deckSize; i++) { From ad668d0c90fc7e7356376d6f8f5721a30558ac82 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 21:40:18 +0900 Subject: [PATCH 54/88] =?UTF-8?q?test:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/ApplicationTest.java | 32 ------------------------------ 1 file changed, 32 deletions(-) delete mode 100644 src/test/java/ApplicationTest.java diff --git a/src/test/java/ApplicationTest.java b/src/test/java/ApplicationTest.java deleted file mode 100644 index 47f1135d09c..00000000000 --- a/src/test/java/ApplicationTest.java +++ /dev/null @@ -1,32 +0,0 @@ -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -public class ApplicationTest { - @DisplayName("Ace 1/11 규칙 테스트") - @ParameterizedTest(name = "[{index}] {0} -> ace={1}") - @MethodSource("cases") - void drawAceTest(List cards, int expectedAce) { - List result = Application.drawAce(new ArrayList<>(cards)); - int actualAce = result.get(result.size() - 1); - assertThat(actualAce).isEqualTo(expectedAce); - } - - static Stream cases() { - return Stream.of( - Arguments.of(List.of(2, 4, 7), 1), - Arguments.of(List.of(3, 6), 11), - Arguments.of(List.of(10), 11), - Arguments.of(List.of(10,10), 1), - Arguments.of(List.of(8,2,4), 1), - Arguments.of(List.of(4,5,7), 1), - Arguments.of(List.of(), 11) - ); - } -} From 146fa66263fa36475718400e9c6bc003146f4ef8 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 22:56:25 +0900 Subject: [PATCH 55/88] =?UTF-8?q?refactor:=20Calculator=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0,=20=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20Hand=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/GameManager.java | 24 ++++----- src/main/java/domain/Hand.java | 34 ++++++++++++ src/main/java/domain/Player.java | 8 ++- src/main/java/domain/ScoreCalculator.java | 38 ------------- src/test/java/domain/ScoreCalculatorTest.java | 53 ------------------- 5 files changed, 50 insertions(+), 107 deletions(-) delete mode 100644 src/main/java/domain/ScoreCalculator.java delete mode 100644 src/test/java/domain/ScoreCalculatorTest.java diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index 14561c6487d..aa3fc3452b1 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -10,7 +10,6 @@ public class GameManager { private final Deck deck = new Deck(); - private final ScoreCalculator scoreCalculator = new ScoreCalculator(); private final Players players = new Players(); private final Dealer dealer = new Dealer(); @@ -25,25 +24,25 @@ public void startGame() { } } - public void judgeBust(int score, Player currentPlayer) { - if (scoreCalculator.isBust(score)) { + public void judgeBust(Player currentPlayer) { + if (currentPlayer.isBust()) { currentPlayer.setBust(); } } - public int calculateScore(List hand) { - return scoreCalculator.calculateScore(hand); + public int calculateScore(Hand hand) { + return hand.calculateScore(); } public List drawPlayerCard(Player player) { player.addCard(deck.draw()); - judgeBust(calculateScore(player.getHand()), player); + judgeBust(player); return player.getHandToString(); } public void drawDealerCard() { dealer.addCard(deck.draw()); - judgeBust(calculateScore(dealer.getHand()), dealer); + judgeBust(dealer); } public void addPlayer(String name) { @@ -68,7 +67,7 @@ private void aggregateDealerResult(List results) { results.add(new GameScoreResultDto( dealer.getName(), dealer.getHandToString(), - scoreCalculator.calculateScore(dealer.getHand()) + dealer.getScore() )); } @@ -77,7 +76,7 @@ private void aggregatePlayerResult(List results) { results.add(new GameScoreResultDto( player.getName(), player.getHandToString(), - scoreCalculator.calculateScore(player.getHand()) + player.getScore() )); } } @@ -85,13 +84,12 @@ private void aggregatePlayerResult(List results) { public List getInitialInfo() { List results = new ArrayList<>(); - // 딜러 첫 카드 공개 List dealerOpenCard = new ArrayList<>(); dealerOpenCard.add(dealer.getHandToString().getFirst()); - // dealer + addDealerInfo(results, dealerOpenCard); - //players + addPlayersInfo(results); return results; @@ -125,10 +123,8 @@ public boolean isDealerTurn() { public List getFinalResult() { List results = new ArrayList<>(); - // 딜러 추가 results.add(new GameFinalResultDto(dealer.getName())); - // 플레이어 추가 determineWinLose(results); return results; diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index 62f5c1f92be..a476642b9a9 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -1,10 +1,13 @@ package domain; +import domain.constant.Rank; import java.util.ArrayList; import java.util.List; public class Hand { private final List hand; + public static final int BLACKJACK_SCORE = 21; + public static final int ACE_BONUS_SCORE = 10; public Hand() { hand = new ArrayList<>(); @@ -24,4 +27,35 @@ public List toStringList() { .toList(); } + private int sumScore() { + int score = 0; + for (Card card : hand) { + score += card.getRankValue(); + } + return score; + } + + public int calculateScore() { + int currentScore = sumScore(); + boolean hasACE = hand.stream() + .anyMatch(c -> c.getRank() == Rank.ACE); + + if (!hasACE) { + return currentScore; + } + + if (currentScore + ACE_BONUS_SCORE > BLACKJACK_SCORE) { + return currentScore; + } + + return currentScore + ACE_BONUS_SCORE; + } + + public boolean isBust() { + return sumScore() > BLACKJACK_SCORE; + } + + public boolean isBlackjack() { + return sumScore() == BLACKJACK_SCORE; + } } diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 0d88fa778a9..0f4e2e3c80f 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -24,8 +24,8 @@ public String getName() { return name; } - public List getHand() { - return hand.getHand(); + public Hand getHand() { + return hand; } public List getHandToString() { @@ -35,4 +35,8 @@ public List getHandToString() { public void setBust() { isBust = true; } + + public int getScore(){ + return hand.calculateScore(); + } } \ No newline at end of file diff --git a/src/main/java/domain/ScoreCalculator.java b/src/main/java/domain/ScoreCalculator.java deleted file mode 100644 index 5c6f7fa9c89..00000000000 --- a/src/main/java/domain/ScoreCalculator.java +++ /dev/null @@ -1,38 +0,0 @@ -package domain; - -import domain.constant.Rank; -import java.util.List; - -public class ScoreCalculator { - - public static final int BLACKJACK_SCORE = 21; - public static final int ACE_BONUS_SCORE = 10; - - private int sumScore(List hand) { - int score = 0; - for (Card card : hand) { - score += card.getRankValue(); - } - return score; - } - - public int calculateScore(List hand) { - int currentScore = sumScore(hand); - boolean hasACE = hand.stream() - .anyMatch(c -> c.getRank() == Rank.ACE); - - if (!hasACE) { - return currentScore; - } - - if (currentScore + ACE_BONUS_SCORE > BLACKJACK_SCORE) { - return currentScore; - } - - return currentScore + ACE_BONUS_SCORE; - } - - public boolean isBust(int score) { - return score > 21; - } -} diff --git a/src/test/java/domain/ScoreCalculatorTest.java b/src/test/java/domain/ScoreCalculatorTest.java deleted file mode 100644 index 07bae63cb1b..00000000000 --- a/src/test/java/domain/ScoreCalculatorTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package domain; - -import domain.constant.Rank; -import domain.constant.Suit; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ScoreCalculatorTest { - - @Test - void 카드_점수를_합산한다() { - ScoreCalculator calculator = new ScoreCalculator(); - List hand = List.of(new Card(Rank.JACK, Suit.SPADE), new Card(Rank.TEN, Suit.SPADE)); - - int score = calculator.calculateScore(hand); - - assertThat(score).isEqualTo(20); - } - - @Test - void 핸드에_A가_있고_합산점수가_11점_이하면_10점을_추가한다() { - ScoreCalculator calculator = new ScoreCalculator(); - List hand = List.of(new Card(Rank.ACE, Suit.SPADE), new Card(Rank.KING, Suit.SPADE)); - - int score = calculator.calculateScore(hand); - - assertThat(score).isEqualTo(21); - } - - @Test - void 핸드에_A가_있고_합산점수가_11점_초과이면_원래점수를_사용한다() { - ScoreCalculator calculator = new ScoreCalculator(); - List hand = List.of( - new Card(Rank.ACE, Suit.SPADE), - new Card(Rank.ACE, Suit.HEART), - new Card(Rank.KING, Suit.HEART)); - - int score = calculator.calculateScore(hand); - - assertThat(score).isEqualTo(12); - } - - @Test - void 핸드가_21점이_넘으면_버스트다() { - ScoreCalculator calculator = new ScoreCalculator(); - boolean result = calculator.isBust(22); - - assertThat(result).isTrue(); - } -} From 7dfb950f42f5d23ac7040380fc6da0e74bed8eef Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 23:22:11 +0900 Subject: [PATCH 56/88] =?UTF-8?q?refactor:=20bust=20=ED=8C=90=EC=A0=95=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=EC=9D=84=20manager=EC=97=90=EC=84=9C=20playe?= =?UTF-8?q?r=EC=97=90=EA=B2=8C=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/GameManager.java | 11 ++--------- src/main/java/domain/Hand.java | 4 ++-- src/main/java/domain/Player.java | 8 +------- src/test/java/domain/GameManagerTest.java | 5 ++--- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index aa3fc3452b1..cc94bd84937 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -24,11 +24,6 @@ public void startGame() { } } - public void judgeBust(Player currentPlayer) { - if (currentPlayer.isBust()) { - currentPlayer.setBust(); - } - } public int calculateScore(Hand hand) { return hand.calculateScore(); @@ -36,13 +31,11 @@ public int calculateScore(Hand hand) { public List drawPlayerCard(Player player) { player.addCard(deck.draw()); - judgeBust(player); return player.getHandToString(); } public void drawDealerCard() { dealer.addCard(deck.draw()); - judgeBust(dealer); } public void addPlayer(String name) { @@ -132,8 +125,8 @@ public List getFinalResult() { private void determineWinLose(List results) { for (Player player : players.getPlayers()) { - int playerScore = calculateScore(player.getHand()); - int dealerScore = calculateScore(dealer.getHand()); + int playerScore = player.getScore(); + int dealerScore = dealer.getScore(); if (player.isBust() || playerScore < dealerScore) { results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); continue; diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index a476642b9a9..d1590ff366e 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -52,10 +52,10 @@ public int calculateScore() { } public boolean isBust() { - return sumScore() > BLACKJACK_SCORE; + return calculateScore() > BLACKJACK_SCORE; } public boolean isBlackjack() { - return sumScore() == BLACKJACK_SCORE; + return calculateScore() == BLACKJACK_SCORE; } } diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 0f4e2e3c80f..c8b205967c7 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -1,19 +1,17 @@ package domain; -import java.util.ArrayList; import java.util.List; public class Player { private final String name; private final Hand hand = new Hand(); - private boolean isBust = false; public Player(String name) { this.name = name; } public boolean isBust() { - return isBust; + return hand.isBust(); } public void addCard(Card card) { @@ -32,10 +30,6 @@ public List getHandToString() { return hand.toStringList(); } - public void setBust() { - isBust = true; - } - public int getScore(){ return hand.calculateScore(); } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index c1372adb87d..9b2396e3d17 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -86,17 +86,16 @@ class GameManagerTest { player.addCard(new Card(Rank.ACE, Suit.SPADE)); player.addCard(new Card(Rank.KING, Suit.SPADE)); - assertThat(manager.isBlackjack(player)).isTrue(); + assertThat(player.getHand().isBlackjack()).isTrue(); } @Test void 합계가_21점이_아니면_블랙잭이_아니다() { - GameManager manager = new GameManager(); Player player = new Player("pobi"); player.addCard(new Card(Rank.TEN, Suit.SPADE)); player.addCard(new Card(Rank.KING, Suit.SPADE)); - assertThat(manager.isBlackjack(player)).isFalse(); + assertThat(player.getHand().isBlackjack()).isFalse(); } @Test From 4184dbce62230207efcfb62a2d09eccbdd91deac Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Mon, 9 Mar 2026 23:59:11 +0900 Subject: [PATCH 57/88] =?UTF-8?q?comment:=20=EB=B2=A0=ED=8C=85=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EC=8B=9C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=9D=B4=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 2 ++ src/main/java/domain/GameManager.java | 3 +++ src/main/java/domain/Player.java | 3 +++ src/main/java/domain/dto/GameFinalResultDto.java | 2 ++ src/main/java/view/InputView.java | 1 + src/main/java/view/OutputView.java | 2 ++ 6 files changed, 13 insertions(+) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 28c2f4634b4..643372f1bfa 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -22,6 +22,7 @@ public GameController(GameManager manager, InputView inputView, OutputView outpu public void run() { registerPlayer(); + // TODO: 베팅 기능 추가 시 플레이어 등록 후 베팅 입력 단계가 추가 필요 initGame(); playPlayerTurn(); playDealerTurn(); @@ -46,6 +47,7 @@ private void playPlayerTurn() { } private void registerPlayer() { + // TODO: 베팅 기능 추가 시 이름 입력 후 각 플레이어의 베팅 금액도 함께 등록 List playerNames = inputView.readPlayerName(); for (String playerName : playerNames) { manager.addPlayer(playerName); diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index cc94bd84937..c36cd00029e 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -39,6 +39,7 @@ public void drawDealerCard() { } public void addPlayer(String name) { + // TODO: 베팅 기능 추가 시 이름만이 아니라 베팅 금액도 함께 받도록 수정 필요 players.add(new Player(name)); } @@ -115,6 +116,7 @@ public boolean isDealerTurn() { } public List getFinalResult() { + // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 List results = new ArrayList<>(); results.add(new GameFinalResultDto(dealer.getName())); @@ -124,6 +126,7 @@ public List getFinalResult() { } private void determineWinLose(List results) { + // TODO: 베팅 기능 추가 시 승패 판정 후 베팅 금액 기준 정산 로직 추가 필요 for (Player player : players.getPlayers()) { int playerScore = player.getScore(); int dealerScore = dealer.getScore(); diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index c8b205967c7..18837a3f7d5 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -5,9 +5,12 @@ public class Player { private final String name; private final Hand hand = new Hand(); + // TODO: 베팅 기능 추가 시 베팅 금액 필드 또는 일급 객체 필요 + public Player(String name) { this.name = name; + // TODO: 베팅 기능 추가 시 생성자에서 베팅 금액도 함께 받아야 할 수 있음 } public boolean isBust() { diff --git a/src/main/java/domain/dto/GameFinalResultDto.java b/src/main/java/domain/dto/GameFinalResultDto.java index f61a9a581da..93d7a7c62e6 100644 --- a/src/main/java/domain/dto/GameFinalResultDto.java +++ b/src/main/java/domain/dto/GameFinalResultDto.java @@ -5,6 +5,8 @@ public class GameFinalResultDto { String name; Result result; + // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 + public GameFinalResultDto(String name) { this(name, null); diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 40fbc931af7..043fe6eb3a9 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -43,4 +43,5 @@ public String readCommand(String playerName) { System.out.println(COMMAND_REINPUT_MESSAGE); } } + // TODO: 베팅 기능 추가 시 플레이어별 베팅 금액 입력 메서드 필요 } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 7383cf017f9..ec97dcb8503 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -49,6 +49,7 @@ public void printScoreResults(List scoreResults) { } public void printFinalResult(List finalResult) { + // TODO: 베팅 기능 추가 시 정산 금액도 출력하도록 형식 수정 필요 System.out.println("## 최종 승패"); GameFinalResultDto firstPlayer = finalResult.removeFirst(); Map resultCounts = new EnumMap<>(Result.class); @@ -84,6 +85,7 @@ private void printDealerResult(GameFinalResultDto firstPlayer, Map finalResult) { + // TODO: 베팅 기능 추가 시 플레이어별 베팅 금액,수익 출력 필요 for (GameFinalResultDto result : finalResult) { System.out.println(MessageFormat.format( FINAL_RESULT_MESSAGE, From 8833d8c99330be28faa94a36ea496d88213352bd Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Tue, 10 Mar 2026 16:40:34 +0900 Subject: [PATCH 58/88] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=ED=84=B4=20=EC=A7=84=ED=96=89=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20GameManager=20=EC=B1=85=EC=9E=84=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++-- src/main/java/controller/GameController.java | 37 ++++++++-------- src/main/java/domain/Card.java | 1 - src/main/java/domain/Dealer.java | 6 +++ src/main/java/domain/GameManager.java | 41 +++++++---------- src/main/java/domain/Hand.java | 4 ++ src/main/java/domain/Player.java | 20 ++++++--- src/main/java/domain/Players.java | 5 ++- src/test/java/domain/GameManagerTest.java | 46 +++++++++++++++++--- 9 files changed, 110 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 9e858a08f87..c173a38c9ef 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,18 @@ - [x] domain.GameManager 리팩터링 - [x] 패키지 정리 - [x] drawDealerCard() 메서드의 응답값 미사용 -- [ ] GameManager의 책임 재분배 (Deck 초기화, 셔플) +- [ ] GameManager의 책임 재분배 + - [X] Deck 초기화, 셔플 책임 제거 + - [ ] - [ ] GameController 구조 수정 -- [ ] 디미터의 법칙 - 스트림 체이닝은 줄바꿈해서 작성, 체이닝 메서드 안생기도록 구조 수정 +- [ ] 디미터의 법칙 + - [ ] 스트림 체이닝은 줄바꿈해서 작성 + - [ ] 체이닝 메서드 안생기도록 구조 수정 - [x] rank 1 보다는 의미있는 값 (`ACE`)가 이해하기 쉽다 - [x] 주석이 정말 필요한지, 이름이나 구조로 충분하지 않은지 - [ ] primitive 타입과 wrapper 타입의 차이 - [X] 일급 컬렉션 -> Hand로 수정 - - [ ] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 + - [X] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 - [ ] Controller 구조 수정 - [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 - [ ] 플레이어가 입력되지 않는 경우에 대한 예외처리 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 643372f1bfa..61de6ac7a70 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -30,22 +30,6 @@ public void run() { outputView.printFinalResult(manager.getFinalResult()); } - private void playDealerTurn() { - while (manager.isDealerTurn()) { - manager.drawDealerCard(); - outputView.printDealerTurn(); - } - } - - private void playPlayerTurn() { - for (Player player : manager.getPlayerSequence()) { - while (isPlayerTurn(player) && isStand(player)) { - List playerHand = manager.drawPlayerCard(player); - outputView.printHand(playerHand, player.getName()); - } - } - } - private void registerPlayer() { // TODO: 베팅 기능 추가 시 이름 입력 후 각 플레이어의 베팅 금액도 함께 등록 List playerNames = inputView.readPlayerName(); @@ -61,11 +45,26 @@ private void initGame() { outputView.printInitialInfo(initialInfo); } - private boolean isStand(Player player) { + private void playPlayerTurn() { + for (Player player : manager.getPlayerSequence()) { + playSinglePlayerTurn(player); + } + } + + private void playSinglePlayerTurn(Player player) { + while (player.canDraw() && wantsToDraw(player)) { + List playerHand = manager.drawPlayerCard(player); + outputView.printHand(playerHand, player.getName()); + } + } + + private boolean wantsToDraw(Player player) { return !inputView.readCommand(player.getName()).equals("n"); } - private boolean isPlayerTurn(Player player) { - return !(player.isBust() || manager.isBlackjack(player)); + private void playDealerTurn() { + while (manager.proceedDealerTurn()) { + outputView.printDealerTurn(); + } } } diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/Card.java index d883947cb5e..d0727d0ee64 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/Card.java @@ -23,7 +23,6 @@ public int getRankValue() { return this.rank.getValue(); } - @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/src/main/java/domain/Dealer.java b/src/main/java/domain/Dealer.java index 06245fe081d..8d388187458 100644 --- a/src/main/java/domain/Dealer.java +++ b/src/main/java/domain/Dealer.java @@ -1,8 +1,14 @@ package domain; public class Dealer extends Player { + private final int DEALER_DRAW_CONDITION = 16; public Dealer() { super("딜러"); } + + @Override + public boolean canDraw(){ + return this.getScore() <= DEALER_DRAW_CONDITION; + } } diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index c36cd00029e..6772e51c919 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -9,6 +9,8 @@ import java.util.List; public class GameManager { + private final int FIRST_DRAW_CARDS = 2; + private final Deck deck = new Deck(); private final Players players = new Players(); private final Dealer dealer = new Dealer(); @@ -16,28 +18,17 @@ public class GameManager { public GameManager() {} public void startGame() { - for (int i = 0; i < 2; i++) { - for (Player player : players.getPlayers()) { - player.addCard(deck.draw()); - } - dealer.addCard(deck.draw()); + for (int i = 0; i < FIRST_DRAW_CARDS; i++) { + players.receiveCard(deck.draw()); + dealer.receiveCard(deck.draw()); } } - - public int calculateScore(Hand hand) { - return hand.calculateScore(); - } - public List drawPlayerCard(Player player) { - player.addCard(deck.draw()); + player.receiveCard(deck.draw()); return player.getHandToString(); } - public void drawDealerCard() { - dealer.addCard(deck.draw()); - } - public void addPlayer(String name) { // TODO: 베팅 기능 추가 시 이름만이 아니라 베팅 금액도 함께 받도록 수정 필요 players.add(new Player(name)); @@ -49,9 +40,7 @@ public List getPlayerSequence() { public List getScoreResults() { List results = new ArrayList<>(); - // dealer aggregateDealerResult(results); - //players aggregatePlayerResult(results); return results; @@ -107,14 +96,6 @@ private void addDealerInfo(List results, List dealer )); } - public boolean isBlackjack(Player player) { - return calculateScore(player.getHand()) == 21; - } - - public boolean isDealerTurn() { - return calculateScore(dealer.getHand()) <= 16; - } - public List getFinalResult() { // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 List results = new ArrayList<>(); @@ -143,4 +124,14 @@ private void determineWinLose(List results) { results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); } } + + public boolean proceedDealerTurn() { + if (!dealer.canDraw()) { + return false; + } + + Card card = deck.draw(); + dealer.receiveCard(card); + return true; + } } diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index d1590ff366e..d873ac8b61e 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -58,4 +58,8 @@ public boolean isBust() { public boolean isBlackjack() { return calculateScore() == BLACKJACK_SCORE; } + + public int size() { + return hand.size(); + } } diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 18837a3f7d5..e038835b8b8 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -17,16 +17,16 @@ public boolean isBust() { return hand.isBust(); } - public void addCard(Card card) { + public void receiveCard(Card card) { hand.add(card); } - public String getName() { - return name; + public boolean canDraw() { + return !(isBust()|| hand.isBlackjack()); } - public Hand getHand() { - return hand; + public int handSize() { + return hand.size(); } public List getHandToString() { @@ -36,4 +36,12 @@ public List getHandToString() { public int getScore(){ return hand.calculateScore(); } -} \ No newline at end of file + + public String getName() { + return name; + } + + public Hand getHand() { + return hand; + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java index e0d1a7f4aba..91a3e3026b3 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/Players.java @@ -6,11 +6,14 @@ public class Players { private final List players = new ArrayList<>(); - public void add(Player player) { players.add(player); } + public void receiveCard(Card card) { + players.forEach(player -> player.receiveCard(card)); + } + public List getPlayers() { return List.copyOf(players); } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 9b2396e3d17..15a33595700 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -83,8 +83,8 @@ class GameManagerTest { void 합계가_21점이면_블랙잭이다() { GameManager manager = new GameManager(); Player player = new Player("pobi"); - player.addCard(new Card(Rank.ACE, Suit.SPADE)); - player.addCard(new Card(Rank.KING, Suit.SPADE)); + player.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + player.receiveCard(new Card(Rank.KING, Suit.SPADE)); assertThat(player.getHand().isBlackjack()).isTrue(); } @@ -92,17 +92,53 @@ class GameManagerTest { @Test void 합계가_21점이_아니면_블랙잭이_아니다() { Player player = new Player("pobi"); - player.addCard(new Card(Rank.TEN, Suit.SPADE)); - player.addCard(new Card(Rank.KING, Suit.SPADE)); + player.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + player.receiveCard(new Card(Rank.KING, Suit.SPADE)); assertThat(player.getHand().isBlackjack()).isFalse(); } @Test void 딜러가_16점_이하인지_확인한다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)) ; + + assertThat(dealer.canDraw()).isTrue(); + } + + @Test + void 플레이어가_카드를_한장_더_받는다() { + GameManager manager = new GameManager(); + manager.addPlayer("pobi"); + + manager.startGame(); + Player player = manager.getPlayerSequence().getFirst(); + + int before = player.handSize(); + + manager.drawPlayerCard(player); + + int after = player.handSize(); + + assertThat(after).isEqualTo(before + 1); + } + + @Test + void 딜러가_카드를_뽑으면_true를_반환한다() { GameManager manager = new GameManager(); - assertThat(manager.isDealerTurn()).isTrue(); + boolean result = manager.proceedDealerTurn(); + + assertThat(result).isTrue(); } + @Test + void 딜러가_더이상_카드를_못뽑으면_false를_반환한다() { + Dealer dealer = new Dealer(); + + dealer.receiveCard(new Card(Rank.KING, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.QUEEN, Suit.SPADE)); + + assertThat(dealer.canDraw()).isFalse(); + } } \ No newline at end of file From 2465c5a33da34970aa70e8169a544fe6a65a35be Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Tue, 10 Mar 2026 16:49:21 +0900 Subject: [PATCH 59/88] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=ED=84=B4=20=EC=A7=84=ED=96=89=20=EC=B1=85=EC=9E=84=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20GameManager=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 37 ++++++++-------- src/main/java/domain/Card.java | 1 - src/main/java/domain/Dealer.java | 6 +++ src/main/java/domain/GameManager.java | 41 +++++++---------- src/main/java/domain/Hand.java | 4 ++ src/main/java/domain/Player.java | 20 ++++++--- src/main/java/domain/Players.java | 5 ++- src/test/java/domain/GameManagerTest.java | 46 +++++++++++++++++--- 8 files changed, 103 insertions(+), 57 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 643372f1bfa..61de6ac7a70 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -30,22 +30,6 @@ public void run() { outputView.printFinalResult(manager.getFinalResult()); } - private void playDealerTurn() { - while (manager.isDealerTurn()) { - manager.drawDealerCard(); - outputView.printDealerTurn(); - } - } - - private void playPlayerTurn() { - for (Player player : manager.getPlayerSequence()) { - while (isPlayerTurn(player) && isStand(player)) { - List playerHand = manager.drawPlayerCard(player); - outputView.printHand(playerHand, player.getName()); - } - } - } - private void registerPlayer() { // TODO: 베팅 기능 추가 시 이름 입력 후 각 플레이어의 베팅 금액도 함께 등록 List playerNames = inputView.readPlayerName(); @@ -61,11 +45,26 @@ private void initGame() { outputView.printInitialInfo(initialInfo); } - private boolean isStand(Player player) { + private void playPlayerTurn() { + for (Player player : manager.getPlayerSequence()) { + playSinglePlayerTurn(player); + } + } + + private void playSinglePlayerTurn(Player player) { + while (player.canDraw() && wantsToDraw(player)) { + List playerHand = manager.drawPlayerCard(player); + outputView.printHand(playerHand, player.getName()); + } + } + + private boolean wantsToDraw(Player player) { return !inputView.readCommand(player.getName()).equals("n"); } - private boolean isPlayerTurn(Player player) { - return !(player.isBust() || manager.isBlackjack(player)); + private void playDealerTurn() { + while (manager.proceedDealerTurn()) { + outputView.printDealerTurn(); + } } } diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/Card.java index d883947cb5e..d0727d0ee64 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/Card.java @@ -23,7 +23,6 @@ public int getRankValue() { return this.rank.getValue(); } - @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/src/main/java/domain/Dealer.java b/src/main/java/domain/Dealer.java index 06245fe081d..8d388187458 100644 --- a/src/main/java/domain/Dealer.java +++ b/src/main/java/domain/Dealer.java @@ -1,8 +1,14 @@ package domain; public class Dealer extends Player { + private final int DEALER_DRAW_CONDITION = 16; public Dealer() { super("딜러"); } + + @Override + public boolean canDraw(){ + return this.getScore() <= DEALER_DRAW_CONDITION; + } } diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index c36cd00029e..6772e51c919 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -9,6 +9,8 @@ import java.util.List; public class GameManager { + private final int FIRST_DRAW_CARDS = 2; + private final Deck deck = new Deck(); private final Players players = new Players(); private final Dealer dealer = new Dealer(); @@ -16,28 +18,17 @@ public class GameManager { public GameManager() {} public void startGame() { - for (int i = 0; i < 2; i++) { - for (Player player : players.getPlayers()) { - player.addCard(deck.draw()); - } - dealer.addCard(deck.draw()); + for (int i = 0; i < FIRST_DRAW_CARDS; i++) { + players.receiveCard(deck.draw()); + dealer.receiveCard(deck.draw()); } } - - public int calculateScore(Hand hand) { - return hand.calculateScore(); - } - public List drawPlayerCard(Player player) { - player.addCard(deck.draw()); + player.receiveCard(deck.draw()); return player.getHandToString(); } - public void drawDealerCard() { - dealer.addCard(deck.draw()); - } - public void addPlayer(String name) { // TODO: 베팅 기능 추가 시 이름만이 아니라 베팅 금액도 함께 받도록 수정 필요 players.add(new Player(name)); @@ -49,9 +40,7 @@ public List getPlayerSequence() { public List getScoreResults() { List results = new ArrayList<>(); - // dealer aggregateDealerResult(results); - //players aggregatePlayerResult(results); return results; @@ -107,14 +96,6 @@ private void addDealerInfo(List results, List dealer )); } - public boolean isBlackjack(Player player) { - return calculateScore(player.getHand()) == 21; - } - - public boolean isDealerTurn() { - return calculateScore(dealer.getHand()) <= 16; - } - public List getFinalResult() { // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 List results = new ArrayList<>(); @@ -143,4 +124,14 @@ private void determineWinLose(List results) { results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); } } + + public boolean proceedDealerTurn() { + if (!dealer.canDraw()) { + return false; + } + + Card card = deck.draw(); + dealer.receiveCard(card); + return true; + } } diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index d1590ff366e..d873ac8b61e 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -58,4 +58,8 @@ public boolean isBust() { public boolean isBlackjack() { return calculateScore() == BLACKJACK_SCORE; } + + public int size() { + return hand.size(); + } } diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 18837a3f7d5..e038835b8b8 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -17,16 +17,16 @@ public boolean isBust() { return hand.isBust(); } - public void addCard(Card card) { + public void receiveCard(Card card) { hand.add(card); } - public String getName() { - return name; + public boolean canDraw() { + return !(isBust()|| hand.isBlackjack()); } - public Hand getHand() { - return hand; + public int handSize() { + return hand.size(); } public List getHandToString() { @@ -36,4 +36,12 @@ public List getHandToString() { public int getScore(){ return hand.calculateScore(); } -} \ No newline at end of file + + public String getName() { + return name; + } + + public Hand getHand() { + return hand; + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java index e0d1a7f4aba..91a3e3026b3 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/Players.java @@ -6,11 +6,14 @@ public class Players { private final List players = new ArrayList<>(); - public void add(Player player) { players.add(player); } + public void receiveCard(Card card) { + players.forEach(player -> player.receiveCard(card)); + } + public List getPlayers() { return List.copyOf(players); } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 9b2396e3d17..15a33595700 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -83,8 +83,8 @@ class GameManagerTest { void 합계가_21점이면_블랙잭이다() { GameManager manager = new GameManager(); Player player = new Player("pobi"); - player.addCard(new Card(Rank.ACE, Suit.SPADE)); - player.addCard(new Card(Rank.KING, Suit.SPADE)); + player.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + player.receiveCard(new Card(Rank.KING, Suit.SPADE)); assertThat(player.getHand().isBlackjack()).isTrue(); } @@ -92,17 +92,53 @@ class GameManagerTest { @Test void 합계가_21점이_아니면_블랙잭이_아니다() { Player player = new Player("pobi"); - player.addCard(new Card(Rank.TEN, Suit.SPADE)); - player.addCard(new Card(Rank.KING, Suit.SPADE)); + player.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + player.receiveCard(new Card(Rank.KING, Suit.SPADE)); assertThat(player.getHand().isBlackjack()).isFalse(); } @Test void 딜러가_16점_이하인지_확인한다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)) ; + + assertThat(dealer.canDraw()).isTrue(); + } + + @Test + void 플레이어가_카드를_한장_더_받는다() { + GameManager manager = new GameManager(); + manager.addPlayer("pobi"); + + manager.startGame(); + Player player = manager.getPlayerSequence().getFirst(); + + int before = player.handSize(); + + manager.drawPlayerCard(player); + + int after = player.handSize(); + + assertThat(after).isEqualTo(before + 1); + } + + @Test + void 딜러가_카드를_뽑으면_true를_반환한다() { GameManager manager = new GameManager(); - assertThat(manager.isDealerTurn()).isTrue(); + boolean result = manager.proceedDealerTurn(); + + assertThat(result).isTrue(); } + @Test + void 딜러가_더이상_카드를_못뽑으면_false를_반환한다() { + Dealer dealer = new Dealer(); + + dealer.receiveCard(new Card(Rank.KING, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.QUEEN, Suit.SPADE)); + + assertThat(dealer.canDraw()).isFalse(); + } } \ No newline at end of file From d74f9045a733646704916778019a6c8f109f89cf Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Tue, 10 Mar 2026 17:28:05 +0900 Subject: [PATCH 60/88] =?UTF-8?q?refactor:=20=EB=B9=84=EC=96=B4=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EB=94=9C=EB=9F=AC=20=EC=98=A4=ED=94=88=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B2=B4=EC=9D=B4?= =?UTF-8?q?=EB=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 21 ++++++++-------- src/main/java/controller/GameController.java | 26 +++++++++++++++++--- src/main/java/domain/Dealer.java | 4 +++ src/main/java/view/OutputView.java | 6 ++++- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c173a38c9ef..e8cf3fadb64 100644 --- a/README.md +++ b/README.md @@ -49,19 +49,20 @@ - [x] 패키지 정리 - [x] drawDealerCard() 메서드의 응답값 미사용 - [ ] GameManager의 책임 재분배 - - [X] Deck 초기화, 셔플 책임 제거 - - [ ] -- [ ] GameController 구조 수정 -- [ ] 디미터의 법칙 - - [ ] 스트림 체이닝은 줄바꿈해서 작성 - - [ ] 체이닝 메서드 안생기도록 구조 수정 + - [x] Deck 초기화, 셔플 책임 제거 + - [ ] DTO 생성 책임 분리 + - [ ] 승패 판정 책임 분리 +- [x] GameController 구조 수정 +- [x] 디미터의 법칙 + - [x] 스트림 체이닝은 줄바꿈해서 작성 + - [x] 체이닝 메서드 안생기도록 구조 수정 - [x] rank 1 보다는 의미있는 값 (`ACE`)가 이해하기 쉽다 - [x] 주석이 정말 필요한지, 이름이나 구조로 충분하지 않은지 -- [ ] primitive 타입과 wrapper 타입의 차이 -- [X] 일급 컬렉션 -> Hand로 수정 - - [X] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 +- [x] primitive 타입 wrapper로 감싸기 +- [x] 일급 컬렉션 -> Hand로 수정 + - [x] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 - [ ] Controller 구조 수정 - [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 -- [ ] 플레이어가 입력되지 않는 경우에 대한 예외처리 +- [x] 플레이어가 입력되지 않는 경우에 대한 예외처리 - [ ] 규칙 적용 - [ ] 테스트 케이스 추가 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 61de6ac7a70..5d409a26725 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -32,9 +32,19 @@ public void run() { private void registerPlayer() { // TODO: 베팅 기능 추가 시 이름 입력 후 각 플레이어의 베팅 금액도 함께 등록 - List playerNames = inputView.readPlayerName(); - for (String playerName : playerNames) { - manager.addPlayer(playerName); + while (true) { + try { + List playerNames = inputView.readPlayerName(); + validatePlayerNames(playerNames); + + for (String playerName : playerNames) { + manager.addPlayer(playerName); + } + return; + + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } } } @@ -67,4 +77,14 @@ private void playDealerTurn() { outputView.printDealerTurn(); } } + + private void validatePlayerNames(List playerNames) { + if (playerNames == null || playerNames.isEmpty()) { + throw new IllegalArgumentException("플레이어 이름을 입력해야 합니다."); + } + + if (playerNames.stream().anyMatch(name -> name == null || name.isBlank())) { + throw new IllegalArgumentException("플레이어 이름은 비어 있을 수 없습니다."); + } + } } diff --git a/src/main/java/domain/Dealer.java b/src/main/java/domain/Dealer.java index 8d388187458..198f4147283 100644 --- a/src/main/java/domain/Dealer.java +++ b/src/main/java/domain/Dealer.java @@ -11,4 +11,8 @@ public Dealer() { public boolean canDraw(){ return this.getScore() <= DEALER_DRAW_CONDITION; } + + public String getOpenCard() { + return getHandToString().getFirst(); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index ec97dcb8503..940af510dca 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -16,6 +16,8 @@ public class OutputView { private static final String SHOW_HAND_MESSAGE = "{0}카드: {1}"; private static final String FINAL_RESULT_MESSAGE = "{0}: {1}"; private static final String DEALER_DRAW_MESSAGE = "딜러는 16이하라 한장의 카드를 더 받았습니다."; + private static final String ERROR_PREFIX = "[ERROR] "; + public void printInitialInfo(List initialInfo) { printHandOutNotice(initialInfo); @@ -107,7 +109,6 @@ private void printHandOutNotice(List initialInfo) { initialInfo.getFirst().getInitialHandSize() )); } - private void printInitialHands(List initialInfo) { for (GameInitialInfoDto info : initialInfo) { System.out.println(MessageFormat.format( @@ -118,4 +119,7 @@ private void printInitialHands(List initialInfo) { } System.out.println(); } + public void printError(String message) { + System.out.println(ERROR_PREFIX + message); + } } From 34257ceeec4076bb26fe45e27a5c2201845f37f7 Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Tue, 10 Mar 2026 17:28:14 +0900 Subject: [PATCH 61/88] =?UTF-8?q?refactor:=20=EB=B9=84=EC=96=B4=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EB=94=9C=EB=9F=AC=20=EC=98=A4=ED=94=88=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B2=B4=EC=9D=B4?= =?UTF-8?q?=EB=8B=9D=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/domain/GameManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index 6772e51c919..ab82e139005 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -68,7 +68,7 @@ public List getInitialInfo() { List results = new ArrayList<>(); List dealerOpenCard = new ArrayList<>(); - dealerOpenCard.add(dealer.getHandToString().getFirst()); + dealerOpenCard.add(dealer.getOpenCard()); addDealerInfo(results, dealerOpenCard); From 3fd45c7d5b33620c328fd9ac50ec78b226695fff Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Tue, 10 Mar 2026 23:10:59 +0900 Subject: [PATCH 62/88] =?UTF-8?q?refactor:=20GameManager=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EB=B6=84=EB=B0=B0(DTO=20=EC=83=9D=EC=84=B1,=20?= =?UTF-8?q?=EC=8A=B9=ED=8C=A8=20=ED=8C=90=EB=8F=85)=20=EB=B0=8F=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +- src/main/java/Application.java | 5 +- src/main/java/domain/DtoFactory.java | 63 ++++++++++ src/main/java/domain/GameManager.java | 104 +++------------ src/main/java/domain/GameResultJudge.java | 53 ++++++++ .../java/domain/dto/GameFinalResultDto.java | 16 +-- src/main/java/view/OutputView.java | 4 +- src/test/java/domain/DealerTest.java | 28 +++++ src/test/java/domain/DtoFactoryTest.java | 72 +++++++++++ src/test/java/domain/GameManagerTest.java | 92 ++++++++------ src/test/java/domain/GameResultJudgeTest.java | 119 ++++++++++++++++++ src/test/java/domain/HandTest.java | 28 +++++ 12 files changed, 451 insertions(+), 142 deletions(-) create mode 100644 src/main/java/domain/DtoFactory.java create mode 100644 src/main/java/domain/GameResultJudge.java create mode 100644 src/test/java/domain/DealerTest.java create mode 100644 src/test/java/domain/DtoFactoryTest.java create mode 100644 src/test/java/domain/GameResultJudgeTest.java create mode 100644 src/test/java/domain/HandTest.java diff --git a/README.md b/README.md index e8cf3fadb64..685ca5d862e 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,10 @@ - [x] domain.GameManager 리팩터링 - [x] 패키지 정리 - [x] drawDealerCard() 메서드의 응답값 미사용 -- [ ] GameManager의 책임 재분배 +- [x] GameManager의 책임 재분배 - [x] Deck 초기화, 셔플 책임 제거 - - [ ] DTO 생성 책임 분리 - - [ ] 승패 판정 책임 분리 + - [x] DTO 생성 책임 분리 + - [x] 승패 판정 책임 분리 - [x] GameController 구조 수정 - [x] 디미터의 법칙 - [x] 스트림 체이닝은 줄바꿈해서 작성 @@ -61,8 +61,7 @@ - [x] primitive 타입 wrapper로 감싸기 - [x] 일급 컬렉션 -> Hand로 수정 - [x] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 -- [ ] Controller 구조 수정 - [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 - [x] 플레이어가 입력되지 않는 경우에 대한 예외처리 -- [ ] 규칙 적용 +- [x] 규칙 적용 - [ ] 테스트 케이스 추가 diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 100c5ed7785..57a073dce52 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,4 +1,5 @@ import controller.GameController; +import domain.Deck; import domain.GameManager; import view.InputView; import view.OutputView; @@ -6,9 +7,11 @@ public class Application { public static void main(String[] args) { + Deck deck = new Deck(); + GameManager manager = new GameManager(deck); + InputView inputView = new InputView(); OutputView outputView = new OutputView(); - GameManager manager = new GameManager(); GameController controller = new GameController(manager, inputView, outputView); controller.run(); diff --git a/src/main/java/domain/DtoFactory.java b/src/main/java/domain/DtoFactory.java new file mode 100644 index 00000000000..91ce39c75d3 --- /dev/null +++ b/src/main/java/domain/DtoFactory.java @@ -0,0 +1,63 @@ +package domain; + +import domain.dto.GameInitialInfoDto; +import domain.dto.GameScoreResultDto; +import java.util.ArrayList; +import java.util.List; + +public class DtoFactory { + private static final int INITIAL_HAND_SIZE = 2; + + private DtoFactory() { + } + + public static List toScoreResults(Dealer dealer, Players players) { + List results = new ArrayList<>(); + addDealerScoreResult(results, dealer); + addPlayerScoreResults(results, players); + return results; + } + + public static List toInitialInfo(Dealer dealer, Players players) { + List results = new ArrayList<>(); + addDealerInitialInfo(results, dealer); + addPlayerInitialInfos(results, players); + return results; + } + + private static void addDealerScoreResult(List results, Dealer dealer) { + results.add(new GameScoreResultDto( + dealer.getName(), + dealer.getHandToString(), + dealer.getScore() + )); + } + + private static void addPlayerScoreResults(List results, Players players) { + for (Player player : players.getPlayers()) { + results.add(new GameScoreResultDto( + player.getName(), + player.getHandToString(), + player.getScore() + )); + } + } + + private static void addDealerInitialInfo(List results, Dealer dealer) { + results.add(new GameInitialInfoDto( + dealer.getName(), + INITIAL_HAND_SIZE, + List.of(dealer.getOpenCard()) + )); + } + + private static void addPlayerInitialInfos(List results, Players players) { + for (Player player : players.getPlayers()) { + results.add(new GameInitialInfoDto( + player.getName(), + INITIAL_HAND_SIZE, + player.getHandToString() + )); + } + } +} diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/GameManager.java index ab82e139005..2a5e2d50fde 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/GameManager.java @@ -1,21 +1,23 @@ package domain; -import domain.constant.Result; import domain.dto.GameFinalResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; -import java.util.ArrayList; import java.util.List; public class GameManager { private final int FIRST_DRAW_CARDS = 2; - private final Deck deck = new Deck(); - private final Players players = new Players(); - private final Dealer dealer = new Dealer(); + private final Deck deck; + private final Players players; + private final Dealer dealer; - public GameManager() {} + public GameManager(Deck deck) { + this.deck = deck; + this.players = new Players(); + this.dealer = new Dealer(); + } public void startGame() { for (int i = 0; i < FIRST_DRAW_CARDS; i++) { @@ -39,99 +41,25 @@ public List getPlayerSequence() { } public List getScoreResults() { - List results = new ArrayList<>(); - aggregateDealerResult(results); - aggregatePlayerResult(results); - - return results; - } - - private void aggregateDealerResult(List results) { - results.add(new GameScoreResultDto( - dealer.getName(), - dealer.getHandToString(), - dealer.getScore() - )); - } - - private void aggregatePlayerResult(List results) { - for (Player player : players.getPlayers()) { - results.add(new GameScoreResultDto( - player.getName(), - player.getHandToString(), - player.getScore() - )); - } + return DtoFactory.toScoreResults(dealer, players); } public List getInitialInfo() { - List results = new ArrayList<>(); - - List dealerOpenCard = new ArrayList<>(); - dealerOpenCard.add(dealer.getOpenCard()); - - - addDealerInfo(results, dealerOpenCard); - - addPlayersInfo(results); - - return results; - } - - private void addPlayersInfo(List results) { - for (Player player : players.getPlayers()) { - results.add(new GameInitialInfoDto( - player.getName(), - 2, - player.getHandToString() - )); - } - } - - private void addDealerInfo(List results, List dealerOpenCard) { - results.add(new GameInitialInfoDto( - dealer.getName(), - 2, - dealerOpenCard - )); - } - - public List getFinalResult() { - // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 - List results = new ArrayList<>(); - results.add(new GameFinalResultDto(dealer.getName())); - - determineWinLose(results); - - return results; + return DtoFactory.toInitialInfo(dealer, players); } - private void determineWinLose(List results) { - // TODO: 베팅 기능 추가 시 승패 판정 후 베팅 금액 기준 정산 로직 추가 필요 - for (Player player : players.getPlayers()) { - int playerScore = player.getScore(); - int dealerScore = dealer.getScore(); - if (player.isBust() || playerScore < dealerScore) { - results.add(new GameFinalResultDto(player.getName(), Result.LOSE)); - continue; - } - - if (playerScore > dealerScore) { - results.add(new GameFinalResultDto(player.getName(), Result.WIN)); - continue; - } - - results.add(new GameFinalResultDto(player.getName(), Result.DRAW)); - } - } public boolean proceedDealerTurn() { if (!dealer.canDraw()) { return false; } - Card card = deck.draw(); - dealer.receiveCard(card); + dealer.receiveCard(deck.draw()); return true; } + + public List getFinalResult() { + return GameResultJudge.judge(dealer, players); + } + } diff --git a/src/main/java/domain/GameResultJudge.java b/src/main/java/domain/GameResultJudge.java new file mode 100644 index 00000000000..5b55fc73ec5 --- /dev/null +++ b/src/main/java/domain/GameResultJudge.java @@ -0,0 +1,53 @@ +package domain; + +import domain.constant.Result; +import domain.dto.GameFinalResultDto; +import java.util.ArrayList; +import java.util.List; + +public class GameResultJudge { + private GameResultJudge() { + } + + public static List judge(Dealer dealer, Players players) { + // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 + List results = new ArrayList<>(); + results.add(new GameFinalResultDto(dealer.getName())); + addPlayerResults(results, dealer, players); + return results; + } + + private static void addPlayerResults(List results, Dealer dealer, Players players) { + for (Player player : players.getPlayers()) { + results.add(judgePlayer(player, dealer)); + } + } + + private static GameFinalResultDto judgePlayer(Player player, Dealer dealer) { + Result result = calculateResult(player, dealer); + return new GameFinalResultDto(player.getName(), result); + } + + private static Result calculateResult(Player player, Dealer dealer) { + int playerScore = player.getScore(); + int dealerScore = dealer.getScore(); + + if (player.isBust()) { + return Result.LOSE; + } + + if (dealer.isBust()) { + return Result.WIN; + } + + if (playerScore > dealerScore) { + return Result.WIN; + } + + if (playerScore < dealerScore) { + return Result.LOSE; + } + + return Result.DRAW; + } +} diff --git a/src/main/java/domain/dto/GameFinalResultDto.java b/src/main/java/domain/dto/GameFinalResultDto.java index 93d7a7c62e6..1ea7ff21350 100644 --- a/src/main/java/domain/dto/GameFinalResultDto.java +++ b/src/main/java/domain/dto/GameFinalResultDto.java @@ -3,22 +3,22 @@ import domain.constant.Result; public class GameFinalResultDto { - String name; + String playerName; Result result; // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 - public GameFinalResultDto(String name) { - this(name, null); + public GameFinalResultDto(String playerName) { + this(playerName, null); } - public GameFinalResultDto(String name, Result result) { - this.name = name; + public GameFinalResultDto(String playerName, Result result) { + this.playerName = playerName; this.result = result; } - public String getName() { - return name; + public String getPlayerName() { + return playerName; } public Result getResult() { @@ -28,7 +28,7 @@ public Result getResult() { @Override public String toString() { return "domain.dto.GameFinalResultDto{" + - "name='" + name + '\'' + + "name='" + playerName + '\'' + ", result=" + result + '}'; } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 940af510dca..c5d584511ce 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -79,7 +79,7 @@ private void countDealerResult(List finalResult, Map resultCounts) { StringBuilder sb = new StringBuilder(); - sb.append(firstPlayer.getName()).append(": "); + sb.append(firstPlayer.getPlayerName()).append(": "); for (Result result : resultCounts.keySet()) { sb.append(resultCounts.get(result)).append(result.getName()); } @@ -91,7 +91,7 @@ private void printPlayerResult(List finalResult) { for (GameFinalResultDto result : finalResult) { System.out.println(MessageFormat.format( FINAL_RESULT_MESSAGE, - result.getName(), + result.getPlayerName(), result.getResult().getName() )); } diff --git a/src/test/java/domain/DealerTest.java b/src/test/java/domain/DealerTest.java new file mode 100644 index 00000000000..669c08777b5 --- /dev/null +++ b/src/test/java/domain/DealerTest.java @@ -0,0 +1,28 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class DealerTest { + + @Test + void 딜러의_점수가_16점_이하면_카드를_더_뽑을_수_있다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.FIVE, Suit.HEART)); + + assertThat(dealer.canDraw()).isTrue(); + } + + @Test + void 딜러의_점수가_17점_이상이면_카드를_더_뽑을_수_없다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + + assertThat(dealer.canDraw()).isFalse(); + } +} \ No newline at end of file diff --git a/src/test/java/domain/DtoFactoryTest.java b/src/test/java/domain/DtoFactoryTest.java new file mode 100644 index 00000000000..2c4572c3ad3 --- /dev/null +++ b/src/test/java/domain/DtoFactoryTest.java @@ -0,0 +1,72 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import domain.dto.GameInitialInfoDto; +import domain.dto.GameScoreResultDto; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class DtoFactoryTest { + + @Test + void 초기정보를_생성하면_딜러는_한장만_공개된다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(domain.constant.Rank.ACE, domain.constant.Suit.SPADE)); + dealer.receiveCard(new Card(domain.constant.Rank.KING, domain.constant.Suit.HEART)); + + Players players = new Players(); + Player player = new Player("pobi"); + player.receiveCard(new Card(domain.constant.Rank.TWO, domain.constant.Suit.CLUB)); + player.receiveCard(new Card(domain.constant.Rank.THREE, domain.constant.Suit.DIAMOND)); + players.add(player); + + List result = DtoFactory.toInitialInfo(dealer, players); + + assertThat(result).hasSize(2); + assertThat(result.get(0).getPlayerName()).isEqualTo("딜러"); + assertThat(result.get(0).getHand()).hasSize(1); + } + + @Test + void 초기정보를_생성하면_플레이어는_두장을_공개한다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(domain.constant.Rank.ACE, domain.constant.Suit.SPADE)); + dealer.receiveCard(new Card(domain.constant.Rank.KING, domain.constant.Suit.HEART)); + + Players players = new Players(); + Player player = new Player("pobi"); + player.receiveCard(new Card(domain.constant.Rank.TWO, domain.constant.Suit.CLUB)); + player.receiveCard(new Card(domain.constant.Rank.THREE, domain.constant.Suit.DIAMOND)); + players.add(player); + + List result = DtoFactory.toInitialInfo(dealer, players); + + assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); + assertThat(result.get(1).getHand()).hasSize(2); + } + + @Test + void 점수결과를_생성하면_딜러와_플레이어의_이름_승패_정보를_포함한다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(domain.constant.Rank.TEN, domain.constant.Suit.SPADE)); + dealer.receiveCard(new Card(domain.constant.Rank.SEVEN, domain.constant.Suit.HEART)); + + Players players = new Players(); + Player player = new Player("pobi"); + player.receiveCard(new Card(domain.constant.Rank.NINE, domain.constant.Suit.CLUB)); + player.receiveCard(new Card(domain.constant.Rank.EIGHT, domain.constant.Suit.DIAMOND)); + players.add(player); + + List result = DtoFactory.toScoreResults(dealer, players); + + assertThat(result).hasSize(2); + assertThat(result.get(0).getPlayerName()).isEqualTo("딜러"); + assertThat(result.get(0).getHand()).hasSize(2); + assertThat(result.get(0).getResult()).isEqualTo(17); + + assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); + assertThat(result.get(1).getHand()).hasSize(2); + assertThat(result.get(1).getResult()).isEqualTo(17); + } +} diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 15a33595700..6046cc066ca 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -2,6 +2,7 @@ import domain.constant.Rank; import domain.constant.Suit; +import domain.dto.GameFinalResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; import org.junit.jupiter.api.Test; @@ -14,7 +15,7 @@ class GameManagerTest { @Test void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi"); manager.addPlayer("cary"); @@ -32,7 +33,7 @@ class GameManagerTest { @Test void 딜러의_카드는_한_장만_공개한다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi"); @@ -44,7 +45,7 @@ class GameManagerTest { @Test void 플레이어의_카드는_두_장_공개한다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi"); @@ -56,7 +57,7 @@ class GameManagerTest { @Test void 플레이어를_한명_등록한다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi"); List result = manager.getPlayerSequence(); @@ -67,7 +68,7 @@ class GameManagerTest { @Test void 플레이어를_세명_등록한다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); List playerNames = List.of("pobi", "cary", "rudy"); for (String playerName : playerNames) { @@ -79,36 +80,10 @@ class GameManagerTest { assertThat(result.size()).isEqualTo(3); } - @Test - void 합계가_21점이면_블랙잭이다() { - GameManager manager = new GameManager(); - Player player = new Player("pobi"); - player.receiveCard(new Card(Rank.ACE, Suit.SPADE)); - player.receiveCard(new Card(Rank.KING, Suit.SPADE)); - - assertThat(player.getHand().isBlackjack()).isTrue(); - } - - @Test - void 합계가_21점이_아니면_블랙잭이_아니다() { - Player player = new Player("pobi"); - player.receiveCard(new Card(Rank.TEN, Suit.SPADE)); - player.receiveCard(new Card(Rank.KING, Suit.SPADE)); - - assertThat(player.getHand().isBlackjack()).isFalse(); - } - - @Test - void 딜러가_16점_이하인지_확인한다() { - Dealer dealer = new Dealer(); - dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)) ; - - assertThat(dealer.canDraw()).isTrue(); - } @Test void 플레이어가_카드를_한장_더_받는다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi"); manager.startGame(); @@ -125,7 +100,7 @@ class GameManagerTest { @Test void 딜러가_카드를_뽑으면_true를_반환한다() { - GameManager manager = new GameManager(); + GameManager manager = new GameManager(new Deck()); boolean result = manager.proceedDealerTurn(); @@ -133,12 +108,53 @@ class GameManagerTest { } @Test - void 딜러가_더이상_카드를_못뽑으면_false를_반환한다() { - Dealer dealer = new Dealer(); + void 게임_최종_결과에는_딜러와_모든_플레이어_결과가_포함된다() { + GameManager manager = new GameManager(new Deck()); + manager.addPlayer("pobi"); + manager.addPlayer("cary"); - dealer.receiveCard(new Card(Rank.KING, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.QUEEN, Suit.SPADE)); + List result = manager.getFinalResult(); - assertThat(dealer.canDraw()).isFalse(); + assertThat(result).hasSize(3); + assertThat(result.get(0).getPlayerName()).isEqualTo("딜러"); + assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); + assertThat(result.get(2).getPlayerName()).isEqualTo("cary"); } + + @Test + void 플레이어가_없는_경우_초기정보에는_딜러만_포함된다() { + GameManager manager = new GameManager(new Deck()); + + manager.startGame(); + + List result = manager.getInitialInfo(); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); + } + + @Test + void 플레이어가_없는_경우_점수결과에는_딜러만_포함된다() { + GameManager manager = new GameManager(new Deck()); + + manager.startGame(); + + List result = manager.getScoreResults(); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); + } + + @Test + void 플레이어가_없는_경우_최종결과에는_딜러만_포함된다() { + GameManager manager = new GameManager(new Deck()); + + manager.startGame(); + + List result = manager.getFinalResult(); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); + } + } \ No newline at end of file diff --git a/src/test/java/domain/GameResultJudgeTest.java b/src/test/java/domain/GameResultJudgeTest.java new file mode 100644 index 00000000000..5c7d7ac08a0 --- /dev/null +++ b/src/test/java/domain/GameResultJudgeTest.java @@ -0,0 +1,119 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Result; +import domain.constant.Suit; +import domain.dto.GameFinalResultDto; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GameResultJudgeTest { + + @Test + void 플레이어가_딜러보다_점수가_높으면_WIN이다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + + Player player = new Player("pobi"); + player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); + player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); + + Players players = new Players(); + players.add(player); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result).hasSize(2); + assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); + assertThat(result.get(1).getResult()).isEqualTo(Result.WIN); + } + + @Test + void 플레이어가_딜러보다_점수가_낮으면_LOSE이다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.NINE, Suit.HEART)); + + Player player = new Player("pobi"); + player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); + player.receiveCard(new Card(Rank.SEVEN, Suit.DIAMOND)); + + Players players = new Players(); + players.add(player); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); + } + + @Test + void 플레이어와_딜러의_점수가_같으면_DRAW이다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.EIGHT, Suit.HEART)); + + Player player = new Player("pobi"); + player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); + player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); + + Players players = new Players(); + players.add(player); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result.get(1).getResult()).isEqualTo(Result.DRAW); + } + + @Test + void 플레이어가_버스트면_딜러와_상관없이_LOSE이다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + + Player player = new Player("pobi"); + player.receiveCard(new Card(Rank.KING, Suit.CLUB)); + player.receiveCard(new Card(Rank.QUEEN, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.TWO, Suit.HEART)); + + Players players = new Players(); + players.add(player); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); + } + + @Test + void 딜러가_버스트면_플레이어가_버스트가_아닌_한_WIN이다() { + Dealer dealer = new Dealer(); + dealer.receiveCard(new Card(Rank.KING, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.QUEEN, Suit.HEART)); + dealer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + + Player player = new Player("pobi"); + player.receiveCard(new Card(Rank.TEN, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + + Players players = new Players(); + players.add(player); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result.get(1).getResult()).isEqualTo(Result.WIN); + } + + @Test + void 최종결과_첫번째에는_딜러가_포함된다() { + Dealer dealer = new Dealer(); + Players players = new Players(); + players.add(new Player("pobi")); + + List result = GameResultJudge.judge(dealer, players); + + assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); + } +} \ No newline at end of file diff --git a/src/test/java/domain/HandTest.java b/src/test/java/domain/HandTest.java new file mode 100644 index 00000000000..26991c4685b --- /dev/null +++ b/src/test/java/domain/HandTest.java @@ -0,0 +1,28 @@ +package domain; + +import domain.constant.Rank; +import domain.constant.Suit; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class HandTest { + + @Test + void 합계가_21점이면_블랙잭이다() { + Hand hand = new Hand(); + hand.add(new Card(Rank.ACE, Suit.SPADE)); + hand.add(new Card(Rank.KING, Suit.HEART)); + + assertThat(hand.isBlackjack()).isTrue(); + } + + @Test + void 합계가_21점이_아니면_블랙잭이_아니다() { + Hand hand = new Hand(); + hand.add(new Card(Rank.TEN, Suit.SPADE)); + hand.add(new Card(Rank.KING, Suit.HEART)); + + assertThat(hand.isBlackjack()).isFalse(); + } +} \ No newline at end of file From 8b709070eed8b478d10fa27ef34b32dc165ff611 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Tue, 10 Mar 2026 23:14:32 +0900 Subject: [PATCH 63/88] =?UTF-8?q?docs:=20README.md=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 685ca5d862e..1f5608afe1a 100644 --- a/README.md +++ b/README.md @@ -64,4 +64,4 @@ - [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 - [x] 플레이어가 입력되지 않는 경우에 대한 예외처리 - [x] 규칙 적용 -- [ ] 테스트 케이스 추가 +- [x] 테스트 케이스 추가 From 9f3c94bfe2f535f64e8bd9c7ec97fd3112a4f177 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Tue, 10 Mar 2026 23:39:33 +0900 Subject: [PATCH 64/88] =?UTF-8?q?refactor:=20domain=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EB=B6=84=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- src/main/java/Application.java | 4 +- src/main/java/controller/GameController.java | 4 +- src/main/java/domain/DtoFactory.java | 3 + src/main/java/domain/Hand.java | 3 +- src/main/java/domain/{ => card}/Card.java | 5 +- src/main/java/domain/{ => card}/Deck.java | 5 +- .../java/domain/{constant => card}/Rank.java | 2 +- .../java/domain/{constant => card}/Suit.java | 2 +- .../java/domain/{ => game}/GameManager.java | 7 +- .../domain/{ => game}/GameResultJudge.java | 109 +++++++++--------- .../java/domain/{ => participant}/Dealer.java | 2 +- .../java/domain/{ => participant}/Player.java | 4 +- .../domain/{ => participant}/Players.java | 3 +- src/test/java/domain/DealerTest.java | 6 +- src/test/java/domain/DeckTest.java | 2 + src/test/java/domain/DtoFactoryTest.java | 30 +++-- src/test/java/domain/GameManagerTest.java | 5 +- src/test/java/domain/GameResultJudgeTest.java | 9 +- src/test/java/domain/HandTest.java | 5 +- src/test/java/domain/PlayersTest.java | 2 + 21 files changed, 122 insertions(+), 94 deletions(-) rename src/main/java/domain/{ => card}/Card.java (90%) rename src/main/java/domain/{ => card}/Deck.java (88%) rename src/main/java/domain/{constant => card}/Rank.java (95%) rename src/main/java/domain/{constant => card}/Suit.java (91%) rename src/main/java/domain/{ => game}/GameManager.java (90%) rename src/main/java/domain/{ => game}/GameResultJudge.java (92%) rename src/main/java/domain/{ => participant}/Dealer.java (92%) rename src/main/java/domain/{ => participant}/Player.java (92%) rename src/main/java/domain/{ => participant}/Players.java (88%) diff --git a/README.md b/README.md index 1f5608afe1a..102a377493b 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,11 @@ ### TO-DO - [x] Enum 출력값 변경 - [x] 승패 출력값 변경 - - [x] domain.constant.Suit 출력값 변경 + - [x] domain.card.Suit 출력값 변경 - [x] 딜러 승패 판정 오류 수정 - [x] 버스트인데 hit/stand 질문 - [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 -- [x] domain.GameManager 리팩터링 +- [x] domain.game.GameManager 리팩터링 - [x] 패키지 정리 - [x] drawDealerCard() 메서드의 응답값 미사용 - [x] GameManager의 책임 재분배 diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 57a073dce52..c460492b0c5 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,6 +1,6 @@ import controller.GameController; -import domain.Deck; -import domain.GameManager; +import domain.card.Deck; +import domain.game.GameManager; import view.InputView; import view.OutputView; diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 5d409a26725..cfaa67630ea 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,7 +1,7 @@ package controller; -import domain.GameManager; -import domain.Player; +import domain.game.GameManager; +import domain.participant.Player; import domain.dto.GameInitialInfoDto; import view.InputView; import view.OutputView; diff --git a/src/main/java/domain/DtoFactory.java b/src/main/java/domain/DtoFactory.java index 91ce39c75d3..78fefee90af 100644 --- a/src/main/java/domain/DtoFactory.java +++ b/src/main/java/domain/DtoFactory.java @@ -2,6 +2,9 @@ import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index d873ac8b61e..046aad2727e 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -1,6 +1,7 @@ package domain; -import domain.constant.Rank; +import domain.card.Card; +import domain.card.Rank; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/domain/Card.java b/src/main/java/domain/card/Card.java similarity index 90% rename from src/main/java/domain/Card.java rename to src/main/java/domain/card/Card.java index d0727d0ee64..eb656f009e9 100644 --- a/src/main/java/domain/Card.java +++ b/src/main/java/domain/card/Card.java @@ -1,7 +1,4 @@ -package domain; - -import domain.constant.Rank; -import domain.constant.Suit; +package domain.card; import java.util.Objects; diff --git a/src/main/java/domain/Deck.java b/src/main/java/domain/card/Deck.java similarity index 88% rename from src/main/java/domain/Deck.java rename to src/main/java/domain/card/Deck.java index cdf0b52d458..eace46ab946 100644 --- a/src/main/java/domain/Deck.java +++ b/src/main/java/domain/card/Deck.java @@ -1,7 +1,4 @@ -package domain; - -import domain.constant.Rank; -import domain.constant.Suit; +package domain.card; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/domain/constant/Rank.java b/src/main/java/domain/card/Rank.java similarity index 95% rename from src/main/java/domain/constant/Rank.java rename to src/main/java/domain/card/Rank.java index e73d863337d..c2c19104a84 100644 --- a/src/main/java/domain/constant/Rank.java +++ b/src/main/java/domain/card/Rank.java @@ -1,4 +1,4 @@ -package domain.constant; +package domain.card; public enum Rank { ACE(1, "A"), diff --git a/src/main/java/domain/constant/Suit.java b/src/main/java/domain/card/Suit.java similarity index 91% rename from src/main/java/domain/constant/Suit.java rename to src/main/java/domain/card/Suit.java index 7e5b7a28243..fc2e592f9f4 100644 --- a/src/main/java/domain/constant/Suit.java +++ b/src/main/java/domain/card/Suit.java @@ -1,4 +1,4 @@ -package domain.constant; +package domain.card; public enum Suit { SPADE("스페이드"), diff --git a/src/main/java/domain/GameManager.java b/src/main/java/domain/game/GameManager.java similarity index 90% rename from src/main/java/domain/GameManager.java rename to src/main/java/domain/game/GameManager.java index 2a5e2d50fde..47cd52c71ec 100644 --- a/src/main/java/domain/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -1,9 +1,14 @@ -package domain; +package domain.game; +import domain.DtoFactory; +import domain.card.Deck; import domain.dto.GameFinalResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; import java.util.List; public class GameManager { diff --git a/src/main/java/domain/GameResultJudge.java b/src/main/java/domain/game/GameResultJudge.java similarity index 92% rename from src/main/java/domain/GameResultJudge.java rename to src/main/java/domain/game/GameResultJudge.java index 5b55fc73ec5..0cba57ba2fc 100644 --- a/src/main/java/domain/GameResultJudge.java +++ b/src/main/java/domain/game/GameResultJudge.java @@ -1,53 +1,56 @@ -package domain; - -import domain.constant.Result; -import domain.dto.GameFinalResultDto; -import java.util.ArrayList; -import java.util.List; - -public class GameResultJudge { - private GameResultJudge() { - } - - public static List judge(Dealer dealer, Players players) { - // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 - List results = new ArrayList<>(); - results.add(new GameFinalResultDto(dealer.getName())); - addPlayerResults(results, dealer, players); - return results; - } - - private static void addPlayerResults(List results, Dealer dealer, Players players) { - for (Player player : players.getPlayers()) { - results.add(judgePlayer(player, dealer)); - } - } - - private static GameFinalResultDto judgePlayer(Player player, Dealer dealer) { - Result result = calculateResult(player, dealer); - return new GameFinalResultDto(player.getName(), result); - } - - private static Result calculateResult(Player player, Dealer dealer) { - int playerScore = player.getScore(); - int dealerScore = dealer.getScore(); - - if (player.isBust()) { - return Result.LOSE; - } - - if (dealer.isBust()) { - return Result.WIN; - } - - if (playerScore > dealerScore) { - return Result.WIN; - } - - if (playerScore < dealerScore) { - return Result.LOSE; - } - - return Result.DRAW; - } -} +package domain.game; + +import domain.constant.Result; +import domain.dto.GameFinalResultDto; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; +import java.util.ArrayList; +import java.util.List; + +public class GameResultJudge { + private GameResultJudge() { + } + + public static List judge(Dealer dealer, Players players) { + // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 + List results = new ArrayList<>(); + results.add(new GameFinalResultDto(dealer.getName())); + addPlayerResults(results, dealer, players); + return results; + } + + private static void addPlayerResults(List results, Dealer dealer, Players players) { + for (Player player : players.getPlayers()) { + results.add(judgePlayer(player, dealer)); + } + } + + private static GameFinalResultDto judgePlayer(Player player, Dealer dealer) { + Result result = calculateResult(player, dealer); + return new GameFinalResultDto(player.getName(), result); + } + + private static Result calculateResult(Player player, Dealer dealer) { + int playerScore = player.getScore(); + int dealerScore = dealer.getScore(); + + if (player.isBust()) { + return Result.LOSE; + } + + if (dealer.isBust()) { + return Result.WIN; + } + + if (playerScore > dealerScore) { + return Result.WIN; + } + + if (playerScore < dealerScore) { + return Result.LOSE; + } + + return Result.DRAW; + } +} diff --git a/src/main/java/domain/Dealer.java b/src/main/java/domain/participant/Dealer.java similarity index 92% rename from src/main/java/domain/Dealer.java rename to src/main/java/domain/participant/Dealer.java index 198f4147283..27936afc5ce 100644 --- a/src/main/java/domain/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -1,4 +1,4 @@ -package domain; +package domain.participant; public class Dealer extends Player { private final int DEALER_DRAW_CONDITION = 16; diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/participant/Player.java similarity index 92% rename from src/main/java/domain/Player.java rename to src/main/java/domain/participant/Player.java index e038835b8b8..b3cbe731eb6 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -1,5 +1,7 @@ -package domain; +package domain.participant; +import domain.card.Card; +import domain.Hand; import java.util.List; public class Player { diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/participant/Players.java similarity index 88% rename from src/main/java/domain/Players.java rename to src/main/java/domain/participant/Players.java index 91a3e3026b3..b26264b8ac8 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,5 +1,6 @@ -package domain; +package domain.participant; +import domain.card.Card; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/domain/DealerTest.java b/src/test/java/domain/DealerTest.java index 669c08777b5..4a35abd772d 100644 --- a/src/test/java/domain/DealerTest.java +++ b/src/test/java/domain/DealerTest.java @@ -1,7 +1,9 @@ package domain; -import domain.constant.Rank; -import domain.constant.Suit; +import domain.card.Card; +import domain.card.Rank; +import domain.card.Suit; +import domain.participant.Dealer; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/domain/DeckTest.java b/src/test/java/domain/DeckTest.java index 795d10dcbeb..46f5d216452 100644 --- a/src/test/java/domain/DeckTest.java +++ b/src/test/java/domain/DeckTest.java @@ -1,5 +1,7 @@ package domain; +import domain.card.Card; +import domain.card.Deck; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/domain/DtoFactoryTest.java b/src/test/java/domain/DtoFactoryTest.java index 2c4572c3ad3..6ee8cfb6375 100644 --- a/src/test/java/domain/DtoFactoryTest.java +++ b/src/test/java/domain/DtoFactoryTest.java @@ -2,8 +2,14 @@ import static org.assertj.core.api.Assertions.assertThat; +import domain.card.Card; +import domain.card.Rank; +import domain.card.Suit; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; import java.util.List; import org.junit.jupiter.api.Test; @@ -12,13 +18,13 @@ public class DtoFactoryTest { @Test void 초기정보를_생성하면_딜러는_한장만_공개된다() { Dealer dealer = new Dealer(); - dealer.receiveCard(new Card(domain.constant.Rank.ACE, domain.constant.Suit.SPADE)); - dealer.receiveCard(new Card(domain.constant.Rank.KING, domain.constant.Suit.HEART)); + dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); Players players = new Players(); Player player = new Player("pobi"); - player.receiveCard(new Card(domain.constant.Rank.TWO, domain.constant.Suit.CLUB)); - player.receiveCard(new Card(domain.constant.Rank.THREE, domain.constant.Suit.DIAMOND)); + player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); players.add(player); List result = DtoFactory.toInitialInfo(dealer, players); @@ -31,13 +37,13 @@ public class DtoFactoryTest { @Test void 초기정보를_생성하면_플레이어는_두장을_공개한다() { Dealer dealer = new Dealer(); - dealer.receiveCard(new Card(domain.constant.Rank.ACE, domain.constant.Suit.SPADE)); - dealer.receiveCard(new Card(domain.constant.Rank.KING, domain.constant.Suit.HEART)); + dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); Players players = new Players(); Player player = new Player("pobi"); - player.receiveCard(new Card(domain.constant.Rank.TWO, domain.constant.Suit.CLUB)); - player.receiveCard(new Card(domain.constant.Rank.THREE, domain.constant.Suit.DIAMOND)); + player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); players.add(player); List result = DtoFactory.toInitialInfo(dealer, players); @@ -49,13 +55,13 @@ public class DtoFactoryTest { @Test void 점수결과를_생성하면_딜러와_플레이어의_이름_승패_정보를_포함한다() { Dealer dealer = new Dealer(); - dealer.receiveCard(new Card(domain.constant.Rank.TEN, domain.constant.Suit.SPADE)); - dealer.receiveCard(new Card(domain.constant.Rank.SEVEN, domain.constant.Suit.HEART)); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); Players players = new Players(); Player player = new Player("pobi"); - player.receiveCard(new Card(domain.constant.Rank.NINE, domain.constant.Suit.CLUB)); - player.receiveCard(new Card(domain.constant.Rank.EIGHT, domain.constant.Suit.DIAMOND)); + player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); + player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); players.add(player); List result = DtoFactory.toScoreResults(dealer, players); diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 6046cc066ca..776118a109b 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -1,10 +1,11 @@ package domain; -import domain.constant.Rank; -import domain.constant.Suit; +import domain.card.Deck; import domain.dto.GameFinalResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; +import domain.game.GameManager; +import domain.participant.Player; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/domain/GameResultJudgeTest.java b/src/test/java/domain/GameResultJudgeTest.java index 5c7d7ac08a0..f7dd192e57b 100644 --- a/src/test/java/domain/GameResultJudgeTest.java +++ b/src/test/java/domain/GameResultJudgeTest.java @@ -1,9 +1,14 @@ package domain; -import domain.constant.Rank; +import domain.card.Card; +import domain.card.Rank; import domain.constant.Result; -import domain.constant.Suit; +import domain.card.Suit; import domain.dto.GameFinalResultDto; +import domain.game.GameResultJudge; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/domain/HandTest.java b/src/test/java/domain/HandTest.java index 26991c4685b..8d52d727be3 100644 --- a/src/test/java/domain/HandTest.java +++ b/src/test/java/domain/HandTest.java @@ -1,7 +1,8 @@ package domain; -import domain.constant.Rank; -import domain.constant.Suit; +import domain.card.Card; +import domain.card.Rank; +import domain.card.Suit; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index c24a27c8719..9b5a673dbc0 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -1,5 +1,7 @@ package domain; +import domain.participant.Player; +import domain.participant.Players; import org.junit.jupiter.api.Test; import java.util.List; From e07785917f9e4964c94ee045f80e32ea1de1211e Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Wed, 11 Mar 2026 15:18:20 +0900 Subject: [PATCH 65/88] =?UTF-8?q?refactor:=20dto=20private=20final=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/dto/GameFinalResultDto.java | 4 ++-- .../java/domain/dto/GameInitialInfoDto.java | 6 +++--- .../java/domain/dto/GameScoreResultDto.java | 18 +++--------------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/main/java/domain/dto/GameFinalResultDto.java b/src/main/java/domain/dto/GameFinalResultDto.java index 1ea7ff21350..ac5910e9694 100644 --- a/src/main/java/domain/dto/GameFinalResultDto.java +++ b/src/main/java/domain/dto/GameFinalResultDto.java @@ -3,8 +3,8 @@ import domain.constant.Result; public class GameFinalResultDto { - String playerName; - Result result; + private final String playerName; + private final Result result; // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 diff --git a/src/main/java/domain/dto/GameInitialInfoDto.java b/src/main/java/domain/dto/GameInitialInfoDto.java index ecef57c2caa..7a9b309dca0 100644 --- a/src/main/java/domain/dto/GameInitialInfoDto.java +++ b/src/main/java/domain/dto/GameInitialInfoDto.java @@ -4,9 +4,9 @@ public class GameInitialInfoDto { - private String playerName; - private int initialHandSize; - private List hand; + private final String playerName; + private final int initialHandSize; + private final List hand; public GameInitialInfoDto(String playerName, int initialHandSize, List hand) { this.playerName = playerName; diff --git a/src/main/java/domain/dto/GameScoreResultDto.java b/src/main/java/domain/dto/GameScoreResultDto.java index 3cc84efa21b..2011f39b206 100644 --- a/src/main/java/domain/dto/GameScoreResultDto.java +++ b/src/main/java/domain/dto/GameScoreResultDto.java @@ -3,9 +3,9 @@ import java.util.List; public class GameScoreResultDto { - String playerName; - List hand; - int result; + private final String playerName; + private final List hand; + private final int result; public GameScoreResultDto(String playerName, List hand, int result) { this.playerName = playerName; @@ -17,26 +17,14 @@ public String getPlayerName() { return playerName; } - public void setPlayerName(String playerName) { - this.playerName = playerName; - } - public List getHand() { return hand; } - public void setHand(List hand) { - this.hand = hand; - } - public int getResult() { return result; } - public void setResult(int result) { - this.result = result; - } - @Override public String toString() { return "domain.dto.GameScoreResultDto{" + From 8b3d822132716620e5fcbf377d610f01a285d73a Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Wed, 11 Mar 2026 15:32:02 +0900 Subject: [PATCH 66/88] =?UTF-8?q?refactor:=20=EB=AF=B8=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=20=EC=84=A0=EC=96=B8=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20final?= =?UTF-8?q?=20=EA=B0=80=EB=8A=A5=ED=95=9C=20=EB=B3=80=EC=88=98=EC=97=90=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Hand.java | 7 ------- src/main/java/domain/card/Deck.java | 2 +- src/main/java/domain/constant/Result.java | 2 +- src/main/java/domain/participant/Player.java | 7 ------- src/test/java/domain/GameManagerTest.java | 6 +++--- 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index 046aad2727e..89db7c3b1e5 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -18,10 +18,6 @@ public void add(Card card) { hand.add(card); } - public List getHand() { - return List.copyOf(hand); - } - public List toStringList() { return hand.stream() .map(Card::toString) @@ -60,7 +56,4 @@ public boolean isBlackjack() { return calculateScore() == BLACKJACK_SCORE; } - public int size() { - return hand.size(); - } } diff --git a/src/main/java/domain/card/Deck.java b/src/main/java/domain/card/Deck.java index eace46ab946..0dde97bdff6 100644 --- a/src/main/java/domain/card/Deck.java +++ b/src/main/java/domain/card/Deck.java @@ -5,7 +5,7 @@ import java.util.List; public class Deck { - List cards = new ArrayList<>(); + final List cards = new ArrayList<>(); public Deck () { init(); diff --git a/src/main/java/domain/constant/Result.java b/src/main/java/domain/constant/Result.java index 7f4455cfb9e..06baa630605 100644 --- a/src/main/java/domain/constant/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -3,7 +3,7 @@ public enum Result { WIN("승"), DRAW("무"), LOSE("패"); - private String name; + private final String name; Result(String name) { this.name = name; diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index b3cbe731eb6..ee155fe60cf 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -27,10 +27,6 @@ public boolean canDraw() { return !(isBust()|| hand.isBlackjack()); } - public int handSize() { - return hand.size(); - } - public List getHandToString() { return hand.toStringList(); } @@ -43,7 +39,4 @@ public String getName() { return name; } - public Hand getHand() { - return hand; - } } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 776118a109b..5ed84857eb8 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -90,13 +90,13 @@ class GameManagerTest { manager.startGame(); Player player = manager.getPlayerSequence().getFirst(); - int before = player.handSize(); + int before = player.getScore(); manager.drawPlayerCard(player); - int after = player.handSize(); + int after = player.getScore(); - assertThat(after).isEqualTo(before + 1); + assertThat(after).isGreaterThan(before); } @Test From 1a35d1beeb702eeef163e46eb3c744a3466604a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=84=A4=EC=98=A4?= Date: Fri, 6 Mar 2026 08:56:27 +0900 Subject: [PATCH 67/88] docs: update GitHub PR template --- .github/pull_request_template.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1c4e3cef883..27e771e7f94 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,11 +12,6 @@ - [ ] 미션의 필수 요구사항을 모두 구현했나요? - [ ] Gradle `test`를 실행했을 때, 모든 테스트가 정상적으로 통과했나요? - [ ] 애플리케이션이 정상적으로 실행되나요? -- [ ] [프롤로그](https://prolog.techcourse.co.kr)에 셀프 체크를 작성했나요? - - - - -## 객체지향 생활체조 요구사항을 얼마나 잘 충족했다고 생각하시나요? ### 1~5점 중에서 선택해주세요. From b7e836b920e8a0369401b2d9f5685981f6e3f715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=84=A4=EC=98=A4?= Date: Fri, 6 Mar 2026 08:58:00 +0900 Subject: [PATCH 68/88] docs: update GitHub PR template --- .github/pull_request_template.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 27e771e7f94..43c871c8563 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,14 +13,6 @@ - [ ] Gradle `test`를 실행했을 때, 모든 테스트가 정상적으로 통과했나요? - [ ] 애플리케이션이 정상적으로 실행되나요? -### 1~5점 중에서 선택해주세요. - -- [ ] 1 (전혀 충족하지 못함) -- [ ] 2 -- [ ] 3 (보통) -- [ ] 4 -- [ ] 5 (완벽하게 충족) - ### 선택한 점수의 이유를 적어주세요. From b0970d3ea1773f5254db127fd9f58d2cf6032567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=84=A4=EC=98=A4?= Date: Fri, 6 Mar 2026 08:58:34 +0900 Subject: [PATCH 69/88] docs: update GitHub PR template --- .github/pull_request_template.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 43c871c8563..71bbfc612fb 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,11 +12,6 @@ - [ ] 미션의 필수 요구사항을 모두 구현했나요? - [ ] Gradle `test`를 실행했을 때, 모든 테스트가 정상적으로 통과했나요? - [ ] 애플리케이션이 정상적으로 실행되나요? - -### 선택한 점수의 이유를 적어주세요. - - - ## 어떤 부분에 집중하여 리뷰해야 할까요? From f5f2773e4b4ee435b8fef2e0d8637c992c632caa Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Thu, 12 Mar 2026 17:37:27 +0900 Subject: [PATCH 70/88] =?UTF-8?q?docs:=20README=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EC=82=AC=EC=9D=B4=ED=81=B42?= =?UTF-8?q?=20=EB=B2=A0=ED=8C=85=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 185 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 137 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 102a377493b..e3607ffcea0 100644 --- a/README.md +++ b/README.md @@ -2,66 +2,155 @@ 블랙잭 미션 저장소 -## 구현할 기능 목록 +--- + +# 사이클1 구현 기능 + +## 1. 카드 덱 생성 및 셔플 -### 카드 덱 생성 + 셔플 - [x] 52장의 카드를 생성한다. -- [x] 카드는 무늬별 숫자순으로 생성된다. -- [x] 카드를 셔플한다. +- [x] 카드는 무늬별 숫자 순서로 생성한다. +- [x] 생성된 카드를 셔플한다. + +--- + +## 2. 플레이어 및 딜러 관리 + +- [x] 플레이어를 생성한다. +- [x] 플레이어 목록에 등록한다. +- [x] 딜러를 생성한다. +- [x] 플레이어와 딜러에게 카드를 분배한다. -### 플레이어/딜러 관리 -- [x] 플레이어를 플레이어 목록에 등록한다. -- [x] 딜러를 만든다. -- [x] 카드를 돌린다. +--- + +## 3. 카드 점수 계산 -### 카드 점수 계산 -- [x] J,Q,K는 10으로 처리한다. -- [x] Ace는 1점으로 처리한다. +- [x] 카드 숫자를 기본 점수로 사용한다. +- [x] Jack, Queen, King은 10점으로 처리한다. +- [x] Ace는 기본적으로 1점으로 처리한다. - [x] 카드 점수를 합산한다. -### Ace 1/11 처리 -- [x] 현재 합산 점수에 10점의 여유가 있으면 10점을 더한다. +--- + +## 4. Ace 점수 처리 (1 / 11) + +- [x] 현재 점수에서 10점을 추가해도 21을 넘지 않는 경우 Ace를 11로 계산한다. + +--- + +## 5. 버스트 판정 + +- [x] 카드 합이 21을 초과하면 버스트로 판정한다. + +--- + +## 6. 히트 / 스탠드 진행 + +- [x] 버스트가 아닌 경우 히트/스탠드 입력을 받는다. +- [x] 히트를 선택하면 카드를 한 장 더 받는다. +- [x] 스탠드를 선택하면 해당 플레이어의 턴을 종료한다. + +--- + +## 7. 승패 판정 + +- [x] 딜러와 플레이어의 점수를 비교한다. +- [x] 게임 결과(승/무/패)를 생성한다. + +--- + +## 8. 결과 출력 -### 버스트 판정 -- [x] 21점이 넘으면 버스트 +- [x] 플레이어 및 딜러의 카드와 점수를 출력한다. +- [x] 게임 결과를 출력한다. -### 히트/스탠드 입력 -- [x] 버스트가 아니면 히트/스탠드를 입력받는다. -- [x] 히트면 카드를 한 장 더 받는다. -- [x] 스탠드면 턴을 종료한다. +--- + +# 사이클1 리팩터링 및 개선 작업 -### 승패 판정 -- [x] 딜러와 점수를 비교한다. -- [x] 결과를 생성한다. +## 출력 및 표현 개선 -### 결과 출력 +- [x] Enum 출력값 수정 + - [x] 승패 결과 출력값 변경 + - [x] `domain.card.Suit` 출력값 변경 +- [x] Ace, Jack, Queen, King이 숫자 값으로 출력되는 문제 수정 --- -### TO-DO -- [x] Enum 출력값 변경 - - [x] 승패 출력값 변경 - - [x] domain.card.Suit 출력값 변경 +## 게임 로직 수정 + - [x] 딜러 승패 판정 오류 수정 -- [x] 버스트인데 hit/stand 질문 -- [x] Ace, Jack, Queen, King 이름이 값(1,10)으로 출력되는 문제 -- [x] domain.game.GameManager 리팩터링 -- [x] 패키지 정리 -- [x] drawDealerCard() 메서드의 응답값 미사용 -- [x] GameManager의 책임 재분배 - - [x] Deck 초기화, 셔플 책임 제거 - - [x] DTO 생성 책임 분리 - - [x] 승패 판정 책임 분리 -- [x] GameController 구조 수정 -- [x] 디미터의 법칙 - - [x] 스트림 체이닝은 줄바꿈해서 작성 - - [x] 체이닝 메서드 안생기도록 구조 수정 -- [x] rank 1 보다는 의미있는 값 (`ACE`)가 이해하기 쉽다 -- [x] 주석이 정말 필요한지, 이름이나 구조로 충분하지 않은지 -- [x] primitive 타입 wrapper로 감싸기 -- [x] 일급 컬렉션 -> Hand로 수정 - - [x] 핸드 기능 추가(스코어 계산, 상태값 판단, ACE 계산 로직) 및 기존 Calculator 제거 -- [x] mutable이어야 할 이유가 없다면, 반드시 final을 붙일 것 -- [x] 플레이어가 입력되지 않는 경우에 대한 예외처리 -- [x] 규칙 적용 +- [x] 버스트 상태에서도 hit/stand 질문이 나오는 문제 수정 + +--- + +## 구조 리팩터링 + +- [x] `GameManager` 리팩터링 +- [x] `GameController` 구조 수정 +- [x] 패키지 구조 정리 + +### GameManager 책임 재분배 + +- [x] Deck 초기화 및 셔플 책임 제거 +- [x] DTO 생성 책임 분리 +- [x] 승패 판정 책임 분리 + +--- + +## 코드 스타일 및 설계 개선 + +- [x] 디미터의 법칙 적용 + - [x] 스트림 체이닝 시 줄바꿈 적용 + - [x] 과도한 체이닝 메서드 제거 +- [x] 의미 있는 상수 사용 (`1` → `ACE`) +- [x] 불필요한 주석 제거 (이름/구조로 표현) +- [x] primitive 타입을 wrapper 객체로 감싸기 +- [x] mutable일 필요가 없는 경우 `final` 사용 + +--- + +## 도메인 구조 개선 + +- [x] 일급 컬렉션 적용 → `Hand` +- [x] `Hand`에 기능 통합 + - [x] 스코어 계산 + - [x] 상태 판단 + - [x] Ace 계산 로직 +- [x] 기존 `Calculator` 제거 + +--- + +## 예외 처리 및 테스트 + +- [x] 플레이어 입력이 없는 경우 예외 처리 +- [x] 게임 규칙 검증 로직 추가 - [x] 테스트 케이스 추가 + + +--- + +# 사이클2 기능 구현 + +## 1. 배팅 금액 관리 +- [ ] 배팅 금액을 관리하는 도메인을 구현한다. + - [ ] 처음 받은 배팅 금액을 저장 + - [ ] 입력 받은 정산 시 결과 상태(승/무/패/블랙잭/버스트)에 따라 계산한 총 수익을 리턴 +## 2. 판정 추가 +- [ ] 기존 `Result`에 블랙잭과 버스트를 추가 +- [ ] 처음 BlackJack이 뜬 경우 블랙잭 상태로 결과에 저장 +- [ ] Hit/Stand 단계에서 Bust가 되면 결과는 Bust로 저장 +- [ ] 결과에 따른 배당 수익을 상태 값으로 가지도록 + - 무승부는 원금 리턴 -> *1 + - 승은 원금 + 수익 -> * 2 + - 패, 버스트는 원금 손실 -> * -1 + - 처음부터 블랙잭인 경우 배팅의 1.5배 수익 -> * 2.5 +## 3. 배팅 금액 입력하여 플레이어 생성 +- [ ] 플레이어 이름 입력 후 배팅 금액도 입력 +- [ ] 플레이어와 금액을 매핑해서 플렝이어 생성 +- [ ] 플레이어의 배팅 금액을 다루는 메서드 구현 + +## 4. 베팅 결과 출력 +- [ ] 기존 딜러의 승,무,패 출력 기능 제거 +- [ ] 플레이어들의 승, 무, 패 기준으로 값을 계산하여 수익을 출력하도록 수정 +- [ ] 딜러 기준 총 수익 계산 받아서 출력하는 기능 구현 From 75a46d840ff42d2da264d675c0ab9ff4418c3ec5 Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Thu, 12 Mar 2026 19:13:49 +0900 Subject: [PATCH 71/88] =?UTF-8?q?feat:=20=EB=B2=A0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20Result=20=EA=B7=9C=EC=B9=99=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- src/main/java/domain/BettingMoney.java | 15 ++++++++++++++ src/main/java/domain/constant/Result.java | 14 +++++++++++-- src/test/java/domain/BettingMoneyTest.java | 23 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/main/java/domain/BettingMoney.java create mode 100644 src/test/java/domain/BettingMoneyTest.java diff --git a/README.md b/README.md index e3607ffcea0..cca9ed78864 100644 --- a/README.md +++ b/README.md @@ -133,11 +133,11 @@ # 사이클2 기능 구현 ## 1. 배팅 금액 관리 -- [ ] 배팅 금액을 관리하는 도메인을 구현한다. - - [ ] 처음 받은 배팅 금액을 저장 - - [ ] 입력 받은 정산 시 결과 상태(승/무/패/블랙잭/버스트)에 따라 계산한 총 수익을 리턴 +- [X] 배팅 금액을 관리하는 도메인을 구현한다. + - [X] 처음 받은 배팅 금액을 저장 + - [X] 입력 받은 정산 시 결과 상태(승/무/패/블랙잭/버스트)에 따라 계산한 총 수익을 리턴 ## 2. 판정 추가 -- [ ] 기존 `Result`에 블랙잭과 버스트를 추가 +- [X] 기존 `Result`에 블랙잭과 버스트를 추가 - [ ] 처음 BlackJack이 뜬 경우 블랙잭 상태로 결과에 저장 - [ ] Hit/Stand 단계에서 Bust가 되면 결과는 Bust로 저장 - [ ] 결과에 따른 배당 수익을 상태 값으로 가지도록 diff --git a/src/main/java/domain/BettingMoney.java b/src/main/java/domain/BettingMoney.java new file mode 100644 index 00000000000..2a9ad60ddc8 --- /dev/null +++ b/src/main/java/domain/BettingMoney.java @@ -0,0 +1,15 @@ +package domain; + +import domain.constant.Result; + +public class BettingMoney { + private final int bettingMoney; + + public BettingMoney(int bettingMoney) { + this.bettingMoney = bettingMoney; + } + + public double calculateProceeds(Result result) { + return bettingMoney * result.getAllocation(); + } +} diff --git a/src/main/java/domain/constant/Result.java b/src/main/java/domain/constant/Result.java index 7f4455cfb9e..cc376d0f73f 100644 --- a/src/main/java/domain/constant/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -1,15 +1,25 @@ package domain.constant; public enum Result { - WIN("승"), DRAW("무"), LOSE("패"); + WIN("승", 1), + DRAW("무", 0), + LOSE("패", -1), + BLACKJACK("블랙잭", 1.5), + BUST("버스트", -1); private String name; + private double allocation; - Result(String name) { + Result(String name, double allocation) { this.name = name; + this.allocation = allocation; } public String getName() { return name + " "; } + + public double getAllocation() { + return allocation; + } } diff --git a/src/test/java/domain/BettingMoneyTest.java b/src/test/java/domain/BettingMoneyTest.java new file mode 100644 index 00000000000..86330dc84c6 --- /dev/null +++ b/src/test/java/domain/BettingMoneyTest.java @@ -0,0 +1,23 @@ +package domain; + +import domain.constant.Result; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import static org.assertj.core.api.Assertions.assertThat; + +public class BettingMoneyTest { + + @ParameterizedTest + @CsvSource({ + "10000, WIN, 10000", + "10000, DRAW, 0", + "10000, LOSE, -10000", + "10000, BUST, -10000", + "10000, BLACKJACK, 15000" + }) + void 결과값에_따라_수익률을_계산하여_수익계산(int betting, Result result, double expected) { + BettingMoney bettingMoney = new BettingMoney(betting); + + assertThat(bettingMoney.calculateProceeds(result)).isEqualTo(expected); + } +} From 9a53db77ba0879c254cc291b98642072de9a6f49 Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Thu, 12 Mar 2026 21:38:08 +0900 Subject: [PATCH 72/88] =?UTF-8?q?feat:=20=EC=B2=98=EC=9D=8C=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=EC=9E=AD=EC=9D=84=20=EB=9D=84=EC=9A=B4=20=ED=94=8C?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=EB=A5=BC=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 ++++++++---- src/main/java/controller/GameController.java | 2 +- src/main/java/domain/BettingMoney.java | 15 ---------- src/main/java/domain/PlayerStatus.java | 24 +++++++++++++++ ...FinalResultDto.java => GameResultDto.java} | 6 ++-- src/main/java/domain/game/GameManager.java | 10 +++---- .../java/domain/game/GameResultJudge.java | 14 ++++----- src/main/java/domain/participant/Dealer.java | 2 +- src/main/java/domain/participant/Player.java | 23 +++++++++++---- src/main/java/domain/participant/Players.java | 6 ++++ src/main/java/view/OutputView.java | 16 +++++----- src/test/java/domain/BettingMoneyTest.java | 16 +++++----- src/test/java/domain/DtoFactoryTest.java | 6 ++-- src/test/java/domain/GameManagerTest.java | 24 +++++++-------- src/test/java/domain/GameResultJudgeTest.java | 26 ++++++++--------- src/test/java/domain/PlayersTest.java | 29 +++++++++++++++++-- 16 files changed, 149 insertions(+), 89 deletions(-) delete mode 100644 src/main/java/domain/BettingMoney.java create mode 100644 src/main/java/domain/PlayerStatus.java rename src/main/java/domain/dto/{GameFinalResultDto.java => GameResultDto.java} (81%) diff --git a/README.md b/README.md index cca9ed78864..2c73d26b796 100644 --- a/README.md +++ b/README.md @@ -136,21 +136,30 @@ - [X] 배팅 금액을 관리하는 도메인을 구현한다. - [X] 처음 받은 배팅 금액을 저장 - [X] 입력 받은 정산 시 결과 상태(승/무/패/블랙잭/버스트)에 따라 계산한 총 수익을 리턴 + - [ ] 딜러를 플레이어의 상속을 받지 않고, 딜러와 플레이어 모두 추상화 시키는 Participants 생성 ## 2. 판정 추가 - [X] 기존 `Result`에 블랙잭과 버스트를 추가 -- [ ] 처음 BlackJack이 뜬 경우 블랙잭 상태로 결과에 저장 -- [ ] Hit/Stand 단계에서 Bust가 되면 결과는 Bust로 저장 -- [ ] 결과에 따른 배당 수익을 상태 값으로 가지도록 +- [X] 처음 BlackJack이 뜬 경우 블랙잭 상태로 결과에 저장 + - 기존에는 상태값을 저장해두지 않고 마지막에 핸드 결과로 최종 Dto 리스트를 만들어 승패판정을 하였으나, 수정된 상황에서 블랙잭을 미리 체크하고 히트/스탠드 및 승패 판정에서 제외해야 하므로 새로운 기능 추가 + - [X] 베팅금액과 결과를 함께 저장하도록 수정 + - [X] 초기 카드 드로우가 끝난 직후 블랙잭인 유저를 찾아서 결과 필드 갱신 +- [X] 결과에 따른 배당 수익을 상태 값으로 가지도록 - 무승부는 원금 리턴 -> *1 - 승은 원금 + 수익 -> * 2 - 패, 버스트는 원금 손실 -> * -1 - 처음부터 블랙잭인 경우 배팅의 1.5배 수익 -> * 2.5 +- [ ] 플레이어 Hit/Stand 단계에서 BlackJack이 아닌 유저만 필터링하여 문답 진행 +- [ ] 플레이어 Hit/Stand 단계에서 Bust가 되면 결과는 Bust로 저장 +- [ ] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 결과 단계로 플로우 이동 + - [ ] ResultDto에 블랙잭, 버스트가 아닌 인원 모두에게 승리배당, 블랙잭은 블랙잭 배당을 적용한 값을 생성 + - [ ] 생성된 값으로 출력 + ## 3. 배팅 금액 입력하여 플레이어 생성 - [ ] 플레이어 이름 입력 후 배팅 금액도 입력 - [ ] 플레이어와 금액을 매핑해서 플렝이어 생성 - [ ] 플레이어의 배팅 금액을 다루는 메서드 구현 -## 4. 베팅 결과 출력 +## 4. 베팅 결과 판정 및 출력 - [ ] 기존 딜러의 승,무,패 출력 기능 제거 -- [ ] 플레이어들의 승, 무, 패 기준으로 값을 계산하여 수익을 출력하도록 수정 +- [ ] 플레이어들의 승, 무, 패(버스트), 블랙잭 기준으로 값을 계산하여 수익을 출력하도록 수정 - [ ] 딜러 기준 총 수익 계산 받아서 출력하는 기능 구현 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index cfaa67630ea..b728aa790f7 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -38,7 +38,7 @@ private void registerPlayer() { validatePlayerNames(playerNames); for (String playerName : playerNames) { - manager.addPlayer(playerName); + manager.addPlayer(playerName, 1000); } return; diff --git a/src/main/java/domain/BettingMoney.java b/src/main/java/domain/BettingMoney.java deleted file mode 100644 index 2a9ad60ddc8..00000000000 --- a/src/main/java/domain/BettingMoney.java +++ /dev/null @@ -1,15 +0,0 @@ -package domain; - -import domain.constant.Result; - -public class BettingMoney { - private final int bettingMoney; - - public BettingMoney(int bettingMoney) { - this.bettingMoney = bettingMoney; - } - - public double calculateProceeds(Result result) { - return bettingMoney * result.getAllocation(); - } -} diff --git a/src/main/java/domain/PlayerStatus.java b/src/main/java/domain/PlayerStatus.java new file mode 100644 index 00000000000..d6ed5eb8895 --- /dev/null +++ b/src/main/java/domain/PlayerStatus.java @@ -0,0 +1,24 @@ +package domain; + +import domain.constant.Result; + +public class PlayerStatus { + private final int bettingMoney; + private Result result; + + public PlayerStatus(int bettingMoney) { + this.bettingMoney = bettingMoney; + } + + public double calculateProceeds() { + return bettingMoney * result.getAllocation(); + } + + public void renewedWithBlackJack() { + result = Result.BLACKJACK; + } + + public Result getResult() { + return result; + } +} diff --git a/src/main/java/domain/dto/GameFinalResultDto.java b/src/main/java/domain/dto/GameResultDto.java similarity index 81% rename from src/main/java/domain/dto/GameFinalResultDto.java rename to src/main/java/domain/dto/GameResultDto.java index 1ea7ff21350..7b06555f5d7 100644 --- a/src/main/java/domain/dto/GameFinalResultDto.java +++ b/src/main/java/domain/dto/GameResultDto.java @@ -2,17 +2,17 @@ import domain.constant.Result; -public class GameFinalResultDto { +public class GameResultDto { String playerName; Result result; // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 - public GameFinalResultDto(String playerName) { + public GameResultDto(String playerName) { this(playerName, null); } - public GameFinalResultDto(String playerName, Result result) { + public GameResultDto(String playerName, Result result) { this.playerName = playerName; this.result = result; } diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index 47cd52c71ec..940b1a62f33 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -2,7 +2,7 @@ import domain.DtoFactory; import domain.card.Deck; -import domain.dto.GameFinalResultDto; +import domain.dto.GameResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; @@ -29,6 +29,7 @@ public void startGame() { players.receiveCard(deck.draw()); dealer.receiveCard(deck.draw()); } + players.renewedWithBlackJack(); } public List drawPlayerCard(Player player) { @@ -36,9 +37,8 @@ public List drawPlayerCard(Player player) { return player.getHandToString(); } - public void addPlayer(String name) { - // TODO: 베팅 기능 추가 시 이름만이 아니라 베팅 금액도 함께 받도록 수정 필요 - players.add(new Player(name)); + public void addPlayer(String name, int bettingMoney) { + players.add(new Player(name, bettingMoney)); } public List getPlayerSequence() { @@ -63,7 +63,7 @@ public boolean proceedDealerTurn() { return true; } - public List getFinalResult() { + public List getFinalResult() { return GameResultJudge.judge(dealer, players); } diff --git a/src/main/java/domain/game/GameResultJudge.java b/src/main/java/domain/game/GameResultJudge.java index 0cba57ba2fc..b17ab8268b6 100644 --- a/src/main/java/domain/game/GameResultJudge.java +++ b/src/main/java/domain/game/GameResultJudge.java @@ -1,7 +1,7 @@ package domain.game; import domain.constant.Result; -import domain.dto.GameFinalResultDto; +import domain.dto.GameResultDto; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; @@ -12,23 +12,23 @@ public class GameResultJudge { private GameResultJudge() { } - public static List judge(Dealer dealer, Players players) { + public static List judge(Dealer dealer, Players players) { // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 - List results = new ArrayList<>(); - results.add(new GameFinalResultDto(dealer.getName())); + List results = new ArrayList<>(); + results.add(new GameResultDto(dealer.getName())); addPlayerResults(results, dealer, players); return results; } - private static void addPlayerResults(List results, Dealer dealer, Players players) { + private static void addPlayerResults(List results, Dealer dealer, Players players) { for (Player player : players.getPlayers()) { results.add(judgePlayer(player, dealer)); } } - private static GameFinalResultDto judgePlayer(Player player, Dealer dealer) { + private static GameResultDto judgePlayer(Player player, Dealer dealer) { Result result = calculateResult(player, dealer); - return new GameFinalResultDto(player.getName(), result); + return new GameResultDto(player.getName(), result); } private static Result calculateResult(Player player, Dealer dealer) { diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index 27936afc5ce..b49c0a051d0 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -4,7 +4,7 @@ public class Dealer extends Player { private final int DEALER_DRAW_CONDITION = 16; public Dealer() { - super("딜러"); + super("딜러", 1000); } @Override diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index b3cbe731eb6..2eb045acac3 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -1,24 +1,38 @@ package domain.participant; +import domain.PlayerStatus; import domain.card.Card; import domain.Hand; +import domain.constant.Result; import java.util.List; public class Player { private final String name; private final Hand hand = new Hand(); - // TODO: 베팅 기능 추가 시 베팅 금액 필드 또는 일급 객체 필요 + private PlayerStatus status; - public Player(String name) { + public Player(String name, int bettingMoney) { this.name = name; - // TODO: 베팅 기능 추가 시 생성자에서 베팅 금액도 함께 받아야 할 수 있음 + this.status = new PlayerStatus(bettingMoney); } public boolean isBust() { return hand.isBust(); } + public boolean isBlackJack() { + return hand.isBlackjack(); + } + + public Result getResult() { + return status.getResult(); + } + + public void renewedWithBlackJack() { + status.renewedWithBlackJack(); + } + public void receiveCard(Card card) { hand.add(card); } @@ -43,7 +57,4 @@ public String getName() { return name; } - public Hand getHand() { - return hand; - } } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index b26264b8ac8..cb44be82b7e 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -18,4 +18,10 @@ public void receiveCard(Card card) { public List getPlayers() { return List.copyOf(players); } + + public void renewedWithBlackJack() { + players.stream() + .filter(Player::isBlackJack) + .forEach(Player::renewedWithBlackJack); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index c5d584511ce..f145f61ae4f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,7 +1,7 @@ package view; import domain.constant.Result; -import domain.dto.GameFinalResultDto; +import domain.dto.GameResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; @@ -50,10 +50,10 @@ public void printScoreResults(List scoreResults) { System.out.println(); } - public void printFinalResult(List finalResult) { + public void printFinalResult(List finalResult) { // TODO: 베팅 기능 추가 시 정산 금액도 출력하도록 형식 수정 필요 System.out.println("## 최종 승패"); - GameFinalResultDto firstPlayer = finalResult.removeFirst(); + GameResultDto firstPlayer = finalResult.removeFirst(); Map resultCounts = new EnumMap<>(Result.class); countDealerResult(finalResult, resultCounts); @@ -61,8 +61,8 @@ public void printFinalResult(List finalResult) { printPlayerResult(finalResult); } - private void countDealerResult(List finalResult, Map resultCounts) { - for (GameFinalResultDto result : finalResult) { + private void countDealerResult(List finalResult, Map resultCounts) { + for (GameResultDto result : finalResult) { if (result.getResult() == Result.WIN) { resultCounts.put(Result.LOSE, resultCounts.getOrDefault(Result.LOSE, 0) + 1); continue; @@ -77,7 +77,7 @@ private void countDealerResult(List finalResult, Map resultCounts) { + private void printDealerResult(GameResultDto firstPlayer, Map resultCounts) { StringBuilder sb = new StringBuilder(); sb.append(firstPlayer.getPlayerName()).append(": "); for (Result result : resultCounts.keySet()) { @@ -86,9 +86,9 @@ private void printDealerResult(GameFinalResultDto firstPlayer, Map finalResult) { + private void printPlayerResult(List finalResult) { // TODO: 베팅 기능 추가 시 플레이어별 베팅 금액,수익 출력 필요 - for (GameFinalResultDto result : finalResult) { + for (GameResultDto result : finalResult) { System.out.println(MessageFormat.format( FINAL_RESULT_MESSAGE, result.getPlayerName(), diff --git a/src/test/java/domain/BettingMoneyTest.java b/src/test/java/domain/BettingMoneyTest.java index 86330dc84c6..44bdafda647 100644 --- a/src/test/java/domain/BettingMoneyTest.java +++ b/src/test/java/domain/BettingMoneyTest.java @@ -9,15 +9,15 @@ public class BettingMoneyTest { @ParameterizedTest @CsvSource({ - "10000, WIN, 10000", - "10000, DRAW, 0", - "10000, LOSE, -10000", - "10000, BUST, -10000", - "10000, BLACKJACK, 15000" + "10000, 10000", + "10000, 0", + "10000, -10000", + "10000, -10000", + "10000, 15000" }) - void 결과값에_따라_수익률을_계산하여_수익계산(int betting, Result result, double expected) { - BettingMoney bettingMoney = new BettingMoney(betting); + void 결과값에_따라_수익률을_계산하여_수익계산(int betting, double expected) { + PlayerStatus bettingMoney = new PlayerStatus(betting); - assertThat(bettingMoney.calculateProceeds(result)).isEqualTo(expected); + assertThat(bettingMoney.calculateProceeds()).isEqualTo(expected); } } diff --git a/src/test/java/domain/DtoFactoryTest.java b/src/test/java/domain/DtoFactoryTest.java index 6ee8cfb6375..a15248d155c 100644 --- a/src/test/java/domain/DtoFactoryTest.java +++ b/src/test/java/domain/DtoFactoryTest.java @@ -22,7 +22,7 @@ public class DtoFactoryTest { dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); Players players = new Players(); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); players.add(player); @@ -41,7 +41,7 @@ public class DtoFactoryTest { dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); Players players = new Players(); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); players.add(player); @@ -59,7 +59,7 @@ public class DtoFactoryTest { dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); Players players = new Players(); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); players.add(player); diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 776118a109b..2aeb8e113a7 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -1,7 +1,7 @@ package domain; import domain.card.Deck; -import domain.dto.GameFinalResultDto; +import domain.dto.GameResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; import domain.game.GameManager; @@ -18,8 +18,8 @@ class GameManagerTest { void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); - manager.addPlayer("cary"); + manager.addPlayer("pobi", 1000); + manager.addPlayer("cary", 1000); manager.startGame(); List scoreResults = manager.getScoreResults(); @@ -36,7 +36,7 @@ class GameManagerTest { void 딜러의_카드는_한_장만_공개한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); + manager.addPlayer("pobi",1000); manager.startGame(); List initialInfo = manager.getInitialInfo(); @@ -48,7 +48,7 @@ class GameManagerTest { void 플레이어의_카드는_두_장_공개한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); + manager.addPlayer("pobi", 1000); manager.startGame(); List initialInfo = manager.getInitialInfo(); @@ -59,7 +59,7 @@ class GameManagerTest { @Test void 플레이어를_한명_등록한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); + manager.addPlayer("pobi",1000); List result = manager.getPlayerSequence(); @@ -73,7 +73,7 @@ class GameManagerTest { List playerNames = List.of("pobi", "cary", "rudy"); for (String playerName : playerNames) { - manager.addPlayer(playerName); + manager.addPlayer(playerName, 1000); } List result = manager.getPlayerSequence(); @@ -85,7 +85,7 @@ class GameManagerTest { @Test void 플레이어가_카드를_한장_더_받는다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); + manager.addPlayer("pobi", 1000); manager.startGame(); Player player = manager.getPlayerSequence().getFirst(); @@ -111,10 +111,10 @@ class GameManagerTest { @Test void 게임_최종_결과에는_딜러와_모든_플레이어_결과가_포함된다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi"); - manager.addPlayer("cary"); + manager.addPlayer("pobi", 1000); + manager.addPlayer("cary", 1000); - List result = manager.getFinalResult(); + List result = manager.getFinalResult(); assertThat(result).hasSize(3); assertThat(result.get(0).getPlayerName()).isEqualTo("딜러"); @@ -152,7 +152,7 @@ class GameManagerTest { manager.startGame(); - List result = manager.getFinalResult(); + List result = manager.getFinalResult(); assertThat(result).hasSize(1); assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); diff --git a/src/test/java/domain/GameResultJudgeTest.java b/src/test/java/domain/GameResultJudgeTest.java index f7dd192e57b..91ff23c5737 100644 --- a/src/test/java/domain/GameResultJudgeTest.java +++ b/src/test/java/domain/GameResultJudgeTest.java @@ -4,7 +4,7 @@ import domain.card.Rank; import domain.constant.Result; import domain.card.Suit; -import domain.dto.GameFinalResultDto; +import domain.dto.GameResultDto; import domain.game.GameResultJudge; import domain.participant.Dealer; import domain.participant.Player; @@ -23,14 +23,14 @@ class GameResultJudgeTest { dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); - Player player = new Player("pobi"); + Player player = new Player("pobi",1000); player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result).hasSize(2); assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); @@ -43,14 +43,14 @@ class GameResultJudgeTest { dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); dealer.receiveCard(new Card(Rank.NINE, Suit.HEART)); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); player.receiveCard(new Card(Rank.SEVEN, Suit.DIAMOND)); Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); } @@ -61,14 +61,14 @@ class GameResultJudgeTest { dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); dealer.receiveCard(new Card(Rank.EIGHT, Suit.HEART)); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result.get(1).getResult()).isEqualTo(Result.DRAW); } @@ -79,7 +79,7 @@ class GameResultJudgeTest { dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.KING, Suit.CLUB)); player.receiveCard(new Card(Rank.QUEEN, Suit.DIAMOND)); player.receiveCard(new Card(Rank.TWO, Suit.HEART)); @@ -87,7 +87,7 @@ class GameResultJudgeTest { Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); } @@ -99,14 +99,14 @@ class GameResultJudgeTest { dealer.receiveCard(new Card(Rank.QUEEN, Suit.HEART)); dealer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); - Player player = new Player("pobi"); + Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TEN, Suit.DIAMOND)); player.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result.get(1).getResult()).isEqualTo(Result.WIN); } @@ -115,9 +115,9 @@ class GameResultJudgeTest { void 최종결과_첫번째에는_딜러가_포함된다() { Dealer dealer = new Dealer(); Players players = new Players(); - players.add(new Player("pobi")); + players.add(new Player("pobi", 1000)); - List result = GameResultJudge.judge(dealer, players); + List result = GameResultJudge.judge(dealer, players); assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); } diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index 9b5a673dbc0..e6494a3948c 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -1,5 +1,9 @@ package domain; +import domain.card.Card; +import domain.card.Rank; +import domain.card.Suit; +import domain.constant.Result; import domain.participant.Player; import domain.participant.Players; import org.junit.jupiter.api.Test; @@ -13,11 +17,32 @@ public class PlayersTest { @Test void 플레이어를_등록한다() { Players players = new Players(); - players.add(new Player("pobi")); - players.add(new Player("abc")); + players.add(new Player("pobi", 1000)); + players.add(new Player("abc", 1000)); List records = players.getPlayers(); assertThat(records).anyMatch(player -> player.getName().equals("abc")); } + + @Test + void 블랙잭인_플레이어는_Result를_플레이어로_변경() { + Players players = new Players(); + Player blackJackPlayer = new Player("pobi", 1000); + Player normalPlayer = new Player("jason", 1000); + + blackJackPlayer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + blackJackPlayer.receiveCard(new Card(Rank.KING, Suit.HEART)); + + normalPlayer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + normalPlayer.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); + + players.add(blackJackPlayer); + players.add(normalPlayer); + + players.renewedWithBlackJack(); + + assertThat(blackJackPlayer.getResult()).isEqualTo(Result.BLACKJACK); + assertThat(normalPlayer.getResult()).isNotEqualTo(Result.BLACKJACK); + } } From ffcd4ddac040d7165a69c67ef23d7797d1c716cf Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Fri, 13 Mar 2026 01:06:25 +0900 Subject: [PATCH 73/88] =?UTF-8?q?feat:=20Player,=20Dealer=20=EC=B6=94?= =?UTF-8?q?=EC=83=81=ED=99=94=20Participant=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/participant/Dealer.java | 12 ++--- .../java/domain/participant/Participant.java | 44 +++++++++++++++ src/main/java/domain/participant/Player.java | 54 +++++-------------- 3 files changed, 62 insertions(+), 48 deletions(-) create mode 100644 src/main/java/domain/participant/Participant.java diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index b49c0a051d0..fe02a5f8c89 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -1,18 +1,18 @@ package domain.participant; -public class Dealer extends Player { - private final int DEALER_DRAW_CONDITION = 16; +public class Dealer extends Participant { + private static final int DEALER_DRAW_CONDITION = 16; public Dealer() { - super("딜러", 1000); + super("딜러"); } @Override - public boolean canDraw(){ - return this.getScore() <= DEALER_DRAW_CONDITION; + public boolean canDraw() { + return getScore() <= DEALER_DRAW_CONDITION; } public String getOpenCard() { return getHandToString().getFirst(); } -} +} \ No newline at end of file diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java new file mode 100644 index 00000000000..8d506248663 --- /dev/null +++ b/src/main/java/domain/participant/Participant.java @@ -0,0 +1,44 @@ +package domain.participant; + +import domain.Hand; +import domain.card.Card; +import java.util.List; + +public abstract class Participant { + private final String name; + private final Hand hand = new Hand(); + + protected Participant(String name) { + this.name = name; + } + + public boolean isBust() { + return hand.isBust(); + } + + public boolean isBlackJack() { + return hand.isBlackjack(); + } + + public void receiveCard(Card card) { + hand.add(card); + } + + public List getHandToString() { + return hand.toStringList(); + } + + public int getScore() { + return hand.calculateScore(); + } + + public String getName() { + return name; + } + + public int handSize() { + return hand.size(); + } + + public abstract boolean canDraw(); +} \ No newline at end of file diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 2eb045acac3..9f6e7282431 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -1,60 +1,30 @@ package domain.participant; import domain.PlayerStatus; -import domain.card.Card; -import domain.Hand; import domain.constant.Result; -import java.util.List; - -public class Player { - private final String name; - private final Hand hand = new Hand(); - private PlayerStatus status; +public class Player extends Participant { + private final PlayerStatus status; public Player(String name, int bettingMoney) { - this.name = name; + super(name); this.status = new PlayerStatus(bettingMoney); } - public boolean isBust() { - return hand.isBust(); - } - - public boolean isBlackJack() { - return hand.isBlackjack(); + public boolean isNaturalBlackJack() { + return status.isNaturalBlackJack(); } - public Result getResult() { - return status.getResult(); + public void markNaturalBlackJack() { + status.markNaturalBlackJack(); } - public void renewedWithBlackJack() { - status.renewedWithBlackJack(); - } - - public void receiveCard(Card card) { - hand.add(card); + public double calculateProceeds(Result result) { + return status.calculateProceeds(result); } + @Override public boolean canDraw() { - return !(isBust()|| hand.isBlackjack()); - } - - public int handSize() { - return hand.size(); + return !(isBust() || isNaturalBlackJack()); } - - public List getHandToString() { - return hand.toStringList(); - } - - public int getScore(){ - return hand.calculateScore(); - } - - public String getName() { - return name; - } - -} +} \ No newline at end of file From 80cca09217a8d50bb499a8e24566b117b364027a Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Fri, 13 Mar 2026 01:07:21 +0900 Subject: [PATCH 74/88] =?UTF-8?q?refactor:=20PlayerStatus=20result=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=A5=BC=20naturalBlackJack=20boolean?= =?UTF-8?q?=EC=9C=BC=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 --- README.md | 9 +++++--- src/main/java/controller/GameController.java | 4 +++- src/main/java/domain/DtoFactory.java | 4 ++-- src/main/java/domain/PlayerStatus.java | 14 ++++++------ src/main/java/domain/game/GameManager.java | 13 +++++------ .../java/domain/game/GameResultJudge.java | 2 +- src/main/java/domain/participant/Players.java | 10 +++++---- src/test/java/domain/BettingMoneyTest.java | 13 ----------- src/test/java/domain/GameManagerTest.java | 6 ++--- src/test/java/domain/PlayersTest.java | 22 +++++-------------- 10 files changed, 38 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 2c73d26b796..029e545ec48 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ - [X] 배팅 금액을 관리하는 도메인을 구현한다. - [X] 처음 받은 배팅 금액을 저장 - [X] 입력 받은 정산 시 결과 상태(승/무/패/블랙잭/버스트)에 따라 계산한 총 수익을 리턴 - - [ ] 딜러를 플레이어의 상속을 받지 않고, 딜러와 플레이어 모두 추상화 시키는 Participants 생성 + - [X] 딜러를 플레이어의 상속을 받지 않고, 딜러와 플레이어 모두 추상화 시키는 Participants 생성 ## 2. 판정 추가 - [X] 기존 `Result`에 블랙잭과 버스트를 추가 - [X] 처음 BlackJack이 뜬 경우 블랙잭 상태로 결과에 저장 @@ -148,8 +148,7 @@ - 승은 원금 + 수익 -> * 2 - 패, 버스트는 원금 손실 -> * -1 - 처음부터 블랙잭인 경우 배팅의 1.5배 수익 -> * 2.5 -- [ ] 플레이어 Hit/Stand 단계에서 BlackJack이 아닌 유저만 필터링하여 문답 진행 -- [ ] 플레이어 Hit/Stand 단계에서 Bust가 되면 결과는 Bust로 저장 +- [X] 플레이어 Hit/Stand 단계에서 BlackJack이 아닌 유저만 필터링하여 문답 진행 - [ ] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 결과 단계로 플로우 이동 - [ ] ResultDto에 블랙잭, 버스트가 아닌 인원 모두에게 승리배당, 블랙잭은 블랙잭 배당을 적용한 값을 생성 - [ ] 생성된 값으로 출력 @@ -163,3 +162,7 @@ - [ ] 기존 딜러의 승,무,패 출력 기능 제거 - [ ] 플레이어들의 승, 무, 패(버스트), 블랙잭 기준으로 값을 계산하여 수익을 출력하도록 수정 - [ ] 딜러 기준 총 수익 계산 받아서 출력하는 기능 구현 + + +## 고민 +- Players를 copyOf로 해도 얕은 복사라 Player 자체에는 접근이 가능해진다. Player 자체의 변동 가능성은? diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index b728aa790f7..fbaebf4f6d7 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -56,7 +56,7 @@ private void initGame() { } private void playPlayerTurn() { - for (Player player : manager.getPlayerSequence()) { + for (Player player : manager.getPlayersToPlay()) { playSinglePlayerTurn(player); } } @@ -68,6 +68,8 @@ private void playSinglePlayerTurn(Player player) { } } + + private boolean wantsToDraw(Player player) { return !inputView.readCommand(player.getName()).equals("n"); } diff --git a/src/main/java/domain/DtoFactory.java b/src/main/java/domain/DtoFactory.java index 78fefee90af..33f5b7f5b51 100644 --- a/src/main/java/domain/DtoFactory.java +++ b/src/main/java/domain/DtoFactory.java @@ -37,7 +37,7 @@ private static void addDealerScoreResult(List results, Deale } private static void addPlayerScoreResults(List results, Players players) { - for (Player player : players.getPlayers()) { + for (Player player : players.getNonNaturalBlackJackPlayers()) { results.add(new GameScoreResultDto( player.getName(), player.getHandToString(), @@ -55,7 +55,7 @@ private static void addDealerInitialInfo(List results, Deale } private static void addPlayerInitialInfos(List results, Players players) { - for (Player player : players.getPlayers()) { + for (Player player : players.getNonNaturalBlackJackPlayers()) { results.add(new GameInitialInfoDto( player.getName(), INITIAL_HAND_SIZE, diff --git a/src/main/java/domain/PlayerStatus.java b/src/main/java/domain/PlayerStatus.java index d6ed5eb8895..83a470e7146 100644 --- a/src/main/java/domain/PlayerStatus.java +++ b/src/main/java/domain/PlayerStatus.java @@ -4,21 +4,21 @@ public class PlayerStatus { private final int bettingMoney; - private Result result; + private boolean naturalBlackJack; public PlayerStatus(int bettingMoney) { this.bettingMoney = bettingMoney; } - public double calculateProceeds() { - return bettingMoney * result.getAllocation(); + public void markNaturalBlackJack() { + naturalBlackJack = true; } - public void renewedWithBlackJack() { - result = Result.BLACKJACK; + public boolean isNaturalBlackJack() { + return naturalBlackJack; } - public Result getResult() { - return result; + public double calculateProceeds(Result result) { + return bettingMoney * result.getAllocation(); } } diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index 940b1a62f33..e7cc0d66697 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -5,14 +5,13 @@ import domain.dto.GameResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; - import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; import java.util.List; public class GameManager { - private final int FIRST_DRAW_CARDS = 2; + private static final int FIRST_DRAW_CARDS = 2; private final Deck deck; private final Players players; @@ -29,7 +28,7 @@ public void startGame() { players.receiveCard(deck.draw()); dealer.receiveCard(deck.draw()); } - players.renewedWithBlackJack(); + players.updateNaturalBlackJackStatus(); } public List drawPlayerCard(Player player) { @@ -41,8 +40,8 @@ public void addPlayer(String name, int bettingMoney) { players.add(new Player(name, bettingMoney)); } - public List getPlayerSequence() { - return players.getPlayers(); + public List getPlayersToPlay() { + return players.getNonNaturalBlackJackPlayers(); } public List getScoreResults() { @@ -53,7 +52,6 @@ public List getInitialInfo() { return DtoFactory.toInitialInfo(dealer, players); } - public boolean proceedDealerTurn() { if (!dealer.canDraw()) { return false; @@ -66,5 +64,4 @@ public boolean proceedDealerTurn() { public List getFinalResult() { return GameResultJudge.judge(dealer, players); } - -} +} \ No newline at end of file diff --git a/src/main/java/domain/game/GameResultJudge.java b/src/main/java/domain/game/GameResultJudge.java index b17ab8268b6..f0a9fd3ce50 100644 --- a/src/main/java/domain/game/GameResultJudge.java +++ b/src/main/java/domain/game/GameResultJudge.java @@ -21,7 +21,7 @@ public static List judge(Dealer dealer, Players players) { } private static void addPlayerResults(List results, Dealer dealer, Players players) { - for (Player player : players.getPlayers()) { + for (Player player : players.getNonNaturalBlackJackPlayers()) { results.add(judgePlayer(player, dealer)); } } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index cb44be82b7e..5ace3b58a62 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -15,13 +15,15 @@ public void receiveCard(Card card) { players.forEach(player -> player.receiveCard(card)); } - public List getPlayers() { - return List.copyOf(players); + public List getNonNaturalBlackJackPlayers() { + return players.stream() + .filter(player -> !player.isNaturalBlackJack()) + .toList(); } - public void renewedWithBlackJack() { + public void updateNaturalBlackJackStatus() { players.stream() .filter(Player::isBlackJack) - .forEach(Player::renewedWithBlackJack); + .forEach(Player::markNaturalBlackJack); } } diff --git a/src/test/java/domain/BettingMoneyTest.java b/src/test/java/domain/BettingMoneyTest.java index 44bdafda647..61f60b51229 100644 --- a/src/test/java/domain/BettingMoneyTest.java +++ b/src/test/java/domain/BettingMoneyTest.java @@ -7,17 +7,4 @@ public class BettingMoneyTest { - @ParameterizedTest - @CsvSource({ - "10000, 10000", - "10000, 0", - "10000, -10000", - "10000, -10000", - "10000, 15000" - }) - void 결과값에_따라_수익률을_계산하여_수익계산(int betting, double expected) { - PlayerStatus bettingMoney = new PlayerStatus(betting); - - assertThat(bettingMoney.calculateProceeds()).isEqualTo(expected); - } } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index 2aeb8e113a7..c0f7e468bd0 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -61,7 +61,7 @@ class GameManagerTest { GameManager manager = new GameManager(new Deck()); manager.addPlayer("pobi",1000); - List result = manager.getPlayerSequence(); + List result = manager.getPlayersToPlay(); assertThat(result.size()).isEqualTo(1); assertThat(result.getFirst().getName()).isEqualTo("pobi"); @@ -76,7 +76,7 @@ class GameManagerTest { manager.addPlayer(playerName, 1000); } - List result = manager.getPlayerSequence(); + List result = manager.getPlayersToPlay(); assertThat(result.size()).isEqualTo(3); } @@ -88,7 +88,7 @@ class GameManagerTest { manager.addPlayer("pobi", 1000); manager.startGame(); - Player player = manager.getPlayerSequence().getFirst(); + Player player = manager.getPlayersToPlay().getFirst(); int before = player.handSize(); diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index e6494a3948c..65dc1f8b473 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -3,7 +3,6 @@ import domain.card.Card; import domain.card.Rank; import domain.card.Suit; -import domain.constant.Result; import domain.participant.Player; import domain.participant.Players; import org.junit.jupiter.api.Test; @@ -15,18 +14,7 @@ public class PlayersTest { @Test - void 플레이어를_등록한다() { - Players players = new Players(); - players.add(new Player("pobi", 1000)); - players.add(new Player("abc", 1000)); - - List records = players.getPlayers(); - - assertThat(records).anyMatch(player -> player.getName().equals("abc")); - } - - @Test - void 블랙잭인_플레이어는_Result를_플레이어로_변경() { + void 초기_블랙잭인_플레이어는_naturalBlackJack_상태가_true가_된다() { Players players = new Players(); Player blackJackPlayer = new Player("pobi", 1000); Player normalPlayer = new Player("jason", 1000); @@ -40,9 +28,9 @@ public class PlayersTest { players.add(blackJackPlayer); players.add(normalPlayer); - players.renewedWithBlackJack(); + players.updateNaturalBlackJackStatus(); - assertThat(blackJackPlayer.getResult()).isEqualTo(Result.BLACKJACK); - assertThat(normalPlayer.getResult()).isNotEqualTo(Result.BLACKJACK); + assertThat(blackJackPlayer.isNaturalBlackJack()).isTrue(); + assertThat(normalPlayer.isNaturalBlackJack()).isFalse(); } -} +} \ No newline at end of file From ade62ac0f5c3391905dbeab98d62594d2835295d Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Fri, 13 Mar 2026 01:15:56 +0900 Subject: [PATCH 75/88] =?UTF-8?q?docs:=20README=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 029e545ec48..15caeb27f4d 100644 --- a/README.md +++ b/README.md @@ -149,13 +149,17 @@ - 패, 버스트는 원금 손실 -> * -1 - 처음부터 블랙잭인 경우 배팅의 1.5배 수익 -> * 2.5 - [X] 플레이어 Hit/Stand 단계에서 BlackJack이 아닌 유저만 필터링하여 문답 진행 -- [ ] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 결과 단계로 플로우 이동 - - [ ] ResultDto에 블랙잭, 버스트가 아닌 인원 모두에게 승리배당, 블랙잭은 블랙잭 배당을 적용한 값을 생성 - - [ ] 생성된 값으로 출력 +- [ ] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 최종 결과 생성 단계로 이동 + - [ ] 각 플레이어에 대해 최종 Result를 계산 + - [ ] 플레이어가 bust면 BUST + - [ ] bust가 아니면 딜러와 점수 비교 후 WIN, LOSE, DRAW 판정 + - [ ] natural blackjack인 경우 블랙잭 배당 규칙을 반영할 수 있도록 별도 처리 + - [ ] 계산된 Result 바탕으로 정산 금액 계산 + - [ ] Result와 정산 금액을 포함한 DTO 생성 ## 3. 배팅 금액 입력하여 플레이어 생성 - [ ] 플레이어 이름 입력 후 배팅 금액도 입력 -- [ ] 플레이어와 금액을 매핑해서 플렝이어 생성 +- [ ] 플레이어와 금액을 매핑해서 플레이어 생성 - [ ] 플레이어의 배팅 금액을 다루는 메서드 구현 ## 4. 베팅 결과 판정 및 출력 From 8901f90b2fc887179e89dedabe3952059dbc6792 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Fri, 13 Mar 2026 01:49:22 +0900 Subject: [PATCH 76/88] =?UTF-8?q?feat:=20=EC=8A=B9,=EB=AC=B4,=ED=8C=A8,?= =?UTF-8?q?=EB=B2=84=EC=8A=A4=ED=8A=B8=20=EA=B2=B0=EA=B3=BC=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=ED=8C=90=EC=A0=95=EA=B3=BC=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B3=84=EC=82=B0=20=EC=B6=9C=EB=A0=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +- .../java/domain/dto/GameFinalResultDto.java | 35 ----- src/main/java/domain/dto/GameResultDto.java | 25 ++-- .../java/domain/game/GameResultJudge.java | 26 +++- src/main/java/domain/participant/Players.java | 4 + src/main/java/view/OutputView.java | 77 ++++------ src/test/java/domain/BettingMoneyTest.java | 10 -- src/test/java/domain/GameResultJudgeTest.java | 139 +++++++++++------- src/test/java/domain/PlayerStatusTest.java | 36 +++++ src/test/java/domain/PlayerTest.java | 34 +++++ src/test/java/domain/PlayersTest.java | 36 +++++ 11 files changed, 266 insertions(+), 170 deletions(-) delete mode 100644 src/main/java/domain/dto/GameFinalResultDto.java delete mode 100644 src/test/java/domain/BettingMoneyTest.java create mode 100644 src/test/java/domain/PlayerStatusTest.java create mode 100644 src/test/java/domain/PlayerTest.java diff --git a/README.md b/README.md index 15caeb27f4d..5bf973387f2 100644 --- a/README.md +++ b/README.md @@ -149,13 +149,13 @@ - 패, 버스트는 원금 손실 -> * -1 - 처음부터 블랙잭인 경우 배팅의 1.5배 수익 -> * 2.5 - [X] 플레이어 Hit/Stand 단계에서 BlackJack이 아닌 유저만 필터링하여 문답 진행 -- [ ] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 최종 결과 생성 단계로 이동 - - [ ] 각 플레이어에 대해 최종 Result를 계산 - - [ ] 플레이어가 bust면 BUST - - [ ] bust가 아니면 딜러와 점수 비교 후 WIN, LOSE, DRAW 판정 - - [ ] natural blackjack인 경우 블랙잭 배당 규칙을 반영할 수 있도록 별도 처리 - - [ ] 계산된 Result 바탕으로 정산 금액 계산 - - [ ] Result와 정산 금액을 포함한 DTO 생성 +- [X] 딜러 추가 드로우 단계에서 Bust가 되면 즉시 최종 결과 생성 단계로 이동 + - [X] 각 플레이어에 대해 최종 Result를 계산 + - [X] 플레이어가 bust면 BUST + - [X] bust가 아니면 딜러와 점수 비교 후 WIN, LOSE, DRAW 판정 + - [X] natural blackjack인 경우 블랙잭 배당 규칙을 반영할 수 있도록 별도 처리 + - [X] 계산된 Result 바탕으로 정산 금액 계산 + - [X] Result와 정산 금액을 포함한 DTO 생성 ## 3. 배팅 금액 입력하여 플레이어 생성 - [ ] 플레이어 이름 입력 후 배팅 금액도 입력 diff --git a/src/main/java/domain/dto/GameFinalResultDto.java b/src/main/java/domain/dto/GameFinalResultDto.java deleted file mode 100644 index ac5910e9694..00000000000 --- a/src/main/java/domain/dto/GameFinalResultDto.java +++ /dev/null @@ -1,35 +0,0 @@ -package domain.dto; - -import domain.constant.Result; - -public class GameFinalResultDto { - private final String playerName; - private final Result result; - // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 - - - public GameFinalResultDto(String playerName) { - this(playerName, null); - } - - public GameFinalResultDto(String playerName, Result result) { - this.playerName = playerName; - this.result = result; - } - - public String getPlayerName() { - return playerName; - } - - public Result getResult() { - return result; - } - - @Override - public String toString() { - return "domain.dto.GameFinalResultDto{" + - "name='" + playerName + '\'' + - ", result=" + result + - '}'; - } -} diff --git a/src/main/java/domain/dto/GameResultDto.java b/src/main/java/domain/dto/GameResultDto.java index 7b06555f5d7..ac97aefd2d4 100644 --- a/src/main/java/domain/dto/GameResultDto.java +++ b/src/main/java/domain/dto/GameResultDto.java @@ -3,18 +3,18 @@ import domain.constant.Result; public class GameResultDto { - String playerName; - Result result; - // TODO: 베팅 기능 추가 시 베팅 금액, 정산 금액(수익/손실) 필드 추가 필요 + private final String playerName; + private final Result result; + private final double proceeds; - - public GameResultDto(String playerName) { - this(playerName, null); + public GameResultDto(String playerName, double proceeds) { + this(playerName, null, proceeds); } - public GameResultDto(String playerName, Result result) { + public GameResultDto(String playerName, Result result, double proceeds) { this.playerName = playerName; this.result = result; + this.proceeds = proceeds; } public String getPlayerName() { @@ -25,11 +25,16 @@ public Result getResult() { return result; } + public double getProceeds() { + return proceeds; + } + @Override public String toString() { - return "domain.dto.GameFinalResultDto{" + - "name='" + playerName + '\'' + + return "GameResultDto{" + + "playerName='" + playerName + '\'' + ", result=" + result + + ", proceeds=" + proceeds + '}'; } -} +} \ No newline at end of file diff --git a/src/main/java/domain/game/GameResultJudge.java b/src/main/java/domain/game/GameResultJudge.java index f0a9fd3ce50..f977d6f9aa9 100644 --- a/src/main/java/domain/game/GameResultJudge.java +++ b/src/main/java/domain/game/GameResultJudge.java @@ -13,22 +13,26 @@ private GameResultJudge() { } public static List judge(Dealer dealer, Players players) { - // TODO: 베팅 기능 추가 시 승/패/무 뿐 아니라 정산 금액까지 포함한 결과 생성 필요 List results = new ArrayList<>(); - results.add(new GameResultDto(dealer.getName())); + addPlayerResults(results, dealer, players); + + double dealerProceeds = calculateDealerProceeds(results); + results.add(0, new GameResultDto(dealer.getName(), dealerProceeds)); + return results; } private static void addPlayerResults(List results, Dealer dealer, Players players) { - for (Player player : players.getNonNaturalBlackJackPlayers()) { + for (Player player : players.getPlayers()) { results.add(judgePlayer(player, dealer)); } } private static GameResultDto judgePlayer(Player player, Dealer dealer) { Result result = calculateResult(player, dealer); - return new GameResultDto(player.getName(), result); + double proceeds = player.calculateProceeds(result); + return new GameResultDto(player.getName(), result, proceeds); } private static Result calculateResult(Player player, Dealer dealer) { @@ -36,11 +40,11 @@ private static Result calculateResult(Player player, Dealer dealer) { int dealerScore = dealer.getScore(); if (player.isBust()) { - return Result.LOSE; + return Result.BUST; } - if (dealer.isBust()) { - return Result.WIN; + if (player.isNaturalBlackJack()) { + return Result.BLACKJACK; } if (playerScore > dealerScore) { @@ -53,4 +57,10 @@ private static Result calculateResult(Player player, Dealer dealer) { return Result.DRAW; } -} + + private static double calculateDealerProceeds(List results) { + return -results.stream() + .mapToDouble(GameResultDto::getProceeds) + .sum(); + } +} \ No newline at end of file diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index 5ace3b58a62..c0f3a476be4 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -15,6 +15,10 @@ public void receiveCard(Card card) { players.forEach(player -> player.receiveCard(card)); } + public List getPlayers() { + return List.copyOf(players); + } + public List getNonNaturalBlackJackPlayers() { return players.stream() .filter(player -> !player.isNaturalBlackJack()) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index f145f61ae4f..effe025bb98 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,24 +1,21 @@ package view; -import domain.constant.Result; import domain.dto.GameResultDto; import domain.dto.GameInitialInfoDto; import domain.dto.GameScoreResultDto; import java.text.MessageFormat; -import java.util.EnumMap; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; public class OutputView { private static final String DEAL_MESSAGE = "딜러와 {0}에게 {1}장을 나누었습니다."; private static final String SHOW_HAND_MESSAGE = "{0}카드: {1}"; - private static final String FINAL_RESULT_MESSAGE = "{0}: {1}"; + private static final String SHOW_DEALER_HAND_MESSAGE = "{0} 카드: {1}"; + private static final String FINAL_PROCEEDS_MESSAGE = "{0}: {1}"; private static final String DEALER_DRAW_MESSAGE = "딜러는 16이하라 한장의 카드를 더 받았습니다."; private static final String ERROR_PREFIX = "[ERROR] "; - public void printInitialInfo(List initialInfo) { printHandOutNotice(initialInfo); printInitialHands(initialInfo); @@ -26,7 +23,7 @@ public void printInitialInfo(List initialInfo) { public void printHand(List hand, String name) { System.out.println(MessageFormat.format( - SHOW_HAND_MESSAGE, + getHandMessageFormat(name), name, String.join(", ", hand) )); @@ -41,65 +38,29 @@ public void printScoreResults(List scoreResults) { System.out.println(); for (GameScoreResultDto scoreResult : scoreResults) { System.out.println(MessageFormat.format( - SHOW_HAND_MESSAGE, + getHandMessageFormat(scoreResult.getPlayerName()), scoreResult.getPlayerName(), - String.join(", ", scoreResult.getHand()) - + " - 결과: " + scoreResult.getResult() + String.join(", ", scoreResult.getHand()) + " - 결과: " + scoreResult.getResult() )); } System.out.println(); } public void printFinalResult(List finalResult) { - // TODO: 베팅 기능 추가 시 정산 금액도 출력하도록 형식 수정 필요 - System.out.println("## 최종 승패"); - GameResultDto firstPlayer = finalResult.removeFirst(); - Map resultCounts = new EnumMap<>(Result.class); - - countDealerResult(finalResult, resultCounts); - printDealerResult(firstPlayer, resultCounts); - printPlayerResult(finalResult); - } - - private void countDealerResult(List finalResult, Map resultCounts) { - for (GameResultDto result : finalResult) { - if (result.getResult() == Result.WIN) { - resultCounts.put(Result.LOSE, resultCounts.getOrDefault(Result.LOSE, 0) + 1); - continue; - } - - if (result.getResult() == Result.LOSE) { - resultCounts.put(Result.WIN, resultCounts.getOrDefault(Result.WIN, 0) + 1); - continue; - } - - resultCounts.put(result.getResult(), resultCounts.getOrDefault(result.getResult(), 0) + 1); - } - } - - private void printDealerResult(GameResultDto firstPlayer, Map resultCounts) { - StringBuilder sb = new StringBuilder(); - sb.append(firstPlayer.getPlayerName()).append(": "); - for (Result result : resultCounts.keySet()) { - sb.append(resultCounts.get(result)).append(result.getName()); - } - System.out.println(sb); - } + System.out.println("## 최종 수익"); - private void printPlayerResult(List finalResult) { - // TODO: 베팅 기능 추가 시 플레이어별 베팅 금액,수익 출력 필요 for (GameResultDto result : finalResult) { System.out.println(MessageFormat.format( - FINAL_RESULT_MESSAGE, + FINAL_PROCEEDS_MESSAGE, result.getPlayerName(), - result.getResult().getName() + formatProceeds(result.getProceeds()) )); } } private void printHandOutNotice(List initialInfo) { String playerNames = initialInfo.stream() - .skip(1) // 0번은 딜러 + .skip(1) .map(GameInitialInfoDto::getPlayerName) .collect(Collectors.joining(", ")); @@ -109,17 +70,33 @@ private void printHandOutNotice(List initialInfo) { initialInfo.getFirst().getInitialHandSize() )); } + private void printInitialHands(List initialInfo) { for (GameInitialInfoDto info : initialInfo) { System.out.println(MessageFormat.format( - SHOW_HAND_MESSAGE, + getHandMessageFormat(info.getPlayerName()), info.getPlayerName(), String.join(", ", info.getHand()) )); } System.out.println(); } + public void printError(String message) { System.out.println(ERROR_PREFIX + message); } -} + + private String getHandMessageFormat(String name) { + if ("딜러".equals(name)) { + return SHOW_DEALER_HAND_MESSAGE; + } + return SHOW_HAND_MESSAGE; + } + + private String formatProceeds(double proceeds) { + if (proceeds == (long) proceeds) { + return String.valueOf((long) proceeds); + } + return String.valueOf(proceeds); + } +} \ No newline at end of file diff --git a/src/test/java/domain/BettingMoneyTest.java b/src/test/java/domain/BettingMoneyTest.java deleted file mode 100644 index 61f60b51229..00000000000 --- a/src/test/java/domain/BettingMoneyTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package domain; - -import domain.constant.Result; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import static org.assertj.core.api.Assertions.assertThat; - -public class BettingMoneyTest { - -} diff --git a/src/test/java/domain/GameResultJudgeTest.java b/src/test/java/domain/GameResultJudgeTest.java index 91ff23c5737..7fa8dc277e4 100644 --- a/src/test/java/domain/GameResultJudgeTest.java +++ b/src/test/java/domain/GameResultJudgeTest.java @@ -2,8 +2,8 @@ import domain.card.Card; import domain.card.Rank; -import domain.constant.Result; import domain.card.Suit; +import domain.constant.Result; import domain.dto.GameResultDto; import domain.game.GameResultJudge; import domain.participant.Dealer; @@ -15,110 +15,149 @@ import static org.assertj.core.api.Assertions.assertThat; -class GameResultJudgeTest { +public class GameResultJudgeTest { @Test - void 플레이어가_딜러보다_점수가_높으면_WIN이다() { + void 플레이어가_bust면_BUST와_음수_수익을_가진다() { Dealer dealer = new Dealer(); + Players players = new Players(); + Player player = new Player("pobi", 1000); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); // 17 - Player player = new Player("pobi",1000); - player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); - player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.KING, Suit.CLUB)); + player.receiveCard(new Card(Rank.QUEEN, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.TWO, Suit.HEART)); // 22 bust - Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List results = GameResultJudge.judge(dealer, players); + + GameResultDto dealerResult = results.get(0); + GameResultDto playerResult = results.get(1); + + assertThat(playerResult.getPlayerName()).isEqualTo("pobi"); + assertThat(playerResult.getResult()).isEqualTo(Result.BUST); + assertThat(playerResult.getProceeds()).isEqualTo(-1000); - assertThat(result).hasSize(2); - assertThat(result.get(1).getPlayerName()).isEqualTo("pobi"); - assertThat(result.get(1).getResult()).isEqualTo(Result.WIN); + assertThat(dealerResult.getPlayerName()).isEqualTo("딜러"); + assertThat(dealerResult.getProceeds()).isEqualTo(1000); } @Test - void 플레이어가_딜러보다_점수가_낮으면_LOSE이다() { + void 플레이어_점수가_더_높으면_WIN이다() { Dealer dealer = new Dealer(); + Players players = new Players(); + Player player = new Player("pobi", 1000); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.NINE, Suit.HEART)); + dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); // 17 - Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); - player.receiveCard(new Card(Rank.SEVEN, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); // 18 - Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List results = GameResultJudge.judge(dealer, players); + GameResultDto playerResult = results.get(1); - assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); + assertThat(playerResult.getResult()).isEqualTo(Result.WIN); + assertThat(playerResult.getProceeds()).isEqualTo(1000); } @Test - void 플레이어와_딜러의_점수가_같으면_DRAW이다() { + void 플레이어_점수가_더_낮으면_LOSE다() { Dealer dealer = new Dealer(); + Players players = new Players(); + Player player = new Player("pobi", 1000); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.EIGHT, Suit.HEART)); + dealer.receiveCard(new Card(Rank.NINE, Suit.HEART)); // 19 - Player player = new Player("pobi", 1000); - player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); - player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); + player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); + player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); // 18 - Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List results = GameResultJudge.judge(dealer, players); + GameResultDto playerResult = results.get(1); - assertThat(result.get(1).getResult()).isEqualTo(Result.DRAW); + assertThat(playerResult.getResult()).isEqualTo(Result.LOSE); + assertThat(playerResult.getProceeds()).isEqualTo(-1000); } @Test - void 플레이어가_버스트면_딜러와_상관없이_LOSE이다() { + void 플레이어와_딜러의_점수가_같으면_DRAW다() { Dealer dealer = new Dealer(); + Players players = new Players(); + Player player = new Player("pobi", 1000); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + dealer.receiveCard(new Card(Rank.EIGHT, Suit.HEART)); // 18 - Player player = new Player("pobi", 1000); - player.receiveCard(new Card(Rank.KING, Suit.CLUB)); - player.receiveCard(new Card(Rank.QUEEN, Suit.DIAMOND)); - player.receiveCard(new Card(Rank.TWO, Suit.HEART)); + player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); + player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); // 18 - Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List results = GameResultJudge.judge(dealer, players); + GameResultDto playerResult = results.get(1); - assertThat(result.get(1).getResult()).isEqualTo(Result.LOSE); + assertThat(playerResult.getResult()).isEqualTo(Result.DRAW); + assertThat(playerResult.getProceeds()).isEqualTo(0); } @Test - void 딜러가_버스트면_플레이어가_버스트가_아닌_한_WIN이다() { + void naturalBlackJack인_플레이어는_BLACKJACK과_블랙잭_배당을_가진다() { Dealer dealer = new Dealer(); - dealer.receiveCard(new Card(Rank.KING, Suit.SPADE)); - dealer.receiveCard(new Card(Rank.QUEEN, Suit.HEART)); - dealer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + Players players = new Players(); + Player player = new Player("pobi", 10000); - Player player = new Player("pobi", 1000); - player.receiveCard(new Card(Rank.TEN, Suit.DIAMOND)); - player.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.NINE, Suit.HEART)); // 19 + + player.receiveCard(new Card(Rank.ACE, Suit.CLUB)); + player.receiveCard(new Card(Rank.KING, Suit.DIAMOND)); // natural blackjack + player.markNaturalBlackJack(); - Players players = new Players(); players.add(player); - List result = GameResultJudge.judge(dealer, players); + List results = GameResultJudge.judge(dealer, players); + GameResultDto playerResult = results.get(1); - assertThat(result.get(1).getResult()).isEqualTo(Result.WIN); + assertThat(playerResult.getResult()).isEqualTo(Result.BLACKJACK); + assertThat(playerResult.getProceeds()).isEqualTo(15000); } @Test - void 최종결과_첫번째에는_딜러가_포함된다() { + void 딜러의_총수익은_플레이어_수익의_합에_음수를_취한_값이다() { Dealer dealer = new Dealer(); Players players = new Players(); - players.add(new Player("pobi", 1000)); - List result = GameResultJudge.judge(dealer, players); + Player winPlayer = new Player("pobi", 1000); + Player losePlayer = new Player("jason", 2000); + + dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); + dealer.receiveCard(new Card(Rank.EIGHT, Suit.HEART)); // 18 + + winPlayer.receiveCard(new Card(Rank.TEN, Suit.CLUB)); + winPlayer.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); // 19 -> WIN + + losePlayer.receiveCard(new Card(Rank.TEN, Suit.HEART)); + losePlayer.receiveCard(new Card(Rank.SEVEN, Suit.CLUB)); // 17 -> LOSE + + players.add(winPlayer); + players.add(losePlayer); + + List results = GameResultJudge.judge(dealer, players); + + GameResultDto dealerResult = results.get(0); + GameResultDto firstPlayerResult = results.get(1); + GameResultDto secondPlayerResult = results.get(2); - assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); + assertThat(firstPlayerResult.getProceeds()).isEqualTo(1000); + assertThat(secondPlayerResult.getProceeds()).isEqualTo(-2000); + assertThat(dealerResult.getProceeds()).isEqualTo(1000); } } \ No newline at end of file diff --git a/src/test/java/domain/PlayerStatusTest.java b/src/test/java/domain/PlayerStatusTest.java new file mode 100644 index 00000000000..c1fb9a41487 --- /dev/null +++ b/src/test/java/domain/PlayerStatusTest.java @@ -0,0 +1,36 @@ +package domain; + +import domain.constant.Result; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PlayerStatusTest { + + @Test + void naturalBlackJack_상태를_true로_변경한다() { + PlayerStatus status = new PlayerStatus(1000); + + status.markNaturalBlackJack(); + + assertThat(status.isNaturalBlackJack()).isTrue(); + } + + @ParameterizedTest + @CsvSource({ + "10000, WIN, 10000", + "10000, DRAW, 0", + "10000, LOSE, -10000", + "10000, BUST, -10000", + "10000, BLACKJACK, 15000" + }) + void 결과값에_따라_정산_금액을_계산한다(int bettingMoney, Result result, double expected) { + PlayerStatus status = new PlayerStatus(bettingMoney); + + double proceeds = status.calculateProceeds(result); + + assertThat(proceeds).isEqualTo(expected); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java new file mode 100644 index 00000000000..b4908deab93 --- /dev/null +++ b/src/test/java/domain/PlayerTest.java @@ -0,0 +1,34 @@ +package domain; + +import domain.card.Card; +import domain.card.Rank; +import domain.card.Suit; +import domain.participant.Player; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PlayerTest { + + @Test + void naturalBlackJack_상태인_플레이어는_카드를_더_뽑을_수_없다() { + Player player = new Player("pobi", 1000); + + player.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + player.receiveCard(new Card(Rank.KING, Suit.HEART)); + player.markNaturalBlackJack(); + + assertThat(player.canDraw()).isFalse(); + } + + @Test + void bust인_플레이어는_카드를_더_뽑을_수_없다() { + Player player = new Player("pobi", 1000); + + player.receiveCard(new Card(Rank.KING, Suit.SPADE)); + player.receiveCard(new Card(Rank.QUEEN, Suit.HEART)); + player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + + assertThat(player.canDraw()).isFalse(); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index 65dc1f8b473..af836645ae3 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -13,6 +13,19 @@ public class PlayersTest { + @Test + void 플레이어를_등록한다() { + Players players = new Players(); + players.add(new Player("pobi", 1000)); + players.add(new Player("abc", 1000)); + + List records = players.getPlayers(); + + assertThat(records).hasSize(2); + assertThat(records).extracting(Player::getName) + .containsExactly("pobi", "abc"); + } + @Test void 초기_블랙잭인_플레이어는_naturalBlackJack_상태가_true가_된다() { Players players = new Players(); @@ -33,4 +46,27 @@ public class PlayersTest { assertThat(blackJackPlayer.isNaturalBlackJack()).isTrue(); assertThat(normalPlayer.isNaturalBlackJack()).isFalse(); } + + @Test + void 초기_블랙잭이_아닌_플레이어들만_반환한다() { + Players players = new Players(); + Player blackJackPlayer = new Player("pobi", 1000); + Player normalPlayer = new Player("jason", 1000); + + blackJackPlayer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); + blackJackPlayer.receiveCard(new Card(Rank.KING, Suit.HEART)); + + normalPlayer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); + normalPlayer.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); + + players.add(blackJackPlayer); + players.add(normalPlayer); + + players.updateNaturalBlackJackStatus(); + + List result = players.getNonNaturalBlackJackPlayers(); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().getName()).isEqualTo("jason"); + } } \ No newline at end of file From 5f1ee76fdf1536f2f0c7d3e38c0f8a24ac9fca2a Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Fri, 13 Mar 2026 02:12:37 +0900 Subject: [PATCH 77/88] =?UTF-8?q?feat:=20=EB=B2=A0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EC=9E=85=EB=A0=A5=EA=B3=BC=20=EC=B5=9C=EC=A2=85=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=20=EC=A0=95=EC=82=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++--- src/main/java/controller/GameController.java | 21 +++++----- src/main/java/view/InputView.java | 44 ++++++++++++++------ 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 5bf973387f2..586feb6e285 100644 --- a/README.md +++ b/README.md @@ -158,14 +158,14 @@ - [X] Result와 정산 금액을 포함한 DTO 생성 ## 3. 배팅 금액 입력하여 플레이어 생성 -- [ ] 플레이어 이름 입력 후 배팅 금액도 입력 -- [ ] 플레이어와 금액을 매핑해서 플레이어 생성 -- [ ] 플레이어의 배팅 금액을 다루는 메서드 구현 +- [X] 플레이어 이름 입력 후 배팅 금액도 입력 +- [X] 플레이어와 금액을 매핑해서 플레이어 생성 +- [X] 플레이어의 배팅 금액을 다루는 메서드 구현 ## 4. 베팅 결과 판정 및 출력 -- [ ] 기존 딜러의 승,무,패 출력 기능 제거 -- [ ] 플레이어들의 승, 무, 패(버스트), 블랙잭 기준으로 값을 계산하여 수익을 출력하도록 수정 -- [ ] 딜러 기준 총 수익 계산 받아서 출력하는 기능 구현 +- [X] 기존 딜러의 승,무,패 출력 기능 제거 +- [X] 플레이어들의 승, 무, 패(버스트), 블랙잭 기준으로 값을 계산하여 수익을 출력하도록 수정 +- [X] 딜러 기준 총 수익 계산 받아서 출력하는 기능 구현 ## 고민 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index fbaebf4f6d7..964f516889e 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,8 +1,8 @@ package controller; +import domain.dto.GameInitialInfoDto; import domain.game.GameManager; import domain.participant.Player; -import domain.dto.GameInitialInfoDto; import view.InputView; import view.OutputView; @@ -22,7 +22,6 @@ public GameController(GameManager manager, InputView inputView, OutputView outpu public void run() { registerPlayer(); - // TODO: 베팅 기능 추가 시 플레이어 등록 후 베팅 입력 단계가 추가 필요 initGame(); playPlayerTurn(); playDealerTurn(); @@ -31,23 +30,25 @@ public void run() { } private void registerPlayer() { - // TODO: 베팅 기능 추가 시 이름 입력 후 각 플레이어의 베팅 금액도 함께 등록 while (true) { try { List playerNames = inputView.readPlayerName(); validatePlayerNames(playerNames); - - for (String playerName : playerNames) { - manager.addPlayer(playerName, 1000); - } + registerPlayersWithBettingMoney(playerNames); return; - } catch (IllegalArgumentException e) { outputView.printError(e.getMessage()); } } } + private void registerPlayersWithBettingMoney(List playerNames) { + for (String playerName : playerNames) { + int bettingMoney = inputView.readBettingMoney(playerName); + manager.addPlayer(playerName, bettingMoney); + } + } + private void initGame() { manager.startGame(); @@ -68,8 +69,6 @@ private void playSinglePlayerTurn(Player player) { } } - - private boolean wantsToDraw(Player player) { return !inputView.readCommand(player.getName()).equals("n"); } @@ -89,4 +88,4 @@ private void validatePlayerNames(List playerNames) { throw new IllegalArgumentException("플레이어 이름은 비어 있을 수 없습니다."); } } -} +} \ No newline at end of file diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 043fe6eb3a9..84a3f5545c8 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -10,10 +10,13 @@ public class InputView { private static final String COMMAND_REINPUT_MESSAGE = "y 혹은 n만 입력할 수 있습니다."; private static final String COMMAND_INPUT_MESSAGE = "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)"; private static final String PLAYER_NAMES_INPUT_MESSAGE = "게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"; + private static final String BETTING_MONEY_INPUT_MESSAGE = "의 배팅 금액은?"; + private static final String BETTING_MONEY_REINPUT_MESSAGE = "배팅 금액은 0보다 큰 숫자만 입력할 수 있습니다."; private static final List CORRECT_COMMAND_INPUT = List.of("y", "n"); + private final Scanner scanner = new Scanner(System.in); + public List readPlayerName() { - Scanner scanner = new Scanner(System.in); System.out.println(PLAYER_NAMES_INPUT_MESSAGE); String input = scanner.nextLine(); System.out.println(); @@ -21,27 +24,42 @@ public List readPlayerName() { return splitPlayerNameInput(input); } - private static List splitPlayerNameInput(String s) { - if (s == null || s.trim().isEmpty()) { - return new ArrayList<>(); - } + public int readBettingMoney(String playerName) { + while (true) { + try { + System.out.println(playerName + BETTING_MONEY_INPUT_MESSAGE); + int bettingMoney = Integer.parseInt(scanner.nextLine()); - return Arrays.stream(s.split(",")) - .map(String::trim) // split된 항목 앞 뒤 공백 제거 - .filter(c -> !c.isEmpty()) // 콤마가 두번 겹치는 경우 필터링 - .collect(Collectors.toList()); + if (bettingMoney <= 0) { + throw new IllegalArgumentException(); + } + System.out.println(); + return bettingMoney; + } catch (IllegalArgumentException e) { + System.out.println(BETTING_MONEY_REINPUT_MESSAGE); + } + } } public String readCommand(String playerName) { - Scanner sc = new Scanner(System.in); while (true) { System.out.println(playerName + COMMAND_INPUT_MESSAGE); - String input = sc.nextLine(); + String input = scanner.nextLine(); if (CORRECT_COMMAND_INPUT.contains(input)) { return input; } System.out.println(COMMAND_REINPUT_MESSAGE); } } - // TODO: 베팅 기능 추가 시 플레이어별 베팅 금액 입력 메서드 필요 -} + + private static List splitPlayerNameInput(String s) { + if (s == null || s.trim().isEmpty()) { + return new ArrayList<>(); + } + + return Arrays.stream(s.split(",")) + .map(String::trim) + .filter(c -> !c.isEmpty()) + .collect(Collectors.toList()); + } +} \ No newline at end of file From e70b9c5ee9fdfa4400d4f8329fd7337f7b4c20d8 Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Fri, 13 Mar 2026 17:00:05 +0900 Subject: [PATCH 78/88] =?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=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/dto/GameScoreResultDto.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/domain/dto/GameScoreResultDto.java b/src/main/java/domain/dto/GameScoreResultDto.java index 3cc84efa21b..b79e5a3f5b1 100644 --- a/src/main/java/domain/dto/GameScoreResultDto.java +++ b/src/main/java/domain/dto/GameScoreResultDto.java @@ -17,26 +17,14 @@ public String getPlayerName() { return playerName; } - public void setPlayerName(String playerName) { - this.playerName = playerName; - } - public List getHand() { return hand; } - public void setHand(List hand) { - this.hand = hand; - } - public int getResult() { return result; } - public void setResult(int result) { - this.result = result; - } - @Override public String toString() { return "domain.dto.GameScoreResultDto{" + From a9512d102853f923cc43365643031bc774f95c8c Mon Sep 17 00:00:00 2001 From: KIM SEON WOO Date: Fri, 13 Mar 2026 17:47:21 +0900 Subject: [PATCH 79/88] =?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=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20final=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 13 +++++++++++-- src/main/java/domain/Hand.java | 4 ---- src/main/java/domain/card/Deck.java | 2 +- src/main/java/domain/constant/Result.java | 8 ++------ src/main/java/domain/dto/GameInitialInfoDto.java | 6 +++--- src/main/java/domain/dto/GameScoreResultDto.java | 6 +++--- src/main/java/domain/participant/Dealer.java | 1 - src/main/java/domain/participant/Participant.java | 1 - src/main/java/domain/participant/Player.java | 1 - 9 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 964f516889e..4e14b3d01f5 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -63,9 +63,18 @@ private void playPlayerTurn() { } private void playSinglePlayerTurn(Player player) { - while (player.canDraw() && wantsToDraw(player)) { - List playerHand = manager.drawPlayerCard(player); + while (player.canDraw()) { + boolean wantsToDraw = wantsToDraw(player); + + List playerHand = player.getHandToString(); + if(wantsToDraw){ + playerHand = manager.drawPlayerCard(player); + } outputView.printHand(playerHand, player.getName()); + + if(!wantsToDraw) { + break; + } } } diff --git a/src/main/java/domain/Hand.java b/src/main/java/domain/Hand.java index 046aad2727e..5c2849bfa0d 100644 --- a/src/main/java/domain/Hand.java +++ b/src/main/java/domain/Hand.java @@ -18,10 +18,6 @@ public void add(Card card) { hand.add(card); } - public List getHand() { - return List.copyOf(hand); - } - public List toStringList() { return hand.stream() .map(Card::toString) diff --git a/src/main/java/domain/card/Deck.java b/src/main/java/domain/card/Deck.java index eace46ab946..0dde97bdff6 100644 --- a/src/main/java/domain/card/Deck.java +++ b/src/main/java/domain/card/Deck.java @@ -5,7 +5,7 @@ import java.util.List; public class Deck { - List cards = new ArrayList<>(); + final List cards = new ArrayList<>(); public Deck () { init(); diff --git a/src/main/java/domain/constant/Result.java b/src/main/java/domain/constant/Result.java index cc376d0f73f..24829ab4818 100644 --- a/src/main/java/domain/constant/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -7,18 +7,14 @@ public enum Result { BLACKJACK("블랙잭", 1.5), BUST("버스트", -1); - private String name; - private double allocation; + private final String name; + private final double allocation; Result(String name, double allocation) { this.name = name; this.allocation = allocation; } - public String getName() { - return name + " "; - } - public double getAllocation() { return allocation; } diff --git a/src/main/java/domain/dto/GameInitialInfoDto.java b/src/main/java/domain/dto/GameInitialInfoDto.java index ecef57c2caa..7a9b309dca0 100644 --- a/src/main/java/domain/dto/GameInitialInfoDto.java +++ b/src/main/java/domain/dto/GameInitialInfoDto.java @@ -4,9 +4,9 @@ public class GameInitialInfoDto { - private String playerName; - private int initialHandSize; - private List hand; + private final String playerName; + private final int initialHandSize; + private final List hand; public GameInitialInfoDto(String playerName, int initialHandSize, List hand) { this.playerName = playerName; diff --git a/src/main/java/domain/dto/GameScoreResultDto.java b/src/main/java/domain/dto/GameScoreResultDto.java index b79e5a3f5b1..5aca4c5132a 100644 --- a/src/main/java/domain/dto/GameScoreResultDto.java +++ b/src/main/java/domain/dto/GameScoreResultDto.java @@ -3,9 +3,9 @@ import java.util.List; public class GameScoreResultDto { - String playerName; - List hand; - int result; + final String playerName; + final List hand; + final int result; public GameScoreResultDto(String playerName, List hand, int result) { this.playerName = playerName; diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index fe02a5f8c89..fdfbce5c3c6 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -7,7 +7,6 @@ public Dealer() { super("딜러"); } - @Override public boolean canDraw() { return getScore() <= DEALER_DRAW_CONDITION; } diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 8d506248663..62ab5311385 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -40,5 +40,4 @@ public int handSize() { return hand.size(); } - public abstract boolean canDraw(); } \ No newline at end of file diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 9f6e7282431..5c56698ffbc 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -23,7 +23,6 @@ public double calculateProceeds(Result result) { return status.calculateProceeds(result); } - @Override public boolean canDraw() { return !(isBust() || isNaturalBlackJack()); } From cce6a31807d7f922395fda1a828184969f32c4f3 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sat, 14 Mar 2026 23:14:25 +0900 Subject: [PATCH 80/88] =?UTF-8?q?refactor:=20enum,=20dto=20=EB=AF=B8?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B0=8F=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20handSize=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 ++++++++++++++ src/main/java/domain/DtoFactory.java | 2 -- src/main/java/domain/constant/Result.java | 20 ++++++++++--------- .../java/domain/dto/GameInitialInfoDto.java | 12 +++-------- .../java/domain/participant/Participant.java | 5 +---- src/main/java/view/OutputView.java | 3 ++- src/test/java/domain/GameManagerTest.java | 4 ++-- 7 files changed, 34 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 586feb6e285..a29c344e535 100644 --- a/README.md +++ b/README.md @@ -170,3 +170,18 @@ ## 고민 - Players를 copyOf로 해도 얕은 복사라 Player 자체에는 접근이 가능해진다. Player 자체의 변동 가능성은? + + +--- + +## PR 리뷰 후 추가 수정 사항 +- [X] 사용하지 않는 Result enum 필드 제거 +- [X] DTO의 intialHandSize 제거 +- [ ] 동일한 카드가 플레이어에게 드로우되는 문제 해결 +- [ ] Players 인스턴스 생성 및 추가 방식 수정 +- [ ] splitPlayerNameInput 스트림 불변 리스트로 수정(toList) +- [ ] 테스트에서만 쓰이는 handSize 메서드 제거 +- [ ] 기록 내용 README.md 추가 +- [ ] 컨트롤러게 매니저를 상태로 들고있는 구조 개선 +- [ ] Result와 배당 수익금 비율 분리 +- [ ] PlayerStatus에서 수익 계산 하는 부분 분리하기 \ No newline at end of file diff --git a/src/main/java/domain/DtoFactory.java b/src/main/java/domain/DtoFactory.java index 33f5b7f5b51..cf66eb68c88 100644 --- a/src/main/java/domain/DtoFactory.java +++ b/src/main/java/domain/DtoFactory.java @@ -49,7 +49,6 @@ private static void addPlayerScoreResults(List results, Play private static void addDealerInitialInfo(List results, Dealer dealer) { results.add(new GameInitialInfoDto( dealer.getName(), - INITIAL_HAND_SIZE, List.of(dealer.getOpenCard()) )); } @@ -58,7 +57,6 @@ private static void addPlayerInitialInfos(List results, Play for (Player player : players.getNonNaturalBlackJackPlayers()) { results.add(new GameInitialInfoDto( player.getName(), - INITIAL_HAND_SIZE, player.getHandToString() )); } diff --git a/src/main/java/domain/constant/Result.java b/src/main/java/domain/constant/Result.java index 24829ab4818..01b6b3fb1e8 100644 --- a/src/main/java/domain/constant/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -1,20 +1,22 @@ package domain.constant; public enum Result { - WIN("승", 1), - DRAW("무", 0), - LOSE("패", -1), - BLACKJACK("블랙잭", 1.5), - BUST("버스트", -1); + WIN(1), + DRAW(0), + LOSE(-1), + BLACKJACK(1.5), + BUST(-1); - private final String name; - private final double allocation; + private double allocation; - Result(String name, double allocation) { - this.name = name; + Result(double allocation) { this.allocation = allocation; } + public String getName() { + return name + " "; + } + public double getAllocation() { return allocation; } diff --git a/src/main/java/domain/dto/GameInitialInfoDto.java b/src/main/java/domain/dto/GameInitialInfoDto.java index 7a9b309dca0..2397243f1b2 100644 --- a/src/main/java/domain/dto/GameInitialInfoDto.java +++ b/src/main/java/domain/dto/GameInitialInfoDto.java @@ -4,13 +4,11 @@ public class GameInitialInfoDto { - private final String playerName; - private final int initialHandSize; - private final List hand; + private String playerName; + private List hand; - public GameInitialInfoDto(String playerName, int initialHandSize, List hand) { + public GameInitialInfoDto(String playerName, List hand) { this.playerName = playerName; - this.initialHandSize = initialHandSize; this.hand = hand; } @@ -18,10 +16,6 @@ public String getPlayerName() { return playerName; } - public int getInitialHandSize() { - return initialHandSize; - } - public List getHand() { return hand; } diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 62ab5311385..7256ec2f80e 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -36,8 +36,5 @@ public String getName() { return name; } - public int handSize() { - return hand.size(); - } - + public abstract boolean canDraw(); } \ No newline at end of file diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index effe025bb98..9b49cf62ac1 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -15,6 +15,7 @@ public class OutputView { private static final String FINAL_PROCEEDS_MESSAGE = "{0}: {1}"; private static final String DEALER_DRAW_MESSAGE = "딜러는 16이하라 한장의 카드를 더 받았습니다."; private static final String ERROR_PREFIX = "[ERROR] "; + private static final int INITIAL_HAND_SIZE = 2; public void printInitialInfo(List initialInfo) { printHandOutNotice(initialInfo); @@ -67,7 +68,7 @@ private void printHandOutNotice(List initialInfo) { System.out.println(MessageFormat.format( DEAL_MESSAGE, playerNames, - initialInfo.getFirst().getInitialHandSize() + 2 )); } diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index c0f7e468bd0..ea98bd88b25 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -90,11 +90,11 @@ class GameManagerTest { manager.startGame(); Player player = manager.getPlayersToPlay().getFirst(); - int before = player.handSize(); + int before = player.getHandToString().size(); manager.drawPlayerCard(player); - int after = player.handSize(); + int after = player.getHandToString().size(); assertThat(after).isEqualTo(before + 1); } From 2390999283683dde522fd18034e61d4f7e00dad2 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 01:02:36 +0900 Subject: [PATCH 81/88] =?UTF-8?q?fix:=20=EB=8F=99=EC=9D=BC=ED=95=9C=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EA=B0=80=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EC=97=90=EA=B2=8C=20=EB=93=9C=EB=A1=9C=EC=9A=B0?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/domain/game/GameManager.java | 2 +- src/main/java/domain/participant/Players.java | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a29c344e535..dc7e726d1b1 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ ## PR 리뷰 후 추가 수정 사항 - [X] 사용하지 않는 Result enum 필드 제거 - [X] DTO의 intialHandSize 제거 -- [ ] 동일한 카드가 플레이어에게 드로우되는 문제 해결 +- [X] 동일한 카드가 플레이어에게 드로우되는 문제 해결 - [ ] Players 인스턴스 생성 및 추가 방식 수정 - [ ] splitPlayerNameInput 스트림 불변 리스트로 수정(toList) - [ ] 테스트에서만 쓰이는 handSize 메서드 제거 diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index e7cc0d66697..fb3e1f84490 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -25,7 +25,7 @@ public GameManager(Deck deck) { public void startGame() { for (int i = 0; i < FIRST_DRAW_CARDS; i++) { - players.receiveCard(deck.draw()); + players.receiveCard(deck); dealer.receiveCard(deck.draw()); } players.updateNaturalBlackJackStatus(); diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index c0f3a476be4..c733fa24f9c 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,6 +1,7 @@ package domain.participant; import domain.card.Card; +import domain.card.Deck; import java.util.ArrayList; import java.util.List; @@ -11,8 +12,8 @@ public void add(Player player) { players.add(player); } - public void receiveCard(Card card) { - players.forEach(player -> player.receiveCard(card)); + public void receiveCard(Deck deck) { + players.forEach(player -> player.receiveCard(deck.draw())); } public List getPlayers() { From b08ead361ec63080febca03abcdf17635839d3af Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 01:32:39 +0900 Subject: [PATCH 82/88] =?UTF-8?q?refactor:=20Players=EC=9D=98=20add=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EB=B0=A9=EC=8B=9D=20=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=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 --- src/main/java/controller/GameController.java | 5 ++++- src/main/java/domain/game/GameManager.java | 16 +++++++++++----- src/main/java/domain/participant/Players.java | 13 ++++++++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 4e14b3d01f5..5fddaf69554 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -3,6 +3,7 @@ import domain.dto.GameInitialInfoDto; import domain.game.GameManager; import domain.participant.Player; +import java.util.ArrayList; import view.InputView; import view.OutputView; @@ -43,10 +44,12 @@ private void registerPlayer() { } private void registerPlayersWithBettingMoney(List playerNames) { + List bettingMoneyList = new ArrayList<>(); for (String playerName : playerNames) { int bettingMoney = inputView.readBettingMoney(playerName); - manager.addPlayer(playerName, bettingMoney); + bettingMoneyList.add(bettingMoney); } + manager.registerPlayers(playerNames, bettingMoneyList); } private void initGame() { diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index fb3e1f84490..41b916c1924 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -8,24 +8,24 @@ import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; +import java.util.ArrayList; import java.util.List; public class GameManager { private static final int FIRST_DRAW_CARDS = 2; private final Deck deck; - private final Players players; + private Players players; private final Dealer dealer; public GameManager(Deck deck) { this.deck = deck; - this.players = new Players(); this.dealer = new Dealer(); } public void startGame() { for (int i = 0; i < FIRST_DRAW_CARDS; i++) { - players.receiveCard(deck); + players.receiveOneCardFrom(deck); dealer.receiveCard(deck.draw()); } players.updateNaturalBlackJackStatus(); @@ -36,8 +36,14 @@ public List drawPlayerCard(Player player) { return player.getHandToString(); } - public void addPlayer(String name, int bettingMoney) { - players.add(new Player(name, bettingMoney)); + public void registerPlayers(List playerNames, List bettingMoneyList) { + List players = new ArrayList<>(); + + for (int i = 0; i < playerNames.size(); i++) { + players.add(new Player(playerNames.get(i), bettingMoneyList.get(i))); + } + + this.players = Players.of(players); } public List getPlayersToPlay() { diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index c733fa24f9c..fddb07bc681 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,18 +1,21 @@ package domain.participant; -import domain.card.Card; import domain.card.Deck; import java.util.ArrayList; import java.util.List; public class Players { - private final List players = new ArrayList<>(); + private final List players; - public void add(Player player) { - players.add(player); + private Players(final List players) { + this.players = new ArrayList<>(players); } - public void receiveCard(Deck deck) { + public static Players of(List playersList) { + return new Players(playersList); + } + + public void receiveOneCardFrom(Deck deck) { players.forEach(player -> player.receiveCard(deck.draw())); } From b6b65a6b60c353394141a2787d5760bb10db6708 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 01:33:44 +0900 Subject: [PATCH 83/88] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=8A=A4=ED=94=8C=EB=A6=BF=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EB=B6=88=EB=B3=80=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A1=9C=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 --- README.md | 2 +- src/main/java/view/InputView.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc7e726d1b1..2e2289cfa9c 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ - [X] 사용하지 않는 Result enum 필드 제거 - [X] DTO의 intialHandSize 제거 - [X] 동일한 카드가 플레이어에게 드로우되는 문제 해결 -- [ ] Players 인스턴스 생성 및 추가 방식 수정 +- [X] Players 인스턴스 생성 및 추가 방식 수정 - [ ] splitPlayerNameInput 스트림 불변 리스트로 수정(toList) - [ ] 테스트에서만 쓰이는 handSize 메서드 제거 - [ ] 기록 내용 README.md 추가 diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 84a3f5545c8..01894d37b07 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -60,6 +60,6 @@ private static List splitPlayerNameInput(String s) { return Arrays.stream(s.split(",")) .map(String::trim) .filter(c -> !c.isEmpty()) - .collect(Collectors.toList()); + .toList(); } } \ No newline at end of file From 0c16c99b8e6d05f27b3933699c0faab06d957f07 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 17:48:53 +0900 Subject: [PATCH 84/88] =?UTF-8?q?refactor:=20dto=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EB=8F=99=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=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/domain/DtoFactory.java | 4 ++-- src/main/java/domain/game/GameManager.java | 6 +++--- src/main/java/{domain => }/dto/GameResultDto.java | 2 +- src/main/java/view/OutputView.java | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) rename src/main/java/{domain => }/dto/GameResultDto.java (97%) diff --git a/src/main/java/domain/DtoFactory.java b/src/main/java/domain/DtoFactory.java index cf66eb68c88..9094f3ec9d7 100644 --- a/src/main/java/domain/DtoFactory.java +++ b/src/main/java/domain/DtoFactory.java @@ -1,7 +1,7 @@ package domain; -import domain.dto.GameInitialInfoDto; -import domain.dto.GameScoreResultDto; +import dto.GameInitialInfoDto; +import dto.GameScoreResultDto; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index 41b916c1924..85200ff3064 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -2,9 +2,9 @@ import domain.DtoFactory; import domain.card.Deck; -import domain.dto.GameResultDto; -import domain.dto.GameInitialInfoDto; -import domain.dto.GameScoreResultDto; +import dto.GameResultDto; +import dto.GameInitialInfoDto; +import dto.GameScoreResultDto; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; diff --git a/src/main/java/domain/dto/GameResultDto.java b/src/main/java/dto/GameResultDto.java similarity index 97% rename from src/main/java/domain/dto/GameResultDto.java rename to src/main/java/dto/GameResultDto.java index ac97aefd2d4..ac5bc03e30d 100644 --- a/src/main/java/domain/dto/GameResultDto.java +++ b/src/main/java/dto/GameResultDto.java @@ -1,4 +1,4 @@ -package domain.dto; +package dto; import domain.constant.Result; diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 9b49cf62ac1..dd7cb0dadbb 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,8 +1,8 @@ package view; -import domain.dto.GameResultDto; -import domain.dto.GameInitialInfoDto; -import domain.dto.GameScoreResultDto; +import dto.GameResultDto; +import dto.GameInitialInfoDto; +import dto.GameScoreResultDto; import java.text.MessageFormat; import java.util.List; From ffce44ce42b80eac73ea31ca735fc049039fe313 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 17:49:54 +0900 Subject: [PATCH 85/88] =?UTF-8?q?refactor:=20=EC=8A=B9=ED=8C=A8=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=20=EB=B6=84=EA=B8=B0=20Result=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99,=20=EC=88=98=EC=9D=B5=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/constant/Result.java | 33 ++++++++++--------- .../java/domain/game/GameResultJudge.java | 27 ++------------- .../java/domain/game/ProceedsCalculator.java | 27 +++++++++++++++ 3 files changed, 46 insertions(+), 41 deletions(-) create mode 100644 src/main/java/domain/game/ProceedsCalculator.java diff --git a/src/main/java/domain/constant/Result.java b/src/main/java/domain/constant/Result.java index 01b6b3fb1e8..e71c79319f1 100644 --- a/src/main/java/domain/constant/Result.java +++ b/src/main/java/domain/constant/Result.java @@ -1,23 +1,24 @@ package domain.constant; -public enum Result { - WIN(1), - DRAW(0), - LOSE(-1), - BLACKJACK(1.5), - BUST(-1); +import domain.participant.Dealer; +import domain.participant.Player; - private double allocation; +public enum Result { + BUST, + BLACKJACK, + WIN, + LOSE, + DRAW; - Result(double allocation) { - this.allocation = allocation; - } + public static Result from(Player player, Dealer dealer) { + int playerScore = player.getScore(); + int dealerScore = dealer.getScore(); - public String getName() { - return name + " "; - } + if (player.isBust()) return BUST; + if (player.isNaturalBlackJack()) return BLACKJACK; + if (playerScore > dealerScore) return WIN; + if (playerScore < dealerScore) return LOSE; - public double getAllocation() { - return allocation; + return DRAW; } -} +} \ No newline at end of file diff --git a/src/main/java/domain/game/GameResultJudge.java b/src/main/java/domain/game/GameResultJudge.java index f977d6f9aa9..986d07cff36 100644 --- a/src/main/java/domain/game/GameResultJudge.java +++ b/src/main/java/domain/game/GameResultJudge.java @@ -1,7 +1,7 @@ package domain.game; import domain.constant.Result; -import domain.dto.GameResultDto; +import dto.GameResultDto; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; @@ -30,34 +30,11 @@ private static void addPlayerResults(List results, Dealer dealer, } private static GameResultDto judgePlayer(Player player, Dealer dealer) { - Result result = calculateResult(player, dealer); + Result result = Result.from(player, dealer); double proceeds = player.calculateProceeds(result); return new GameResultDto(player.getName(), result, proceeds); } - private static Result calculateResult(Player player, Dealer dealer) { - int playerScore = player.getScore(); - int dealerScore = dealer.getScore(); - - if (player.isBust()) { - return Result.BUST; - } - - if (player.isNaturalBlackJack()) { - return Result.BLACKJACK; - } - - if (playerScore > dealerScore) { - return Result.WIN; - } - - if (playerScore < dealerScore) { - return Result.LOSE; - } - - return Result.DRAW; - } - private static double calculateDealerProceeds(List results) { return -results.stream() .mapToDouble(GameResultDto::getProceeds) diff --git a/src/main/java/domain/game/ProceedsCalculator.java b/src/main/java/domain/game/ProceedsCalculator.java new file mode 100644 index 00000000000..5a50d9ed479 --- /dev/null +++ b/src/main/java/domain/game/ProceedsCalculator.java @@ -0,0 +1,27 @@ +package domain.game; + +import domain.constant.Result; + +public class ProceedsCalculator { + + private static final double BLACKJACK_PROCEEDS_RATE = 1.5; + private static final double WIN_PROCEEDS_RATE = 1.0; + private static final double DRAW_PROCEEDS_RATE = 0.0; + private static final double LOSE_PROCEEDS_RATE = -1.0; + + private ProceedsCalculator() { + } + + public static double calculate(int bettingMoney, Result result) { + if (result == Result.BLACKJACK) { + return bettingMoney * BLACKJACK_PROCEEDS_RATE; + } + if (result == Result.WIN) { + return bettingMoney * WIN_PROCEEDS_RATE; + } + if (result == Result.DRAW) { + return bettingMoney * DRAW_PROCEEDS_RATE; + } + return bettingMoney * LOSE_PROCEEDS_RATE; + } +} \ No newline at end of file From 0bc8aeea6db23ee5e080b96eb09542764370fa06 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 17:50:30 +0900 Subject: [PATCH 86/88] =?UTF-8?q?refactor:=20dto=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=97=90=20=EC=9D=98=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 128 +++++++++++++++++- src/main/java/controller/GameController.java | 2 +- src/main/java/domain/PlayerStatus.java | 5 +- .../{domain => }/dto/GameInitialInfoDto.java | 2 +- .../{domain => }/dto/GameScoreResultDto.java | 2 +- src/test/java/domain/DtoFactoryTest.java | 20 +-- src/test/java/domain/GameManagerTest.java | 58 +++++--- src/test/java/domain/GameResultJudgeTest.java | 21 +-- src/test/java/domain/PlayersTest.java | 15 +- 9 files changed, 190 insertions(+), 63 deletions(-) rename src/main/java/{domain => }/dto/GameInitialInfoDto.java (95%) rename src/main/java/{domain => }/dto/GameScoreResultDto.java (97%) diff --git a/README.md b/README.md index 2e2289cfa9c..461f755234e 100644 --- a/README.md +++ b/README.md @@ -179,9 +179,125 @@ - [X] DTO의 intialHandSize 제거 - [X] 동일한 카드가 플레이어에게 드로우되는 문제 해결 - [X] Players 인스턴스 생성 및 추가 방식 수정 -- [ ] splitPlayerNameInput 스트림 불변 리스트로 수정(toList) -- [ ] 테스트에서만 쓰이는 handSize 메서드 제거 -- [ ] 기록 내용 README.md 추가 -- [ ] 컨트롤러게 매니저를 상태로 들고있는 구조 개선 -- [ ] Result와 배당 수익금 비율 분리 -- [ ] PlayerStatus에서 수익 계산 하는 부분 분리하기 \ No newline at end of file +- [X] splitPlayerNameInput 스트림 불변 리스트로 수정(toList) +- [X] 테스트에서만 쓰이는 handSize 메서드 제거 +- [X] GameResultJudge의 결과 분기 책임을 enum에게 넘기기 +~~- [ ] 컨트롤러가 매니저를 상태로 들고있는 구조 개선~~ +- [X] Result와 배당 수익금 비율 분리 +- [X] PlayerStatus에서 수익 계산 하는 부분 분리하기 +- [X] 기록 내용 README.md 추가 +- [ ] updateNaturalBlackJack 상태 업데이트가 밖에서 호출되는 문제 수정 + + + + +## 📝 미션 기록 + +### 기능 추가로 인해 수정한 위치 + +이번 미션에서는 **베팅 기능을 추가한다고 가정하고 변경 범위를 분석**하였다. + +베팅 기능은 단순한 내부 로직이 아니라 +**입력 → 상태 저장 → 게임 진행 → 결과 계산 → 출력** 전체 흐름에 영향을 주는 기능이었다. + +그 결과 다음 위치에서 수정이 필요하다고 판단하였다. + +| 수정 위치 | 이유 | +|---|---| +| Player | 플레이어가 베팅 금액을 상태로 가져야 한다 | +| Players | 플레이어 집합에서 베팅 정보와 결과 집계가 필요 | +| GameManager | 게임 결과 계산 시 베팅 정산 로직 추가 | +| GameController | 게임 시작 전에 베팅 금액 입력 필요 | +| InputView | 플레이어별 베팅 금액 입력 | +| OutputView | 베팅 결과 및 수익 출력 | +| GameFinalResultDto | 결과 DTO에 수익 정보 추가 | +| Result | 승패에 따른 정산 기준 추가 | + +**총 수정 위치: 8개** + +이를 통해 **하나의 기능이 여러 계층을 따라 이동하면 수정 범위가 넓어진다**는 것을 확인했다. + +--- + +### 사이클 1 대비 수정 범위 + +사이클1에서는 게임 로직 대부분이 `GameManager`에 집중되어 있었다. + +``` +GameManager + ├ 카드 분배 + ├ 점수 계산 + ├ 게임 진행 + └ 승패 계산 +``` + +이 구조에서는 기능이 추가될 때 **GameManager에 수정이 집중되는 문제**가 있었다. + +이번 사이클에서는 다음과 같이 책임을 분리하였다. + +- `Hand` → 카드 점수 계산 +- `Players` → 플레이어 집합 관리 +- `GameResultJudge` → 승패 판정 +- `PlayerStatus` → 플레이어 상태 관리 + +그 결과 **기능 추가 시 수정 범위가 특정 객체에 집중되지 않고 분산되도록 개선되었다.** + +--- + +### 규칙 적용으로 변경한 코드 + +팀에서 다음과 같은 규칙을 정하였다. + +- 책임 분리 기준 + - **(If-Then)** 만약 특정 요구사항이 변경되었을 때, 그와 무관한 코드들까지 한 클래스 안에서 함께 수정하거나 테스트해야 한다면 → 변경의 원인이 하나가 되도록 책임을 분리하여 응집도를 높인다. + - **(기준)** 변경의 이유가 하나 이상일 때 분리한다. +- 변경 범위 제한 규칙 + - **(If-Then)** 만약 기능 추가 시 3곳 이상의 파일 수정이 필요하면 → 공통 로직을 추출하거나 책임을 재분배한다 + - **(기준)** 책임을 적절히 캡슐화하지 못해, 단일 변경의 파급 효과가 여러 객체(3곳 이상)로 흩어질 때 변경 범위를 제한한다. +- 테스트와 설계의 관계 규칙 + - **(If-Then)** 만약 비교와 같은 연산을 위해 해당 데이터를 가진 객체의 데이터를 직접 꺼내와서 사용하고 있다면 → 데이터를 가진 객체에게 직접 물어보도록(Tell, Don't Ask) 수정하여 변경 여파를 내부에 가둔다. + - **(기준)** 외부에서 객체의 데이터를 직접 꺼내어 연산이나 판단을 수행하는 경우, 데이터를 가진 객체에게 직접 물어보도록 변경한다. + +모든 규칙을 항상 의식하면서 작업하진 못하였지만, 대표적으로 아래의 규칙을 가장 의식하면서 작업했다. + +> **Tell, Don't Ask** +> +> 객체의 데이터를 꺼내와 외부에서 판단하지 말고 +> 해당 객체에게 직접 물어보도록 한다. + +이 규칙을 적용하면서, 기존에 도메인 객체의 필드 값을 외부에 호출하여 사용하던 방식에서 +도메인 객체 스스로 행동하여 상태 값을 활용한 책임을 지도록 하였고 외부에서는 내부 구현을 몰라도 +요청만으로 원하는 값을 얻을 수 있도록 하였다. + +이를 통해 응집도가 감소하고, 객체 간의 협력 관계를 기존보다 개선된 형태로 구축할 수 있었다고 생각한다. + +--- + +### 테스트가 설계를 도운 순간 + +딜러의 최종 수익을 계산하는 테스트를 작성하면서 +딜러 수익을 별도의 규칙으로 다시 계산하기보다 +**플레이어 수익의 합에 음수를 취한 값으로 정의하는 구조**가 더 자연스럽다는 점을 확인했다. + +```java +assertThat(firstPlayerResult.getProceeds()).isEqualTo(1000); +assertThat(secondPlayerResult.getProceeds()).isEqualTo(-2000); +assertThat(dealerResult.getProceeds()).isEqualTo(1000); +``` +이 테스트를 통해 +딜러와 플레이어의 정산 로직을 각각 따로 두기보다 +플레이어 결과를 먼저 계산한 뒤 딜러 결과를 합산으로 구하는 것이 +규칙 중복을 줄이고 설계를 더 단순하게 만든다는 점을 알 수 있었다. + +--- + +### 이번 미션에서 얻은 인사이트 + +기능 추가 자체보다 더 크게 느낀 점은 다음이다. + +- 역할이 명확한 객체 (`Card`, `Hand`, `Deck`) 는 변화에 강하다. +- 여러 책임이 섞인 객체 (`GameManager`) 는 변화에 약하다. +- 테스트를 작성하면서 설계에서 불안정한 지점이 어디인지 파악할 수 있다. + +이번 미션을 통해 구조에 대한 설계가 잘못 되었는지 알아챌 수 있는 신호에는 무엇이 있고, +어떤 설계가 유연하면서도 안정적인 코드를 작성할 수 있는지 알 수 있었다. diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 5fddaf69554..290449bc838 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,6 +1,6 @@ package controller; -import domain.dto.GameInitialInfoDto; +import dto.GameInitialInfoDto; import domain.game.GameManager; import domain.participant.Player; import java.util.ArrayList; diff --git a/src/main/java/domain/PlayerStatus.java b/src/main/java/domain/PlayerStatus.java index 83a470e7146..0b950a74535 100644 --- a/src/main/java/domain/PlayerStatus.java +++ b/src/main/java/domain/PlayerStatus.java @@ -1,6 +1,7 @@ package domain; import domain.constant.Result; +import domain.game.ProceedsCalculator; public class PlayerStatus { private final int bettingMoney; @@ -19,6 +20,6 @@ public boolean isNaturalBlackJack() { } public double calculateProceeds(Result result) { - return bettingMoney * result.getAllocation(); + return ProceedsCalculator.calculate(bettingMoney, result); } -} +} \ No newline at end of file diff --git a/src/main/java/domain/dto/GameInitialInfoDto.java b/src/main/java/dto/GameInitialInfoDto.java similarity index 95% rename from src/main/java/domain/dto/GameInitialInfoDto.java rename to src/main/java/dto/GameInitialInfoDto.java index 2397243f1b2..5877b90425a 100644 --- a/src/main/java/domain/dto/GameInitialInfoDto.java +++ b/src/main/java/dto/GameInitialInfoDto.java @@ -1,4 +1,4 @@ -package domain.dto; +package dto; import java.util.List; diff --git a/src/main/java/domain/dto/GameScoreResultDto.java b/src/main/java/dto/GameScoreResultDto.java similarity index 97% rename from src/main/java/domain/dto/GameScoreResultDto.java rename to src/main/java/dto/GameScoreResultDto.java index 5aca4c5132a..460f742396e 100644 --- a/src/main/java/domain/dto/GameScoreResultDto.java +++ b/src/main/java/dto/GameScoreResultDto.java @@ -1,4 +1,4 @@ -package domain.dto; +package dto; import java.util.List; diff --git a/src/test/java/domain/DtoFactoryTest.java b/src/test/java/domain/DtoFactoryTest.java index a15248d155c..019e91fe0f6 100644 --- a/src/test/java/domain/DtoFactoryTest.java +++ b/src/test/java/domain/DtoFactoryTest.java @@ -5,8 +5,8 @@ import domain.card.Card; import domain.card.Rank; import domain.card.Suit; -import domain.dto.GameInitialInfoDto; -import domain.dto.GameScoreResultDto; +import dto.GameInitialInfoDto; +import dto.GameScoreResultDto; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; @@ -21,11 +21,11 @@ public class DtoFactoryTest { dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); - Players players = new Players(); Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); - players.add(player); + + Players players = Players.of(List.of(player)); List result = DtoFactory.toInitialInfo(dealer, players); @@ -40,11 +40,11 @@ public class DtoFactoryTest { dealer.receiveCard(new Card(Rank.ACE, Suit.SPADE)); dealer.receiveCard(new Card(Rank.KING, Suit.HEART)); - Players players = new Players(); Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.TWO, Suit.CLUB)); player.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); - players.add(player); + + Players players = Players.of(List.of(player)); List result = DtoFactory.toInitialInfo(dealer, players); @@ -53,16 +53,16 @@ public class DtoFactoryTest { } @Test - void 점수결과를_생성하면_딜러와_플레이어의_이름_승패_정보를_포함한다() { + void 점수결과를_생성하면_딜러와_플레이어의_이름과_점수_정보를_포함한다() { Dealer dealer = new Dealer(); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); dealer.receiveCard(new Card(Rank.SEVEN, Suit.HEART)); - Players players = new Players(); Player player = new Player("pobi", 1000); player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); - players.add(player); + + Players players = Players.of(List.of(player)); List result = DtoFactory.toScoreResults(dealer, players); @@ -75,4 +75,4 @@ public class DtoFactoryTest { assertThat(result.get(1).getHand()).hasSize(2); assertThat(result.get(1).getResult()).isEqualTo(17); } -} +} \ No newline at end of file diff --git a/src/test/java/domain/GameManagerTest.java b/src/test/java/domain/GameManagerTest.java index ea98bd88b25..ef5c2fd6cac 100644 --- a/src/test/java/domain/GameManagerTest.java +++ b/src/test/java/domain/GameManagerTest.java @@ -1,9 +1,9 @@ package domain; import domain.card.Deck; -import domain.dto.GameResultDto; -import domain.dto.GameInitialInfoDto; -import domain.dto.GameScoreResultDto; +import dto.GameInitialInfoDto; +import dto.GameResultDto; +import dto.GameScoreResultDto; import domain.game.GameManager; import domain.participant.Player; import org.junit.jupiter.api.Test; @@ -18,8 +18,10 @@ class GameManagerTest { void 등록된_플레이어와_딜러_순서대로_카드를_돌린다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi", 1000); - manager.addPlayer("cary", 1000); + manager.registerPlayers( + List.of("pobi", "cary"), + List.of(1000, 1000) + ); manager.startGame(); List scoreResults = manager.getScoreResults(); @@ -36,7 +38,10 @@ class GameManagerTest { void 딜러의_카드는_한_장만_공개한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi",1000); + manager.registerPlayers( + List.of("pobi"), + List.of(1000) + ); manager.startGame(); List initialInfo = manager.getInitialInfo(); @@ -48,7 +53,10 @@ class GameManagerTest { void 플레이어의_카드는_두_장_공개한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi", 1000); + manager.registerPlayers( + List.of("pobi"), + List.of(1000) + ); manager.startGame(); List initialInfo = manager.getInitialInfo(); @@ -59,33 +67,40 @@ class GameManagerTest { @Test void 플레이어를_한명_등록한다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi",1000); + + manager.registerPlayers( + List.of("pobi"), + List.of(1000) + ); List result = manager.getPlayersToPlay(); - assertThat(result.size()).isEqualTo(1); + assertThat(result).hasSize(1); assertThat(result.getFirst().getName()).isEqualTo("pobi"); } @Test void 플레이어를_세명_등록한다() { GameManager manager = new GameManager(new Deck()); - List playerNames = List.of("pobi", "cary", "rudy"); - for (String playerName : playerNames) { - manager.addPlayer(playerName, 1000); - } + manager.registerPlayers( + List.of("pobi", "cary", "rudy"), + List.of(1000, 1000, 1000) + ); List result = manager.getPlayersToPlay(); - assertThat(result.size()).isEqualTo(3); + assertThat(result).hasSize(3); } - @Test void 플레이어가_카드를_한장_더_받는다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi", 1000); + + manager.registerPlayers( + List.of("pobi"), + List.of(1000) + ); manager.startGame(); Player player = manager.getPlayersToPlay().getFirst(); @@ -111,8 +126,11 @@ class GameManagerTest { @Test void 게임_최종_결과에는_딜러와_모든_플레이어_결과가_포함된다() { GameManager manager = new GameManager(new Deck()); - manager.addPlayer("pobi", 1000); - manager.addPlayer("cary", 1000); + + manager.registerPlayers( + List.of("pobi", "cary"), + List.of(1000, 1000) + ); List result = manager.getFinalResult(); @@ -126,6 +144,7 @@ class GameManagerTest { void 플레이어가_없는_경우_초기정보에는_딜러만_포함된다() { GameManager manager = new GameManager(new Deck()); + manager.registerPlayers(List.of(), List.of()); manager.startGame(); List result = manager.getInitialInfo(); @@ -138,6 +157,7 @@ class GameManagerTest { void 플레이어가_없는_경우_점수결과에는_딜러만_포함된다() { GameManager manager = new GameManager(new Deck()); + manager.registerPlayers(List.of(), List.of()); manager.startGame(); List result = manager.getScoreResults(); @@ -150,6 +170,7 @@ class GameManagerTest { void 플레이어가_없는_경우_최종결과에는_딜러만_포함된다() { GameManager manager = new GameManager(new Deck()); + manager.registerPlayers(List.of(), List.of()); manager.startGame(); List result = manager.getFinalResult(); @@ -157,5 +178,4 @@ class GameManagerTest { assertThat(result).hasSize(1); assertThat(result.getFirst().getPlayerName()).isEqualTo("딜러"); } - } \ No newline at end of file diff --git a/src/test/java/domain/GameResultJudgeTest.java b/src/test/java/domain/GameResultJudgeTest.java index 7fa8dc277e4..066365afecc 100644 --- a/src/test/java/domain/GameResultJudgeTest.java +++ b/src/test/java/domain/GameResultJudgeTest.java @@ -4,7 +4,7 @@ import domain.card.Rank; import domain.card.Suit; import domain.constant.Result; -import domain.dto.GameResultDto; +import dto.GameResultDto; import domain.game.GameResultJudge; import domain.participant.Dealer; import domain.participant.Player; @@ -20,7 +20,6 @@ public class GameResultJudgeTest { @Test void 플레이어가_bust면_BUST와_음수_수익을_가진다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player player = new Player("pobi", 1000); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); @@ -30,7 +29,7 @@ public class GameResultJudgeTest { player.receiveCard(new Card(Rank.QUEEN, Suit.DIAMOND)); player.receiveCard(new Card(Rank.TWO, Suit.HEART)); // 22 bust - players.add(player); + Players players = Players.of(List.of(player)); List results = GameResultJudge.judge(dealer, players); @@ -48,7 +47,6 @@ public class GameResultJudgeTest { @Test void 플레이어_점수가_더_높으면_WIN이다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player player = new Player("pobi", 1000); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); @@ -57,7 +55,7 @@ public class GameResultJudgeTest { player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); // 18 - players.add(player); + Players players = Players.of(List.of(player)); List results = GameResultJudge.judge(dealer, players); GameResultDto playerResult = results.get(1); @@ -69,7 +67,6 @@ public class GameResultJudgeTest { @Test void 플레이어_점수가_더_낮으면_LOSE다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player player = new Player("pobi", 1000); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); @@ -78,7 +75,7 @@ public class GameResultJudgeTest { player.receiveCard(new Card(Rank.TEN, Suit.CLUB)); player.receiveCard(new Card(Rank.EIGHT, Suit.DIAMOND)); // 18 - players.add(player); + Players players = Players.of(List.of(player)); List results = GameResultJudge.judge(dealer, players); GameResultDto playerResult = results.get(1); @@ -90,7 +87,6 @@ public class GameResultJudgeTest { @Test void 플레이어와_딜러의_점수가_같으면_DRAW다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player player = new Player("pobi", 1000); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); @@ -99,7 +95,7 @@ public class GameResultJudgeTest { player.receiveCard(new Card(Rank.NINE, Suit.CLUB)); player.receiveCard(new Card(Rank.NINE, Suit.DIAMOND)); // 18 - players.add(player); + Players players = Players.of(List.of(player)); List results = GameResultJudge.judge(dealer, players); GameResultDto playerResult = results.get(1); @@ -111,7 +107,6 @@ public class GameResultJudgeTest { @Test void naturalBlackJack인_플레이어는_BLACKJACK과_블랙잭_배당을_가진다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player player = new Player("pobi", 10000); dealer.receiveCard(new Card(Rank.TEN, Suit.SPADE)); @@ -121,7 +116,7 @@ public class GameResultJudgeTest { player.receiveCard(new Card(Rank.KING, Suit.DIAMOND)); // natural blackjack player.markNaturalBlackJack(); - players.add(player); + Players players = Players.of(List.of(player)); List results = GameResultJudge.judge(dealer, players); GameResultDto playerResult = results.get(1); @@ -133,7 +128,6 @@ public class GameResultJudgeTest { @Test void 딜러의_총수익은_플레이어_수익의_합에_음수를_취한_값이다() { Dealer dealer = new Dealer(); - Players players = new Players(); Player winPlayer = new Player("pobi", 1000); Player losePlayer = new Player("jason", 2000); @@ -147,8 +141,7 @@ public class GameResultJudgeTest { losePlayer.receiveCard(new Card(Rank.TEN, Suit.HEART)); losePlayer.receiveCard(new Card(Rank.SEVEN, Suit.CLUB)); // 17 -> LOSE - players.add(winPlayer); - players.add(losePlayer); + Players players = Players.of(List.of(winPlayer, losePlayer)); List results = GameResultJudge.judge(dealer, players); diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index af836645ae3..e4a5cced04f 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -15,9 +15,10 @@ public class PlayersTest { @Test void 플레이어를_등록한다() { - Players players = new Players(); - players.add(new Player("pobi", 1000)); - players.add(new Player("abc", 1000)); + Players players = Players.of(List.of( + new Player("pobi", 1000), + new Player("abc", 1000) + )); List records = players.getPlayers(); @@ -28,7 +29,6 @@ public class PlayersTest { @Test void 초기_블랙잭인_플레이어는_naturalBlackJack_상태가_true가_된다() { - Players players = new Players(); Player blackJackPlayer = new Player("pobi", 1000); Player normalPlayer = new Player("jason", 1000); @@ -38,8 +38,7 @@ public class PlayersTest { normalPlayer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); normalPlayer.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); - players.add(blackJackPlayer); - players.add(normalPlayer); + Players players = Players.of(List.of(blackJackPlayer, normalPlayer)); players.updateNaturalBlackJackStatus(); @@ -49,7 +48,6 @@ public class PlayersTest { @Test void 초기_블랙잭이_아닌_플레이어들만_반환한다() { - Players players = new Players(); Player blackJackPlayer = new Player("pobi", 1000); Player normalPlayer = new Player("jason", 1000); @@ -59,8 +57,7 @@ public class PlayersTest { normalPlayer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); normalPlayer.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); - players.add(blackJackPlayer); - players.add(normalPlayer); + Players players = Players.of(List.of(blackJackPlayer, normalPlayer)); players.updateNaturalBlackJackStatus(); From d3d2443ba67cb4e3c4b223976b37e83399b396ba Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 17:58:58 +0900 Subject: [PATCH 87/88] =?UTF-8?q?refactor:=20updateNaturalBlackJack=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=EC=9D=84=20Player=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/game/GameManager.java | 1 - .../java/domain/participant/Participant.java | 4 ++++ src/main/java/domain/participant/Player.java | 17 +++++++++++++++++ src/main/java/domain/participant/Players.java | 6 ------ src/test/java/domain/PlayersTest.java | 6 ------ 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/main/java/domain/game/GameManager.java b/src/main/java/domain/game/GameManager.java index 85200ff3064..ec890f18518 100644 --- a/src/main/java/domain/game/GameManager.java +++ b/src/main/java/domain/game/GameManager.java @@ -28,7 +28,6 @@ public void startGame() { players.receiveOneCardFrom(deck); dealer.receiveCard(deck.draw()); } - players.updateNaturalBlackJackStatus(); } public List drawPlayerCard(Player player) { diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 7256ec2f80e..a0a538d39a6 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -12,6 +12,10 @@ protected Participant(String name) { this.name = name; } + protected boolean hasTwoCards() { + return hand.size() == 2; + } + public boolean isBust() { return hand.isBust(); } diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 5c56698ffbc..6f94691adf4 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -1,6 +1,7 @@ package domain.participant; import domain.PlayerStatus; +import domain.card.Card; import domain.constant.Result; public class Player extends Participant { @@ -11,6 +12,22 @@ public Player(String name, int bettingMoney) { this.status = new PlayerStatus(bettingMoney); } + @Override + public void receiveCard(Card card) { + super.receiveCard(card); + updateNaturalBlackJackStatus(); + } + + private void updateNaturalBlackJackStatus() { + if (isInitialBlackJack()) { + status.markNaturalBlackJack(); + } + } + + private boolean isInitialBlackJack() { + return hasTwoCards() && isBlackJack(); + } + public boolean isNaturalBlackJack() { return status.isNaturalBlackJack(); } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index fddb07bc681..7dd9a8d0008 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -28,10 +28,4 @@ public List getNonNaturalBlackJackPlayers() { .filter(player -> !player.isNaturalBlackJack()) .toList(); } - - public void updateNaturalBlackJackStatus() { - players.stream() - .filter(Player::isBlackJack) - .forEach(Player::markNaturalBlackJack); - } } diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index e4a5cced04f..77c7de3fdf9 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -38,10 +38,6 @@ public class PlayersTest { normalPlayer.receiveCard(new Card(Rank.TWO, Suit.CLUB)); normalPlayer.receiveCard(new Card(Rank.THREE, Suit.DIAMOND)); - Players players = Players.of(List.of(blackJackPlayer, normalPlayer)); - - players.updateNaturalBlackJackStatus(); - assertThat(blackJackPlayer.isNaturalBlackJack()).isTrue(); assertThat(normalPlayer.isNaturalBlackJack()).isFalse(); } @@ -59,8 +55,6 @@ public class PlayersTest { Players players = Players.of(List.of(blackJackPlayer, normalPlayer)); - players.updateNaturalBlackJackStatus(); - List result = players.getNonNaturalBlackJackPlayers(); assertThat(result).hasSize(1); From 8f67685cc429560cb4cd0ea1dde3f4a73782cf15 Mon Sep 17 00:00:00 2001 From: SeonWu Kim Date: Sun, 15 Mar 2026 17:59:20 +0900 Subject: [PATCH 88/88] =?UTF-8?q?docs:=20README.md=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 461f755234e..2bb212491fb 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ - [X] Result와 배당 수익금 비율 분리 - [X] PlayerStatus에서 수익 계산 하는 부분 분리하기 - [X] 기록 내용 README.md 추가 -- [ ] updateNaturalBlackJack 상태 업데이트가 밖에서 호출되는 문제 수정 +- [X] updateNaturalBlackJack 상태 업데이트가 밖에서 호출되는 문제 수정