From ab35e08d80742a10893cfb3424204068f657f77a Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 25 May 2024 12:47:55 +0900 Subject: [PATCH 01/15] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20README=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..16e3a77bf29 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +## 기능 요구사항 +* 사용자에게 블랙잭 게임에 참여할 플레이어를 입력받는다. + * 블랙잭 게임의 참가자는 딜러 + 플레이어이다. +* 게임 처음에는 게임의 참가자들은 카드덱에서 무작위로 카드 2장을 받는다. + * 카드덱은 하트, 클로버, 스페이드, 다이아몬드 4개의 모양이 있고 각각 ACE, 2~9, KING, QUEEN, JACK이 있다. + * ACE는 1또는 11로 계산할 수 있고 (합계가 21이 넘으면 1로 계산, 아니면 11), KING, QUEEN, JACK은 각각 10으로 계산한다. +* 플레이어는 처음에 받은 두 장의 카드의 숫자 합계가 21을 넘지 않으면 얼마든지 카드를 더 받을 수 있다. +* 딜러는 처음에 받은 카드 2장의 합계가 16이하라면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다. +* 21이 초과된 플레이어는 무조건 패배한다. +* 21에 가장 가까운 플레이어가 승리한다. +* 게임을 완료한 후 각 플레이어별로 승패를 출력한다. \ No newline at end of file From 75f23cb59ded15b163796a75a600a76d59faa65f Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 25 May 2024 15:29:32 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20Card=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 5 +++++ src/main/java/card/Card.java | 15 +++++++++++++++ src/main/java/card/CardDeck.java | 23 +++++++++++++++++++++++ src/main/java/card/CardEmblem.java | 18 ++++++++++++++++++ src/main/java/card/CardNumber.java | 26 ++++++++++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/card/Card.java create mode 100644 src/main/java/card/CardDeck.java create mode 100644 src/main/java/card/CardEmblem.java create mode 100644 src/main/java/card/CardNumber.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000000..44ac86ae235 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,5 @@ +public class Application { + public static void main(String[] args) { + System.out.println("Hello, BlackJack"); + } +} diff --git a/src/main/java/card/Card.java b/src/main/java/card/Card.java new file mode 100644 index 00000000000..93d9c4a9c13 --- /dev/null +++ b/src/main/java/card/Card.java @@ -0,0 +1,15 @@ +package card; + +public class Card { + private final CardEmblem emblem; + private final CardNumber number; + + private Card(final CardEmblem emblem, final CardNumber number) { + this.emblem = emblem; + this.number = number; + } + + public static Card of(final CardEmblem emblem, final CardNumber number) { + return new Card(emblem, number); + } +} diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/CardDeck.java new file mode 100644 index 00000000000..0a0b7346798 --- /dev/null +++ b/src/main/java/card/CardDeck.java @@ -0,0 +1,23 @@ +package card; + +import java.util.ArrayList; +import java.util.List; + +public class CardDeck { + private static final List CARD_EMBLEMS = List.of(CardEmblem.CLOVER, CardEmblem.HEART, CardEmblem.SPADE, CardEmblem.DIAMOND); + private static final List CARD_NUMBER = List.of(CardNumber.ACE, CardNumber.TWO, CardNumber.THREE, CardNumber.FOUR, CardNumber.FIVE, CardNumber.SIX, CardNumber.SEVEN, CardNumber.EIGHT, CardNumber.NINE, CardNumber.JACK, CardNumber.QUEEN, CardNumber.KING); + + private final List cards = new ArrayList<>(); + + public CardDeck() { + for (CardEmblem emblem : CARD_EMBLEMS) { + cards.addAll(CARD_NUMBER.stream() + .map(cardNumber -> Card.of(emblem, cardNumber)) + .toList()); + } + } + + public List getCards() { + return List.copyOf(cards); + } +} diff --git a/src/main/java/card/CardEmblem.java b/src/main/java/card/CardEmblem.java new file mode 100644 index 00000000000..a9c8b327290 --- /dev/null +++ b/src/main/java/card/CardEmblem.java @@ -0,0 +1,18 @@ +package card; + +public enum CardEmblem { + CLOVER("클로버"), + HEART("하트"), + SPADE("스페이드"), + DIAMOND("다이아몬드"); + + private final String name; + + CardEmblem(final String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/card/CardNumber.java b/src/main/java/card/CardNumber.java new file mode 100644 index 00000000000..be6f35eed8f --- /dev/null +++ b/src/main/java/card/CardNumber.java @@ -0,0 +1,26 @@ +package card; + +public enum CardNumber { + ACE(1), + TWO(2), + THREE(3), + FOUR(4), + FIVE(5), + SIX(6), + SEVEN(7), + EIGHT(8), + NINE(9), + JACK(10), + QUEEN(10), + KING(10); + + private final int number; + + CardNumber(final int number) { + this.number = number; + } + + public int getNumber() { + return this.number; + } +} From 1dd97779ae20ecd9fe04ef9bd4ef09d6988cc69c Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 25 May 2024 15:48:17 +0900 Subject: [PATCH 03/15] =?UTF-8?q?modify:=20Card=20=EA=B0=9D=EC=B2=B4=20rec?= =?UTF-8?q?ord?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/card/Card.java | 16 ++++------------ src/main/java/card/CardDeck.java | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/main/java/card/Card.java b/src/main/java/card/Card.java index 93d9c4a9c13..02912a27fe7 100644 --- a/src/main/java/card/Card.java +++ b/src/main/java/card/Card.java @@ -1,15 +1,7 @@ package card; -public class Card { - private final CardEmblem emblem; - private final CardNumber number; - - private Card(final CardEmblem emblem, final CardNumber number) { - this.emblem = emblem; - this.number = number; - } - - public static Card of(final CardEmblem emblem, final CardNumber number) { - return new Card(emblem, number); - } +public record Card ( + CardEmblem emblem, + CardNumber number +) { } diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/CardDeck.java index 0a0b7346798..79dd63f7009 100644 --- a/src/main/java/card/CardDeck.java +++ b/src/main/java/card/CardDeck.java @@ -12,7 +12,7 @@ public class CardDeck { public CardDeck() { for (CardEmblem emblem : CARD_EMBLEMS) { cards.addAll(CARD_NUMBER.stream() - .map(cardNumber -> Card.of(emblem, cardNumber)) + .map(cardNumber -> new Card(emblem, cardNumber)) .toList()); } } From efe67af34fa1d35143ea6d33af5baca949cf85f3 Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 25 May 2024 17:46:22 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=B0=B8?= =?UTF-8?q?=EA=B0=80=EC=9E=90=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B0=B8=EA=B0=80=EC=9E=90=EC=9D=98=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=EC=B9=B4=EB=93=9C=20=EC=A0=90=EC=88=98=20=EA=B3=84?= =?UTF-8?q?=EC=82=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/card/CardNumber.java | 14 ++++--- src/main/java/participant/Participant.java | 48 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/main/java/participant/Participant.java diff --git a/src/main/java/card/CardNumber.java b/src/main/java/card/CardNumber.java index be6f35eed8f..66ef288d1ed 100644 --- a/src/main/java/card/CardNumber.java +++ b/src/main/java/card/CardNumber.java @@ -14,13 +14,17 @@ public enum CardNumber { QUEEN(10), KING(10); - private final int number; + private final int score; - CardNumber(final int number) { - this.number = number; + CardNumber(final int score) { + this.score = score; } - public int getNumber() { - return this.number; + public int getScore() { + return this.score; + } + + public boolean isAce() { + return this == ACE; } } diff --git a/src/main/java/participant/Participant.java b/src/main/java/participant/Participant.java new file mode 100644 index 00000000000..b7c60b8dae9 --- /dev/null +++ b/src/main/java/participant/Participant.java @@ -0,0 +1,48 @@ +package participant; + +import card.Card; + +import java.util.ArrayList; +import java.util.List; + +public class Participant { + private static final int ACE_BOTTOM_SCORE = 1; + private static final int ACE_TOP_SCORE = 11; + private static final int BLACK_JACK_WINNING_MAX = 21; + + private final String name; + private final List cards = new ArrayList<>(); + + public Participant(final String name) { + this.name = name; + } + + public void addCard(final Card card) { + this.cards.add(card); + } + + public int calculateCurrentScore() { + int currentScore = 0; + + for (Card card : cards) { + currentScore += fetchCardScore(currentScore, card); + } + + return currentScore; + } + + private int fetchCardScore(final int currentScore, final Card card) { + if (card.number().isAce()) { + return fetchAceScore(currentScore); + } + return card.number().getScore(); + } + + private int fetchAceScore(final int currentScore) { + if (currentScore + ACE_TOP_SCORE > BLACK_JACK_WINNING_MAX) { + return ACE_BOTTOM_SCORE; + } + return ACE_TOP_SCORE; + } + +} From 414858bcb676503852ee45279b47a2a7430af153 Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 20:55:30 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor:=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EB=AC=B8=EC=96=91=20:=20suit,=20=EC=B9=B4=EB=93=9C=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=20:=20rank=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/card/Card.java | 4 ++-- src/main/java/card/CardDeck.java | 8 ++++---- src/main/java/card/{CardNumber.java => CardRank.java} | 4 ++-- src/main/java/card/{CardEmblem.java => CardSuit.java} | 4 ++-- src/main/java/participant/Participant.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/main/java/card/{CardNumber.java => CardRank.java} (84%) rename src/main/java/card/{CardEmblem.java => CardSuit.java} (78%) diff --git a/src/main/java/card/Card.java b/src/main/java/card/Card.java index 02912a27fe7..c35a77e0d2f 100644 --- a/src/main/java/card/Card.java +++ b/src/main/java/card/Card.java @@ -1,7 +1,7 @@ package card; public record Card ( - CardEmblem emblem, - CardNumber number + CardSuit suit, + CardRank rank ) { } diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/CardDeck.java index 79dd63f7009..a4d2326daa5 100644 --- a/src/main/java/card/CardDeck.java +++ b/src/main/java/card/CardDeck.java @@ -4,15 +4,15 @@ import java.util.List; public class CardDeck { - private static final List CARD_EMBLEMS = List.of(CardEmblem.CLOVER, CardEmblem.HEART, CardEmblem.SPADE, CardEmblem.DIAMOND); - private static final List CARD_NUMBER = List.of(CardNumber.ACE, CardNumber.TWO, CardNumber.THREE, CardNumber.FOUR, CardNumber.FIVE, CardNumber.SIX, CardNumber.SEVEN, CardNumber.EIGHT, CardNumber.NINE, CardNumber.JACK, CardNumber.QUEEN, CardNumber.KING); + private static final List CARD_EMBLEMS = List.of(CardSuit.CLOVER, CardSuit.HEART, CardSuit.SPADE, CardSuit.DIAMOND); + private static final List CARD_NUMBER = List.of(CardRank.ACE, CardRank.TWO, CardRank.THREE, CardRank.FOUR, CardRank.FIVE, CardRank.SIX, CardRank.SEVEN, CardRank.EIGHT, CardRank.NINE, CardRank.JACK, CardRank.QUEEN, CardRank.KING); private final List cards = new ArrayList<>(); public CardDeck() { - for (CardEmblem emblem : CARD_EMBLEMS) { + for (CardSuit emblem : CARD_EMBLEMS) { cards.addAll(CARD_NUMBER.stream() - .map(cardNumber -> new Card(emblem, cardNumber)) + .map(cardRank -> new Card(emblem, cardRank)) .toList()); } } diff --git a/src/main/java/card/CardNumber.java b/src/main/java/card/CardRank.java similarity index 84% rename from src/main/java/card/CardNumber.java rename to src/main/java/card/CardRank.java index 66ef288d1ed..e2168840cd3 100644 --- a/src/main/java/card/CardNumber.java +++ b/src/main/java/card/CardRank.java @@ -1,6 +1,6 @@ package card; -public enum CardNumber { +public enum CardRank { ACE(1), TWO(2), THREE(3), @@ -16,7 +16,7 @@ public enum CardNumber { private final int score; - CardNumber(final int score) { + CardRank(final int score) { this.score = score; } diff --git a/src/main/java/card/CardEmblem.java b/src/main/java/card/CardSuit.java similarity index 78% rename from src/main/java/card/CardEmblem.java rename to src/main/java/card/CardSuit.java index a9c8b327290..f3aa020e2f6 100644 --- a/src/main/java/card/CardEmblem.java +++ b/src/main/java/card/CardSuit.java @@ -1,6 +1,6 @@ package card; -public enum CardEmblem { +public enum CardSuit { CLOVER("클로버"), HEART("하트"), SPADE("스페이드"), @@ -8,7 +8,7 @@ public enum CardEmblem { private final String name; - CardEmblem(final String name) { + CardSuit(final String name) { this.name = name; } diff --git a/src/main/java/participant/Participant.java b/src/main/java/participant/Participant.java index b7c60b8dae9..ef578424968 100644 --- a/src/main/java/participant/Participant.java +++ b/src/main/java/participant/Participant.java @@ -32,10 +32,10 @@ public int calculateCurrentScore() { } private int fetchCardScore(final int currentScore, final Card card) { - if (card.number().isAce()) { + if (card.rank().isAce()) { return fetchAceScore(currentScore); } - return card.number().getScore(); + return card.rank().getScore(); } private int fetchAceScore(final int currentScore) { From a291a12598cffd675f961872b16d89628d84da7e Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 21:00:07 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=B0=B8?= =?UTF-8?q?=EA=B0=80=EC=9E=90=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ParticipantRequest.java | 16 +++++++++++ .../participant/{ => model}/Participant.java | 2 +- .../validator/ParticipantInputValidator.java | 13 +++++++++ src/main/java/utils/Console.java | 27 +++++++++++++++++++ src/main/java/view/InputView.java | 16 +++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/main/java/participant/controller/ParticipantRequest.java rename src/main/java/participant/{ => model}/Participant.java (97%) create mode 100644 src/main/java/participant/validator/ParticipantInputValidator.java create mode 100644 src/main/java/utils/Console.java create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/participant/controller/ParticipantRequest.java b/src/main/java/participant/controller/ParticipantRequest.java new file mode 100644 index 00000000000..6a625eccf32 --- /dev/null +++ b/src/main/java/participant/controller/ParticipantRequest.java @@ -0,0 +1,16 @@ +package participant.controller; + +import participant.validator.ParticipantInputValidator; + +public class ParticipantRequest { + private final String participant; + + private ParticipantRequest(final String participant) { + this.participant = participant; + } + + public static ParticipantRequest from(final String participant) { + ParticipantInputValidator.validate(participant); + return new ParticipantRequest(participant); + } +} diff --git a/src/main/java/participant/Participant.java b/src/main/java/participant/model/Participant.java similarity index 97% rename from src/main/java/participant/Participant.java rename to src/main/java/participant/model/Participant.java index ef578424968..cb2c20240e2 100644 --- a/src/main/java/participant/Participant.java +++ b/src/main/java/participant/model/Participant.java @@ -1,4 +1,4 @@ -package participant; +package participant.model; import card.Card; diff --git a/src/main/java/participant/validator/ParticipantInputValidator.java b/src/main/java/participant/validator/ParticipantInputValidator.java new file mode 100644 index 00000000000..6f50ae024c8 --- /dev/null +++ b/src/main/java/participant/validator/ParticipantInputValidator.java @@ -0,0 +1,13 @@ +package participant.validator; + +public class ParticipantInputValidator { + private static final String SPLIT_DELIMETER = ","; + + public static void validate(final String participant) { + try { + participant.split(SPLIT_DELIMETER); + } catch (Exception e) { + throw new IllegalArgumentException("게임 참여할 사람의 이름을 입력할 때 문제가 발생했습니다."); + } + } +} diff --git a/src/main/java/utils/Console.java b/src/main/java/utils/Console.java new file mode 100644 index 00000000000..1a9a3bd3ae5 --- /dev/null +++ b/src/main/java/utils/Console.java @@ -0,0 +1,27 @@ +package utils; + +import java.util.Scanner; + +public class Console { + private static Scanner scanner; + + private Console() {} + + public static String readLine() { + return getInstance().nextLine(); + } + + public static void close() { + if (scanner != null) { + scanner.close(); + scanner = null; + } + } + + private static Scanner getInstance() { + if (scanner == null) { + scanner = new Scanner(System.in); + } + return scanner; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000000..3836ec9d08d --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,16 @@ +package view; + +import participant.controller.ParticipantRequest; +import utils.Console; + +public class InputView { + public static ParticipantRequest inputParticipants() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + try { + return ParticipantRequest.from(Console.readLine()); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return inputParticipants(); + } + } +} From fa3d6755ed16ae861d9f29f9c9a75494bf2c34ec Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 21:07:50 +0900 Subject: [PATCH 07/15] =?UTF-8?q?modify:=20=EC=B9=B4=EB=93=9C=EB=8D=B1=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EB=BD=91=EA=B8=B0=20=EB=B0=A9=EB=B2=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/card/CardDeck.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/CardDeck.java index a4d2326daa5..c8c3eb0f223 100644 --- a/src/main/java/card/CardDeck.java +++ b/src/main/java/card/CardDeck.java @@ -1,23 +1,25 @@ package card; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class CardDeck { private static final List CARD_EMBLEMS = List.of(CardSuit.CLOVER, CardSuit.HEART, CardSuit.SPADE, CardSuit.DIAMOND); private static final List CARD_NUMBER = List.of(CardRank.ACE, CardRank.TWO, CardRank.THREE, CardRank.FOUR, CardRank.FIVE, CardRank.SIX, CardRank.SEVEN, CardRank.EIGHT, CardRank.NINE, CardRank.JACK, CardRank.QUEEN, CardRank.KING); - private final List cards = new ArrayList<>(); + private final Deque cards; public CardDeck() { + List cardList = new ArrayList<>(); for (CardSuit emblem : CARD_EMBLEMS) { - cards.addAll(CARD_NUMBER.stream() + cardList.addAll(CARD_NUMBER.stream() .map(cardRank -> new Card(emblem, cardRank)) .toList()); } + Collections.shuffle(cardList); + cards = new ArrayDeque<>(cardList); } - public List getCards() { - return List.copyOf(cards); + public Card pickCard() { + return this.cards.pollFirst(); } } From 0d620ebdb1cfc6bbde2cf5cbef707aac007c083b Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 21:08:18 +0900 Subject: [PATCH 08/15] =?UTF-8?q?modify:=20=EC=B9=B4=EB=93=9C=EB=8D=B1=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EB=BD=91=EA=B8=B0=20=EB=B0=A9=EB=B2=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/card/CardDeck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/CardDeck.java index c8c3eb0f223..3bdb421eba3 100644 --- a/src/main/java/card/CardDeck.java +++ b/src/main/java/card/CardDeck.java @@ -16,7 +16,7 @@ public CardDeck() { .toList()); } Collections.shuffle(cardList); - cards = new ArrayDeque<>(cardList); + this.cards = new ArrayDeque<>(cardList); } public Card pickCard() { From eff7337db5c1a402b8547d8f7c866b65d9e83f5b Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 21:37:30 +0900 Subject: [PATCH 09/15] =?UTF-8?q?feat:=20=EC=B0=B8=EC=97=AC=EC=9E=90=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=B0=9B=EB=8A=94=20GamePlayground=20(=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=EC=9E=A5)=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/game/GamePlayground.java | 16 ++++++++++++ .../controller/ParticipantRequest.java | 23 +++++++++++----- .../domain/ParticipantRegister.java | 26 +++++++++++++++++++ .../validator/ParticipantInputValidator.java | 7 ++--- src/main/java/utils/SplitUtils.java | 7 +++++ 5 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 src/main/java/game/GamePlayground.java create mode 100644 src/main/java/participant/domain/ParticipantRegister.java create mode 100644 src/main/java/utils/SplitUtils.java diff --git a/src/main/java/game/GamePlayground.java b/src/main/java/game/GamePlayground.java new file mode 100644 index 00000000000..6fe80292632 --- /dev/null +++ b/src/main/java/game/GamePlayground.java @@ -0,0 +1,16 @@ +package game; + +import card.CardDeck; +import participant.model.Participant; + +import java.util.ArrayList; +import java.util.List; + +public class GamePlayground { + private final List participants = new ArrayList<>(); + private final CardDeck cardDeck = new CardDeck(); + + public GamePlayground(final List participants) { + this.participants.addAll(participants); + } +} diff --git a/src/main/java/participant/controller/ParticipantRequest.java b/src/main/java/participant/controller/ParticipantRequest.java index 6a625eccf32..a91038aeaf4 100644 --- a/src/main/java/participant/controller/ParticipantRequest.java +++ b/src/main/java/participant/controller/ParticipantRequest.java @@ -1,16 +1,27 @@ package participant.controller; import participant.validator.ParticipantInputValidator; +import utils.SplitUtils; + +import java.util.Arrays; +import java.util.List; public class ParticipantRequest { - private final String participant; + private static final String SPLIT_DELIMITER = ","; + + private final List participantNames; + + private ParticipantRequest(final List participantNames) { + this.participantNames = participantNames; + } - private ParticipantRequest(final String participant) { - this.participant = participant; + public static ParticipantRequest from(final String participantInput) { + ParticipantInputValidator.validate(participantInput, SPLIT_DELIMITER); + final String[] splitInput = SplitUtils.split(participantInput, SPLIT_DELIMITER); + return new ParticipantRequest(Arrays.asList(splitInput)); } - public static ParticipantRequest from(final String participant) { - ParticipantInputValidator.validate(participant); - return new ParticipantRequest(participant); + public List getParticipantNames() { + return List.copyOf(participantNames); } } diff --git a/src/main/java/participant/domain/ParticipantRegister.java b/src/main/java/participant/domain/ParticipantRegister.java new file mode 100644 index 00000000000..41c68b0d92b --- /dev/null +++ b/src/main/java/participant/domain/ParticipantRegister.java @@ -0,0 +1,26 @@ +package participant.domain; + +import participant.controller.ParticipantRequest; +import participant.model.Participant; + +import java.util.List; +import java.util.stream.Collectors; + +public class ParticipantRegister { + private static final String DEALER = "딜러"; + + private final ParticipantRequest participantRequest; + + public ParticipantRegister(final ParticipantRequest participantRequest) { + this.participantRequest = participantRequest; + } + + public List registerParticipants() { + List participants = participantRequest.getParticipantNames().stream() + .map(Participant::new) + .collect(Collectors.toList()); + + participants.add(new Participant(DEALER)); + return participants; + } +} diff --git a/src/main/java/participant/validator/ParticipantInputValidator.java b/src/main/java/participant/validator/ParticipantInputValidator.java index 6f50ae024c8..e3b3aab8fbb 100644 --- a/src/main/java/participant/validator/ParticipantInputValidator.java +++ b/src/main/java/participant/validator/ParticipantInputValidator.java @@ -1,11 +1,12 @@ package participant.validator; +import utils.SplitUtils; + public class ParticipantInputValidator { - private static final String SPLIT_DELIMETER = ","; - public static void validate(final String participant) { + public static void validate(final String participant, final String delimiter) { try { - participant.split(SPLIT_DELIMETER); + SplitUtils.split(participant, delimiter); } catch (Exception e) { throw new IllegalArgumentException("게임 참여할 사람의 이름을 입력할 때 문제가 발생했습니다."); } diff --git a/src/main/java/utils/SplitUtils.java b/src/main/java/utils/SplitUtils.java new file mode 100644 index 00000000000..f6be9dc8a49 --- /dev/null +++ b/src/main/java/utils/SplitUtils.java @@ -0,0 +1,7 @@ +package utils; + +public class SplitUtils { + public static String[] split(final String target, final String delimiter) { + return target.split(delimiter); + } +} From 94efede1eb68e503a18260a55b63f2c185adce73 Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Wed, 29 May 2024 21:38:04 +0900 Subject: [PATCH 10/15] =?UTF-8?q?modify:=20Card=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=97=90=20toString()=20=EC=98=A4=EB=B2=84=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20-=20=EC=B9=B4=EB=93=9C=20=EC=A2=85=EB=A5=98=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/card/Card.java | 4 ++++ src/main/java/card/CardRank.java | 32 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/java/card/Card.java b/src/main/java/card/Card.java index c35a77e0d2f..4e725bb7390 100644 --- a/src/main/java/card/Card.java +++ b/src/main/java/card/Card.java @@ -4,4 +4,8 @@ public record Card ( CardSuit suit, CardRank rank ) { + @Override + public String toString() { + return "%s%s".formatted(rank.getRank(), suit.getName()); + } } diff --git a/src/main/java/card/CardRank.java b/src/main/java/card/CardRank.java index e2168840cd3..78639491f49 100644 --- a/src/main/java/card/CardRank.java +++ b/src/main/java/card/CardRank.java @@ -1,29 +1,35 @@ package card; public enum CardRank { - ACE(1), - TWO(2), - THREE(3), - FOUR(4), - FIVE(5), - SIX(6), - SEVEN(7), - EIGHT(8), - NINE(9), - 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"), + JACK(10, "J"), + QUEEN(10, "Q"), + KING(10, "K"); private final int score; + private final String rank; - CardRank(final int score) { + CardRank(final int score, final String rank) { this.score = score; + this.rank = rank; } public int getScore() { return this.score; } + public String getRank() { + return this.rank; + } + public boolean isAce() { return this == ACE; } From 778c323969e0b1eab3c75cdcc8df3dd434774345 Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 1 Jun 2024 13:04:43 +0900 Subject: [PATCH 11/15] =?UTF-8?q?feat:=20GameController=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EA=B5=AC=EC=84=B1=20-=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EC=9D=98=20=EC=A0=84=EB=B0=98=EC=A0=81=EC=9D=B8=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=20=EA=B3=BC=EC=A0=95=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 7 +- src/main/java/card/controller/DrawCard.java | 10 +++ .../java/card/controller/DrawCardRequest.java | 31 +++++++ .../validator/DrawCardInputValidator.java | 9 ++ src/main/java/game/GamePlayground.java | 16 ---- .../java/game/controller/GameController.java | 82 +++++++++++++++++++ .../controller/ParticipantRequest.java | 5 +- .../domain/ParticipantRegister.java | 7 +- .../java/participant/model/Participant.java | 8 ++ src/main/java/view/InputView.java | 14 +++- src/main/java/view/OutputView.java | 50 +++++++++++ 11 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 src/main/java/card/controller/DrawCard.java create mode 100644 src/main/java/card/controller/DrawCardRequest.java create mode 100644 src/main/java/card/validator/DrawCardInputValidator.java delete mode 100644 src/main/java/game/GamePlayground.java create mode 100644 src/main/java/game/controller/GameController.java create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 44ac86ae235..602543b9b80 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,5 +1,10 @@ +import game.controller.GameController; +import view.InputView; +import view.OutputView; + public class Application { public static void main(String[] args) { - System.out.println("Hello, BlackJack"); + GameController gameController = new GameController(new InputView(), new OutputView()); + gameController.run(); } } diff --git a/src/main/java/card/controller/DrawCard.java b/src/main/java/card/controller/DrawCard.java new file mode 100644 index 00000000000..f86c313863d --- /dev/null +++ b/src/main/java/card/controller/DrawCard.java @@ -0,0 +1,10 @@ +package card.controller; + +public enum DrawCard { + y, + n; + + public boolean isY() { + return this == y; + } +} diff --git a/src/main/java/card/controller/DrawCardRequest.java b/src/main/java/card/controller/DrawCardRequest.java new file mode 100644 index 00000000000..65c7e283510 --- /dev/null +++ b/src/main/java/card/controller/DrawCardRequest.java @@ -0,0 +1,31 @@ +package card.controller; + +import card.validator.DrawCardInputValidator; + +import java.util.List; + +public class DrawCardRequest { + private static final List DRAW_YES = List.of("y", "Y"); + public final DrawCard drawCard; + + private DrawCardRequest(final DrawCard drawCard) { + this.drawCard = drawCard; + } + + public static DrawCardRequest from(final String input) { + DrawCardInputValidator.validate(input); + return new DrawCardRequest(formattedDrawCardInput(input)); + } + + private static DrawCard formattedDrawCardInput(final String input) { + if (DRAW_YES.contains(input)) { + return DrawCard.y; + } + + return DrawCard.n; + } + + public boolean isNotDrawCard() { + return !this.drawCard.isY(); + } +} diff --git a/src/main/java/card/validator/DrawCardInputValidator.java b/src/main/java/card/validator/DrawCardInputValidator.java new file mode 100644 index 00000000000..5a9e6c55216 --- /dev/null +++ b/src/main/java/card/validator/DrawCardInputValidator.java @@ -0,0 +1,9 @@ +package card.validator; + +public class DrawCardInputValidator { + public static void validate(final String drawCardInput) { + if (drawCardInput == null || drawCardInput.isBlank()) { + throw new IllegalArgumentException("카드를 더 뽑을지 y 또는 n을 입력해주세요."); + } + } +} diff --git a/src/main/java/game/GamePlayground.java b/src/main/java/game/GamePlayground.java deleted file mode 100644 index 6fe80292632..00000000000 --- a/src/main/java/game/GamePlayground.java +++ /dev/null @@ -1,16 +0,0 @@ -package game; - -import card.CardDeck; -import participant.model.Participant; - -import java.util.ArrayList; -import java.util.List; - -public class GamePlayground { - private final List participants = new ArrayList<>(); - private final CardDeck cardDeck = new CardDeck(); - - public GamePlayground(final List participants) { - this.participants.addAll(participants); - } -} diff --git a/src/main/java/game/controller/GameController.java b/src/main/java/game/controller/GameController.java new file mode 100644 index 00000000000..7108a24acf1 --- /dev/null +++ b/src/main/java/game/controller/GameController.java @@ -0,0 +1,82 @@ +package game.controller; + +import card.CardDeck; +import card.controller.DrawCardRequest; +import participant.controller.ParticipantRequest; +import participant.domain.ParticipantRegister; +import participant.model.Participant; +import view.InputView; +import view.OutputView; + +import java.util.List; +import java.util.stream.IntStream; + +public class GameController { + private static final int FIRST_CARD_COUNT = 2; + private static final int DEALER_DRAW_CARD_SCORE = 16; + private static final String DEALER = "딜러"; + + private final InputView inputView; + private final OutputView outputView; + + private final CardDeck cardDeck = new CardDeck(); + + public GameController(final InputView inputView, final OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + List participants = fetchParticipants(); + firstDrawCards(participants); + drawCardsWithoutDealer(participants); + drawCardDealer(participants.stream() + .filter(participant -> DEALER.equals(participant.getName())) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("게임에 딜러가 존재하지 않습니다.")) + ); + + this.outputView.printFinalResult(participants); + } + + private List fetchParticipants() { + ParticipantRequest participantRequest = this.inputView.inputParticipants(); + ParticipantRegister participantRegister = new ParticipantRegister(participantRequest); + return participantRegister.registerParticipants(); + } + + private void firstDrawCards(List participants) { + this.outputView.firstDistributeCard(participants); + for (Participant participant : participants) { + IntStream.range(0, FIRST_CARD_COUNT).forEach(it -> { + participant.addCard(this.cardDeck.pickCard()); + }); + } + this.outputView.printParticipantsCard(participants); + } + + private void drawCardsWithoutDealer(List participants) { + for (Participant participant : participants.stream() + .filter(participant -> !DEALER.equals(participant.getName())) + .toList()) { + choiceDrawCard(participant); + } + } + + private void choiceDrawCard(Participant participant) { + while (true) { + DrawCardRequest drawCardRequest = this.inputView.inputDrawCard(participant); + if (drawCardRequest.isNotDrawCard()) break; + + participant.addCard(this.cardDeck.pickCard()); + this.outputView.printParticipantCard(participant); + } + } + + private void drawCardDealer(Participant participant) { + if (participant.calculateCurrentScore() <= DEALER_DRAW_CARD_SCORE) { + this.outputView.printDealerDrawCard(); + participant.addCard(this.cardDeck.pickCard()); + } + } +} diff --git a/src/main/java/participant/controller/ParticipantRequest.java b/src/main/java/participant/controller/ParticipantRequest.java index a91038aeaf4..f6105fe5831 100644 --- a/src/main/java/participant/controller/ParticipantRequest.java +++ b/src/main/java/participant/controller/ParticipantRequest.java @@ -16,8 +16,9 @@ private ParticipantRequest(final List participantNames) { } public static ParticipantRequest from(final String participantInput) { - ParticipantInputValidator.validate(participantInput, SPLIT_DELIMITER); - final String[] splitInput = SplitUtils.split(participantInput, SPLIT_DELIMITER); + String trimmedInput = participantInput.replaceAll(" ", ""); + ParticipantInputValidator.validate(trimmedInput, SPLIT_DELIMITER); + final String[] splitInput = SplitUtils.split(trimmedInput, SPLIT_DELIMITER); return new ParticipantRequest(Arrays.asList(splitInput)); } diff --git a/src/main/java/participant/domain/ParticipantRegister.java b/src/main/java/participant/domain/ParticipantRegister.java index 41c68b0d92b..aff4584ac5f 100644 --- a/src/main/java/participant/domain/ParticipantRegister.java +++ b/src/main/java/participant/domain/ParticipantRegister.java @@ -3,6 +3,7 @@ import participant.controller.ParticipantRequest; import participant.model.Participant; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -21,6 +22,10 @@ public List registerParticipants() { .collect(Collectors.toList()); participants.add(new Participant(DEALER)); - return participants; + + // 참여자 리스트 순서 정렬 - 딜러가 앞에 오도록 정렬 + return participants.stream() + .sorted(Comparator.comparing(Participant::getName).reversed()) + .collect(Collectors.toList()); } } diff --git a/src/main/java/participant/model/Participant.java b/src/main/java/participant/model/Participant.java index cb2c20240e2..e2f3876c2f7 100644 --- a/src/main/java/participant/model/Participant.java +++ b/src/main/java/participant/model/Participant.java @@ -45,4 +45,12 @@ private int fetchAceScore(final int currentScore) { return ACE_TOP_SCORE; } + public String getName() { + return this.name; + } + + public List getCards() { + return List.copyOf(cards); + } + } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 3836ec9d08d..1ea37c65ba4 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,10 +1,12 @@ package view; +import card.controller.DrawCardRequest; import participant.controller.ParticipantRequest; +import participant.model.Participant; import utils.Console; public class InputView { - public static ParticipantRequest inputParticipants() { + public ParticipantRequest inputParticipants() { System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); try { return ParticipantRequest.from(Console.readLine()); @@ -13,4 +15,14 @@ public static ParticipantRequest inputParticipants() { return inputParticipants(); } } + + public DrawCardRequest inputDrawCard(final Participant participant) { + System.out.println("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)".formatted(participant.getName())); + try { + return DrawCardRequest.from(Console.readLine()); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return inputDrawCard(participant); + } + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000000..03cedf583e7 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,50 @@ +package view; + +import card.Card; +import participant.model.Participant; + +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + private static final String JOINING_DELIMITER = ", "; + private static final String DEALER = "딜러"; + + public void firstDistributeCard(final List participants) { + final String joiningParticipant = participants.stream() + .filter(participant -> !DEALER.equals(participant.getName())) + .map(Participant::getName) + .collect(Collectors.joining(JOINING_DELIMITER)); + + System.out.println("딜러와 %s에게 2장을 나누었습니다.".formatted(joiningParticipant)); + } + + public void printParticipantsCard(final List participants) { + for (Participant participant : participants) { + printParticipantCard(participant); + } + } + + public void printParticipantCard(final Participant participant) { + final String joiningCard = participant.getCards().stream() + .map(Card::toString) + .collect(Collectors.joining(JOINING_DELIMITER)); + System.out.println("%s카드: %s".formatted(participant.getName(), joiningCard)); + } + + public void printDealerDrawCard() { + System.out.println("딜러는 16이하라 한장의 카드를 더 받았습니다."); + } + + public void printFinalResult(final List participants) { + for (Participant participant : participants) { + String joiningCard = participant.getCards().stream() + .map(Card::toString) + .collect(Collectors.joining(JOINING_DELIMITER)); + int score = participant.calculateCurrentScore(); + + System.out.println("%s 카드: %s - 결과: %d".formatted(participant.getName(), joiningCard, score)); + } + } + +} From c4d9413ae3f9dbb9b40a1651475f3dbb5a1dbfd9 Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 1 Jun 2024 15:33:43 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=8A=B9?= =?UTF-8?q?=ED=8C=A8=20=ED=8C=90=EB=8B=A8=20GameJudgement=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20A=EC=B9=B4=EB=93=9C=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=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 --- .../java/game/controller/GameController.java | 7 +- src/main/java/game/domain/GameJudgement.java | 82 +++++++++++++++++++ .../java/participant/model/Participant.java | 30 ++++--- src/main/java/view/OutputView.java | 10 ++- 4 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 src/main/java/game/domain/GameJudgement.java diff --git a/src/main/java/game/controller/GameController.java b/src/main/java/game/controller/GameController.java index 7108a24acf1..21569c23c1b 100644 --- a/src/main/java/game/controller/GameController.java +++ b/src/main/java/game/controller/GameController.java @@ -2,6 +2,7 @@ import card.CardDeck; import card.controller.DrawCardRequest; +import game.domain.GameJudgement; import participant.controller.ParticipantRequest; import participant.domain.ParticipantRegister; import participant.model.Participant; @@ -14,7 +15,6 @@ public class GameController { private static final int FIRST_CARD_COUNT = 2; private static final int DEALER_DRAW_CARD_SCORE = 16; - private static final String DEALER = "딜러"; private final InputView inputView; private final OutputView outputView; @@ -31,12 +31,13 @@ public void run() { firstDrawCards(participants); drawCardsWithoutDealer(participants); drawCardDealer(participants.stream() - .filter(participant -> DEALER.equals(participant.getName())) + .filter(Participant::isDealer) .findAny() .orElseThrow(() -> new IllegalArgumentException("게임에 딜러가 존재하지 않습니다.")) ); this.outputView.printFinalResult(participants); + this.outputView.printGameJudgement(new GameJudgement(participants)); } private List fetchParticipants() { @@ -57,7 +58,7 @@ private void firstDrawCards(List participants) { private void drawCardsWithoutDealer(List participants) { for (Participant participant : participants.stream() - .filter(participant -> !DEALER.equals(participant.getName())) + .filter(participant -> !participant.isDealer()) .toList()) { choiceDrawCard(participant); } diff --git a/src/main/java/game/domain/GameJudgement.java b/src/main/java/game/domain/GameJudgement.java new file mode 100644 index 00000000000..3db5ecffecf --- /dev/null +++ b/src/main/java/game/domain/GameJudgement.java @@ -0,0 +1,82 @@ +package game.domain; + +import participant.model.Participant; + +import java.util.ArrayList; +import java.util.List; + +public class GameJudgement { + private static final String WIN_PARTICIPANT_MESSAGE = "%s: 승"; + private static final String LOSE_PARTICIPANT_MESSAGE = "%s: 패"; + + private final Participant dealer; + private final List participantWithoutDealers = new ArrayList<>(); + + public GameJudgement(final List participants) { + this.dealer = participants.stream() + .filter(Participant::isDealer) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("게임에 딜러가 존재하지 않습니다.")); + this.participantWithoutDealers.addAll(participants.stream() + .filter(participant -> !participant.isDealer()) + .toList() + ); + } + + public String fetchDealerJudge() { + final int dealerScore = this.dealer.calculateCurrentScore(); + final String dealerJudgeMessage = "딜러: %d승 %d패"; + int winCount = 0; + int loseCount = 0; + + // 21점이 넘어가면 무조건 패배 - 참여자 수만큼 패배한 수로 세팅 + if (this.dealer.isOverWinningMaxScore()) { + loseCount = participantWithoutDealers.size(); + return dealerJudgeMessage.formatted(winCount, loseCount); + } + + winCount = fetchDealerWinningCount(dealerScore); + loseCount = fetchDealerLoseCount(dealerScore); + + return dealerJudgeMessage.formatted(winCount, loseCount); + } + + private int fetchDealerWinningCount(final int dealerScore) { + int winCount; + winCount = participantWithoutDealers.stream() + .map(Participant::calculateCurrentScore) + .filter(participantScore -> dealerScore > participantScore) + .toList() + .size(); + return winCount; + } + + private int fetchDealerLoseCount(final int dealerScore) { + return participantWithoutDealers.stream() + .map(Participant::calculateCurrentScore) + .filter(participantScore -> dealerScore < participantScore) + .toList() + .size(); + } + + public List fetchParticipantJudge() { + return participantWithoutDealers.stream() + .map(participant -> { + String loseMessage = LOSE_PARTICIPANT_MESSAGE.formatted(participant.getName()); + if (participant.isOverWinningMaxScore()) { + return loseMessage; + } + + int participantScore = participant.calculateCurrentScore(); + if (participantWithoutDealers.stream() + .filter(p -> !(p.getName().equals(participant.getName()) || + p.isOverWinningMaxScore())) + .allMatch(innerParticipant -> participantScore > innerParticipant.calculateCurrentScore())) { + return WIN_PARTICIPANT_MESSAGE.formatted(participant.getName()); + } + + return loseMessage; + }) + .toList(); + } +} diff --git a/src/main/java/participant/model/Participant.java b/src/main/java/participant/model/Participant.java index e2f3876c2f7..6fe30087f22 100644 --- a/src/main/java/participant/model/Participant.java +++ b/src/main/java/participant/model/Participant.java @@ -9,6 +9,8 @@ public class Participant { private static final int ACE_BOTTOM_SCORE = 1; private static final int ACE_TOP_SCORE = 11; private static final int BLACK_JACK_WINNING_MAX = 21; + private static final String DEALER = "딜러"; + private final String name; private final List cards = new ArrayList<>(); @@ -22,29 +24,31 @@ public void addCard(final Card card) { } public int calculateCurrentScore() { - int currentScore = 0; + // 우선 A 카드 제외하고 점수 합산 + int currentScore = cards.stream() + .filter(card -> !card.rank().isAce()) + .mapToInt(card -> card.rank().getScore()) + .sum(); - for (Card card : cards) { - currentScore += fetchCardScore(currentScore, card); + // A 카드 점수 합산 + for (Card card : cards.stream().filter(card -> card.rank().isAce()).toList()) { + currentScore += fetchContainAceCardScore(currentScore); } return currentScore; } - private int fetchCardScore(final int currentScore, final Card card) { - if (card.rank().isAce()) { - return fetchAceScore(currentScore); - } - return card.rank().getScore(); - } - - private int fetchAceScore(final int currentScore) { + private int fetchContainAceCardScore(final int currentScore) { if (currentScore + ACE_TOP_SCORE > BLACK_JACK_WINNING_MAX) { return ACE_BOTTOM_SCORE; } return ACE_TOP_SCORE; } + public boolean isOverWinningMaxScore() { + return calculateCurrentScore() > BLACK_JACK_WINNING_MAX; + } + public String getName() { return this.name; } @@ -53,4 +57,8 @@ public List getCards() { return List.copyOf(cards); } + public boolean isDealer() { + return DEALER.equals(this.name); + } + } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 03cedf583e7..a1d942bf69c 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,6 +1,7 @@ package view; import card.Card; +import game.domain.GameJudgement; import participant.model.Participant; import java.util.List; @@ -8,11 +9,10 @@ public class OutputView { private static final String JOINING_DELIMITER = ", "; - private static final String DEALER = "딜러"; public void firstDistributeCard(final List participants) { final String joiningParticipant = participants.stream() - .filter(participant -> !DEALER.equals(participant.getName())) + .filter(participant -> !participant.isDealer()) .map(Participant::getName) .collect(Collectors.joining(JOINING_DELIMITER)); @@ -47,4 +47,10 @@ public void printFinalResult(final List participants) { } } + public void printGameJudgement(final GameJudgement gameJudgement) { + System.out.println("## 최종 승패"); + System.out.println(gameJudgement.fetchDealerJudge()); + gameJudgement.fetchParticipantJudge().forEach(System.out::println); + } + } From 2d7cb6d0d69577a2173fed009f345a0c817a716a Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 1 Jun 2024 15:37:43 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor:=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=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/card/{ => model}/Card.java | 2 +- src/main/java/card/{ => model}/CardDeck.java | 2 +- src/main/java/card/{ => model}/CardRank.java | 2 +- src/main/java/card/{ => model}/CardSuit.java | 2 +- src/main/java/game/controller/GameController.java | 2 +- src/main/java/participant/model/Participant.java | 2 +- src/main/java/view/OutputView.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/card/{ => model}/Card.java (88%) rename src/main/java/card/{ => model}/CardDeck.java (97%) rename src/main/java/card/{ => model}/CardRank.java (96%) rename src/main/java/card/{ => model}/CardSuit.java (92%) diff --git a/src/main/java/card/Card.java b/src/main/java/card/model/Card.java similarity index 88% rename from src/main/java/card/Card.java rename to src/main/java/card/model/Card.java index 4e725bb7390..9726c82954d 100644 --- a/src/main/java/card/Card.java +++ b/src/main/java/card/model/Card.java @@ -1,4 +1,4 @@ -package card; +package card.model; public record Card ( CardSuit suit, diff --git a/src/main/java/card/CardDeck.java b/src/main/java/card/model/CardDeck.java similarity index 97% rename from src/main/java/card/CardDeck.java rename to src/main/java/card/model/CardDeck.java index 3bdb421eba3..4b8a105ee03 100644 --- a/src/main/java/card/CardDeck.java +++ b/src/main/java/card/model/CardDeck.java @@ -1,4 +1,4 @@ -package card; +package card.model; import java.util.*; diff --git a/src/main/java/card/CardRank.java b/src/main/java/card/model/CardRank.java similarity index 96% rename from src/main/java/card/CardRank.java rename to src/main/java/card/model/CardRank.java index 78639491f49..85caed01835 100644 --- a/src/main/java/card/CardRank.java +++ b/src/main/java/card/model/CardRank.java @@ -1,4 +1,4 @@ -package card; +package card.model; public enum CardRank { ACE(1, "A"), diff --git a/src/main/java/card/CardSuit.java b/src/main/java/card/model/CardSuit.java similarity index 92% rename from src/main/java/card/CardSuit.java rename to src/main/java/card/model/CardSuit.java index f3aa020e2f6..f4928cc61c8 100644 --- a/src/main/java/card/CardSuit.java +++ b/src/main/java/card/model/CardSuit.java @@ -1,4 +1,4 @@ -package card; +package card.model; public enum CardSuit { CLOVER("클로버"), diff --git a/src/main/java/game/controller/GameController.java b/src/main/java/game/controller/GameController.java index 21569c23c1b..83d7104187d 100644 --- a/src/main/java/game/controller/GameController.java +++ b/src/main/java/game/controller/GameController.java @@ -1,6 +1,6 @@ package game.controller; -import card.CardDeck; +import card.model.CardDeck; import card.controller.DrawCardRequest; import game.domain.GameJudgement; import participant.controller.ParticipantRequest; diff --git a/src/main/java/participant/model/Participant.java b/src/main/java/participant/model/Participant.java index 6fe30087f22..9c3898dc85d 100644 --- a/src/main/java/participant/model/Participant.java +++ b/src/main/java/participant/model/Participant.java @@ -1,6 +1,6 @@ package participant.model; -import card.Card; +import card.model.Card; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index a1d942bf69c..2af930b9fab 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,6 +1,6 @@ package view; -import card.Card; +import card.model.Card; import game.domain.GameJudgement; import participant.model.Participant; From a1efa103ba2022b44ffa63f69b91c80d2269c71a Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 1 Jun 2024 16:13:17 +0900 Subject: [PATCH 14/15] =?UTF-8?q?test:=20Output=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/view/IOTest.java | 25 ++++++ src/test/java/view/OutputViewTest.java | 119 +++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/test/java/view/IOTest.java create mode 100644 src/test/java/view/OutputViewTest.java diff --git a/src/test/java/view/IOTest.java b/src/test/java/view/IOTest.java new file mode 100644 index 00000000000..a09654339c1 --- /dev/null +++ b/src/test/java/view/IOTest.java @@ -0,0 +1,25 @@ +package view; + +import org.junit.jupiter.api.BeforeEach; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +public abstract class IOTest { + private ByteArrayOutputStream byteArrayOutputStream; + + protected void systemIn(final String input) { + System.setIn(new ByteArrayInputStream(input.getBytes())); + } + + @BeforeEach + void setUp() { + byteArrayOutputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(byteArrayOutputStream)); + } + + protected String fetchOutput() { + return byteArrayOutputStream.toString(); + } +} diff --git a/src/test/java/view/OutputViewTest.java b/src/test/java/view/OutputViewTest.java new file mode 100644 index 00000000000..40e5718e500 --- /dev/null +++ b/src/test/java/view/OutputViewTest.java @@ -0,0 +1,119 @@ +package view; + +import card.model.Card; +import card.model.CardRank; +import card.model.CardSuit; +import game.domain.GameJudgement; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import participant.model.Participant; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +public class OutputViewTest extends IOTest { + + @Test + void 게임_참가자에게_최초_카드_분배한다는_메시지_출력_테스트() { + OutputView sut = new OutputView(); + + sut.firstDistributeCard(createParticipants(List.of("딜러", "pobi"))); + + assertThat(fetchOutput()).contains("딜러와 pobi에게 2장을 나누었습니다."); + } + + @ParameterizedTest + @MethodSource("provideCard") + void 참가자들의_현재_카드_상황_메시지_출력_테스트(String name, List dealerCards, List participantCards) { + List participants = createParticipants(List.of("딜러", name)); + dealerCards.forEach(card -> participants.get(0).addCard(card)); + participantCards.forEach(card -> participants.get(1).addCard(card)); + + OutputView sut = new OutputView(); + + String dealerCardJoining = dealerCards.stream() + .map(Card::toString) + .collect(Collectors.joining(", ")); + + String participantCardJoining = participantCards.stream() + .map(Card::toString) + .collect(Collectors.joining(", ")); + + sut.printParticipantsCard(participants); + + assertAll( + () -> assertThat(fetchOutput()).contains("딜러카드: %s".formatted(dealerCardJoining)), + () -> assertThat(fetchOutput()).contains("%s카드: %s".formatted(name, participantCardJoining)) + ); + } + + @ParameterizedTest + @MethodSource("provideCard") + void 최종_카드의_점수_현황_메시지_출력_테스트(String name, List dealerCards, List participantCards) { + List participants = createParticipants(List.of("딜러", name)); + Participant dealer = participants.get(0); + Participant participant = participants.get(1); + + dealerCards.forEach(dealer::addCard); + participantCards.forEach(participant::addCard); + + OutputView sut = new OutputView(); + + String dealerCardJoining = dealerCards.stream() + .map(Card::toString) + .collect(Collectors.joining(", ")); + + String participantCardJoining = participantCards.stream() + .map(Card::toString) + .collect(Collectors.joining(", ")); + + sut.printFinalResult(participants); + + assertAll( + () -> assertThat(fetchOutput()).contains("딜러 카드: %s - 결과: %d".formatted(dealerCardJoining, dealer.calculateCurrentScore())), + () -> assertThat(fetchOutput()).contains("%s 카드: %s - 결과: %d".formatted(name, participantCardJoining, participant.calculateCurrentScore())) + ); + } + + @ParameterizedTest + @MethodSource("provideCard") + void 최종_승패_판정_메시지_출력_테스트(String name, List dealerCards, List participantCards) { + List participants = createParticipants(List.of("딜러", name)); + Participant dealer = participants.get(0); + Participant participant = participants.get(1); + + dealerCards.forEach(dealer::addCard); + participantCards.forEach(participant::addCard); + + OutputView sut = new OutputView(); + + sut.printGameJudgement(new GameJudgement(participants)); + + assertThat(fetchOutput()).contains("%s: 승".formatted(name)); + } + + private List createParticipants(final List names) { + return names.stream() + .map(Participant::new) + .toList(); + } + + private static Stream provideCard() { + return Stream.of( + Arguments.of("pobi", + List.of(new Card(CardSuit.CLOVER, CardRank.TWO), new Card(CardSuit.CLOVER, CardRank.FIVE)), + List.of(new Card(CardSuit.CLOVER, CardRank.NINE), new Card(CardSuit.CLOVER, CardRank.QUEEN)) + ), + Arguments.of("pobi", + List.of(new Card(CardSuit.HEART, CardRank.NINE), new Card(CardSuit.HEART, CardRank.EIGHT)), + List.of(new Card(CardSuit.HEART, CardRank.JACK), new Card(CardSuit.HEART, CardRank.ACE)) + ) + ); + } +} From b37874e08a1c76ede910c0fac718a6ce85de212a Mon Sep 17 00:00:00 2001 From: lgm1007 Date: Sat, 1 Jun 2024 16:21:47 +0900 Subject: [PATCH 15/15] =?UTF-8?q?test:=20Participant=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/ParticipantTest.java | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/java/model/ParticipantTest.java diff --git a/src/test/java/model/ParticipantTest.java b/src/test/java/model/ParticipantTest.java new file mode 100644 index 00000000000..83cb0e38418 --- /dev/null +++ b/src/test/java/model/ParticipantTest.java @@ -0,0 +1,49 @@ +package model; + +import card.model.Card; +import card.model.CardRank; +import card.model.CardSuit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import participant.model.Participant; + +import java.util.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class ParticipantTest { + + @Test + void 참가자가_딜러인지_확인하기() { + Participant sut = new Participant("딜러"); + assertThat(sut.isDealer()).isTrue(); + } + + @ParameterizedTest + @MethodSource("provideCard") + void 참가자의_현재_카드_점수_합산(List cards) { + Participant sut = new Participant("name"); + cards.forEach(sut::addCard); + + assertThat(sut.calculateCurrentScore()).isEqualTo(21); + } + + @ParameterizedTest + @MethodSource("provideCard") + void 참가자의_현재_카드_점수_합산이_오버되었는지_확인하기(List cards) { + Participant sut = new Participant("name"); + cards.forEach(sut::addCard); + + assertThat(sut.isOverWinningMaxScore()).isFalse(); + } + + private static Stream provideCard() { + return Stream.of( + Arguments.of(List.of(new Card(CardSuit.CLOVER, CardRank.ACE), new Card(CardSuit.CLOVER, CardRank.JACK))), + Arguments.of(List.of(new Card(CardSuit.HEART, CardRank.ACE), new Card(CardSuit.SPADE, CardRank.ACE), new Card(CardSuit.DIAMOND, CardRank.KING), new Card(CardSuit.DIAMOND, CardRank.NINE))) + ); + } +}