From 6f92f8fcfa1e2f8582a6353b096f530428ae1067 Mon Sep 17 00:00:00 2001 From: Redddy <78539407+reddevilmidzy@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:58:44 +0900 Subject: [PATCH 01/40] =?UTF-8?q?[1=EB=8B=A8=EA=B3=84=20-=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=EC=9E=AD=20=EA=B2=8C=EC=9E=84=20=EC=8B=A4=ED=96=89]?= =?UTF-8?q?=20=EB=A0=88=EB=94=94(=EC=B5=9C=EB=8F=99=EA=B7=BC)=20=EB=AF=B8?= =?UTF-8?q?=EC=85=98=20=EC=A0=9C=EC=B6=9C=ED=95=A9=EB=8B=88=EB=8B=A4.=20(#?= =?UTF-8?q?642)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: 기능 요구 사항 작성 * test: 카드 합 구하기 * feat: 카드 합 구하기 * chore: 패키지 변경 * feat: 참여자 생성 기능 구현 * feat: null 이나 공백인 경우 예외가 발생 기능 구현 * feat: 참여자 이름이 중복시 예외 발생 기능 구현 * feat: 총 참여자의 수는 2이상 8이하가 아닐시 예외 발생 기능 구현 * feat: 카드를 추가하는 기능 구현 * feat: Player가 Packet을 필드로 갖도록 구현 * feat: CardDeck 생성 기능 구현 * test: 플레이어에게 카드 2장을 나눠주는 기능 구현 * refactor: 리스트에서 스택으로 변경 * feat: 참여자에게 카드를 2장씩 분배하는 기능 구현 * feat: 딜러가 카드 2장을 분해하다. * refactor: 스택에서 덱으로 변경 * fix: CardNumber ONE 제거, TEN으로 추가 * feat: 카드 내의 ACE 가 포함된 경우 합이 21이하이면 에이스는 11로 계산 기능 구현 * feat: 카드 합 계산시 ACE 고려하는 로직 추가 * refactor: Packet 클래스 이름을 Hands로 변경 * feat: 참여자의 대답이 y, n 가 아닐시 예외가 발생한다. * feat: 참여자 이름 입력받는 기능 구현 * feat: 플레이어의 시작 카드 출력 기능 구현 * feat: 딜러 카드 출력하는 기능 구현 * docs: 완료한 기능 체크 * feat: answer에 따라 카드를 추가 기능 구현 * refactor: Dealer 필드에서 Players 제거 * feat: 추가된 카드 출력하는 기능 구현 * style: 사용하지 않는 메서드 삭제 * feat: 참여자의 대답이 y일시 한번 더 deal 기능 구현 * feat: 변경된 카드가 있을 경우 출력하는 기능 구현 * feat: 딜러의 카드가 17 이상이 될때까지 카드 받는 기능 구현 * feat: 딜러가 카드를 받을 때 메시지 출력기능 구현 * feat: 모든 참여자의 카드의 합을 출력하는 기능 구현 * feat: hands의 승패 판단 기능 구현 * feat: 참여자의 승패 확인 기능 구현 * style: '플레이어'를 '참여자'로 변경 * fix: 컴파일 에러 수정 * feat: 딜러의 승패를 확인 기능 구현 * docs: 구현해야 할 기능 목록 추가 * feat: 최종 결과 출력하는 기능 구현 * feat: 참가자의 카드의 합이 21을 초과하면 BUST 메시지 출력 기능 구현 * feat: 모든 참여자가 버스트라면 딜러는 딜하지 않는 기능 구현 * feat: 무승부 기능 구현 * fix: 딜러가 버스트일때 참여자가 버스트가 아니면 WIN * feat: 블랙잭 시 메시지 출력후 카드 더 받지 않는 기능 구현 * docs: 블랙잭 규칙 추가 * refactor: 'CardNumber'를 'Rank'로 변경, 'CardShape'를 'Shape'로 변경 및 card 패키지 생성 * refactor: players 관련 메서드의 파라미터 및 변수명 변경 * refactor: 메서드 삭제 및 이름 변경 * refactor: Player 클래스 메서드명 및 순서 변경 * refactor: CardDeck의 generate메서드 스트림 활용 * refactor: Dealer 초기 카드 넘버 상수명 변경 * refactor: Dealer가 Participant 상속받도록 변경 * docs: 기능 요구 사항 수정 * fix: 카드의 사이즈가 같을 때 21에 가까운 카드 합이 이기는 기능 수정 * refactor: Participant 추상클래스 생성 * refactor: Dto의 이름 변경 및 정적 팩터리 메서드 명 변경 * refactor: getCardNames 메서드 동작 로직을 hands 안으로 이동 * refactor: Participant 생성자 접근제한자 변경 및 메서드 정렬 * refactor: Dealer 의 deal을 Dealer 클래스로 이동 * refactor: controller 인덴트 줄이기 및 메서드 분리 * refactor: cardDeckTest 클래스 접근제한자 변경 * refactor: null과 blank 테스트 코드 메서드 분리 * refactor: 중복되는 테스트코드 변수 분리 * style: static 변수 import * refactor: 테스트 코드내에 중복되는 변수를 필드로 선언 * refactor: outputView FORM 상수static 으로 변경 * refactor: 사용하지 않는 필드 및 메서드 삭제 * style: 코드 정렬 * refactor: HandsTest 중복되는 테스트코드 분리 * refactor: ParticipantDto 레코드로 변경 * refactor: Hands 메서드 분리 * refactor: calculateResult 메서드 인덴트 줄이기 * docs: 리팩터링 목록 추가 * refactor: createEmptyPacket 메서드명 createEmptyHands로 수정 * feat: 카드덱이 비었을때 꺼낸 경우 예외 발생 * refactor: Name 객체 포장 * refactor: 승패무 판단을 Result의 책임으로 이동 (재미있게 BiPredicate 활용) * refactor: Game 클래스 삭제 및 책임 분리 * refactor: TestFixture 생성 * style: import 문 순서 변경 * refactor: 테스트코드 변수명 변경 및 테스트 추가 * fix: LinkedHashMap으로 변경하여 참여자 순서 유지 * refactor: System.out.println 대신 %n과 System.lineSeparator 사용 * docs: 리팩터링 목록 수정 * feat: 참가자의 이름에 딜러가 사용될 시 예외 발생 기능 구현 * refactor: isHit 메서드 생성 * docs: 리팩터링 목록 수정 * style: 메서드 위치 변경 * refactor: controller 메서드 추출 * chore: 패키지 정리 * docs: 리팩터링 목록 추가 * feat: 예외 시 재입력 기능 구현 * feat: 커스텀 예외 구현 * refactor: Participant 추상 메서드 사용 * refactor: InvalidPlayerName 예외 클래스 이름 변경 * refactor: 카드 생성 책임을 Card로 변경 및 카드를 캐시하여 가져오는 기능 구현 * docs: 리팩터링 목록 수정 * refactor: cardDeck 생성 책임 위치 변경 --------- Co-authored-by: jinwoo22 --- docs/README.md | 90 +++++++++++ src/main/java/application/Application.java | 18 +++ src/main/java/constants/ErrorCode.java | 15 ++ .../java/controller/BlackJackController.java | 92 ++++++++++++ src/main/java/controller/InputController.java | 55 +++++++ src/main/java/domain/Answer.java | 28 ++++ src/main/java/domain/Result.java | 55 +++++++ src/main/java/domain/card/Card.java | 63 ++++++++ src/main/java/domain/card/CardDeck.java | 39 +++++ src/main/java/domain/card/Rank.java | 38 +++++ src/main/java/domain/card/Shape.java | 19 +++ src/main/java/domain/participant/Dealer.java | 79 ++++++++++ src/main/java/domain/participant/Hands.java | 88 +++++++++++ src/main/java/domain/participant/Name.java | 52 +++++++ .../java/domain/participant/Participant.java | 72 +++++++++ src/main/java/domain/participant/Player.java | 25 +++ src/main/java/domain/participant/Players.java | 73 +++++++++ src/main/java/dto/DealerHandsDto.java | 22 +++ src/main/java/dto/ParticipantDto.java | 11 ++ src/main/java/dto/ParticipantsDto.java | 42 ++++++ src/main/java/exception/CustomException.java | 16 ++ .../DuplicatePlayerNameException.java | 10 ++ .../exception/InvalidCommandException.java | 10 ++ .../java/exception/InvalidInputException.java | 10 ++ .../exception/InvalidPlayerNameException.java | 10 ++ .../InvalidPlayersSizeException.java | 10 ++ .../exception/InvalidSeparatorException.java | 10 ++ .../MessageDoesNotExistException.java | 10 ++ .../java/exception/NoMoreCardException.java | 10 ++ .../ReservedPlayerNameException.java | 10 ++ src/main/java/view/InputView.java | 58 +++++++ src/main/java/view/OutputView.java | 94 ++++++++++++ .../java/view/message/ErrorCodeMessage.java | 49 ++++++ src/test/java/domain/AnswerTest.java | 18 +++ src/test/java/domain/CardTest.java | 20 +++ src/test/java/domain/DealerTest.java | 105 +++++++++++++ src/test/java/domain/HandsTest.java | 84 +++++++++++ src/test/java/domain/HandsTestFixture.java | 49 ++++++ src/test/java/domain/NameTest.java | 28 ++++ src/test/java/domain/PlayerTest.java | 28 ++++ src/test/java/domain/PlayersTest.java | 142 ++++++++++++++++++ src/test/java/domain/ResultTest.java | 48 ++++++ src/test/java/domain/card/CardDeckTest.java | 39 +++++ 43 files changed, 1844 insertions(+) create mode 100644 docs/README.md create mode 100644 src/main/java/application/Application.java create mode 100644 src/main/java/constants/ErrorCode.java create mode 100644 src/main/java/controller/BlackJackController.java create mode 100644 src/main/java/controller/InputController.java create mode 100644 src/main/java/domain/Answer.java create mode 100644 src/main/java/domain/Result.java create mode 100644 src/main/java/domain/card/Card.java create mode 100644 src/main/java/domain/card/CardDeck.java create mode 100644 src/main/java/domain/card/Rank.java create mode 100644 src/main/java/domain/card/Shape.java create mode 100644 src/main/java/domain/participant/Dealer.java create mode 100644 src/main/java/domain/participant/Hands.java create mode 100644 src/main/java/domain/participant/Name.java create mode 100644 src/main/java/domain/participant/Participant.java create mode 100644 src/main/java/domain/participant/Player.java create mode 100644 src/main/java/domain/participant/Players.java create mode 100644 src/main/java/dto/DealerHandsDto.java create mode 100644 src/main/java/dto/ParticipantDto.java create mode 100644 src/main/java/dto/ParticipantsDto.java create mode 100644 src/main/java/exception/CustomException.java create mode 100644 src/main/java/exception/DuplicatePlayerNameException.java create mode 100644 src/main/java/exception/InvalidCommandException.java create mode 100644 src/main/java/exception/InvalidInputException.java create mode 100644 src/main/java/exception/InvalidPlayerNameException.java create mode 100644 src/main/java/exception/InvalidPlayersSizeException.java create mode 100644 src/main/java/exception/InvalidSeparatorException.java create mode 100644 src/main/java/exception/MessageDoesNotExistException.java create mode 100644 src/main/java/exception/NoMoreCardException.java create mode 100644 src/main/java/exception/ReservedPlayerNameException.java create mode 100644 src/main/java/view/InputView.java create mode 100644 src/main/java/view/OutputView.java create mode 100644 src/main/java/view/message/ErrorCodeMessage.java create mode 100644 src/test/java/domain/AnswerTest.java create mode 100644 src/test/java/domain/CardTest.java create mode 100644 src/test/java/domain/DealerTest.java create mode 100644 src/test/java/domain/HandsTest.java create mode 100644 src/test/java/domain/HandsTestFixture.java create mode 100644 src/test/java/domain/NameTest.java create mode 100644 src/test/java/domain/PlayerTest.java create mode 100644 src/test/java/domain/PlayersTest.java create mode 100644 src/test/java/domain/ResultTest.java create mode 100644 src/test/java/domain/card/CardDeckTest.java diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..b819b8e049b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,90 @@ +# 블랙잭 규칙 + +## 참여자 + +**승** + +* (딜러 카드 합 < 참여자 카드 합) && 참여자가 버스트가 아닌 경우 +* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 > 참여자 카드 수) && 참여자가 버스트가 아닌 경우 +* 딜러가 버스트인 경우 && 참여자가 버스트가 아닌 경우 + +**무** + +* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 == 참여자 카드 수) && 참여자가 버스트가 아닌 경우 + +**패** + +* 참여자가 버스트인 경우 +* (딜러 카드 합 > 참여자 카드 합) + +
+ +# 기능 요구 사항 + +* [x] 참여자 이름 입력 받는다. + * [x] 양 끝 공백을 제거한다. + * [x] 참여자는 쉼표(,)로 구분한다. + * [x] null 이나 공백인 경우 예외가 발생한다. + * [x] 쉼표로 시작시 예외가 발생한다. ex) ,pobi,jason + * [x] 쉼표로 끝날시 예외가 발생한다. ex) pobi,jason, + * [x] 쉼표가 연속으로 올시 예외가 발생한다. ex) pobi,,jason + * [x] 참여자 이름이 중복시 예외가 발생한다. +* [x] 총 참여자의 수는 2이상 8이하여야 한다. + +
+ +* [x] 딜러가 카드 2장을 분배하다. + * [x] 카드는 총 6벌을 둔다. (52 * 6) +* [x] 딜러의 카드를 출력한다. (1장) +* [x] 참여자의 카드를 출력한다. (2장) + +
+ +* [x] 참여자는 hit(y) / stay(n)를 선택한다. + * [x] y, n 가 아닐시 예외가 발생한다. +* [x] 참여자가 hit을 하는 경우 현재 가지고 있는 카드를 출력한다. +* [x] 참여자가 hit을 한 적 없이 stay를 하는 경우 현재 가지고 있는 카드를 출력한다. +* [x] 카드 합이 블랙잭인 경우 블랙잭 메시지를 출력한다. +* [x] 카드 합이 21 초과시 버스트 메시지를 출력한다. + +
+ +* [x] 딜러의 카드의 합을 계산한다. +* [x] 카드 내의 ACE 가 포함된 경우 + * ACE: 11 + * 11로 했을 때 카드의 합이 21을 초과한 경우 1로 계산 +* [x] 17 이상이 될때까지 카드를 받는다. + +
+ +* [x] 모든 참여자의 카드의 합을 계산한다. +* [x] 딜러의 승패무를 확인한다. +* [x] 참여자의 승패무를 확인한다. +* [x] 게임 결과를 출력한다. + +--- + +## 리팩터링 목록 + +~~추상 클래스 활용~~ + +* [x] 카드덱이 비었을때 꺼낸 경우 예외 발생 +* [x] createEmptyPacket 메서드명 수정 +* [x] 참가자의 이름 딜러 불가 +* [x] Name 객체 포장하기 +* [x] Result 함수형 프로그래밍 사용 +* [x] TestFixture 사용 +* [x] 패키지 정리 +* [x] 메서드 컨벤션 작성 및 확인 +* [x] final 컨벤션 통일 +* [x] CardDeck 생성자 닫기 + +
+ +* [x] 예외 시 재입력 기능 +* [x] 예외 메시지 상수화 + * 커스텀 예외 구현 +* [x] CardDeck 웨어하우스로 바라보기 +* [ ] ~~컨트롤러 메서드 수정하기~~ +* [x] ~~Participant 추상 클래스 대신 클래스로 변경하기~~ + * 추상 클래스를 유지하고 추상 메서드 추가 diff --git a/src/main/java/application/Application.java b/src/main/java/application/Application.java new file mode 100644 index 00000000000..2d98d55bfcb --- /dev/null +++ b/src/main/java/application/Application.java @@ -0,0 +1,18 @@ +package application; + +import controller.BlackJackController; +import controller.InputController; +import java.util.Scanner; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + final Scanner scanner = new Scanner(System.in); + final InputView inputView = new InputView(scanner); + final OutputView outputView = new OutputView(); + final InputController inputController = new InputController(inputView, outputView); + final BlackJackController blackJackController = new BlackJackController(inputController, outputView); + blackJackController.run(); + } +} diff --git a/src/main/java/constants/ErrorCode.java b/src/main/java/constants/ErrorCode.java new file mode 100644 index 00000000000..d6278bf1c5a --- /dev/null +++ b/src/main/java/constants/ErrorCode.java @@ -0,0 +1,15 @@ +package constants; + +public enum ErrorCode { + + NOT_EXIST_MESSAGE, + INVALID_SEPARATOR, + INVALID_INPUT, + INVALID_SIZE, + DUPLICATE_NAME, + RESERVED_NAME, + BLANK_VALUE, + EMPTY_CARD, + INVALID_COMMAND, + ; +} diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java new file mode 100644 index 00000000000..e44b17ed968 --- /dev/null +++ b/src/main/java/controller/BlackJackController.java @@ -0,0 +1,92 @@ +package controller; + +import domain.Answer; +import domain.participant.Dealer; +import domain.participant.Player; +import domain.participant.Players; +import dto.DealerHandsDto; +import dto.ParticipantDto; +import dto.ParticipantsDto; +import view.OutputView; + +public class BlackJackController { + + private final InputController inputController; + private final OutputView outputView; + + + public BlackJackController(final InputController inputController, final OutputView outputView) { + this.inputController = inputController; + this.outputView = outputView; + } + + public void run() { + final Players players = inputController.getPlayers(); + final Dealer dealer = new Dealer(); + + initHands(players, dealer); + dealWithPlayers(players, dealer); + + if (!players.isAllBust()) { + dealer.deal(); + printDealerTurnMessage(dealer.countAddedHands()); + } + + printFinalResult(players, dealer); + } + + private void printDealerTurnMessage(final int turn) { + for (int i = 0; i < turn; i++) { + outputView.printDealerTurnMessage(); + } + } + + private void dealWithPlayers(final Players players, final Dealer dealer) { + for (Player player : players.getPlayers()) { + deal(player, dealer); + } + } + + private void initHands(final Players players, final Dealer dealer) { + dealer.initHands(players); + outputView.printStartDeal(DealerHandsDto.from(dealer), ParticipantsDto.of(players)); + } + + private void printFinalResult(final Players players, final Dealer dealer) { + outputView.printHandsResult(ParticipantsDto.of(dealer, players)); + outputView.printGameResult(dealer.getDealerResult(players), players.getPlayersResult(dealer)); + } + + private void deal(final Player player, final Dealer dealer) { + boolean handsChanged = false; + boolean turnEnded = false; + + while (!turnEnded) { + final Answer answer = inputController.getAnswer(player.getName()); + dealer.deal(player, answer); + + printHandsIfRequired(player, handsChanged, answer); + + handsChanged = true; + turnEnded = isTurnEnded(player, answer); + } + } + + private void printHandsIfRequired(final Player player, final boolean handsChanged, final Answer answer) { + if (shouldShowHands(handsChanged, answer)) { + outputView.printHands(ParticipantDto.from(player)); + } + } + + private boolean isTurnEnded(final Player player, final Answer answer) { + if (player.canDeal()) { + return !answer.isHit(); + } + outputView.printDealEndMessage(player.isBust()); + return true; + } + + private boolean shouldShowHands(final boolean handsChanged, final Answer answer) { + return answer.isHit() || !handsChanged; + } +} diff --git a/src/main/java/controller/InputController.java b/src/main/java/controller/InputController.java new file mode 100644 index 00000000000..4f9bb5df966 --- /dev/null +++ b/src/main/java/controller/InputController.java @@ -0,0 +1,55 @@ +package controller; + +import domain.Answer; +import domain.participant.Players; +import exception.CustomException; +import java.util.List; +import view.InputView; +import view.OutputView; + +public class InputController { + + private final InputView inputView; + private final OutputView outputView; + + public InputController(final InputView inputView, final OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public Players getPlayers() { + Players players; + do { + players = readPlayers(); + } while (players == null); + return players; + } + + public Answer getAnswer(String name) { + Answer answer; + do { + answer = readAnswer(name); + } while (answer == null); + return answer; + } + + private Players readPlayers() { + try { + List rawNames = inputView.readNames(); + return Players.from(rawNames); + } catch (CustomException exception) { + outputView.printException(exception.getErrorCode()); + return null; + } + } + + private Answer readAnswer(String name) { + try { + String value = inputView.readAnswer(name); + return Answer.from(value); + } catch (CustomException exception) { + outputView.printException(exception.getErrorCode()); + return null; + } + } +} diff --git a/src/main/java/domain/Answer.java b/src/main/java/domain/Answer.java new file mode 100644 index 00000000000..dc53bfc33a4 --- /dev/null +++ b/src/main/java/domain/Answer.java @@ -0,0 +1,28 @@ +package domain; + +import constants.ErrorCode; +import exception.InvalidCommandException; +import java.util.Arrays; + +public enum Answer { + + HIT("y"), + STAY("n"); + + private final String value; + + Answer(final String value) { + this.value = value; + } + + public static Answer from(final String value) { + return Arrays.stream(Answer.values()) + .filter(answer -> answer.value.equals(value)) + .findFirst() + .orElseThrow(() -> new InvalidCommandException(ErrorCode.INVALID_COMMAND)); + } + + public boolean isHit() { + return HIT.equals(this); + } +} diff --git a/src/main/java/domain/Result.java b/src/main/java/domain/Result.java new file mode 100644 index 00000000000..15cdb949940 --- /dev/null +++ b/src/main/java/domain/Result.java @@ -0,0 +1,55 @@ +package domain; + +import domain.participant.Hands; +import java.util.Arrays; +import java.util.function.BiPredicate; + +public enum Result { + + WIN("승", Result::winningCondition), + TIE("무", Result::tieCondition), + LOSE("패", Result::loseCondition); + + private final String value; + private final BiPredicate condition; + + Result(final String value, final BiPredicate condition) { + this.value = value; + this.condition = condition; + } + + public Result reverse() { + if (Result.WIN.equals(this)) { + return LOSE; + } + if (Result.LOSE.equals(this)) { + return WIN; + } + return TIE; + } + + public static Result calculateOf(final Hands hands, final Hands target) { + return Arrays.stream(Result.values()) + .filter(result -> result.condition.test(hands, target)) + .findFirst() + .orElseThrow(); + } + + private static boolean winningCondition(final Hands hands, final Hands target) { + return (!hands.isBust() && target.isBust()) + || (hands.sum() > target.sum() && !hands.isBust()) + || (hands.sum() == target.sum() && hands.size() < target.size() && !hands.isBust()); + } + + private static boolean tieCondition(final Hands hands, final Hands target) { + return hands.sum() == target.sum() && hands.size() == target.size() && !hands.isBust(); + } + + private static boolean loseCondition(final Hands hands, final Hands target) { + return hands.isBust() || hands.sum() < target.sum() || !target.isBust(); + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/domain/card/Card.java b/src/main/java/domain/card/Card.java new file mode 100644 index 00000000000..f32cdd138f5 --- /dev/null +++ b/src/main/java/domain/card/Card.java @@ -0,0 +1,63 @@ +package domain.card; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Card { + + private static final List CACHE = new ArrayList<>(); + + static { + for (Shape shape : Shape.values()) { + generateCard(shape); + } + } + + private final Rank rank; + private final Shape shape; + + public Card(final Rank rank, final Shape shape) { + this.rank = rank; + this.shape = shape; + } + + private static void generateCard(final Shape shape) { + for (Rank rank : Rank.values()) { + CACHE.add(new Card(rank, shape)); + } + } + + public static List values() { + return List.copyOf(CACHE); + } + + public boolean isAce() { + return rank.isAce(); + } + + public int getCardNumber() { + return rank.getValue(); + } + + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + if (!(target instanceof Card card)) { + return false; + } + return Objects.equals(rank, card.rank) && Objects.equals(shape, card.shape); + } + + @Override + public int hashCode() { + return Objects.hash(rank, shape); + } + + @Override + public String toString() { + return rank.getName() + shape.getName(); + } +} diff --git a/src/main/java/domain/card/CardDeck.java b/src/main/java/domain/card/CardDeck.java new file mode 100644 index 00000000000..90432e4fa5d --- /dev/null +++ b/src/main/java/domain/card/CardDeck.java @@ -0,0 +1,39 @@ +package domain.card; + +import constants.ErrorCode; +import exception.NoMoreCardException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; + +public class CardDeck { + + private final Deque cards; + + public CardDeck(final Deque cards) { + this.cards = cards; + } + + protected static CardDeck generate(int size) { + final List deck = new ArrayList<>(); + + for (int i = 0; i < size; i++) { + deck.addAll(Card.values()); + } + Collections.shuffle(deck); + return new CardDeck(new ArrayDeque<>(deck)); + } + + public Card pop() { + if (cards.isEmpty()) { + throw new NoMoreCardException(ErrorCode.EMPTY_CARD); + } + return cards.pop(); + } + + public int size() { + return cards.size(); + } +} diff --git a/src/main/java/domain/card/Rank.java b/src/main/java/domain/card/Rank.java new file mode 100644 index 00000000000..aa92ef34659 --- /dev/null +++ b/src/main/java/domain/card/Rank.java @@ -0,0 +1,38 @@ +package domain.card; + +public enum Rank { + + ACE("A", 1), + 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("J", 10), + QUEEN("Q", 10), + KING("K", 10); + + private final String name; + private final int value; + + Rank(final String name, final int value) { + this.name = name; + this.value = value; + } + + public boolean isAce() { + return this == ACE; + } + + public int getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/domain/card/Shape.java b/src/main/java/domain/card/Shape.java new file mode 100644 index 00000000000..093d73cfa8c --- /dev/null +++ b/src/main/java/domain/card/Shape.java @@ -0,0 +1,19 @@ +package domain.card; + +public enum Shape { + + SPADE("스페이드"), + HEART("하트"), + CLOVER("클로버"), + DIAMOND("다이아몬드"); + + private final String name; + + Shape(final String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java new file mode 100644 index 00000000000..08cc130792d --- /dev/null +++ b/src/main/java/domain/participant/Dealer.java @@ -0,0 +1,79 @@ +package domain.participant; + +import domain.Answer; +import domain.Result; +import domain.card.Card; +import domain.card.CardDeck; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +public class Dealer extends Participant { + + public static final int INIT_HANDS_SIZE = 2; + public static final int THRESHOLD = 16; + public static final int DECK_SIZE = 6; + public static final Name DEALER_NAME = new Name("딜러"); + + private final CardDeck cardDeck; + + public Dealer() { + super(DEALER_NAME, Hands.createEmptyHands()); + this.cardDeck = new CardDeck(generate()); + } + + public Dealer(final Hands hands) { + super(DEALER_NAME, hands); + this.cardDeck = new CardDeck(generate()); + } + + private static ArrayDeque generate() { + final List deck = new ArrayList<>(); + for (int i = 0; i < DECK_SIZE; i++) { + deck.addAll(Card.values()); + } + Collections.shuffle(deck); + return new ArrayDeque<>(deck); + } + + public void initHands(final Players players) { + for (int i = 0; i < INIT_HANDS_SIZE; i++) { + players.forEach(player -> player.add(cardDeck.pop())); + super.add(cardDeck.pop()); + } + } + + public void deal(final Player player, final Answer answer) { + if (answer.isHit()) { + player.add(cardDeck.pop()); + } + } + + public void deal() { + while (canDeal()) { + super.add(cardDeck.pop()); + } + } + + public int countAddedHands() { + return handsSize() - INIT_HANDS_SIZE; + } + + public Map getDealerResult(final Players players) { + Map dealerResult = new EnumMap<>(Result.class); + + for (Result value : players.getPlayersResult(this).values()) { + Result reversed = value.reverse(); + dealerResult.put(reversed, dealerResult.getOrDefault(reversed, 0) + 1); + } + return dealerResult; + } + + @Override + public boolean canDeal() { + return handsSum() <= THRESHOLD; + } +} diff --git a/src/main/java/domain/participant/Hands.java b/src/main/java/domain/participant/Hands.java new file mode 100644 index 00000000000..102d2966e86 --- /dev/null +++ b/src/main/java/domain/participant/Hands.java @@ -0,0 +1,88 @@ +package domain.participant; + +import domain.card.Card; +import domain.Result; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Hands { + + public static final int BLACK_JACK = 21; + private static final int EXTRA_ACE_VALUE = 10; + + private final List cards; + + public Hands(final List cards) { + this.cards = new ArrayList<>(cards); + } + + public static Hands createEmptyHands() { + return new Hands(new ArrayList<>()); + } + + public int sum() { + int total = cards.stream() + .mapToInt(Card::getCardNumber) + .sum(); + + return calculateTotalByAce(total); + } + + public void add(final Card card) { + cards.add(card); + } + + public boolean isBust() { + return sum() > BLACK_JACK; + } + + public boolean isBlackJack() { + return sum() == BLACK_JACK; + } + + private boolean hasAce() { + return cards.stream() + .anyMatch(Card::isAce); + } + + public int size() { + return cards.size(); + } + + public List getCards() { + return cards.stream() + .map(Card::toString) + .toList(); + } + + public Result calculateResult(final Hands target) { + return Result.calculateOf(this, target); + } + + private int calculateTotalByAce(final int total) { + if (hasAce() && total + EXTRA_ACE_VALUE <= BLACK_JACK) { + return total + EXTRA_ACE_VALUE; + } + + return total; + } + + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + + if (!(target instanceof Hands hands)) { + return false; + } + + return Objects.equals(cards, hands.cards); + } + + @Override + public int hashCode() { + return Objects.hash(cards); + } +} diff --git a/src/main/java/domain/participant/Name.java b/src/main/java/domain/participant/Name.java new file mode 100644 index 00000000000..ffb95b64dbb --- /dev/null +++ b/src/main/java/domain/participant/Name.java @@ -0,0 +1,52 @@ +package domain.participant; + +import constants.ErrorCode; +import exception.InvalidPlayerNameException; +import java.util.Objects; + +public class Name { + + private final String value; + + public Name(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String name) { + validateNull(name); + validateBlank(name); + } + + private void validateNull(final String name) { + if (name == null) { + throw new InvalidPlayerNameException(ErrorCode.BLANK_VALUE); + } + } + + private void validateBlank(final String name) { + if (name.isBlank()) { + throw new InvalidPlayerNameException(ErrorCode.BLANK_VALUE); + } + } + + public String getValue() { + return value; + } + + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + if (!(target instanceof Name name)) { + return false; + } + return Objects.equals(value, name.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } +} diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java new file mode 100644 index 00000000000..0bfa97b988b --- /dev/null +++ b/src/main/java/domain/participant/Participant.java @@ -0,0 +1,72 @@ +package domain.participant; + +import domain.Result; +import domain.card.Card; +import java.util.List; +import java.util.Objects; + +public abstract class Participant { + + private final Name name; + private final Hands hands; + + protected Participant(final Name name, final Hands hands) { + this.name = name; + this.hands = hands; + } + + public abstract boolean canDeal(); + + public void add(final Card card) { + hands.add(card); + } + + public boolean isBust() { + return hands.isBust(); + } + + //TODO 시작시에 블랙잭일 때 쓸거에용 + public boolean isBlackJack() { + return hands.isBlackJack(); + } + + public int handsSum() { + return hands.sum(); + } + + public int handsSize() { + return hands.size(); + } + + public Result calculateResult(final Participant participant) { + return hands.calculateResult(participant.getHands()); + } + + public List getCardNames() { + return hands.getCards(); + } + + public String getName() { + return name.getValue(); + } + + public Hands getHands() { + return hands; + } + + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + if (!(target instanceof Participant participant)) { + return false; + } + return Objects.equals(name, participant.name) && Objects.equals(hands, participant.hands); + } + + @Override + public int hashCode() { + return Objects.hash(name, hands); + } +} diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java new file mode 100644 index 00000000000..4674d6e99e9 --- /dev/null +++ b/src/main/java/domain/participant/Player.java @@ -0,0 +1,25 @@ +package domain.participant; + +import static domain.participant.Dealer.DEALER_NAME; + +import constants.ErrorCode; +import exception.ReservedPlayerNameException; + +public class Player extends Participant { + + public Player(final Name name, final Hands hands) { + super(name, hands); + validate(name); + } + + private void validate(final Name name) { + if (DEALER_NAME.equals(name)) { + throw new ReservedPlayerNameException(ErrorCode.RESERVED_NAME); + } + } + + @Override + public boolean canDeal() { + return handsSum() <= Hands.BLACK_JACK; + } +} diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java new file mode 100644 index 00000000000..b007d830b9d --- /dev/null +++ b/src/main/java/domain/participant/Players.java @@ -0,0 +1,73 @@ +package domain.participant; + +import constants.ErrorCode; +import domain.Result; +import exception.DuplicatePlayerNameException; +import exception.InvalidPlayersSizeException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +public class Players { + + private static final int MIN_SIZE = 2; + private static final int MAX_SIZE = 8; + + private final List names; + + public Players(final List names) { + this.names = names; + } + + public static Players from(final List names) { + validate(names); + return new Players(mapToPlayers(names)); + } + + public void forEach(Consumer action) { + names.forEach(action); + } + + public boolean isAllBust() { + return names.stream() + .allMatch(Player::isBust); + } + + public Map getPlayersResult(final Dealer dealer) { + final Map result = new LinkedHashMap<>(); + for (Player name : names) { + result.put(name, name.calculateResult(dealer)); + } + return result; + } + + private static List mapToPlayers(final List names) { + return names.stream() + .map(String::trim) + .map(name -> new Player(new Name(name), Hands.createEmptyHands())) + .toList(); + } + + private static void validate(final List names) { + validateSize(names); + validateDuplicate(names); + } + + private static void validateSize(final List names) { + if (names.size() < MIN_SIZE || MAX_SIZE < names.size()) { + throw new InvalidPlayersSizeException(ErrorCode.INVALID_SIZE); + } + } + + private static void validateDuplicate(final List names) { + if (names.size() != Set.copyOf(names).size()) { + throw new DuplicatePlayerNameException(ErrorCode.DUPLICATE_NAME); + } + } + + public List getPlayers() { + return names; + } +} diff --git a/src/main/java/dto/DealerHandsDto.java b/src/main/java/dto/DealerHandsDto.java new file mode 100644 index 00000000000..dae38677154 --- /dev/null +++ b/src/main/java/dto/DealerHandsDto.java @@ -0,0 +1,22 @@ +package dto; + +import domain.participant.Participant; +import java.util.List; + +public class DealerHandsDto { + + private final String displayedCard; + + private DealerHandsDto(final String displayedCard) { + this.displayedCard = displayedCard; + } + + public static DealerHandsDto from(final Participant dealer) { + List cards = dealer.getCardNames(); + return new DealerHandsDto(cards.get(0)); + } + + public String getDisplayedCard() { + return displayedCard; + } +} diff --git a/src/main/java/dto/ParticipantDto.java b/src/main/java/dto/ParticipantDto.java new file mode 100644 index 00000000000..795bae6b575 --- /dev/null +++ b/src/main/java/dto/ParticipantDto.java @@ -0,0 +1,11 @@ +package dto; + +import domain.participant.Participant; +import java.util.List; + +public record ParticipantDto(String name, List cards, int totalSum) { + + public static ParticipantDto from(final Participant player) { + return new ParticipantDto(player.getName(), player.getCardNames(), player.handsSum()); + } +} diff --git a/src/main/java/dto/ParticipantsDto.java b/src/main/java/dto/ParticipantsDto.java new file mode 100644 index 00000000000..c7a2984c4ab --- /dev/null +++ b/src/main/java/dto/ParticipantsDto.java @@ -0,0 +1,42 @@ +package dto; + +import domain.participant.Participant; +import domain.participant.Players; +import java.util.ArrayList; +import java.util.List; + +public class ParticipantsDto { + + private final List players; + + private ParticipantsDto(final List players) { + this.players = players; + } + + public static ParticipantsDto of(final Participant dealer, final Players players) { + List result = new ArrayList<>(); + result.add(ParticipantDto.from(dealer)); + for (Participant player : players.getPlayers()) { + result.add(ParticipantDto.from(player)); + } + return new ParticipantsDto(result); + } + + public static ParticipantsDto of(final Players players) { + List result = new ArrayList<>(); + for (Participant player : players.getPlayers()) { + result.add(ParticipantDto.from(player)); + } + return new ParticipantsDto(result); + } + + public List getNames() { + return players.stream() + .map(ParticipantDto::name) + .toList(); + } + + public List getPlayers() { + return players; + } +} diff --git a/src/main/java/exception/CustomException.java b/src/main/java/exception/CustomException.java new file mode 100644 index 00000000000..fa189d08d1f --- /dev/null +++ b/src/main/java/exception/CustomException.java @@ -0,0 +1,16 @@ +package exception; + +import constants.ErrorCode; + +public class CustomException extends RuntimeException { + + private final ErrorCode errorCode; + + public CustomException(final ErrorCode errorCode) { + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} diff --git a/src/main/java/exception/DuplicatePlayerNameException.java b/src/main/java/exception/DuplicatePlayerNameException.java new file mode 100644 index 00000000000..8eb7bb2b5ac --- /dev/null +++ b/src/main/java/exception/DuplicatePlayerNameException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class DuplicatePlayerNameException extends CustomException { + + public DuplicatePlayerNameException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/InvalidCommandException.java b/src/main/java/exception/InvalidCommandException.java new file mode 100644 index 00000000000..ea970cc7419 --- /dev/null +++ b/src/main/java/exception/InvalidCommandException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidCommandException extends CustomException { + + public InvalidCommandException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/InvalidInputException.java b/src/main/java/exception/InvalidInputException.java new file mode 100644 index 00000000000..1ade7a5b234 --- /dev/null +++ b/src/main/java/exception/InvalidInputException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidInputException extends CustomException { + + public InvalidInputException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/InvalidPlayerNameException.java b/src/main/java/exception/InvalidPlayerNameException.java new file mode 100644 index 00000000000..2bf217ea37e --- /dev/null +++ b/src/main/java/exception/InvalidPlayerNameException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidPlayerNameException extends CustomException{ + + public InvalidPlayerNameException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/InvalidPlayersSizeException.java b/src/main/java/exception/InvalidPlayersSizeException.java new file mode 100644 index 00000000000..72428435841 --- /dev/null +++ b/src/main/java/exception/InvalidPlayersSizeException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidPlayersSizeException extends CustomException{ + + public InvalidPlayersSizeException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/InvalidSeparatorException.java b/src/main/java/exception/InvalidSeparatorException.java new file mode 100644 index 00000000000..76538c156d8 --- /dev/null +++ b/src/main/java/exception/InvalidSeparatorException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidSeparatorException extends CustomException{ + + public InvalidSeparatorException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/MessageDoesNotExistException.java b/src/main/java/exception/MessageDoesNotExistException.java new file mode 100644 index 00000000000..74251064ca6 --- /dev/null +++ b/src/main/java/exception/MessageDoesNotExistException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class MessageDoesNotExistException extends CustomException{ + + public MessageDoesNotExistException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/NoMoreCardException.java b/src/main/java/exception/NoMoreCardException.java new file mode 100644 index 00000000000..25551e0a6bc --- /dev/null +++ b/src/main/java/exception/NoMoreCardException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class NoMoreCardException extends CustomException{ + + public NoMoreCardException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/exception/ReservedPlayerNameException.java b/src/main/java/exception/ReservedPlayerNameException.java new file mode 100644 index 00000000000..836ba975412 --- /dev/null +++ b/src/main/java/exception/ReservedPlayerNameException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class ReservedPlayerNameException extends CustomException { + + public ReservedPlayerNameException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000000..c4320997323 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,58 @@ +package view; + +import constants.ErrorCode; +import exception.InvalidInputException; +import exception.InvalidSeparatorException; +import java.util.List; +import java.util.Scanner; + +public class InputView { + + private static final String NAME_SEPARATOR = ","; + + private final Scanner scanner; + + public InputView(final Scanner scanner) { + this.scanner = scanner; + } + + public List readNames() { + System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); + String rawNames = scanner.nextLine().trim(); + validateBlank(rawNames); + validateSeparators(rawNames); + List names = List.of(rawNames.split(NAME_SEPARATOR)); + System.out.println(); + return names; + } + + public String readAnswer(String name) { + System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)", name); + System.out.println(); + String rawAnswer = scanner.nextLine().trim(); + validateBlank(rawAnswer); + return rawAnswer; + } + + private void validateBlank(final String rawNames) { + if (rawNames == null || rawNames.isBlank()) { + throw new InvalidInputException(ErrorCode.INVALID_INPUT); + } + } + + private void validateSeparators(final String rawNames) { + if (isInvalidSeparator(rawNames)) { + throw new InvalidSeparatorException(ErrorCode.INVALID_SEPARATOR); + } + } + + private boolean isInvalidSeparator(final String rawNames) { + if (rawNames.startsWith(NAME_SEPARATOR)) { + return true; + } + if (rawNames.endsWith(NAME_SEPARATOR)) { + return true; + } + return rawNames.contains(NAME_SEPARATOR.repeat(2)); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000000..87c607de6bf --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,94 @@ +package view; + +import static domain.participant.Dealer.INIT_HANDS_SIZE; +import static domain.participant.Dealer.THRESHOLD; + +import constants.ErrorCode; +import domain.Result; +import domain.participant.Player; +import dto.DealerHandsDto; +import dto.ParticipantDto; +import dto.ParticipantsDto; +import java.util.List; +import java.util.Map; +import view.message.ErrorCodeMessage; + +public class OutputView { + + private static final String LINE = System.lineSeparator(); + private static final String FORM = "%s카드: %s%n"; + private static final String TOTAL_SUM_FORM = "%s 카드: %s - 결과: %d%n"; + private static final String RESULT_FORM = "%s: %s%n"; + private static final String ERROR_FORM = "[ERROR] %s%n"; + + + public void printStartDeal(final DealerHandsDto dealerHandsDto, final ParticipantsDto participantsDto) { + final String dealerCard = dealerHandsDto.getDisplayedCard(); + + final List playerNames = participantsDto.getNames(); + System.out.printf("딜러와 %s 에게 %d장을 나누었습니다.%n", format(playerNames), INIT_HANDS_SIZE); + System.out.printf("딜러: %s%n", dealerCard); + + for (ParticipantDto participantDto : participantsDto.getPlayers()) { + System.out.printf(FORM, participantDto.name(), format(participantDto.cards())); + } + System.out.print(LINE); + } + + public void printHands(final ParticipantDto participantDto) { + System.out.printf(FORM, participantDto.name(), format(participantDto.cards())); + } + + public void printDealerTurnMessage() { + System.out.printf("딜러는 %d이하라 한장의 카드를 더 받았습니다.%n%n", THRESHOLD); + } + + public void printHandsResult(final ParticipantsDto participantsDto) { + for (ParticipantDto participantDto : participantsDto.getPlayers()) { + System.out.printf(TOTAL_SUM_FORM, participantDto.name(), format(participantDto.cards()), + participantDto.totalSum()); + } + System.out.print(LINE); + } + + public void printGameResult(final Map dealerResult, final Map playerResult) { + System.out.println("## 최종결과"); + System.out.printf(RESULT_FORM, "딜러", format(dealerResult)); + for (Map.Entry entry : playerResult.entrySet()) { + System.out.printf(RESULT_FORM, entry.getKey().getName(), entry.getValue().getValue()); + } + } + + private String format(final Map dealerResult) { + StringBuilder stringBuilder = new StringBuilder(); + for (Map.Entry entry : dealerResult.entrySet()) { + stringBuilder.append(entry.getValue()).append(entry.getKey().getValue()).append(" "); + } + + return stringBuilder.toString(); + } + + private String format(final List playerNames) { + return String.join(", ", playerNames); + } + + public void printBust() { + System.out.printf("BUST%n"); + } + + public void printBlackJack() { + System.out.printf("BLACK JACK!!!%n"); + } + + public void printException(final ErrorCode errorCode) { + System.out.printf(ERROR_FORM, ErrorCodeMessage.from(errorCode).getMessage()); + } + + public void printDealEndMessage(final boolean isBust) { + if (isBust) { + printBust(); + return; + } + printBlackJack(); + } +} diff --git a/src/main/java/view/message/ErrorCodeMessage.java b/src/main/java/view/message/ErrorCodeMessage.java new file mode 100644 index 00000000000..507dc908f71 --- /dev/null +++ b/src/main/java/view/message/ErrorCodeMessage.java @@ -0,0 +1,49 @@ +package view.message; + +import constants.ErrorCode; +import exception.MessageDoesNotExistException; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public enum ErrorCodeMessage { + + NOT_EXIST_MESSAGE(ErrorCode.NOT_EXIST_MESSAGE, "해당 메시지가 없습니다."), + INVALID_SEPARATOR(ErrorCode.INVALID_SEPARATOR, "유효하지 않은 구분자입니다."), + INVALID_INPUT(ErrorCode.INVALID_INPUT, "유효하지 않은 입력입니다."), + INVALID_SIZE(ErrorCode.INVALID_SIZE, "유효하지 않은 참여자 수입니다."), + DUPLICATE_NAME(ErrorCode.DUPLICATE_NAME, "중복된 이름은 사용할 수 없습니다."), + RESERVED_NAME(ErrorCode.RESERVED_NAME, "이름은 딜러일 수 없습니다."), + BLANK_VALUE(ErrorCode.BLANK_VALUE, "이름은 공백일 수 없습니다."), + EMPTY_CARD(ErrorCode.EMPTY_CARD, "뽑을 수 있는 카드가 없습니다."), + INVALID_COMMAND(ErrorCode.INVALID_COMMAND, "y 또는 n을 입력해주세요"), + ; + + private static final Map SUIT_MESSAGE = Arrays.stream(values()) + .collect(Collectors.toMap(ErrorCodeMessage::getCode, Function.identity())); + + + private final ErrorCode errorCode; + private final String message; + + ErrorCodeMessage(final ErrorCode errorCode, final String message) { + this.errorCode = errorCode; + this.message = message; + } + + public static ErrorCodeMessage from(ErrorCode errorCode) { + if (SUIT_MESSAGE.containsKey(errorCode)) { + return SUIT_MESSAGE.get(errorCode); + } + throw new MessageDoesNotExistException(ErrorCode.NOT_EXIST_MESSAGE); + } + + private ErrorCode getCode() { + return errorCode; + } + + public String getMessage() { + return message; + } +} diff --git a/src/test/java/domain/AnswerTest.java b/src/test/java/domain/AnswerTest.java new file mode 100644 index 00000000000..ea61387a175 --- /dev/null +++ b/src/test/java/domain/AnswerTest.java @@ -0,0 +1,18 @@ +package domain; + +import exception.InvalidCommandException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class AnswerTest { + + @ParameterizedTest + @DisplayName("y혹은 n이 아닐시 예외가 발생한다.") + @ValueSource(strings = {"Y", "nn", "aa"}) + void invalidAnswer(String value) { + Assertions.assertThatThrownBy(() -> Answer.from(value)) + .isInstanceOf(InvalidCommandException.class); + } +} diff --git a/src/test/java/domain/CardTest.java b/src/test/java/domain/CardTest.java new file mode 100644 index 00000000000..39c5667e1de --- /dev/null +++ b/src/test/java/domain/CardTest.java @@ -0,0 +1,20 @@ +package domain; + +import domain.card.Card; +import java.util.List; +import java.util.Set; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CardTest { + + @Test + @DisplayName("중복없는 52장의 카드를 생성한다.") + void generate() { + List values = Card.values(); + + Assertions.assertThat(values).hasSize(52); + Assertions.assertThat(Set.copyOf(values)).hasSize(52); + } +} diff --git a/src/test/java/domain/DealerTest.java b/src/test/java/domain/DealerTest.java new file mode 100644 index 00000000000..fcec8af2249 --- /dev/null +++ b/src/test/java/domain/DealerTest.java @@ -0,0 +1,105 @@ +package domain; + +import static domain.HandsTestFixture.sum10Size2; +import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum20Size3; +import static domain.HandsTestFixture.sum21Size2; +import static domain.Result.LOSE; +import static domain.Result.TIE; +import static domain.Result.WIN; + +import domain.participant.Dealer; +import domain.participant.Hands; +import domain.participant.Name; +import domain.participant.Player; +import domain.participant.Players; +import java.util.List; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DealerTest { + + @Test + @DisplayName("참여자에게 카드 2장을 나눠준다.") + void dealCards() { + //given + final Players players = Players.from(List.of("레디", "제제")); + final Dealer dealer = new Dealer(); + + //when + dealer.initHands(players); + + //then + Assertions.assertThat(players.getPlayers()).allMatch(player -> player.handsSize() == 2); + } + + @Test + @DisplayName("참여자의 답변이 y라면 카드를 한장 추가한다.") + void addOneCard() { + //given + final Player hitPlayer = new Player(new Name("레디"), Hands.createEmptyHands()); + final Player stayPlayer = new Player(new Name("제제"), Hands.createEmptyHands()); + + final Players players = new Players(List.of(hitPlayer, stayPlayer)); + + final Dealer dealer = new Dealer(); + dealer.initHands(players); + + //when + dealer.deal(hitPlayer, Answer.HIT); + dealer.deal(stayPlayer, Answer.STAY); + + //then + Assertions.assertThat(hitPlayer.handsSize()).isEqualTo(3); + Assertions.assertThat(stayPlayer.handsSize()).isEqualTo(2); + } + + @Test + @DisplayName("딜러의 카드의 합이 17이상이 될때까지 카드를 추가한다.") + void dealerDeal() { + //given + final Dealer dealer = new Dealer(sum10Size2); + + //when + dealer.deal(); + + //then + Assertions.assertThat(dealer.countAddedHands()).isPositive(); + Assertions.assertThat(dealer.handsSum()).isGreaterThanOrEqualTo(17); + } + + @DisplayName("딜러의 카드의 합이 17이상이라면 카드를 추가하지 않는다") + @Test + void dealerNoDeal() { + //given + final Dealer dealer = new Dealer(sum18Size2); + + //when + dealer.deal(); + + //then + Assertions.assertThat(dealer.countAddedHands()).isZero(); + Assertions.assertThat(dealer.handsSum()).isGreaterThanOrEqualTo(17); + } + + @DisplayName("딜러의 승패무를 판단한다.") + @Test + void dealerResult() { + // given + Player loser1 = new Player(new Name("레디"), sum18Size2); + Player loser2 = new Player(new Name("피케이"), sum18Size2); + Player winner = new Player(new Name("제제"), sum21Size2); + Player tier = new Player(new Name("브라운"), sum20Size3); + + Players players = new Players(List.of(loser1, loser2, winner, tier)); + Dealer dealer = new Dealer(sum20Size3); + + // when + Map expected = Map.of(WIN, 2, LOSE, 1, TIE, 1); + + // then + Assertions.assertThat(dealer.getDealerResult(players)).isEqualTo(expected); + } +} diff --git a/src/test/java/domain/HandsTest.java b/src/test/java/domain/HandsTest.java new file mode 100644 index 00000000000..8c5bb396d81 --- /dev/null +++ b/src/test/java/domain/HandsTest.java @@ -0,0 +1,84 @@ +package domain; + +import static domain.HandsTestFixture.sum19Size3Ace1; +import static domain.HandsTestFixture.sum19Size4Ace11; +import static domain.HandsTestFixture.sum20Size2; +import static domain.HandsTestFixture.sum20Size3Ace1; +import static domain.HandsTestFixture.sum21Size3Ace11; +import static domain.card.Rank.EIGHT; +import static domain.card.Shape.CLOVER; + +import domain.card.Card; +import domain.participant.Hands; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +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; + +class HandsTest { + + @Test + @DisplayName("카드를 가지고 있는 객체를 생성한다.") + void createPacket() { + Assertions.assertThatCode(Hands::createEmptyHands) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("카드를 추가한다.") + void addCard() { + //given + final Hands hands = Hands.createEmptyHands(); + + //when + hands.add(new Card(EIGHT, CLOVER)); + + //then + Assertions.assertThat(hands.size()).isEqualTo(1); + } + + @DisplayName("카드의 합을 구한다.") + @Test + void sum() { + Assertions.assertThat(sum20Size2.sum()).isEqualTo(20); + } + + @DisplayName("에이스를 11로 계산한다.") + @ParameterizedTest + @MethodSource("sumAce11ParameterProvider") + void sumAce11(final Hands hands, final int expected) { + // given & when + final int result = hands.sum(); + + // then + Assertions.assertThat(result).isEqualTo(expected); + } + + @DisplayName("에이스를 1로 계산한다.") + @ParameterizedTest + @MethodSource("sumAce1ParameterProvider") + void sumAce1(final Hands hands, final int expected) { + // given & when + final int result = hands.sum(); + + // then + Assertions.assertThat(result).isEqualTo(expected); + } + + static Stream sumAce11ParameterProvider() { + return Stream.of( + Arguments.of(sum21Size3Ace11, 21), + Arguments.of(sum19Size4Ace11, 19) + ); + } + + static Stream sumAce1ParameterProvider() { + return Stream.of( + Arguments.of(sum19Size3Ace1, 19), + Arguments.of(sum20Size3Ace1, 20) + ); + } +} diff --git a/src/test/java/domain/HandsTestFixture.java b/src/test/java/domain/HandsTestFixture.java new file mode 100644 index 00000000000..bb1adb416d2 --- /dev/null +++ b/src/test/java/domain/HandsTestFixture.java @@ -0,0 +1,49 @@ +package domain; + +import static domain.card.Rank.ACE; +import static domain.card.Rank.EIGHT; +import static domain.card.Rank.FIVE; +import static domain.card.Rank.FOUR; +import static domain.card.Rank.JACK; +import static domain.card.Rank.KING; +import static domain.card.Rank.NINE; +import static domain.card.Rank.QUEEN; +import static domain.card.Rank.SEVEN; +import static domain.card.Rank.SIX; +import static domain.card.Rank.TEN; +import static domain.card.Rank.THREE; +import static domain.card.Rank.TWO; +import static domain.card.Shape.CLOVER; +import static domain.card.Shape.DIAMOND; +import static domain.card.Shape.HEART; +import static domain.card.Shape.SPADE; + +import domain.card.Card; +import domain.participant.Hands; +import java.util.List; + +class HandsTestFixture { + + static final Hands sum10Size2 = new Hands(List.of(new Card(FIVE, SPADE), new Card(FIVE, HEART))); + static final Hands sum17Size3One = new Hands( + List.of(new Card(SEVEN, SPADE), new Card(FOUR, SPADE), new Card(SIX, SPADE))); + static final Hands sum17Size3Two = new Hands( + List.of(new Card(TEN, SPADE), new Card(THREE, SPADE), new Card(FOUR, SPADE))); + static final Hands sum18Size2 = new Hands(List.of(new Card(EIGHT, CLOVER), new Card(TEN, DIAMOND))); + static final Hands sum19Size4Ace11 = new Hands( + List.of(new Card(ACE, DIAMOND), new Card(TWO, CLOVER), new Card(FOUR, CLOVER), new Card(TWO, CLOVER))); + static final Hands sum19Size3Ace1 = new Hands( + List.of(new Card(ACE, HEART), new Card(NINE, SPADE), new Card(NINE, CLOVER))); + static final Hands sum20Size2 = new Hands(List.of(new Card(NINE, SPADE), new Card(ACE, SPADE))); + static final Hands sum20Size3 = new Hands( + List.of(new Card(SEVEN, SPADE), new Card(TWO, SPADE), new Card(ACE, SPADE))); + static final Hands sum20Size3Ace1 = new Hands( + List.of(new Card(ACE, DIAMOND), new Card(EIGHT, CLOVER), new Card(FIVE, CLOVER), new Card(SIX, CLOVER))); + static final Hands sum21Size2 = new Hands(List.of(new Card(QUEEN, HEART), new Card(ACE, SPADE))); + static final Hands sum21Size3Ace11 = new Hands( + List.of(new Card(ACE, HEART), new Card(EIGHT, SPADE), new Card(TWO, CLOVER))); + static final Hands bustHands = new Hands( + List.of(new Card(EIGHT, DIAMOND), new Card(TWO, DIAMOND), new Card(TWO, DIAMOND), new Card(KING, CLOVER))); + static final Hands noBustHands = new Hands(List.of(new Card(JACK, HEART), new Card(TEN, SPADE))); + static final Hands blackJack = new Hands(List.of(new Card(JACK, HEART), new Card(ACE, SPADE))); +} diff --git a/src/test/java/domain/NameTest.java b/src/test/java/domain/NameTest.java new file mode 100644 index 00000000000..401a38f7832 --- /dev/null +++ b/src/test/java/domain/NameTest.java @@ -0,0 +1,28 @@ +package domain; + +import domain.participant.Name; +import exception.InvalidPlayerNameException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +class NameTest { + + @DisplayName("공백을 입력하면 예외를 발생시킨다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", " "}) + void BlankInputThrowException(String value) { + Assertions.assertThatThrownBy(() -> new Name(value)) + .isInstanceOf(InvalidPlayerNameException.class); + } + + @DisplayName("null을 입력하면 예외를 발생시킨다.") + @ParameterizedTest + @NullSource + void nullInputThrowException(String value) { + Assertions.assertThatThrownBy(() -> new Name(value)) + .isInstanceOf(InvalidPlayerNameException.class); + } +} diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java new file mode 100644 index 00000000000..850c1599eca --- /dev/null +++ b/src/test/java/domain/PlayerTest.java @@ -0,0 +1,28 @@ +package domain; + +import domain.participant.Hands; +import domain.participant.Name; +import domain.participant.Player; +import exception.ReservedPlayerNameException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PlayerTest { + @DisplayName("이름으로 참여자를 생성한다.") + @Test + void createPlayerWithName() { + Assertions.assertThatCode(() -> new Player(new Name("pobi"), Hands.createEmptyHands())) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("참여자 이름이 딜러이면 예외가 발생한다.") + void validateName() { + final Name name = new Name("딜러"); + final Hands hands = Hands.createEmptyHands(); + + Assertions.assertThatThrownBy(() -> new Player(name, hands)) + .isInstanceOf(ReservedPlayerNameException.class); + } +} diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java new file mode 100644 index 00000000000..f038cb7a758 --- /dev/null +++ b/src/test/java/domain/PlayersTest.java @@ -0,0 +1,142 @@ +package domain; + +import static domain.HandsTestFixture.bustHands; +import static domain.HandsTestFixture.noBustHands; +import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum20Size2; +import static domain.HandsTestFixture.sum20Size3; +import static domain.HandsTestFixture.sum21Size2; +import static domain.Result.LOSE; +import static domain.Result.TIE; +import static domain.Result.WIN; + +import domain.participant.Dealer; +import domain.participant.Name; +import domain.participant.Player; +import domain.participant.Players; +import exception.DuplicatePlayerNameException; +import exception.InvalidPlayersSizeException; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +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; + +class PlayersTest { + + @Test + @DisplayName("참여자 이름 중복시 예외가 발생한다.") + void duplicatePlayerName() { + //given + final List names = List.of("redy", "redy"); + + //when & then + Assertions.assertThatThrownBy(() -> Players.from(names)) + .isInstanceOf(DuplicatePlayerNameException.class); + } + + @DisplayName("총 참여자 수가 2이상 8이하이면 참여자를 생성한다.") + @ParameterizedTest + @MethodSource("validPlayersSizeParameterProvider") + void validPlayersSize(final List names) { + Assertions.assertThatCode(() -> Players.from(names)) + .doesNotThrowAnyException(); + } + + @DisplayName("총 참여자 수는 2이상 8이하가 아니면 예외가 발생한다.") + @ParameterizedTest + @MethodSource("invalidPlayersSizeParameterProvider") + void invalidPlayersSize(final List names) { + Assertions.assertThatThrownBy(() -> Players.from(names)) + .isInstanceOf(InvalidPlayersSizeException.class); + } + + @Test + @DisplayName("참가자 중 버스트 되지 않은 참가자가 있다면 isAllBust가 False를 반환한다.") + void isAllBustFalse() { + //given + final Player bustPlayer = new Player(new Name("레디"), bustHands); + final Player noBustPlayer = new Player(new Name("제제"), noBustHands); + final Players players = new Players(List.of(bustPlayer, noBustPlayer)); + + //when && then + Assertions.assertThat(players.isAllBust()).isFalse(); + } + + @Test + @DisplayName("모든 참가자가 버스트되면 isAllBust가 True를 반환한다.") + void isAllBustTrue() { + //given + Player player1 = new Player(new Name("레디"), bustHands); + Player player2 = new Player(new Name("제제"), bustHands); + Player player3 = new Player(new Name("수달"), bustHands); + Player player4 = new Player(new Name("피케이"), bustHands); + + Players players = new Players(List.of(player1, player2, player3, player4)); + + //when && then + Assertions.assertThat(players.isAllBust()).isTrue(); + } + + @Test + @DisplayName("참여자의 승패무를 판단한다.") + void playerResult() { + //given + Player loser = new Player(new Name("레디"), sum18Size2); + Player winner = new Player(new Name("제제"), sum21Size2); + Player tier = new Player(new Name("수달"), sum20Size3); + + Players players = new Players(List.of(loser, winner, tier)); + Dealer dealer = new Dealer(sum20Size3); + + //when & then + Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); + Assertions.assertThat(players.getPlayersResult(dealer)).isEqualTo(expected); + } + + @Test + @DisplayName("딜러가 버스트일때 참여자가 버스트가 아니면 WIN") + void all() { + //given + Dealer bustDealer = new Dealer(bustHands); + Player winner1 = new Player(new Name("레디"), sum18Size2); + Player winner2 = new Player(new Name("브라운"), sum20Size2); + Player loser = new Player(new Name("제제"), bustHands); + + Players players = new Players(List.of(winner1, winner2, loser)); + + //when + Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); + Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); + + //then + Assertions.assertThat(players.getPlayersResult(bustDealer)).isEqualTo(expectedPlayerResult); + Assertions.assertThat(bustDealer.getDealerResult(players)).isEqualTo(expectedDealerResult); + } + + static Stream validPlayersSizeParameterProvider() { + return Stream.of( + Arguments.of( + List.of("pobi", "jason") + ), + Arguments.of( + List.of("1", "2", "3", "4", "5", "6", "7", "8") + ) + ); + } + + static Stream invalidPlayersSizeParameterProvider() { + return Stream.of( + Arguments.of( + List.of("pobi") + ), + Arguments.of( + List.of("1", "2", "3", "4", "5", "6", "7", "8", "9") + ) + ); + } +} diff --git a/src/test/java/domain/ResultTest.java b/src/test/java/domain/ResultTest.java new file mode 100644 index 00000000000..01ad8e26a10 --- /dev/null +++ b/src/test/java/domain/ResultTest.java @@ -0,0 +1,48 @@ +package domain; + +import static domain.HandsTestFixture.blackJack; +import static domain.HandsTestFixture.bustHands; +import static domain.HandsTestFixture.sum17Size3One; +import static domain.HandsTestFixture.sum17Size3Two; +import static domain.HandsTestFixture.sum20Size2; +import static domain.HandsTestFixture.sum20Size3; +import static domain.HandsTestFixture.sum21Size2; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ResultTest { + + @DisplayName("카드 합이 같고 카드 갯수가 같으면 무승부이다.") + @Test + void isTie() { + Assertions.assertThat(sum17Size3One.calculateResult(sum17Size3Two)).isEqualTo(Result.TIE); + } + + @DisplayName("카드 합이 같은데 카드 갯수가 더 적으면 승리이다.") + @Test + void isWinBySize() { + Assertions.assertThat(sum20Size2.calculateResult(sum20Size3)).isEqualTo(Result.WIN); + } + + @Test + @DisplayName("카드 합이 21이하이면서 21에 가까운 카드가 승리한다.") + void isWin() { + Assertions.assertThat(sum21Size2.calculateResult(sum20Size2)).isEqualTo(Result.WIN); + Assertions.assertThat(sum20Size2.calculateResult(sum21Size2)).isEqualTo(Result.LOSE); + } + + @Test + @DisplayName("카드 합이 21초과이면 패배한다.") + void isLoseWhenCardSumGreater21() { + Assertions.assertThat(bustHands.calculateResult(sum20Size2)).isEqualTo(Result.LOSE); + } + + @Test + @DisplayName("blackjack이 이긴다.") + void isWinBlackJack() { + Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(Result.WIN); + Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(Result.LOSE); + } +} diff --git a/src/test/java/domain/card/CardDeckTest.java b/src/test/java/domain/card/CardDeckTest.java new file mode 100644 index 00000000000..a7bf0c60bd5 --- /dev/null +++ b/src/test/java/domain/card/CardDeckTest.java @@ -0,0 +1,39 @@ +package domain.card; + +import static domain.participant.Dealer.DECK_SIZE; + +import exception.NoMoreCardException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CardDeckTest { + + @DisplayName("카드를 52 * 6 만큼 생성한다.") + @Test + void generate() { + // given + CardDeck cardDeck = CardDeck.generate(DECK_SIZE); + + // when && then + Assertions.assertThat(cardDeck.size()).isEqualTo(52 * 6); + } + + @Test + @DisplayName("카드가 없는데 카드를 뽑을 경우 예외가 발생한다.") + void pop() { + //given + CardDeck cardDeck = CardDeck.generate(1); + + //when + int cardSize = 52; + while (cardSize > 0) { + cardDeck.pop(); + cardSize--; + } + + //then + Assertions.assertThatThrownBy(cardDeck::pop) + .isInstanceOf(NoMoreCardException.class); + } +} From c7a83f1f253d8d86d67c02735265747920cb624b Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 11:12:59 +0900 Subject: [PATCH 02/40] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EB=AA=A9?= =?UTF-8?q?=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 --- docs/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/README.md b/docs/README.md index b819b8e049b..99344e8cf43 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,6 +2,8 @@ ## 참여자 +* [ ] 다시한번 룰 숙지 필요 + **승** * (딜러 카드 합 < 참여자 카드 합) && 참여자가 버스트가 아닌 경우 @@ -19,6 +21,12 @@
+## 블랙잭 + +* 카드의 갯수가 2장이고 카드의 합이 21인 경우 블랙잭이다. + +
+ # 기능 요구 사항 * [x] 참여자 이름 입력 받는다. @@ -33,6 +41,12 @@
+* [ ] 각 참여자의 배팅 금액을 입력받는다. +* [ ] 정수가 아닐 시 예외가 발생한다. +* [ ] 양의 정수가 아닐 시 예외가 발생한다. + +
+ * [x] 딜러가 카드 2장을 분배하다. * [x] 카드는 총 6벌을 둔다. (52 * 6) * [x] 딜러의 카드를 출력한다. (1장) @@ -62,6 +76,15 @@ * [x] 참여자의 승패무를 확인한다. * [x] 게임 결과를 출력한다. +
+ +* [ ] 딜러의 최종 수익을 계산한다. +* [ ] 참가자의 최종 수익을 계산한다. +* [ ] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. +* [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. +* [ ] 참가자가 패한다면 배팅한 금액을 잃는다. +* [ ] 참가자가 승리한다면 배팅한 금액을 받는다. + --- ## 리팩터링 목록 From 2206919516c1b5f0e2673b7bc193fa1b36213012 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 11:21:06 +0900 Subject: [PATCH 03/40] =?UTF-8?q?feat:=20=EB=B0=B0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=B4=20=EC=96=91=EC=9D=98=20=EC=A0=95=EC=88=98?= =?UTF-8?q?=EA=B0=80=20=EC=95=84=EB=8B=90=20=EC=8B=9C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=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 --- docs/README.md | 4 ++-- src/main/java/constants/ErrorCode.java | 1 + src/main/java/domain/BetAmount.java | 20 +++++++++++++++++++ .../exception/InvalidBetAmountException.java | 10 ++++++++++ src/test/java/domain/BetAmountTest.java | 19 ++++++++++++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/main/java/domain/BetAmount.java create mode 100644 src/main/java/exception/InvalidBetAmountException.java create mode 100644 src/test/java/domain/BetAmountTest.java diff --git a/docs/README.md b/docs/README.md index 99344e8cf43..66b3095b082 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,8 +42,8 @@
* [ ] 각 참여자의 배팅 금액을 입력받는다. -* [ ] 정수가 아닐 시 예외가 발생한다. -* [ ] 양의 정수가 아닐 시 예외가 발생한다. + * [ ] 정수가 아닐 시 예외가 발생한다. + * [x] 양의 정수가 아닐 시 예외가 발생한다.
diff --git a/src/main/java/constants/ErrorCode.java b/src/main/java/constants/ErrorCode.java index d6278bf1c5a..28769d16cc7 100644 --- a/src/main/java/constants/ErrorCode.java +++ b/src/main/java/constants/ErrorCode.java @@ -6,6 +6,7 @@ public enum ErrorCode { INVALID_SEPARATOR, INVALID_INPUT, INVALID_SIZE, + INVALID_BET_AMOUNT, DUPLICATE_NAME, RESERVED_NAME, BLANK_VALUE, diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java new file mode 100644 index 00000000000..c42c04e2a82 --- /dev/null +++ b/src/main/java/domain/BetAmount.java @@ -0,0 +1,20 @@ +package domain; + +import constants.ErrorCode; +import exception.InvalidBetAmountException; + +public class BetAmount { + + private final long amount; + + public BetAmount(final long amount) { + validate(amount); + this.amount = amount; + } + + private void validate(final long value) { + if (value <= 0) { + throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); + } + } +} diff --git a/src/main/java/exception/InvalidBetAmountException.java b/src/main/java/exception/InvalidBetAmountException.java new file mode 100644 index 00000000000..94b1688fe57 --- /dev/null +++ b/src/main/java/exception/InvalidBetAmountException.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class InvalidBetAmountException extends CustomException{ + + public InvalidBetAmountException(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java new file mode 100644 index 00000000000..b7a3af2a985 --- /dev/null +++ b/src/test/java/domain/BetAmountTest.java @@ -0,0 +1,19 @@ +package domain; + +import exception.InvalidBetAmountException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BetAmountTest { + + @ParameterizedTest + @DisplayName("베팅 금액이 0 이하일 시 예외가 발생한다.") + @ValueSource(ints = {0, -1, -100000}) + void invalidBetAmount(long value) { + Assertions.assertThatThrownBy(() -> new BetAmount(value)) + .isInstanceOf(InvalidBetAmountException.class); + } +} From dec4970eded8e02401e390cf8fc7382d6a3ccffc Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 13:23:50 +0900 Subject: [PATCH 04/40] =?UTF-8?q?test:=20player=EC=9D=98=20canDeal=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/main/java/domain/participant/Player.java | 2 +- src/test/java/domain/PlayerTest.java | 41 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 4674d6e99e9..2785bca78de 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -20,6 +20,6 @@ private void validate(final Name name) { @Override public boolean canDeal() { - return handsSum() <= Hands.BLACK_JACK; + return handsSum() < Hands.BLACK_JACK; } } diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java index 850c1599eca..6ea0a236293 100644 --- a/src/test/java/domain/PlayerTest.java +++ b/src/test/java/domain/PlayerTest.java @@ -1,12 +1,21 @@ package domain; +import static domain.HandsTestFixture.bustHands; +import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum20Size2; +import static domain.HandsTestFixture.sum21Size3Ace11; + import domain.participant.Hands; import domain.participant.Name; import domain.participant.Player; import exception.ReservedPlayerNameException; +import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; 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; class PlayerTest { @DisplayName("이름으로 참여자를 생성한다.") @@ -25,4 +34,36 @@ void validateName() { Assertions.assertThatThrownBy(() -> new Player(name, hands)) .isInstanceOf(ReservedPlayerNameException.class); } + + @ParameterizedTest + @DisplayName("참여자가 21 이상이면 더이상 딜을 할 수가 없다.") + @MethodSource("canNotDealParameterProvider") + void canNotDeal(Hands hands) { + final Name name = new Name("레디"); + final Player player = new Player(name, hands); + Assertions.assertThat(player.canDeal()).isFalse(); + } + + @ParameterizedTest + @DisplayName("참여자가 21 이하라면 딜 할 수가 있다.") + @MethodSource("canDealParameterProvider") + void canDeal(Hands hands) { + final Name name = new Name("레디"); + final Player player = new Player(name, hands); + Assertions.assertThat(player.canDeal()).isTrue(); + } + + static Stream canNotDealParameterProvider() { + return Stream.of( + Arguments.of(sum21Size3Ace11), + Arguments.of(bustHands) + ); + } + + static Stream canDealParameterProvider() { + return Stream.of( + Arguments.of(sum18Size2), + Arguments.of(sum20Size2) + ); + } } From ffbc5e325af9bf99c5de172f202efb03bc15e44a Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 13:31:06 +0900 Subject: [PATCH 05/40] =?UTF-8?q?refactor:=20testFixture=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/HandsTestFixture.java | 3 ++- src/test/java/domain/PlayersTest.java | 4 ++-- src/test/java/domain/ResultTest.java | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/java/domain/HandsTestFixture.java b/src/test/java/domain/HandsTestFixture.java index bb1adb416d2..70f6a7e7148 100644 --- a/src/test/java/domain/HandsTestFixture.java +++ b/src/test/java/domain/HandsTestFixture.java @@ -39,7 +39,8 @@ class HandsTestFixture { List.of(new Card(SEVEN, SPADE), new Card(TWO, SPADE), new Card(ACE, SPADE))); static final Hands sum20Size3Ace1 = new Hands( List.of(new Card(ACE, DIAMOND), new Card(EIGHT, CLOVER), new Card(FIVE, CLOVER), new Card(SIX, CLOVER))); - static final Hands sum21Size2 = new Hands(List.of(new Card(QUEEN, HEART), new Card(ACE, SPADE))); + static final Hands sum21Size3 = new Hands( + List.of(new Card(QUEEN, HEART), new Card(SIX, SPADE), new Card(FIVE, CLOVER))); static final Hands sum21Size3Ace11 = new Hands( List.of(new Card(ACE, HEART), new Card(EIGHT, SPADE), new Card(TWO, CLOVER))); static final Hands bustHands = new Hands( diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index f038cb7a758..4bfe411ccae 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -5,7 +5,7 @@ import static domain.HandsTestFixture.sum18Size2; import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum20Size3; -import static domain.HandsTestFixture.sum21Size2; +import static domain.HandsTestFixture.sum21Size3; import static domain.Result.LOSE; import static domain.Result.TIE; import static domain.Result.WIN; @@ -87,7 +87,7 @@ void isAllBustTrue() { void playerResult() { //given Player loser = new Player(new Name("레디"), sum18Size2); - Player winner = new Player(new Name("제제"), sum21Size2); + Player winner = new Player(new Name("제제"), sum21Size3); Player tier = new Player(new Name("수달"), sum20Size3); Players players = new Players(List.of(loser, winner, tier)); diff --git a/src/test/java/domain/ResultTest.java b/src/test/java/domain/ResultTest.java index 01ad8e26a10..c1c2ce418df 100644 --- a/src/test/java/domain/ResultTest.java +++ b/src/test/java/domain/ResultTest.java @@ -6,7 +6,7 @@ import static domain.HandsTestFixture.sum17Size3Two; import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum20Size3; -import static domain.HandsTestFixture.sum21Size2; +import static domain.HandsTestFixture.sum21Size3; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -29,8 +29,8 @@ void isWinBySize() { @Test @DisplayName("카드 합이 21이하이면서 21에 가까운 카드가 승리한다.") void isWin() { - Assertions.assertThat(sum21Size2.calculateResult(sum20Size2)).isEqualTo(Result.WIN); - Assertions.assertThat(sum20Size2.calculateResult(sum21Size2)).isEqualTo(Result.LOSE); + Assertions.assertThat(sum21Size3.calculateResult(sum20Size2)).isEqualTo(Result.WIN); + Assertions.assertThat(sum20Size2.calculateResult(sum21Size3)).isEqualTo(Result.LOSE); } @Test From ee8b66e55238ecd1e69a70a08be211ddb0df03a9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 13:31:41 +0900 Subject: [PATCH 06/40] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=EC=9D=98=20?= =?UTF-8?q?=EA=B0=AF=EC=88=98=EA=B0=80=202=EC=9E=A5=EC=9D=B4=EA=B3=A0=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EC=9D=98=20=ED=95=A9=EC=9D=B4=2021=EC=9D=B8?= =?UTF-8?q?=20=EA=B2=BD=EC=9A=B0=20=EB=B8=94=EB=9E=99=EC=9E=AD=EC=9D=B4?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 6 ++--- .../java/controller/BlackJackController.java | 8 +++++++ .../java/domain/participant/Participant.java | 3 +-- src/test/java/domain/DealerTest.java | 24 +++++++++++++++++-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index 66b3095b082..bba3516253d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -79,9 +79,9 @@
* [ ] 딜러의 최종 수익을 계산한다. -* [ ] 참가자의 최종 수익을 계산한다. -* [ ] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. -* [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. +* [ ] 참가자의 최종 수익을 계산한다. +* [ ] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. +* [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. * [ ] 참가자가 패한다면 배팅한 금액을 잃는다. * [ ] 참가자가 승리한다면 배팅한 금액을 받는다. diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index e44b17ed968..e0d169bbec4 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -42,7 +42,15 @@ private void printDealerTurnMessage(final int turn) { } private void dealWithPlayers(final Players players, final Dealer dealer) { + if (dealer.isBlackJack()) { + System.out.println("딜러가 블랙잭임"); + return; + } for (Player player : players.getPlayers()) { + if (player.isBlackJack()) { + System.out.println("플레이어가 블랙잭임"); + break; + } deal(player, dealer); } } diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 0bfa97b988b..2afd7663a92 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -25,9 +25,8 @@ public boolean isBust() { return hands.isBust(); } - //TODO 시작시에 블랙잭일 때 쓸거에용 public boolean isBlackJack() { - return hands.isBlackJack(); + return hands.isBlackJack() && hands.size() == 2; } public int handsSum() { diff --git a/src/test/java/domain/DealerTest.java b/src/test/java/domain/DealerTest.java index fcec8af2249..cd2d3b4e5b0 100644 --- a/src/test/java/domain/DealerTest.java +++ b/src/test/java/domain/DealerTest.java @@ -1,9 +1,11 @@ package domain; +import static domain.HandsTestFixture.blackJack; import static domain.HandsTestFixture.sum10Size2; import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum20Size3; -import static domain.HandsTestFixture.sum21Size2; +import static domain.HandsTestFixture.sum21Size3; import static domain.Result.LOSE; import static domain.Result.TIE; import static domain.Result.WIN; @@ -90,7 +92,7 @@ void dealerResult() { // given Player loser1 = new Player(new Name("레디"), sum18Size2); Player loser2 = new Player(new Name("피케이"), sum18Size2); - Player winner = new Player(new Name("제제"), sum21Size2); + Player winner = new Player(new Name("제제"), sum21Size3); Player tier = new Player(new Name("브라운"), sum20Size3); Players players = new Players(List.of(loser1, loser2, winner, tier)); @@ -102,4 +104,22 @@ void dealerResult() { // then Assertions.assertThat(dealer.getDealerResult(players)).isEqualTo(expected); } + + @Test + @DisplayName("처음 나눠준 카드 두장의 합이 21이라면 블랙잭이다.") + void checkingBlackJack() { + //given + Dealer dealer = new Dealer(sum20Size2); + Player blackJackPlayer = new Player(new Name("수달"), blackJack); + Player noBlackJackPlayer = new Player(new Name("레디"), sum18Size2); + + //when + org.junit.jupiter.api.Assertions.assertAll( + () -> Assertions.assertThat(dealer.isBlackJack()).isFalse(), + () -> Assertions.assertThat(blackJackPlayer.isBlackJack()).isTrue(), + () -> Assertions.assertThat(noBlackJackPlayer.isBlackJack()).isFalse() + ); + + //then + } } From f37f2881220f8719bf8c0a4bd8f08257eb9ba477 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 13 Mar 2024 14:11:11 +0900 Subject: [PATCH 07/40] =?UTF-8?q?fix:=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=A6=84=EC=9D=98=20=EA=B3=B5=EB=B0=B1?= =?UTF-8?q?=EC=9D=B4=20=ED=8F=AC=ED=95=A8=EB=90=9C=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EC=97=AC=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=ED=8C=90=EB=8B=A8=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackJackController.java | 2 +- src/main/java/domain/participant/Players.java | 11 ++++++----- src/main/java/view/InputView.java | 10 ++++++---- src/test/java/domain/PlayersTest.java | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index e0d169bbec4..5571a0284ee 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -49,7 +49,7 @@ private void dealWithPlayers(final Players players, final Dealer dealer) { for (Player player : players.getPlayers()) { if (player.isBlackJack()) { System.out.println("플레이어가 블랙잭임"); - break; + continue; } deal(player, dealer); } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index b007d830b9d..3a36865b2d9 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -22,8 +22,9 @@ public Players(final List names) { } public static Players from(final List names) { - validate(names); - return new Players(mapToPlayers(names)); + List players = mapToPlayers(names); + validate(players); + return new Players(players); } public void forEach(Consumer action) { @@ -50,18 +51,18 @@ private static List mapToPlayers(final List names) { .toList(); } - private static void validate(final List names) { + private static void validate(final List names) { validateSize(names); validateDuplicate(names); } - private static void validateSize(final List names) { + private static void validateSize(final List names) { if (names.size() < MIN_SIZE || MAX_SIZE < names.size()) { throw new InvalidPlayersSizeException(ErrorCode.INVALID_SIZE); } } - private static void validateDuplicate(final List names) { + private static void validateDuplicate(final List names) { if (names.size() != Set.copyOf(names).size()) { throw new DuplicatePlayerNameException(ErrorCode.DUPLICATE_NAME); } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index c4320997323..7981dfbabf3 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -3,6 +3,7 @@ import constants.ErrorCode; import exception.InvalidInputException; import exception.InvalidSeparatorException; +import java.util.Arrays; import java.util.List; import java.util.Scanner; @@ -18,17 +19,18 @@ public InputView(final Scanner scanner) { public List readNames() { System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)"); - String rawNames = scanner.nextLine().trim(); + String rawNames = scanner.nextLine(); validateBlank(rawNames); validateSeparators(rawNames); - List names = List.of(rawNames.split(NAME_SEPARATOR)); + List names = Arrays.stream(rawNames.split(NAME_SEPARATOR)) + .map(String::trim) + .toList(); System.out.println(); return names; } public String readAnswer(String name) { - System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)", name); - System.out.println(); + System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)%n", name); String rawAnswer = scanner.nextLine().trim(); validateBlank(rawAnswer); return rawAnswer; diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java index 4bfe411ccae..2aacee41b52 100644 --- a/src/test/java/domain/PlayersTest.java +++ b/src/test/java/domain/PlayersTest.java @@ -39,6 +39,14 @@ void duplicatePlayerName() { .isInstanceOf(DuplicatePlayerNameException.class); } + @ParameterizedTest + @DisplayName("참여자 이름에 공백이 있는 경우 제거하여 중복을 판단한다.") + @MethodSource("duplicateBlankNameParameterProvider") + void duplicateBlankName(final List names) { + Assertions.assertThatThrownBy(() -> Players.from(names)) + .isInstanceOf(DuplicatePlayerNameException.class); + } + @DisplayName("총 참여자 수가 2이상 8이하이면 참여자를 생성한다.") @ParameterizedTest @MethodSource("validPlayersSizeParameterProvider") @@ -118,6 +126,14 @@ void all() { Assertions.assertThat(bustDealer.getDealerResult(players)).isEqualTo(expectedDealerResult); } + static Stream duplicateBlankNameParameterProvider() { + return Stream.of( + Arguments.of(List.of("a", "a ", "b")), + Arguments.of(List.of(" a ", " a", "b", "c")), + Arguments.of(List.of("a", " a")) + ); + } + static Stream validPlayersSizeParameterProvider() { return Stream.of( Arguments.of( From 285f322056fd9a39c647402eebe2112b240f1a34 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 00:18:36 +0900 Subject: [PATCH 08/40] =?UTF-8?q?feat:=20=EC=B0=B8=EA=B0=80=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=8A=B9=ED=8C=A8=EC=97=90=20=EB=94=B0=EB=9D=BC=20?= =?UTF-8?q?=EB=B0=B0=ED=8C=85=ED=95=9C=20=EA=B8=88=EC=95=A1=20=EC=9E=83?= =?UTF-8?q?=EA=B1=B0=EB=82=98=20=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 4 +- src/main/java/domain/Amount.java | 28 ++++++++++++ src/main/java/domain/BetAmount.java | 31 ++++++++++++- src/main/java/domain/participant/Player.java | 4 ++ .../java/repository/BetAmountRepository.java | 43 +++++++++++++++++++ src/test/java/domain/HandsTestFixture.java | 30 ++++++------- .../repository/BetAmountRepositoryTest.java | 40 +++++++++++++++++ 7 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 src/main/java/domain/Amount.java create mode 100644 src/main/java/repository/BetAmountRepository.java create mode 100644 src/test/java/repository/BetAmountRepositoryTest.java diff --git a/docs/README.md b/docs/README.md index bba3516253d..d7670d6b92a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -82,8 +82,8 @@ * [ ] 참가자의 최종 수익을 계산한다. * [ ] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. * [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. -* [ ] 참가자가 패한다면 배팅한 금액을 잃는다. -* [ ] 참가자가 승리한다면 배팅한 금액을 받는다. +* [x] 참가자가 패한다면 배팅한 금액을 잃는다. +* [x] 참가자가 승리한다면 배팅한 금액을 받는다. --- diff --git a/src/main/java/domain/Amount.java b/src/main/java/domain/Amount.java new file mode 100644 index 00000000000..f0b1b75614a --- /dev/null +++ b/src/main/java/domain/Amount.java @@ -0,0 +1,28 @@ +package domain; + +import java.util.Objects; + +public class Amount { + + private final long value; + + public Amount(final long value) { + this.value = value; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Amount amount)) { + return false; + } + return Objects.equals(value, amount.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } +} diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java index c42c04e2a82..59a60ca1891 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/BetAmount.java @@ -2,6 +2,7 @@ import constants.ErrorCode; import exception.InvalidBetAmountException; +import java.util.Objects; public class BetAmount { @@ -12,9 +13,37 @@ public BetAmount(final long amount) { this.amount = amount; } - private void validate(final long value) { + private void validate(final long value) { // TODO 블랙잭일 경우 1.5배를 해줘야하기에 10원 단위인지 확인필요 if (value <= 0) { throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); } } + + public Amount loseAmount() { + return new Amount(-amount); + } + + public Amount winAmount() { + return new Amount(amount); + } + + public Amount tieAmount() { + return new Amount(0); + } + + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + if (!(target instanceof BetAmount betAmount)) { + return false; + } + return Objects.equals(amount, betAmount.amount); + } + + @Override + public int hashCode() { + return Objects.hashCode(amount); + } } diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 2785bca78de..61044a9c5be 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -7,6 +7,10 @@ public class Player extends Participant { + // TODO: Hands 로 레포지토리로 분리해보기? + // 만약 새로운 게임을 하고싶다 가정하면, + // Name 은 이미 있는 상태에서 Hands 만 바꿔보고 싶다. + public Player(final Name name, final Hands hands) { super(name, hands); validate(name); diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java new file mode 100644 index 00000000000..029230f1d40 --- /dev/null +++ b/src/main/java/repository/BetAmountRepository.java @@ -0,0 +1,43 @@ +package repository; + +import domain.Amount; +import domain.BetAmount; +import domain.Result; +import domain.participant.Dealer; +import domain.participant.Player; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +//TODO 이런 형태 정말 괜찮은가? +// 쓸만한가, 장점은 무엇인가, 단점은 무엇인가, 대안은 무엇인가 +public class BetAmountRepository { + + private final Map repository; + + public BetAmountRepository() { + this(new HashMap<>()); + } + + protected BetAmountRepository(final Map repository) { + this.repository = repository; + } + + public void put(final Player player, final BetAmount betAmount) { + repository.put(player, betAmount); + } + + public Map calculateResult(final Dealer dealer) { + final Map result = new HashMap<>(); + for (Entry entry : repository.entrySet()) { + if (Result.WIN == entry.getKey().calculateResult(dealer)) { + result.put(entry.getKey(), entry.getValue().winAmount()); + } else if (Result.TIE == entry.getKey().calculateResult(dealer)) { + result.put(entry.getKey(), entry.getValue().tieAmount()); + } else { + result.put(entry.getKey(), entry.getValue().loseAmount()); + } + } + return result; + } +} diff --git a/src/test/java/domain/HandsTestFixture.java b/src/test/java/domain/HandsTestFixture.java index 70f6a7e7148..c9a8d148242 100644 --- a/src/test/java/domain/HandsTestFixture.java +++ b/src/test/java/domain/HandsTestFixture.java @@ -22,29 +22,29 @@ import domain.participant.Hands; import java.util.List; -class HandsTestFixture { +public class HandsTestFixture { - static final Hands sum10Size2 = new Hands(List.of(new Card(FIVE, SPADE), new Card(FIVE, HEART))); - static final Hands sum17Size3One = new Hands( + public static final Hands sum10Size2 = new Hands(List.of(new Card(FIVE, SPADE), new Card(FIVE, HEART))); + public static final Hands sum17Size3One = new Hands( List.of(new Card(SEVEN, SPADE), new Card(FOUR, SPADE), new Card(SIX, SPADE))); - static final Hands sum17Size3Two = new Hands( + public static final Hands sum17Size3Two = new Hands( List.of(new Card(TEN, SPADE), new Card(THREE, SPADE), new Card(FOUR, SPADE))); - static final Hands sum18Size2 = new Hands(List.of(new Card(EIGHT, CLOVER), new Card(TEN, DIAMOND))); - static final Hands sum19Size4Ace11 = new Hands( + public static final Hands sum18Size2 = new Hands(List.of(new Card(EIGHT, CLOVER), new Card(TEN, DIAMOND))); + public static final Hands sum19Size4Ace11 = new Hands( List.of(new Card(ACE, DIAMOND), new Card(TWO, CLOVER), new Card(FOUR, CLOVER), new Card(TWO, CLOVER))); - static final Hands sum19Size3Ace1 = new Hands( + public static final Hands sum19Size3Ace1 = new Hands( List.of(new Card(ACE, HEART), new Card(NINE, SPADE), new Card(NINE, CLOVER))); - static final Hands sum20Size2 = new Hands(List.of(new Card(NINE, SPADE), new Card(ACE, SPADE))); - static final Hands sum20Size3 = new Hands( + public static final Hands sum20Size2 = new Hands(List.of(new Card(NINE, SPADE), new Card(ACE, SPADE))); + public static final Hands sum20Size3 = new Hands( List.of(new Card(SEVEN, SPADE), new Card(TWO, SPADE), new Card(ACE, SPADE))); - static final Hands sum20Size3Ace1 = new Hands( + public static final Hands sum20Size3Ace1 = new Hands( List.of(new Card(ACE, DIAMOND), new Card(EIGHT, CLOVER), new Card(FIVE, CLOVER), new Card(SIX, CLOVER))); - static final Hands sum21Size3 = new Hands( + public static final Hands sum21Size3 = new Hands( List.of(new Card(QUEEN, HEART), new Card(SIX, SPADE), new Card(FIVE, CLOVER))); - static final Hands sum21Size3Ace11 = new Hands( + public static final Hands sum21Size3Ace11 = new Hands( List.of(new Card(ACE, HEART), new Card(EIGHT, SPADE), new Card(TWO, CLOVER))); - static final Hands bustHands = new Hands( + public static final Hands bustHands = new Hands( List.of(new Card(EIGHT, DIAMOND), new Card(TWO, DIAMOND), new Card(TWO, DIAMOND), new Card(KING, CLOVER))); - static final Hands noBustHands = new Hands(List.of(new Card(JACK, HEART), new Card(TEN, SPADE))); - static final Hands blackJack = new Hands(List.of(new Card(JACK, HEART), new Card(ACE, SPADE))); + public static final Hands noBustHands = new Hands(List.of(new Card(JACK, HEART), new Card(TEN, SPADE))); + public static final Hands blackJack = new Hands(List.of(new Card(JACK, HEART), new Card(ACE, SPADE))); } diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java new file mode 100644 index 00000000000..093cfe21e13 --- /dev/null +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -0,0 +1,40 @@ +package repository; + +import static domain.HandsTestFixture.sum17Size3One; +import static domain.HandsTestFixture.sum20Size3; +import static domain.HandsTestFixture.sum21Size3; + +import domain.Amount; +import domain.BetAmount; +import domain.participant.Dealer; +import domain.participant.Name; +import domain.participant.Player; +import java.util.HashMap; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BetAmountRepositoryTest { + + @Test + @DisplayName("모든 플레이어가 이긴 경우, 최종 수익을 계산한다. (블랙잭인 경우는 없다)") + void calculateTotalAmountWhenAllPlayersWin() { + //given + final Dealer dealer = new Dealer(sum17Size3One); + final Player winner1 = new Player(new Name("레디"), sum20Size3); + final Player winner2 = new Player(new Name("제제"), sum21Size3); + + BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); + repository.put(winner1, new BetAmount(1000)); + repository.put(winner2, new BetAmount(2000)); + + Map expected = Map.of(winner1, new Amount(1000), winner2, new Amount(2000)); + + //when + Map result = repository.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } +} From 197f942a6440ec74a7fab4355394306c2772b411 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 00:42:57 +0900 Subject: [PATCH 09/40] =?UTF-8?q?feat:=20=EA=B0=81=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=EC=9E=90=EC=9D=98=20=EB=B0=B0=ED=8C=85=20=EA=B8=88=EC=95=A1?= =?UTF-8?q?=EC=9D=84=20=EC=9E=85=EB=A0=A5=20=EB=B0=9B=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=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 --- docs/README.md | 4 ++-- .../java/controller/BlackJackController.java | 8 ++++++++ src/main/java/controller/InputController.java | 19 +++++++++++++++++++ src/main/java/view/InputView.java | 19 +++++++++++++++++++ .../java/view/message/ErrorCodeMessage.java | 1 + 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index d7670d6b92a..cf563b5ee56 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,8 +41,8 @@
-* [ ] 각 참여자의 배팅 금액을 입력받는다. - * [ ] 정수가 아닐 시 예외가 발생한다. +* [x] 각 참여자의 배팅 금액을 입력받는다. + * [x] 정수가 아닐 시 예외가 발생한다. * [x] 양의 정수가 아닐 시 예외가 발생한다.
diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 5571a0284ee..21af1ca9028 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -1,18 +1,21 @@ package controller; import domain.Answer; +import domain.BetAmount; import domain.participant.Dealer; import domain.participant.Player; import domain.participant.Players; import dto.DealerHandsDto; import dto.ParticipantDto; import dto.ParticipantsDto; +import repository.BetAmountRepository; import view.OutputView; public class BlackJackController { private final InputController inputController; private final OutputView outputView; + private final BetAmountRepository repository = new BetAmountRepository(); // TODO 리팩터링 필요 public BlackJackController(final InputController inputController, final OutputView outputView) { @@ -24,6 +27,11 @@ public void run() { final Players players = inputController.getPlayers(); final Dealer dealer = new Dealer(); + for (Player player : players.getPlayers()) { + BetAmount betAmount = inputController.getBetAmount(player.getName()); + repository.put(player, betAmount); + } + initHands(players, dealer); dealWithPlayers(players, dealer); diff --git a/src/main/java/controller/InputController.java b/src/main/java/controller/InputController.java index 4f9bb5df966..31e29039b27 100644 --- a/src/main/java/controller/InputController.java +++ b/src/main/java/controller/InputController.java @@ -1,6 +1,7 @@ package controller; import domain.Answer; +import domain.BetAmount; import domain.participant.Players; import exception.CustomException; import java.util.List; @@ -33,6 +34,14 @@ public Answer getAnswer(String name) { return answer; } + public BetAmount getBetAmount(String name) { + BetAmount betAmount; + do { + betAmount = readBetAmount(name); + } while (betAmount == null); + return betAmount; + } + private Players readPlayers() { try { List rawNames = inputView.readNames(); @@ -52,4 +61,14 @@ private Answer readAnswer(String name) { return null; } } + + private BetAmount readBetAmount(final String name) { + try { + Long value = inputView.readBetAmount(name); + return new BetAmount(value); + } catch (CustomException exception) { + outputView.printException(exception.getErrorCode()); + return null; + } + } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 7981dfbabf3..ee7217fd8f2 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,6 +1,7 @@ package view; import constants.ErrorCode; +import exception.InvalidBetAmountException; import exception.InvalidInputException; import exception.InvalidSeparatorException; import java.util.Arrays; @@ -29,6 +30,16 @@ public List readNames() { return names; } + public Long readBetAmount(String name) { + System.out.printf("%s의 배팅 금액은?%n", name); + String rawAmount = scanner.nextLine().trim(); + validateBlank(rawAmount); + validateLong(rawAmount); + System.out.println(); + return Long.parseLong(rawAmount); + } + + public String readAnswer(String name) { System.out.printf("%s는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)%n", name); String rawAnswer = scanner.nextLine().trim(); @@ -57,4 +68,12 @@ private boolean isInvalidSeparator(final String rawNames) { } return rawNames.contains(NAME_SEPARATOR.repeat(2)); } + + private void validateLong(final String rawAmount) { + try { + Long.parseLong(rawAmount); + } catch (NumberFormatException exception) { + throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); + } + } } diff --git a/src/main/java/view/message/ErrorCodeMessage.java b/src/main/java/view/message/ErrorCodeMessage.java index 507dc908f71..f630c425ce2 100644 --- a/src/main/java/view/message/ErrorCodeMessage.java +++ b/src/main/java/view/message/ErrorCodeMessage.java @@ -16,6 +16,7 @@ public enum ErrorCodeMessage { DUPLICATE_NAME(ErrorCode.DUPLICATE_NAME, "중복된 이름은 사용할 수 없습니다."), RESERVED_NAME(ErrorCode.RESERVED_NAME, "이름은 딜러일 수 없습니다."), BLANK_VALUE(ErrorCode.BLANK_VALUE, "이름은 공백일 수 없습니다."), + INVALID_BET_AMOUNT(ErrorCode.INVALID_BET_AMOUNT, "유효하지 않은 배팅 금액입니다."), // TODO 세분화 필요? EMPTY_CARD(ErrorCode.EMPTY_CARD, "뽑을 수 있는 카드가 없습니다."), INVALID_COMMAND(ErrorCode.INVALID_COMMAND, "y 또는 n을 입력해주세요"), ; From 93e5b86e05bd310d419778047ce4d8d6de472a32 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 11:17:39 +0900 Subject: [PATCH 10/40] =?UTF-8?q?feat:=20=EB=8F=84=EB=A9=94=EC=9D=B8=20toS?= =?UTF-8?q?tring=20=EC=9E=AC=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Amount.java | 5 +++++ src/main/java/domain/BetAmount.java | 5 +++++ src/main/java/domain/participant/Hands.java | 8 +++++++- src/main/java/domain/participant/Name.java | 5 +++++ src/main/java/domain/participant/Participant.java | 8 ++++++++ src/main/java/domain/participant/Player.java | 5 +++++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/Amount.java b/src/main/java/domain/Amount.java index f0b1b75614a..ec0eba1c948 100644 --- a/src/main/java/domain/Amount.java +++ b/src/main/java/domain/Amount.java @@ -25,4 +25,9 @@ public boolean equals(final Object obj) { public int hashCode() { return Objects.hashCode(value); } + + @Override + public String toString() { + return String.valueOf(value); + } } diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java index 59a60ca1891..9296eadb1c2 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/BetAmount.java @@ -46,4 +46,9 @@ public boolean equals(final Object target) { public int hashCode() { return Objects.hashCode(amount); } + + @Override + public String toString() { + return String.valueOf(amount); + } } diff --git a/src/main/java/domain/participant/Hands.java b/src/main/java/domain/participant/Hands.java index 102d2966e86..c83ac788519 100644 --- a/src/main/java/domain/participant/Hands.java +++ b/src/main/java/domain/participant/Hands.java @@ -1,7 +1,7 @@ package domain.participant; -import domain.card.Card; import domain.Result; +import domain.card.Card; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -85,4 +85,10 @@ public boolean equals(final Object target) { public int hashCode() { return Objects.hash(cards); } + + @Override + public String toString() { + return "Hands=" + + cards; + } } diff --git a/src/main/java/domain/participant/Name.java b/src/main/java/domain/participant/Name.java index ffb95b64dbb..d8d0744bc3f 100644 --- a/src/main/java/domain/participant/Name.java +++ b/src/main/java/domain/participant/Name.java @@ -49,4 +49,9 @@ public boolean equals(final Object target) { public int hashCode() { return Objects.hashCode(value); } + + @Override + public String toString() { + return value; + } } diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 2afd7663a92..b0c8362b899 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -68,4 +68,12 @@ public boolean equals(final Object target) { public int hashCode() { return Objects.hash(name, hands); } + + @Override + public String toString() { + return "Participant{" + + "name=" + name + + ", hands=" + hands + + '}'; + } } diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 61044a9c5be..474c3f69d10 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -26,4 +26,9 @@ private void validate(final Name name) { public boolean canDeal() { return handsSum() < Hands.BLACK_JACK; } + + @Override + public String toString() { + return super.toString(); + } } From 8aba953ae0fd89703b093f79dac055641a5e23cd Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 12:00:14 +0900 Subject: [PATCH 11/40] =?UTF-8?q?feat:=20=EC=B0=B8=EA=B0=80=EC=9E=90?= =?UTF-8?q?=EB=A7=8C=20=EB=B8=94=EB=9E=99=EC=9E=AD=EC=9D=B8=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EB=B0=B0=ED=8C=85=20=EA=B8=88=EC=95=A1=EC=9D=98=20?= =?UTF-8?q?1.5=EB=B0=B0=EB=A5=BC=20=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/main/java/domain/BetAmount.java | 4 ++++ src/main/java/domain/Result.java | 12 +++++++++- src/main/java/domain/participant/Hands.java | 2 +- .../java/domain/participant/Participant.java | 2 +- .../java/repository/BetAmountRepository.java | 4 +++- src/test/java/domain/ResultTest.java | 2 +- .../repository/BetAmountRepositoryTest.java | 22 +++++++++++++++++++ 8 files changed, 44 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index cf563b5ee56..16749d09f64 100644 --- a/docs/README.md +++ b/docs/README.md @@ -80,7 +80,7 @@ * [ ] 딜러의 최종 수익을 계산한다. * [ ] 참가자의 최종 수익을 계산한다. -* [ ] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. +* [x] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. * [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. * [x] 참가자가 패한다면 배팅한 금액을 잃는다. * [x] 참가자가 승리한다면 배팅한 금액을 받는다. diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java index 9296eadb1c2..f42dccf7dca 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/BetAmount.java @@ -23,6 +23,10 @@ public Amount loseAmount() { return new Amount(-amount); } + public Amount blackJackWinAmount() { + return new Amount(amount + (amount / 2)); + } + public Amount winAmount() { return new Amount(amount); } diff --git a/src/main/java/domain/Result.java b/src/main/java/domain/Result.java index 15cdb949940..ac3c7418d20 100644 --- a/src/main/java/domain/Result.java +++ b/src/main/java/domain/Result.java @@ -6,7 +6,9 @@ public enum Result { + BLACK_JACK_WIN("블랙잭승", Result::blackJackWinningCondition), WIN("승", Result::winningCondition), + BLACK_JACK_TIE("블랙잭비김", Result::blackJackTieCondition), TIE("무", Result::tieCondition), LOSE("패", Result::loseCondition); @@ -19,7 +21,7 @@ public enum Result { } public Result reverse() { - if (Result.WIN.equals(this)) { + if (Result.WIN.equals(this) || Result.BLACK_JACK_WIN.equals(this)) { return LOSE; } if (Result.LOSE.equals(this)) { @@ -35,12 +37,20 @@ public static Result calculateOf(final Hands hands, final Hands target) { .orElseThrow(); } + private static boolean blackJackWinningCondition(Hands hands, Hands target) { + return hands.isBlackJack() && !target.isBlackJack(); + } + private static boolean winningCondition(final Hands hands, final Hands target) { return (!hands.isBust() && target.isBust()) || (hands.sum() > target.sum() && !hands.isBust()) || (hands.sum() == target.sum() && hands.size() < target.size() && !hands.isBust()); } + private static boolean blackJackTieCondition(final Hands hands, final Hands target) { + return hands.isBlackJack() && target.isBlackJack(); + } + private static boolean tieCondition(final Hands hands, final Hands target) { return hands.sum() == target.sum() && hands.size() == target.size() && !hands.isBust(); } diff --git a/src/main/java/domain/participant/Hands.java b/src/main/java/domain/participant/Hands.java index c83ac788519..0cea0b74d42 100644 --- a/src/main/java/domain/participant/Hands.java +++ b/src/main/java/domain/participant/Hands.java @@ -38,7 +38,7 @@ public boolean isBust() { } public boolean isBlackJack() { - return sum() == BLACK_JACK; + return sum() == BLACK_JACK && size() == 2; } private boolean hasAce() { diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index b0c8362b899..ff97e5eb41c 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -26,7 +26,7 @@ public boolean isBust() { } public boolean isBlackJack() { - return hands.isBlackJack() && hands.size() == 2; + return hands.isBlackJack(); } public int handsSum() { diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index 029230f1d40..919731ffae8 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -30,7 +30,9 @@ public void put(final Player player, final BetAmount betAmount) { public Map calculateResult(final Dealer dealer) { final Map result = new HashMap<>(); for (Entry entry : repository.entrySet()) { - if (Result.WIN == entry.getKey().calculateResult(dealer)) { + if (Result.BLACK_JACK_WIN == entry.getKey().calculateResult(dealer)) { + result.put(entry.getKey(), entry.getValue().blackJackWinAmount()); + } else if (Result.WIN == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().winAmount()); } else if (Result.TIE == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().tieAmount()); diff --git a/src/test/java/domain/ResultTest.java b/src/test/java/domain/ResultTest.java index c1c2ce418df..c4178890b81 100644 --- a/src/test/java/domain/ResultTest.java +++ b/src/test/java/domain/ResultTest.java @@ -42,7 +42,7 @@ void isLoseWhenCardSumGreater21() { @Test @DisplayName("blackjack이 이긴다.") void isWinBlackJack() { - Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(Result.WIN); + Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(Result.BLACK_JACK_WIN); Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(Result.LOSE); } } diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java index 093cfe21e13..63f6481cc52 100644 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -1,5 +1,7 @@ package repository; +import static domain.HandsTestFixture.blackJack; +import static domain.HandsTestFixture.sum10Size2; import static domain.HandsTestFixture.sum17Size3One; import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; @@ -37,4 +39,24 @@ void calculateTotalAmountWhenAllPlayersWin() { //then Assertions.assertThat(result).isEqualTo(expected); } + + @Test + @DisplayName("참여자가 블랙잭인 경우 1.5배의 수익을 얻는다.") + void blackJackAmount() { + final Dealer dealer = new Dealer(sum17Size3One); + final Player blackJackPlayer = new Player(new Name("수달"), blackJack); + final Player loser = new Player(new Name("레디"), sum10Size2); + + BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); + repository.put(blackJackPlayer, new BetAmount(10000)); + repository.put(loser, new BetAmount(2000)); + + Map expected = Map.of(blackJackPlayer, new Amount(15000), loser, new Amount(-2000)); + + //when + Map result = repository.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } } From b8b1ef95a252f6565207d3161790675cff41233b Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 13:24:46 +0900 Subject: [PATCH 12/40] =?UTF-8?q?feat:=20=EC=B0=B8=EA=B0=80=EC=9E=90?= =?UTF-8?q?=EC=99=80=20=EB=94=9C=EB=9F=AC=20=EB=AA=A8=EB=91=90=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=EC=9E=AD=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EB=B0=B0?= =?UTF-8?q?=ED=8C=85=ED=95=9C=20=EA=B8=88=EC=95=A1=20=EB=8F=8C=EB=A0=A4=20?= =?UTF-8?q?=EB=B0=9B=EB=8A=94=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 --- docs/README.md | 2 +- .../java/repository/BetAmountRepository.java | 5 ++++- .../repository/BetAmountRepositoryTest.java | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 16749d09f64..7fe5dc14f83 100644 --- a/docs/README.md +++ b/docs/README.md @@ -81,7 +81,7 @@ * [ ] 딜러의 최종 수익을 계산한다. * [ ] 참가자의 최종 수익을 계산한다. * [x] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. -* [ ] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. +* [x] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. * [x] 참가자가 패한다면 배팅한 금액을 잃는다. * [x] 참가자가 승리한다면 배팅한 금액을 받는다. diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index 919731ffae8..77b22c89478 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -29,12 +29,15 @@ public void put(final Player player, final BetAmount betAmount) { public Map calculateResult(final Dealer dealer) { final Map result = new HashMap<>(); + + //TODO 리팩터링 대상 for (Entry entry : repository.entrySet()) { if (Result.BLACK_JACK_WIN == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().blackJackWinAmount()); } else if (Result.WIN == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().winAmount()); - } else if (Result.TIE == entry.getKey().calculateResult(dealer)) { + } else if (Result.TIE == entry.getKey().calculateResult(dealer) + || Result.BLACK_JACK_TIE == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().tieAmount()); } else { result.put(entry.getKey(), entry.getValue().loseAmount()); diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java index 63f6481cc52..7f06d0b2db3 100644 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -3,6 +3,7 @@ import static domain.HandsTestFixture.blackJack; import static domain.HandsTestFixture.sum10Size2; import static domain.HandsTestFixture.sum17Size3One; +import static domain.HandsTestFixture.sum18Size2; import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; @@ -59,4 +60,24 @@ void blackJackAmount() { //then Assertions.assertThat(result).isEqualTo(expected); } + + @Test + @DisplayName("참가자와 딜러 모두 블랙잭인 경우 배팅 금액을 돌려받는다.") + void playerAndDealerBlackJack() { + final Dealer dealer = new Dealer(blackJack); + final Player blackJackPlayer = new Player(new Name("수달"), blackJack); + final Player loser = new Player(new Name("레디"), sum18Size2); + + BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); + repository.put(blackJackPlayer, new BetAmount(10000)); + repository.put(loser, new BetAmount(2000)); + + Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2000)); + + //when + Map result = repository.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } } From d51ecdf381d8ab80aa3ae2e14b3720bae0e7fd52 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 13:46:29 +0900 Subject: [PATCH 13/40] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=EC=9D=98=20?= =?UTF-8?q?=EC=B5=9C=EC=A2=85=20=EC=88=98=EC=9D=B5=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=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 --- docs/README.md | 4 +- src/main/java/domain/Amount.java | 4 ++ .../java/repository/BetAmountRepository.java | 10 +++++ .../repository/BetAmountRepositoryTest.java | 43 +++++++++++++++---- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7fe5dc14f83..6e2d6d2c11d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -78,8 +78,8 @@
-* [ ] 딜러의 최종 수익을 계산한다. -* [ ] 참가자의 최종 수익을 계산한다. +* [x] 딜러의 최종 수익을 계산한다. +* [x] 참가자의 최종 수익을 계산한다. * [x] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. * [x] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다. * [x] 참가자가 패한다면 배팅한 금액을 잃는다. diff --git a/src/main/java/domain/Amount.java b/src/main/java/domain/Amount.java index ec0eba1c948..17aef7518b0 100644 --- a/src/main/java/domain/Amount.java +++ b/src/main/java/domain/Amount.java @@ -10,6 +10,10 @@ public Amount(final long value) { this.value = value; } + public long getValue() { + return value; + } + @Override public boolean equals(final Object obj) { if (this == obj) { diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index 77b22c89478..e0c5c5ac2b1 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -14,6 +14,7 @@ public class BetAmountRepository { private final Map repository; + private Map result; // TODO 리팩터링 대상 public BetAmountRepository() { this(new HashMap<>()); @@ -43,6 +44,15 @@ public Map calculateResult(final Dealer dealer) { result.put(entry.getKey(), entry.getValue().loseAmount()); } } + this.result = result; return result; } + + public Amount calculateDealerAmount() { + long dealerAmount = result.values().stream() + .map(Amount::getValue) + .mapToLong(Long::longValue) + .sum(); + return new Amount(dealerAmount); + } } diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java index 7f06d0b2db3..12469a8a0ac 100644 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -4,6 +4,7 @@ import static domain.HandsTestFixture.sum10Size2; import static domain.HandsTestFixture.sum17Size3One; import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum19Size3Ace1; import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; @@ -29,10 +30,10 @@ void calculateTotalAmountWhenAllPlayersWin() { final Player winner2 = new Player(new Name("제제"), sum21Size3); BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(winner1, new BetAmount(1000)); - repository.put(winner2, new BetAmount(2000)); + repository.put(winner1, new BetAmount(1_000)); + repository.put(winner2, new BetAmount(2_000)); - Map expected = Map.of(winner1, new Amount(1000), winner2, new Amount(2000)); + Map expected = Map.of(winner1, new Amount(1_000), winner2, new Amount(2_000)); //when Map result = repository.calculateResult(dealer); @@ -49,10 +50,10 @@ void blackJackAmount() { final Player loser = new Player(new Name("레디"), sum10Size2); BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(blackJackPlayer, new BetAmount(10000)); - repository.put(loser, new BetAmount(2000)); + repository.put(blackJackPlayer, new BetAmount(10_000)); + repository.put(loser, new BetAmount(2_000)); - Map expected = Map.of(blackJackPlayer, new Amount(15000), loser, new Amount(-2000)); + Map expected = Map.of(blackJackPlayer, new Amount(15_000), loser, new Amount(-2_000)); //when Map result = repository.calculateResult(dealer); @@ -69,10 +70,10 @@ void playerAndDealerBlackJack() { final Player loser = new Player(new Name("레디"), sum18Size2); BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(blackJackPlayer, new BetAmount(10000)); - repository.put(loser, new BetAmount(2000)); + repository.put(blackJackPlayer, new BetAmount(10_000)); + repository.put(loser, new BetAmount(2_000)); - Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2000)); + Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2_000)); //when Map result = repository.calculateResult(dealer); @@ -80,4 +81,28 @@ void playerAndDealerBlackJack() { //then Assertions.assertThat(result).isEqualTo(expected); } + + @Test + @DisplayName("딜러의 최종 수익을 계산한다.") + void dealerAmount() { + //given + final Dealer dealer = new Dealer(sum19Size3Ace1); + final Player winner1 = new Player(new Name("레디"), sum20Size3); + final Player winner2 = new Player(new Name("제제"), sum21Size3); + final Player loser1 = new Player(new Name("브라운"), sum17Size3One); + + BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); + repository.put(winner1, new BetAmount(10_000)); + repository.put(winner2, new BetAmount(30_000)); + repository.put(loser1, new BetAmount(500_000)); + + //when + //TODO 이거 한번에 수행하는 게 더 좋을듯 + repository.calculateResult(dealer); + final Amount amount = repository.calculateDealerAmount(); + final Amount expected = new Amount(-460_000); + + //then + Assertions.assertThat(amount).isEqualTo(expected); + } } From 4a03db2eeb4d183d2f5169d522f21a1bfa28e383 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 15:23:53 +0900 Subject: [PATCH 14/40] =?UTF-8?q?feat:=20=EB=94=9C=EB=9F=AC=EC=99=80=20?= =?UTF-8?q?=EC=B0=B8=EA=B0=80=EC=9E=90=EC=9D=98=20=EC=B5=9C=EC=A2=85=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackJackController.java | 2 +- src/main/java/repository/BetAmountRepository.java | 7 ++++--- src/main/java/view/OutputView.java | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 21af1ca9028..2ef9e7bcb3e 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -70,7 +70,7 @@ private void initHands(final Players players, final Dealer dealer) { private void printFinalResult(final Players players, final Dealer dealer) { outputView.printHandsResult(ParticipantsDto.of(dealer, players)); - outputView.printGameResult(dealer.getDealerResult(players), players.getPlayersResult(dealer)); + outputView.printGameResult(repository.calculateResult(dealer), repository.calculateDealerAmount()); } private void deal(final Player player, final Dealer dealer) { diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index e0c5c5ac2b1..de593b2d1ee 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -6,6 +6,7 @@ import domain.participant.Dealer; import domain.participant.Player; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -17,7 +18,7 @@ public class BetAmountRepository { private Map result; // TODO 리팩터링 대상 public BetAmountRepository() { - this(new HashMap<>()); + this(new LinkedHashMap<>()); } protected BetAmountRepository(final Map repository) { @@ -29,7 +30,7 @@ public void put(final Player player, final BetAmount betAmount) { } public Map calculateResult(final Dealer dealer) { - final Map result = new HashMap<>(); + final Map result = new LinkedHashMap<>(); //TODO 리팩터링 대상 for (Entry entry : repository.entrySet()) { @@ -53,6 +54,6 @@ public Amount calculateDealerAmount() { .map(Amount::getValue) .mapToLong(Long::longValue) .sum(); - return new Amount(dealerAmount); + return new Amount(-dealerAmount); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 87c607de6bf..a242c1cd708 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -4,6 +4,7 @@ import static domain.participant.Dealer.THRESHOLD; import constants.ErrorCode; +import domain.Amount; import domain.Result; import domain.participant.Player; import dto.DealerHandsDto; @@ -11,6 +12,7 @@ import dto.ParticipantsDto; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import view.message.ErrorCodeMessage; public class OutputView { @@ -51,10 +53,11 @@ public void printHandsResult(final ParticipantsDto participantsDto) { System.out.print(LINE); } - public void printGameResult(final Map dealerResult, final Map playerResult) { - System.out.println("## 최종결과"); - System.out.printf(RESULT_FORM, "딜러", format(dealerResult)); - for (Map.Entry entry : playerResult.entrySet()) { + public void printGameResult(final Map playerAmountMap, final Amount amount) { + System.out.println("## 최종 수익"); + System.out.printf("딜러: %d%n", amount.getValue()); // TODO 숫자 세자리마다 쉼표 + + for (Entry entry : playerAmountMap.entrySet()) { System.out.printf(RESULT_FORM, entry.getKey().getName(), entry.getValue().getValue()); } } From 874cd417a1e61edd085430c00ea67bdee63fe8e8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 15:24:44 +0900 Subject: [PATCH 15/40] =?UTF-8?q?fix:=20test=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/repository/BetAmountRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java index 12469a8a0ac..e22eeafe6a9 100644 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -100,7 +100,7 @@ void dealerAmount() { //TODO 이거 한번에 수행하는 게 더 좋을듯 repository.calculateResult(dealer); final Amount amount = repository.calculateDealerAmount(); - final Amount expected = new Amount(-460_000); + final Amount expected = new Amount(460_000); //then Assertions.assertThat(amount).isEqualTo(expected); From 52a9b0f294ff1738b99ad4b3bc15fdfc7e652628 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 16:53:39 +0900 Subject: [PATCH 16/40] =?UTF-8?q?refactor:=20=EB=94=9C=EB=9F=AC=EA=B0=80?= =?UTF-8?q?=20=EB=B8=94=EB=9E=99=EC=9E=AD=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EB=A9=94=EC=84=9C=EB=93=9C=20view=20?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackJackController.java | 4 ++-- src/main/java/view/OutputView.java | 14 ++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 2ef9e7bcb3e..8d2d92f7760 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -51,12 +51,12 @@ private void printDealerTurnMessage(final int turn) { private void dealWithPlayers(final Players players, final Dealer dealer) { if (dealer.isBlackJack()) { - System.out.println("딜러가 블랙잭임"); + outputView.printDealerBlackJack(); return; } for (Player player : players.getPlayers()) { if (player.isBlackJack()) { - System.out.println("플레이어가 블랙잭임"); + outputView.printBlackJack(); continue; } deal(player, dealer); diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index a242c1cd708..0c33697661d 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -5,7 +5,6 @@ import constants.ErrorCode; import domain.Amount; -import domain.Result; import domain.participant.Player; import dto.DealerHandsDto; import dto.ParticipantDto; @@ -62,15 +61,6 @@ public void printGameResult(final Map playerAmountMap, final Amo } } - private String format(final Map dealerResult) { - StringBuilder stringBuilder = new StringBuilder(); - for (Map.Entry entry : dealerResult.entrySet()) { - stringBuilder.append(entry.getValue()).append(entry.getKey().getValue()).append(" "); - } - - return stringBuilder.toString(); - } - private String format(final List playerNames) { return String.join(", ", playerNames); } @@ -94,4 +84,8 @@ public void printDealEndMessage(final boolean isBust) { } printBlackJack(); } + + public void printDealerBlackJack() { + System.out.println("딜러가 블랙잭!!!"); + } } From f5c0b4da6032eae7c9595cca0b68cf176c786754 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 17:18:32 +0900 Subject: [PATCH 17/40] =?UTF-8?q?fix:=20=EB=AC=B4=EC=8A=B9=EB=B6=80=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 5 ++--- src/main/java/domain/Result.java | 11 ++--------- src/main/java/repository/BetAmountRepository.java | 4 +--- src/test/java/domain/BetAmountTest.java | 3 +-- src/test/java/domain/ResultTest.java | 9 ++------- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/docs/README.md b/docs/README.md index 6e2d6d2c11d..7bc55b96efc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,17 +2,16 @@ ## 참여자 -* [ ] 다시한번 룰 숙지 필요 +* [x] 다시한번 룰 숙지 필요 **승** * (딜러 카드 합 < 참여자 카드 합) && 참여자가 버스트가 아닌 경우 -* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 > 참여자 카드 수) && 참여자가 버스트가 아닌 경우 * 딜러가 버스트인 경우 && 참여자가 버스트가 아닌 경우 **무** -* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 == 참여자 카드 수) && 참여자가 버스트가 아닌 경우 +* (딜러 카드 합 == 참여자 카드 합) && 참여자가 버스트가 아닌 경우 **패** diff --git a/src/main/java/domain/Result.java b/src/main/java/domain/Result.java index ac3c7418d20..6f50f158d29 100644 --- a/src/main/java/domain/Result.java +++ b/src/main/java/domain/Result.java @@ -8,7 +8,6 @@ public enum Result { BLACK_JACK_WIN("블랙잭승", Result::blackJackWinningCondition), WIN("승", Result::winningCondition), - BLACK_JACK_TIE("블랙잭비김", Result::blackJackTieCondition), TIE("무", Result::tieCondition), LOSE("패", Result::loseCondition); @@ -42,17 +41,11 @@ private static boolean blackJackWinningCondition(Hands hands, Hands target) { } private static boolean winningCondition(final Hands hands, final Hands target) { - return (!hands.isBust() && target.isBust()) - || (hands.sum() > target.sum() && !hands.isBust()) - || (hands.sum() == target.sum() && hands.size() < target.size() && !hands.isBust()); - } - - private static boolean blackJackTieCondition(final Hands hands, final Hands target) { - return hands.isBlackJack() && target.isBlackJack(); + return (!hands.isBust() && target.isBust()) || (hands.sum() > target.sum() && !hands.isBust()); } private static boolean tieCondition(final Hands hands, final Hands target) { - return hands.sum() == target.sum() && hands.size() == target.size() && !hands.isBust(); + return hands.sum() == target.sum() && !hands.isBust(); } private static boolean loseCondition(final Hands hands, final Hands target) { diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index de593b2d1ee..81f8843c4d9 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -5,7 +5,6 @@ import domain.Result; import domain.participant.Dealer; import domain.participant.Player; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -38,8 +37,7 @@ public Map calculateResult(final Dealer dealer) { result.put(entry.getKey(), entry.getValue().blackJackWinAmount()); } else if (Result.WIN == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().winAmount()); - } else if (Result.TIE == entry.getKey().calculateResult(dealer) - || Result.BLACK_JACK_TIE == entry.getKey().calculateResult(dealer)) { + } else if (Result.TIE == entry.getKey().calculateResult(dealer)) { result.put(entry.getKey(), entry.getValue().tieAmount()); } else { result.put(entry.getKey(), entry.getValue().loseAmount()); diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java index b7a3af2a985..bf13bf812d6 100644 --- a/src/test/java/domain/BetAmountTest.java +++ b/src/test/java/domain/BetAmountTest.java @@ -3,12 +3,11 @@ import exception.InvalidBetAmountException; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; class BetAmountTest { - + @ParameterizedTest @DisplayName("베팅 금액이 0 이하일 시 예외가 발생한다.") @ValueSource(ints = {0, -1, -100000}) diff --git a/src/test/java/domain/ResultTest.java b/src/test/java/domain/ResultTest.java index c4178890b81..35effa14d25 100644 --- a/src/test/java/domain/ResultTest.java +++ b/src/test/java/domain/ResultTest.java @@ -14,16 +14,11 @@ class ResultTest { - @DisplayName("카드 합이 같고 카드 갯수가 같으면 무승부이다.") + @DisplayName("카드 합이 같다면 무승부이다.") @Test void isTie() { Assertions.assertThat(sum17Size3One.calculateResult(sum17Size3Two)).isEqualTo(Result.TIE); - } - - @DisplayName("카드 합이 같은데 카드 갯수가 더 적으면 승리이다.") - @Test - void isWinBySize() { - Assertions.assertThat(sum20Size2.calculateResult(sum20Size3)).isEqualTo(Result.WIN); + Assertions.assertThat(sum20Size2.calculateResult(sum20Size3)).isEqualTo(Result.TIE); } @Test From 87d8f09d0dae41e5bab9fcdae110188c169c5bcb Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 17:47:04 +0900 Subject: [PATCH 18/40] =?UTF-8?q?refactor:=20=EB=B0=B0=ED=8C=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=EC=9D=84=20=EC=B5=9C=EC=A2=85=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EA=B8=88=EC=95=A1=EC=9D=84=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=ED=98=95=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98=EB=B0=8D=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Result.java | 23 ++++++++++--------- .../java/repository/BetAmountRepository.java | 19 +++++---------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/main/java/domain/Result.java b/src/main/java/domain/Result.java index 6f50f158d29..a62d4cd2def 100644 --- a/src/main/java/domain/Result.java +++ b/src/main/java/domain/Result.java @@ -3,20 +3,21 @@ import domain.participant.Hands; import java.util.Arrays; import java.util.function.BiPredicate; +import java.util.function.Function; public enum Result { - BLACK_JACK_WIN("블랙잭승", Result::blackJackWinningCondition), - WIN("승", Result::winningCondition), - TIE("무", Result::tieCondition), - LOSE("패", Result::loseCondition); + BLACK_JACK_WIN(Result::blackJackWinningCondition, BetAmount::blackJackWinAmount), + WIN(Result::winningCondition, BetAmount::winAmount), + TIE(Result::tieCondition, BetAmount::tieAmount), + LOSE(Result::loseCondition, BetAmount::loseAmount); - private final String value; private final BiPredicate condition; + private final Function calculate; - Result(final String value, final BiPredicate condition) { - this.value = value; + Result(final BiPredicate condition, final Function calculate) { this.condition = condition; + this.calculate = calculate; } public Result reverse() { @@ -36,6 +37,10 @@ public static Result calculateOf(final Hands hands, final Hands target) { .orElseThrow(); } + public Amount apply(BetAmount betAmount) { + return calculate.apply(betAmount); + } + private static boolean blackJackWinningCondition(Hands hands, Hands target) { return hands.isBlackJack() && !target.isBlackJack(); } @@ -51,8 +56,4 @@ private static boolean tieCondition(final Hands hands, final Hands target) { private static boolean loseCondition(final Hands hands, final Hands target) { return hands.isBust() || hands.sum() < target.sum() || !target.isBust(); } - - public String getValue() { - return value; - } } diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java index 81f8843c4d9..2fad2932e90 100644 --- a/src/main/java/repository/BetAmountRepository.java +++ b/src/main/java/repository/BetAmountRepository.java @@ -29,22 +29,15 @@ public void put(final Player player, final BetAmount betAmount) { } public Map calculateResult(final Dealer dealer) { - final Map result = new LinkedHashMap<>(); - //TODO 리팩터링 대상 + final Map playerAmountMap = new LinkedHashMap<>(); + for (Entry entry : repository.entrySet()) { - if (Result.BLACK_JACK_WIN == entry.getKey().calculateResult(dealer)) { - result.put(entry.getKey(), entry.getValue().blackJackWinAmount()); - } else if (Result.WIN == entry.getKey().calculateResult(dealer)) { - result.put(entry.getKey(), entry.getValue().winAmount()); - } else if (Result.TIE == entry.getKey().calculateResult(dealer)) { - result.put(entry.getKey(), entry.getValue().tieAmount()); - } else { - result.put(entry.getKey(), entry.getValue().loseAmount()); - } + Result calculateResult = entry.getKey().calculateResult(dealer); + playerAmountMap.put(entry.getKey(), calculateResult.apply(entry.getValue())); } - this.result = result; - return result; + this.result = playerAmountMap; + return playerAmountMap; } public Amount calculateDealerAmount() { From 29889478d7d13d722d0f455e56cb810498036a7c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 18:57:23 +0900 Subject: [PATCH 19/40] =?UTF-8?q?feat:=2010=EC=9C=BC=EB=A1=9C=20=EB=82=98?= =?UTF-8?q?=EB=88=84=EC=96=B4=20=EB=96=A8=EC=96=B4=EC=A7=80=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=9C=BC=EB=A9=B4=20=EC=98=88=EC=99=B8=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=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 --- docs/README.md | 2 ++ src/main/java/domain/BetAmount.java | 25 ++++++++++++++++++++----- src/test/java/domain/BetAmountTest.java | 10 +++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7bc55b96efc..3b290e7925b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -43,6 +43,8 @@ * [x] 각 참여자의 배팅 금액을 입력받는다. * [x] 정수가 아닐 시 예외가 발생한다. * [x] 양의 정수가 아닐 시 예외가 발생한다. + * [x] 10으로 나누어 떨어지지 않으면 예외가 발생한다. + * 블랙잭시 1.5배를 해주기 위함
diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java index f42dccf7dca..8c7f4e4506a 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/BetAmount.java @@ -6,6 +6,9 @@ public class BetAmount { + private static final int UNIT = 10; + private static final int MIN_RANGE = 0; + private final long amount; public BetAmount(final long amount) { @@ -13,11 +16,6 @@ public BetAmount(final long amount) { this.amount = amount; } - private void validate(final long value) { // TODO 블랙잭일 경우 1.5배를 해줘야하기에 10원 단위인지 확인필요 - if (value <= 0) { - throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); - } - } public Amount loseAmount() { return new Amount(-amount); @@ -35,6 +33,23 @@ public Amount tieAmount() { return new Amount(0); } + private void validate(final long value) { + validateRange(value); + validateUnit(value); + } + + private void validateUnit(final long value) { + if (value % UNIT != 0) { + throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); + } + } + + private void validateRange(final long value) { + if (value <= MIN_RANGE) { + throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); + } + } + @Override public boolean equals(final Object target) { if (this == target) { diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java index bf13bf812d6..5d5c12d05bd 100644 --- a/src/test/java/domain/BetAmountTest.java +++ b/src/test/java/domain/BetAmountTest.java @@ -10,9 +10,17 @@ class BetAmountTest { @ParameterizedTest @DisplayName("베팅 금액이 0 이하일 시 예외가 발생한다.") - @ValueSource(ints = {0, -1, -100000}) + @ValueSource(longs = {0, -1, -100000}) void invalidBetAmount(long value) { Assertions.assertThatThrownBy(() -> new BetAmount(value)) .isInstanceOf(InvalidBetAmountException.class); } + + @ParameterizedTest + @DisplayName("배팅 금액이 10으로 나누어 떨어질 시 예외가 발생한다.") + @ValueSource(longs = {5, 13, 10001}) + void invalidUnitBetAmount(long value) { + Assertions.assertThatThrownBy(() -> new BetAmount(value)) + .isInstanceOf(InvalidBetAmountException.class); + } } From 24e020d635abe4d148996760deec30011c9a3187 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 19:02:36 +0900 Subject: [PATCH 20/40] =?UTF-8?q?refactor:=20Participant=20equals=20&=20ha?= =?UTF-8?q?shCode=20=EC=97=90=EC=84=9C=20Hands=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/participant/Participant.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index ff97e5eb41c..2749ecd524d 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -61,12 +61,12 @@ public boolean equals(final Object target) { if (!(target instanceof Participant participant)) { return false; } - return Objects.equals(name, participant.name) && Objects.equals(hands, participant.hands); + return Objects.equals(name, participant.name); } @Override public int hashCode() { - return Objects.hash(name, hands); + return Objects.hash(name); } @Override From 2fb529fd60b79d132998a88c1448806a2e9d2f10 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 19:25:18 +0900 Subject: [PATCH 21/40] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8F=AC=EB=A7=A4=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/exception/InvalidBetAmountException.java | 2 +- src/main/java/exception/InvalidPlayerNameException.java | 2 +- src/main/java/exception/InvalidPlayersSizeException.java | 2 +- src/main/java/exception/InvalidSeparatorException.java | 2 +- src/main/java/exception/MessageDoesNotExistException.java | 2 +- src/main/java/exception/NoMoreCardException.java | 2 +- src/test/java/domain/PlayerTest.java | 1 + 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/exception/InvalidBetAmountException.java b/src/main/java/exception/InvalidBetAmountException.java index 94b1688fe57..38c2ab15431 100644 --- a/src/main/java/exception/InvalidBetAmountException.java +++ b/src/main/java/exception/InvalidBetAmountException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class InvalidBetAmountException extends CustomException{ +public class InvalidBetAmountException extends CustomException { public InvalidBetAmountException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/main/java/exception/InvalidPlayerNameException.java b/src/main/java/exception/InvalidPlayerNameException.java index 2bf217ea37e..0d43def32d7 100644 --- a/src/main/java/exception/InvalidPlayerNameException.java +++ b/src/main/java/exception/InvalidPlayerNameException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class InvalidPlayerNameException extends CustomException{ +public class InvalidPlayerNameException extends CustomException { public InvalidPlayerNameException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/main/java/exception/InvalidPlayersSizeException.java b/src/main/java/exception/InvalidPlayersSizeException.java index 72428435841..9fbc5e47a08 100644 --- a/src/main/java/exception/InvalidPlayersSizeException.java +++ b/src/main/java/exception/InvalidPlayersSizeException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class InvalidPlayersSizeException extends CustomException{ +public class InvalidPlayersSizeException extends CustomException { public InvalidPlayersSizeException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/main/java/exception/InvalidSeparatorException.java b/src/main/java/exception/InvalidSeparatorException.java index 76538c156d8..36336cabc62 100644 --- a/src/main/java/exception/InvalidSeparatorException.java +++ b/src/main/java/exception/InvalidSeparatorException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class InvalidSeparatorException extends CustomException{ +public class InvalidSeparatorException extends CustomException { public InvalidSeparatorException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/main/java/exception/MessageDoesNotExistException.java b/src/main/java/exception/MessageDoesNotExistException.java index 74251064ca6..d7669bd6dd5 100644 --- a/src/main/java/exception/MessageDoesNotExistException.java +++ b/src/main/java/exception/MessageDoesNotExistException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class MessageDoesNotExistException extends CustomException{ +public class MessageDoesNotExistException extends CustomException { public MessageDoesNotExistException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/main/java/exception/NoMoreCardException.java b/src/main/java/exception/NoMoreCardException.java index 25551e0a6bc..000c233da86 100644 --- a/src/main/java/exception/NoMoreCardException.java +++ b/src/main/java/exception/NoMoreCardException.java @@ -2,7 +2,7 @@ import constants.ErrorCode; -public class NoMoreCardException extends CustomException{ +public class NoMoreCardException extends CustomException { public NoMoreCardException(final ErrorCode errorCode) { super(errorCode); diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java index 6ea0a236293..0d8010ce697 100644 --- a/src/test/java/domain/PlayerTest.java +++ b/src/test/java/domain/PlayerTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.params.provider.MethodSource; class PlayerTest { + @DisplayName("이름으로 참여자를 생성한다.") @Test void createPlayerWithName() { From 09ea27a90724b532d962246539692aeb1f431890 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 20:50:20 +0900 Subject: [PATCH 22/40] =?UTF-8?q?refactor:=20Player=EC=9D=98=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EC=97=90=20BetAmount=20=ED=8F=AC=ED=95=A8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=ED=98=95=ED=83=9C=EB=A1=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackJackController.java | 25 +- src/main/java/controller/InputController.java | 16 +- src/main/java/domain/participant/Dealer.java | 10 + src/main/java/domain/participant/Names.java | 49 ++++ src/main/java/domain/participant/Player.java | 17 +- src/main/java/domain/participant/Players.java | 13 +- .../repository/BetAmountRepositoryTest.java | 216 +++++++++--------- 7 files changed, 219 insertions(+), 127 deletions(-) create mode 100644 src/main/java/domain/participant/Names.java diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 8d2d92f7760..b54b2b2f54d 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -1,13 +1,19 @@ package controller; +import domain.Amount; import domain.Answer; import domain.BetAmount; import domain.participant.Dealer; +import domain.participant.Name; +import domain.participant.Names; import domain.participant.Player; import domain.participant.Players; import dto.DealerHandsDto; import dto.ParticipantDto; import dto.ParticipantsDto; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import repository.BetAmountRepository; import view.OutputView; @@ -15,7 +21,7 @@ public class BlackJackController { private final InputController inputController; private final OutputView outputView; - private final BetAmountRepository repository = new BetAmountRepository(); // TODO 리팩터링 필요 +// private final BetAmountRepository repository = new BetAmountRepository(); // TODO 리팩터링 필요 public BlackJackController(final InputController inputController, final OutputView outputView) { @@ -24,14 +30,18 @@ public BlackJackController(final InputController inputController, final OutputVi } public void run() { - final Players players = inputController.getPlayers(); + final Names names = inputController.getPlayers(); final Dealer dealer = new Dealer(); - for (Player player : players.getPlayers()) { - BetAmount betAmount = inputController.getBetAmount(player.getName()); - repository.put(player, betAmount); + final List temp = new ArrayList<>(); + for (final Name name : names.getPlayerNames()) { + BetAmount betAmount = inputController.getBetAmount(name.getValue()); + temp.add(new Player(name, betAmount)); +// repository.put(player, betAmount); } + final Players players = new Players(temp); + initHands(players, dealer); dealWithPlayers(players, dealer); @@ -70,7 +80,10 @@ private void initHands(final Players players, final Dealer dealer) { private void printFinalResult(final Players players, final Dealer dealer) { outputView.printHandsResult(ParticipantsDto.of(dealer, players)); - outputView.printGameResult(repository.calculateResult(dealer), repository.calculateDealerAmount()); + Map finalResult = players.calculateResult(dealer); + Amount dealerAmount = dealer.calculateRevenue(finalResult); + outputView.printGameResult(finalResult, dealerAmount); +// outputView.printGameResult(repository.calculateResult(dealer), repository.calculateDealerAmount()); } private void deal(final Player player, final Dealer dealer) { diff --git a/src/main/java/controller/InputController.java b/src/main/java/controller/InputController.java index 31e29039b27..cecfcb18788 100644 --- a/src/main/java/controller/InputController.java +++ b/src/main/java/controller/InputController.java @@ -2,7 +2,7 @@ import domain.Answer; import domain.BetAmount; -import domain.participant.Players; +import domain.participant.Names; import exception.CustomException; import java.util.List; import view.InputView; @@ -18,12 +18,12 @@ public InputController(final InputView inputView, final OutputView outputView) { this.outputView = outputView; } - public Players getPlayers() { - Players players; + public Names getPlayers() { + Names playerNames; do { - players = readPlayers(); - } while (players == null); - return players; + playerNames = readPlayerNames(); + } while (playerNames == null); + return playerNames; } public Answer getAnswer(String name) { @@ -42,10 +42,10 @@ public BetAmount getBetAmount(String name) { return betAmount; } - private Players readPlayers() { + private Names readPlayerNames() { try { List rawNames = inputView.readNames(); - return Players.from(rawNames); + return Names.from(rawNames); } catch (CustomException exception) { outputView.printException(exception.getErrorCode()); return null; diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index 08cc130792d..a5d30da547f 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -1,5 +1,6 @@ package domain.participant; +import domain.Amount; import domain.Answer; import domain.Result; import domain.card.Card; @@ -72,6 +73,15 @@ public Map getDealerResult(final Players players) { return dealerResult; } + public Amount calculateRevenue(final Map finalResult) { + long dealerAmount = finalResult.values() + .stream() + .map(Amount::getValue) + .mapToLong(Long::longValue) + .sum(); + return new Amount(-dealerAmount); + } + @Override public boolean canDeal() { return handsSum() <= THRESHOLD; diff --git a/src/main/java/domain/participant/Names.java b/src/main/java/domain/participant/Names.java new file mode 100644 index 00000000000..a6f5a1b67fa --- /dev/null +++ b/src/main/java/domain/participant/Names.java @@ -0,0 +1,49 @@ +package domain.participant; + +import constants.ErrorCode; +import exception.DuplicatePlayerNameException; +import exception.InvalidPlayersSizeException; +import java.util.List; +import java.util.Set; + +public class Names { + + private static final int MIN_SIZE = 2; + private static final int MAX_SIZE = 8; + + private final List playerNames; + + private Names(final List playerNames) { + this.playerNames = playerNames; + } + + public static Names from(final List names) { + List result = names.stream() + .map(String::trim) + .map(Name::new) + .toList(); + validate(result); + return new Names(result); + } + + private static void validate(final List names) { + validateSize(names); + validateDuplicate(names); + } + + private static void validateSize(final List names) { + if (names.size() < MIN_SIZE || MAX_SIZE < names.size()) { + throw new InvalidPlayersSizeException(ErrorCode.INVALID_SIZE); + } + } + + private static void validateDuplicate(final List names) { + if (names.size() != Set.copyOf(names).size()) { + throw new DuplicatePlayerNameException(ErrorCode.DUPLICATE_NAME); + } + } + + public List getPlayerNames() { + return playerNames; + } +} diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 474c3f69d10..efdb038a371 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -3,17 +3,22 @@ import static domain.participant.Dealer.DEALER_NAME; import constants.ErrorCode; +import domain.BetAmount; import exception.ReservedPlayerNameException; public class Player extends Participant { - // TODO: Hands 로 레포지토리로 분리해보기? - // 만약 새로운 게임을 하고싶다 가정하면, - // Name 은 이미 있는 상태에서 Hands 만 바꿔보고 싶다. + private final BetAmount betAmount; - public Player(final Name name, final Hands hands) { + public Player(final Name name, final Hands hands) { // TODO 이전 테스트를 위한 생성자 super(name, hands); validate(name); + this.betAmount = new BetAmount(10); + } + + public Player(final Name name, final BetAmount betAmount) { + super(name, Hands.createEmptyHands()); + this.betAmount = betAmount; } private void validate(final Name name) { @@ -22,6 +27,10 @@ private void validate(final Name name) { } } + public BetAmount getBetAmount() { + return betAmount; + } + @Override public boolean canDeal() { return handsSum() < Hands.BLACK_JACK; diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index 3a36865b2d9..88503f75e46 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 constants.ErrorCode; +import domain.Amount; import domain.Result; import exception.DuplicatePlayerNameException; import exception.InvalidPlayersSizeException; @@ -21,7 +22,7 @@ public Players(final List names) { this.names = names; } - public static Players from(final List names) { + protected static Players from(final List names) { List players = mapToPlayers(names); validate(players); return new Players(players); @@ -44,6 +45,16 @@ public Map getPlayersResult(final Dealer dealer) { return result; } + public Map calculateResult(final Dealer dealer) { + final Map playerAmountMap = new LinkedHashMap<>(); + + for (Player player : names) { + Result gameResult = player.calculateResult(dealer); + playerAmountMap.put(player, gameResult.apply(player.getBetAmount())); + } + return playerAmountMap; + } + private static List mapToPlayers(final List names) { return names.stream() .map(String::trim) diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java index e22eeafe6a9..3215dbac2d3 100644 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ b/src/test/java/repository/BetAmountRepositoryTest.java @@ -1,108 +1,108 @@ -package repository; - -import static domain.HandsTestFixture.blackJack; -import static domain.HandsTestFixture.sum10Size2; -import static domain.HandsTestFixture.sum17Size3One; -import static domain.HandsTestFixture.sum18Size2; -import static domain.HandsTestFixture.sum19Size3Ace1; -import static domain.HandsTestFixture.sum20Size3; -import static domain.HandsTestFixture.sum21Size3; - -import domain.Amount; -import domain.BetAmount; -import domain.participant.Dealer; -import domain.participant.Name; -import domain.participant.Player; -import java.util.HashMap; -import java.util.Map; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class BetAmountRepositoryTest { - - @Test - @DisplayName("모든 플레이어가 이긴 경우, 최종 수익을 계산한다. (블랙잭인 경우는 없다)") - void calculateTotalAmountWhenAllPlayersWin() { - //given - final Dealer dealer = new Dealer(sum17Size3One); - final Player winner1 = new Player(new Name("레디"), sum20Size3); - final Player winner2 = new Player(new Name("제제"), sum21Size3); - - BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(winner1, new BetAmount(1_000)); - repository.put(winner2, new BetAmount(2_000)); - - Map expected = Map.of(winner1, new Amount(1_000), winner2, new Amount(2_000)); - - //when - Map result = repository.calculateResult(dealer); - - //then - Assertions.assertThat(result).isEqualTo(expected); - } - - @Test - @DisplayName("참여자가 블랙잭인 경우 1.5배의 수익을 얻는다.") - void blackJackAmount() { - final Dealer dealer = new Dealer(sum17Size3One); - final Player blackJackPlayer = new Player(new Name("수달"), blackJack); - final Player loser = new Player(new Name("레디"), sum10Size2); - - BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(blackJackPlayer, new BetAmount(10_000)); - repository.put(loser, new BetAmount(2_000)); - - Map expected = Map.of(blackJackPlayer, new Amount(15_000), loser, new Amount(-2_000)); - - //when - Map result = repository.calculateResult(dealer); - - //then - Assertions.assertThat(result).isEqualTo(expected); - } - - @Test - @DisplayName("참가자와 딜러 모두 블랙잭인 경우 배팅 금액을 돌려받는다.") - void playerAndDealerBlackJack() { - final Dealer dealer = new Dealer(blackJack); - final Player blackJackPlayer = new Player(new Name("수달"), blackJack); - final Player loser = new Player(new Name("레디"), sum18Size2); - - BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(blackJackPlayer, new BetAmount(10_000)); - repository.put(loser, new BetAmount(2_000)); - - Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2_000)); - - //when - Map result = repository.calculateResult(dealer); - - //then - Assertions.assertThat(result).isEqualTo(expected); - } - - @Test - @DisplayName("딜러의 최종 수익을 계산한다.") - void dealerAmount() { - //given - final Dealer dealer = new Dealer(sum19Size3Ace1); - final Player winner1 = new Player(new Name("레디"), sum20Size3); - final Player winner2 = new Player(new Name("제제"), sum21Size3); - final Player loser1 = new Player(new Name("브라운"), sum17Size3One); - - BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); - repository.put(winner1, new BetAmount(10_000)); - repository.put(winner2, new BetAmount(30_000)); - repository.put(loser1, new BetAmount(500_000)); - - //when - //TODO 이거 한번에 수행하는 게 더 좋을듯 - repository.calculateResult(dealer); - final Amount amount = repository.calculateDealerAmount(); - final Amount expected = new Amount(460_000); - - //then - Assertions.assertThat(amount).isEqualTo(expected); - } -} +//package repository; +// +//import static domain.HandsTestFixture.blackJack; +//import static domain.HandsTestFixture.sum10Size2; +//import static domain.HandsTestFixture.sum17Size3One; +//import static domain.HandsTestFixture.sum18Size2; +//import static domain.HandsTestFixture.sum19Size3Ace1; +//import static domain.HandsTestFixture.sum20Size3; +//import static domain.HandsTestFixture.sum21Size3; +// +//import domain.Amount; +//import domain.BetAmount; +//import domain.participant.Dealer; +//import domain.participant.Name; +//import domain.participant.Player; +//import java.util.HashMap; +//import java.util.Map; +//import org.assertj.core.api.Assertions; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +// +//class BetAmountRepositoryTest { +// +// @Test +// @DisplayName("모든 플레이어가 이긴 경우, 최종 수익을 계산한다. (블랙잭인 경우는 없다)") +// void calculateTotalAmountWhenAllPlayersWin() { +// //given +// final Dealer dealer = new Dealer(sum17Size3One); +// final Player winner1 = new Player(new Name("레디"), sum20Size3); +// final Player winner2 = new Player(new Name("제제"), sum21Size3); +// +// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); +// repository.put(winner1, new BetAmount(1_000)); +// repository.put(winner2, new BetAmount(2_000)); +// +// Map expected = Map.of(winner1, new Amount(1_000), winner2, new Amount(2_000)); +// +// //when +// Map result = repository.calculateResult(dealer); +// +// //then +// Assertions.assertThat(result).isEqualTo(expected); +// } +// +// @Test +// @DisplayName("참여자가 블랙잭인 경우 1.5배의 수익을 얻는다.") +// void blackJackAmount() { +// final Dealer dealer = new Dealer(sum17Size3One); +// final Player blackJackPlayer = new Player(new Name("수달"), blackJack); +// final Player loser = new Player(new Name("레디"), sum10Size2); +// +// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); +// repository.put(blackJackPlayer, new BetAmount(10_000)); +// repository.put(loser, new BetAmount(2_000)); +// +// Map expected = Map.of(blackJackPlayer, new Amount(15_000), loser, new Amount(-2_000)); +// +// //when +// Map result = repository.calculateResult(dealer); +// +// //then +// Assertions.assertThat(result).isEqualTo(expected); +// } +// +// @Test +// @DisplayName("참가자와 딜러 모두 블랙잭인 경우 배팅 금액을 돌려받는다.") +// void playerAndDealerBlackJack() { +// final Dealer dealer = new Dealer(blackJack); +// final Player blackJackPlayer = new Player(new Name("수달"), blackJack); +// final Player loser = new Player(new Name("레디"), sum18Size2); +// +// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); +// repository.put(blackJackPlayer, new BetAmount(10_000)); +// repository.put(loser, new BetAmount(2_000)); +// +// Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2_000)); +// +// //when +// Map result = repository.calculateResult(dealer); +// +// //then +// Assertions.assertThat(result).isEqualTo(expected); +// } +// +// @Test +// @DisplayName("딜러의 최종 수익을 계산한다.") +// void dealerAmount() { +// //given +// final Dealer dealer = new Dealer(sum19Size3Ace1); +// final Player winner1 = new Player(new Name("레디"), sum20Size3); +// final Player winner2 = new Player(new Name("제제"), sum21Size3); +// final Player loser1 = new Player(new Name("브라운"), sum17Size3One); +// +// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); +// repository.put(winner1, new BetAmount(10_000)); +// repository.put(winner2, new BetAmount(30_000)); +// repository.put(loser1, new BetAmount(500_000)); +// +// //when +// //TODO 이거 한번에 수행하는 게 더 좋을듯 +// repository.calculateResult(dealer); +// final Amount amount = repository.calculateDealerAmount(); +// final Amount expected = new Amount(460_000); +// +// //then +// Assertions.assertThat(amount).isEqualTo(expected); +// } +//} From 02f44e08ffc5b378caaac2a287bee99865baf9e9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 21:09:04 +0900 Subject: [PATCH 23/40] =?UTF-8?q?refactor:=20repository=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackJackController.java | 5 - src/main/java/domain/participant/Player.java | 6 + src/main/java/domain/participant/Players.java | 37 ---- .../java/repository/BetAmountRepository.java | 50 ------ src/test/java/domain/PlayersTest.java | 158 ----------------- .../domain/{ => participant}/DealerTest.java | 24 ++- .../java/domain/participant/NamesTest.java | 80 +++++++++ .../domain/{ => participant}/PlayerTest.java | 5 +- .../java/domain/participant/PlayersTest.java | 160 ++++++++++++++++++ .../repository/BetAmountRepositoryTest.java | 108 ------------ 10 files changed, 258 insertions(+), 375 deletions(-) delete mode 100644 src/main/java/repository/BetAmountRepository.java delete mode 100644 src/test/java/domain/PlayersTest.java rename src/test/java/domain/{ => participant}/DealerTest.java (87%) create mode 100644 src/test/java/domain/participant/NamesTest.java rename src/test/java/domain/{ => participant}/PlayerTest.java (95%) create mode 100644 src/test/java/domain/participant/PlayersTest.java delete mode 100644 src/test/java/repository/BetAmountRepositoryTest.java diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index b54b2b2f54d..0da470e0900 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -14,15 +14,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import repository.BetAmountRepository; import view.OutputView; public class BlackJackController { private final InputController inputController; private final OutputView outputView; -// private final BetAmountRepository repository = new BetAmountRepository(); // TODO 리팩터링 필요 - public BlackJackController(final InputController inputController, final OutputView outputView) { this.inputController = inputController; @@ -37,7 +34,6 @@ public void run() { for (final Name name : names.getPlayerNames()) { BetAmount betAmount = inputController.getBetAmount(name.getValue()); temp.add(new Player(name, betAmount)); -// repository.put(player, betAmount); } final Players players = new Players(temp); @@ -83,7 +79,6 @@ private void printFinalResult(final Players players, final Dealer dealer) { Map finalResult = players.calculateResult(dealer); Amount dealerAmount = dealer.calculateRevenue(finalResult); outputView.printGameResult(finalResult, dealerAmount); -// outputView.printGameResult(repository.calculateResult(dealer), repository.calculateDealerAmount()); } private void deal(final Player player, final Dealer dealer) { diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index efdb038a371..5fdc403b5f7 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -10,12 +10,18 @@ public class Player extends Participant { private final BetAmount betAmount; + protected Player(final Name name, final Hands hands, final BetAmount betAmount) { + super(name, hands); + this.betAmount = betAmount; + } + public Player(final Name name, final Hands hands) { // TODO 이전 테스트를 위한 생성자 super(name, hands); validate(name); this.betAmount = new BetAmount(10); } + public Player(final Name name, final BetAmount betAmount) { super(name, Hands.createEmptyHands()); this.betAmount = betAmount; diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index 88503f75e46..c9294a947cf 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,33 +1,20 @@ package domain.participant; -import constants.ErrorCode; import domain.Amount; import domain.Result; -import exception.DuplicatePlayerNameException; -import exception.InvalidPlayersSizeException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Consumer; public class Players { - private static final int MIN_SIZE = 2; - private static final int MAX_SIZE = 8; - private final List names; public Players(final List names) { this.names = names; } - protected static Players from(final List names) { - List players = mapToPlayers(names); - validate(players); - return new Players(players); - } - public void forEach(Consumer action) { names.forEach(action); } @@ -55,30 +42,6 @@ public Map calculateResult(final Dealer dealer) { return playerAmountMap; } - private static List mapToPlayers(final List names) { - return names.stream() - .map(String::trim) - .map(name -> new Player(new Name(name), Hands.createEmptyHands())) - .toList(); - } - - private static void validate(final List names) { - validateSize(names); - validateDuplicate(names); - } - - private static void validateSize(final List names) { - if (names.size() < MIN_SIZE || MAX_SIZE < names.size()) { - throw new InvalidPlayersSizeException(ErrorCode.INVALID_SIZE); - } - } - - private static void validateDuplicate(final List names) { - if (names.size() != Set.copyOf(names).size()) { - throw new DuplicatePlayerNameException(ErrorCode.DUPLICATE_NAME); - } - } - public List getPlayers() { return names; } diff --git a/src/main/java/repository/BetAmountRepository.java b/src/main/java/repository/BetAmountRepository.java deleted file mode 100644 index 2fad2932e90..00000000000 --- a/src/main/java/repository/BetAmountRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -package repository; - -import domain.Amount; -import domain.BetAmount; -import domain.Result; -import domain.participant.Dealer; -import domain.participant.Player; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; - -//TODO 이런 형태 정말 괜찮은가? -// 쓸만한가, 장점은 무엇인가, 단점은 무엇인가, 대안은 무엇인가 -public class BetAmountRepository { - - private final Map repository; - private Map result; // TODO 리팩터링 대상 - - public BetAmountRepository() { - this(new LinkedHashMap<>()); - } - - protected BetAmountRepository(final Map repository) { - this.repository = repository; - } - - public void put(final Player player, final BetAmount betAmount) { - repository.put(player, betAmount); - } - - public Map calculateResult(final Dealer dealer) { - //TODO 리팩터링 대상 - final Map playerAmountMap = new LinkedHashMap<>(); - - for (Entry entry : repository.entrySet()) { - Result calculateResult = entry.getKey().calculateResult(dealer); - playerAmountMap.put(entry.getKey(), calculateResult.apply(entry.getValue())); - } - this.result = playerAmountMap; - return playerAmountMap; - } - - public Amount calculateDealerAmount() { - long dealerAmount = result.values().stream() - .map(Amount::getValue) - .mapToLong(Long::longValue) - .sum(); - return new Amount(-dealerAmount); - } -} diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java deleted file mode 100644 index 2aacee41b52..00000000000 --- a/src/test/java/domain/PlayersTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package domain; - -import static domain.HandsTestFixture.bustHands; -import static domain.HandsTestFixture.noBustHands; -import static domain.HandsTestFixture.sum18Size2; -import static domain.HandsTestFixture.sum20Size2; -import static domain.HandsTestFixture.sum20Size3; -import static domain.HandsTestFixture.sum21Size3; -import static domain.Result.LOSE; -import static domain.Result.TIE; -import static domain.Result.WIN; - -import domain.participant.Dealer; -import domain.participant.Name; -import domain.participant.Player; -import domain.participant.Players; -import exception.DuplicatePlayerNameException; -import exception.InvalidPlayersSizeException; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -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; - -class PlayersTest { - - @Test - @DisplayName("참여자 이름 중복시 예외가 발생한다.") - void duplicatePlayerName() { - //given - final List names = List.of("redy", "redy"); - - //when & then - Assertions.assertThatThrownBy(() -> Players.from(names)) - .isInstanceOf(DuplicatePlayerNameException.class); - } - - @ParameterizedTest - @DisplayName("참여자 이름에 공백이 있는 경우 제거하여 중복을 판단한다.") - @MethodSource("duplicateBlankNameParameterProvider") - void duplicateBlankName(final List names) { - Assertions.assertThatThrownBy(() -> Players.from(names)) - .isInstanceOf(DuplicatePlayerNameException.class); - } - - @DisplayName("총 참여자 수가 2이상 8이하이면 참여자를 생성한다.") - @ParameterizedTest - @MethodSource("validPlayersSizeParameterProvider") - void validPlayersSize(final List names) { - Assertions.assertThatCode(() -> Players.from(names)) - .doesNotThrowAnyException(); - } - - @DisplayName("총 참여자 수는 2이상 8이하가 아니면 예외가 발생한다.") - @ParameterizedTest - @MethodSource("invalidPlayersSizeParameterProvider") - void invalidPlayersSize(final List names) { - Assertions.assertThatThrownBy(() -> Players.from(names)) - .isInstanceOf(InvalidPlayersSizeException.class); - } - - @Test - @DisplayName("참가자 중 버스트 되지 않은 참가자가 있다면 isAllBust가 False를 반환한다.") - void isAllBustFalse() { - //given - final Player bustPlayer = new Player(new Name("레디"), bustHands); - final Player noBustPlayer = new Player(new Name("제제"), noBustHands); - final Players players = new Players(List.of(bustPlayer, noBustPlayer)); - - //when && then - Assertions.assertThat(players.isAllBust()).isFalse(); - } - - @Test - @DisplayName("모든 참가자가 버스트되면 isAllBust가 True를 반환한다.") - void isAllBustTrue() { - //given - Player player1 = new Player(new Name("레디"), bustHands); - Player player2 = new Player(new Name("제제"), bustHands); - Player player3 = new Player(new Name("수달"), bustHands); - Player player4 = new Player(new Name("피케이"), bustHands); - - Players players = new Players(List.of(player1, player2, player3, player4)); - - //when && then - Assertions.assertThat(players.isAllBust()).isTrue(); - } - - @Test - @DisplayName("참여자의 승패무를 판단한다.") - void playerResult() { - //given - Player loser = new Player(new Name("레디"), sum18Size2); - Player winner = new Player(new Name("제제"), sum21Size3); - Player tier = new Player(new Name("수달"), sum20Size3); - - Players players = new Players(List.of(loser, winner, tier)); - Dealer dealer = new Dealer(sum20Size3); - - //when & then - Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); - Assertions.assertThat(players.getPlayersResult(dealer)).isEqualTo(expected); - } - - @Test - @DisplayName("딜러가 버스트일때 참여자가 버스트가 아니면 WIN") - void all() { - //given - Dealer bustDealer = new Dealer(bustHands); - Player winner1 = new Player(new Name("레디"), sum18Size2); - Player winner2 = new Player(new Name("브라운"), sum20Size2); - Player loser = new Player(new Name("제제"), bustHands); - - Players players = new Players(List.of(winner1, winner2, loser)); - - //when - Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); - Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); - - //then - Assertions.assertThat(players.getPlayersResult(bustDealer)).isEqualTo(expectedPlayerResult); - Assertions.assertThat(bustDealer.getDealerResult(players)).isEqualTo(expectedDealerResult); - } - - static Stream duplicateBlankNameParameterProvider() { - return Stream.of( - Arguments.of(List.of("a", "a ", "b")), - Arguments.of(List.of(" a ", " a", "b", "c")), - Arguments.of(List.of("a", " a")) - ); - } - - static Stream validPlayersSizeParameterProvider() { - return Stream.of( - Arguments.of( - List.of("pobi", "jason") - ), - Arguments.of( - List.of("1", "2", "3", "4", "5", "6", "7", "8") - ) - ); - } - - static Stream invalidPlayersSizeParameterProvider() { - return Stream.of( - Arguments.of( - List.of("pobi") - ), - Arguments.of( - List.of("1", "2", "3", "4", "5", "6", "7", "8", "9") - ) - ); - } -} diff --git a/src/test/java/domain/DealerTest.java b/src/test/java/domain/participant/DealerTest.java similarity index 87% rename from src/test/java/domain/DealerTest.java rename to src/test/java/domain/participant/DealerTest.java index cd2d3b4e5b0..4dd24fd6693 100644 --- a/src/test/java/domain/DealerTest.java +++ b/src/test/java/domain/participant/DealerTest.java @@ -1,4 +1,4 @@ -package domain; +package domain.participant; import static domain.HandsTestFixture.blackJack; import static domain.HandsTestFixture.sum10Size2; @@ -9,12 +9,11 @@ import static domain.Result.LOSE; import static domain.Result.TIE; import static domain.Result.WIN; +import static org.junit.jupiter.api.Assertions.assertAll; -import domain.participant.Dealer; -import domain.participant.Hands; -import domain.participant.Name; -import domain.participant.Player; -import domain.participant.Players; +import domain.Answer; +import domain.BetAmount; +import domain.Result; import java.util.List; import java.util.Map; import org.assertj.core.api.Assertions; @@ -27,7 +26,9 @@ class DealerTest { @DisplayName("참여자에게 카드 2장을 나눠준다.") void dealCards() { //given - final Players players = Players.from(List.of("레디", "제제")); + final Player player1 = new Player(new Name("레디"), new BetAmount(100)); + final Player player2 = new Player(new Name("제제"), new BetAmount(1000)); + final Players players = new Players(List.of(player1, player2)); final Dealer dealer = new Dealer(); //when @@ -113,13 +114,10 @@ void checkingBlackJack() { Player blackJackPlayer = new Player(new Name("수달"), blackJack); Player noBlackJackPlayer = new Player(new Name("레디"), sum18Size2); - //when - org.junit.jupiter.api.Assertions.assertAll( - () -> Assertions.assertThat(dealer.isBlackJack()).isFalse(), + //when && then + assertAll(() -> Assertions.assertThat(dealer.isBlackJack()).isFalse(), () -> Assertions.assertThat(blackJackPlayer.isBlackJack()).isTrue(), - () -> Assertions.assertThat(noBlackJackPlayer.isBlackJack()).isFalse() - ); + () -> Assertions.assertThat(noBlackJackPlayer.isBlackJack()).isFalse()); - //then } } diff --git a/src/test/java/domain/participant/NamesTest.java b/src/test/java/domain/participant/NamesTest.java new file mode 100644 index 00000000000..4c21707a2e5 --- /dev/null +++ b/src/test/java/domain/participant/NamesTest.java @@ -0,0 +1,80 @@ +package domain.participant; + +import exception.DuplicatePlayerNameException; +import exception.InvalidPlayersSizeException; +import java.util.List; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +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; + +class NamesTest { + + @Test + @DisplayName("참여자 이름 중복시 예외가 발생한다.") + void duplicatePlayerName() { + //given + final List names = List.of("redy", "redy"); + + //when & then + Assertions.assertThatThrownBy(() -> Names.from(names)) + .isInstanceOf(DuplicatePlayerNameException.class); + } + + @ParameterizedTest + @DisplayName("참여자 이름에 공백이 있는 경우 제거하여 중복을 판단한다.") + @MethodSource("duplicateBlankNameParameterProvider") + void duplicateBlankName(final List names) { + Assertions.assertThatThrownBy(() -> Names.from(names)) + .isInstanceOf(DuplicatePlayerNameException.class); + } + + @DisplayName("총 참여자 수가 2이상 8이하이면 참여자를 생성한다.") + @ParameterizedTest + @MethodSource("validPlayersSizeParameterProvider") + void validPlayersSize(final List names) { + Assertions.assertThatCode(() -> Names.from(names)) + .doesNotThrowAnyException(); + } + + @DisplayName("총 참여자 수는 2이상 8이하가 아니면 예외가 발생한다.") + @ParameterizedTest + @MethodSource("invalidPlayersSizeParameterProvider") + void invalidPlayersSize(final List names) { + Assertions.assertThatThrownBy(() -> Names.from(names)) + .isInstanceOf(InvalidPlayersSizeException.class); + } + + static Stream duplicateBlankNameParameterProvider() { + return Stream.of( + Arguments.of(List.of("a", "a ", "b")), + Arguments.of(List.of(" a ", " a", "b", "c")), + Arguments.of(List.of("a", " a")) + ); + } + + static Stream validPlayersSizeParameterProvider() { + return Stream.of( + Arguments.of( + List.of("pobi", "jason") + ), + Arguments.of( + List.of("1", "2", "3", "4", "5", "6", "7", "8") + ) + ); + } + + static Stream invalidPlayersSizeParameterProvider() { + return Stream.of( + Arguments.of( + List.of("pobi") + ), + Arguments.of( + List.of("1", "2", "3", "4", "5", "6", "7", "8", "9") + ) + ); + } +} diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/participant/PlayerTest.java similarity index 95% rename from src/test/java/domain/PlayerTest.java rename to src/test/java/domain/participant/PlayerTest.java index 0d8010ce697..eaa5b170595 100644 --- a/src/test/java/domain/PlayerTest.java +++ b/src/test/java/domain/participant/PlayerTest.java @@ -1,13 +1,10 @@ -package domain; +package domain.participant; import static domain.HandsTestFixture.bustHands; import static domain.HandsTestFixture.sum18Size2; import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum21Size3Ace11; -import domain.participant.Hands; -import domain.participant.Name; -import domain.participant.Player; import exception.ReservedPlayerNameException; import java.util.stream.Stream; import org.assertj.core.api.Assertions; diff --git a/src/test/java/domain/participant/PlayersTest.java b/src/test/java/domain/participant/PlayersTest.java new file mode 100644 index 00000000000..8b8b656f605 --- /dev/null +++ b/src/test/java/domain/participant/PlayersTest.java @@ -0,0 +1,160 @@ +package domain.participant; + +import static domain.HandsTestFixture.blackJack; +import static domain.HandsTestFixture.bustHands; +import static domain.HandsTestFixture.noBustHands; +import static domain.HandsTestFixture.sum10Size2; +import static domain.HandsTestFixture.sum17Size3One; +import static domain.HandsTestFixture.sum18Size2; +import static domain.HandsTestFixture.sum19Size3Ace1; +import static domain.HandsTestFixture.sum20Size2; +import static domain.HandsTestFixture.sum20Size3; +import static domain.HandsTestFixture.sum21Size3; +import static domain.Result.LOSE; +import static domain.Result.TIE; +import static domain.Result.WIN; + +import domain.Amount; +import domain.BetAmount; +import domain.Result; +import java.util.List; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PlayersTest { + + @Test + @DisplayName("참가자 중 버스트 되지 않은 참가자가 있다면 isAllBust가 False를 반환한다.") + void isAllBustFalse() { + //given + final Player bustPlayer = new Player(new Name("레디"), bustHands); + final Player noBustPlayer = new Player(new Name("제제"), noBustHands); + final Players players = new Players(List.of(bustPlayer, noBustPlayer)); + + //when && then + Assertions.assertThat(players.isAllBust()).isFalse(); + } + + @Test + @DisplayName("모든 참가자가 버스트되면 isAllBust가 True를 반환한다.") + void isAllBustTrue() { + //given + Player player1 = new Player(new Name("레디"), bustHands); + Player player2 = new Player(new Name("제제"), bustHands); + Player player3 = new Player(new Name("수달"), bustHands); + Player player4 = new Player(new Name("피케이"), bustHands); + + Players players = new Players(List.of(player1, player2, player3, player4)); + + //when && then + Assertions.assertThat(players.isAllBust()).isTrue(); + } + + @Test + @DisplayName("참여자의 승패무를 판단한다.") + void playerResult() { + //given + Player loser = new Player(new Name("레디"), sum18Size2); + Player winner = new Player(new Name("제제"), sum21Size3); + Player tier = new Player(new Name("수달"), sum20Size3); + + Players players = new Players(List.of(loser, winner, tier)); + Dealer dealer = new Dealer(sum20Size3); + + //when & then + Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); + Assertions.assertThat(players.getPlayersResult(dealer)).isEqualTo(expected); + } + + @Test + @DisplayName("딜러가 버스트일때 참여자가 버스트가 아니면 WIN") + void all() { + //given + Dealer bustDealer = new Dealer(bustHands); + Player winner1 = new Player(new Name("레디"), sum18Size2); + Player winner2 = new Player(new Name("브라운"), sum20Size2); + Player loser = new Player(new Name("제제"), bustHands); + + Players players = new Players(List.of(winner1, winner2, loser)); + + //when + Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); + Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); + + //then + Assertions.assertThat(players.getPlayersResult(bustDealer)).isEqualTo(expectedPlayerResult); + Assertions.assertThat(bustDealer.getDealerResult(players)).isEqualTo(expectedDealerResult); + } + + + @Test + @DisplayName("모든 플레이어가 이긴 경우, 최종 수익을 계산한다. (블랙잭인 경우는 없다)") + void calculateTotalAmountWhenAllPlayersWin() { + //given + final Dealer dealer = new Dealer(sum17Size3One); + final Player winner1 = new Player(new Name("레디"), sum20Size3, new BetAmount(1_000)); + final Player winner2 = new Player(new Name("제제"), sum21Size3, new BetAmount(2_000)); + final Players players = new Players(List.of(winner1, winner2)); + final Map expected = Map.of(winner1, new Amount(1_000), winner2, new Amount(2_000)); + + //when + final Map result = players.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("참여자가 블랙잭인 경우 1.5배의 수익을 얻는다.") + void blackJackAmount() { + final Dealer dealer = new Dealer(sum17Size3One); + final Player blackJackPlayer = new Player(new Name("수달"), blackJack, new BetAmount(10_000)); + final Player loser = new Player(new Name("레디"), sum10Size2, new BetAmount(2_000)); + final Players players = new Players(List.of(blackJackPlayer, loser)); + + final Map expected = Map.of(blackJackPlayer, new Amount(15_000), loser, new Amount(-2_000)); + + //when + final Map result = players.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("참가자와 딜러 모두 블랙잭인 경우 배팅 금액을 돌려받는다.") + void playerAndDealerBlackJack() { + final Dealer dealer = new Dealer(blackJack); + final Player blackJackPlayer = new Player(new Name("수달"), blackJack, new BetAmount(10_000)); + final Player loser = new Player(new Name("레디"), sum18Size2, new BetAmount(2_000)); + final Players players = new Players(List.of(blackJackPlayer, loser)); + final Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2_000)); + + //when + final Map result = players.calculateResult(dealer); + + //then + Assertions.assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("딜러의 최종 수익을 계산한다.") + void dealerAmount() { + //given + final Dealer dealer = new Dealer(sum19Size3Ace1); + final Player winner1 = new Player(new Name("레디"), sum20Size3, new BetAmount(10_000)); + final Player winner2 = new Player(new Name("제제"), sum21Size3, new BetAmount(30_000)); + final Player loser1 = new Player(new Name("브라운"), sum17Size3One, new BetAmount(500_000)); + final Players players = new Players(List.of(winner1, winner2, loser1)); + + //when + final Map playerAmountMap = players.calculateResult(dealer); + final Amount amount = dealer.calculateRevenue(playerAmountMap); + final Amount expected = new Amount(460_000); + + //then + Assertions.assertThat(amount).isEqualTo(expected); + } +} diff --git a/src/test/java/repository/BetAmountRepositoryTest.java b/src/test/java/repository/BetAmountRepositoryTest.java deleted file mode 100644 index 3215dbac2d3..00000000000 --- a/src/test/java/repository/BetAmountRepositoryTest.java +++ /dev/null @@ -1,108 +0,0 @@ -//package repository; -// -//import static domain.HandsTestFixture.blackJack; -//import static domain.HandsTestFixture.sum10Size2; -//import static domain.HandsTestFixture.sum17Size3One; -//import static domain.HandsTestFixture.sum18Size2; -//import static domain.HandsTestFixture.sum19Size3Ace1; -//import static domain.HandsTestFixture.sum20Size3; -//import static domain.HandsTestFixture.sum21Size3; -// -//import domain.Amount; -//import domain.BetAmount; -//import domain.participant.Dealer; -//import domain.participant.Name; -//import domain.participant.Player; -//import java.util.HashMap; -//import java.util.Map; -//import org.assertj.core.api.Assertions; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -// -//class BetAmountRepositoryTest { -// -// @Test -// @DisplayName("모든 플레이어가 이긴 경우, 최종 수익을 계산한다. (블랙잭인 경우는 없다)") -// void calculateTotalAmountWhenAllPlayersWin() { -// //given -// final Dealer dealer = new Dealer(sum17Size3One); -// final Player winner1 = new Player(new Name("레디"), sum20Size3); -// final Player winner2 = new Player(new Name("제제"), sum21Size3); -// -// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); -// repository.put(winner1, new BetAmount(1_000)); -// repository.put(winner2, new BetAmount(2_000)); -// -// Map expected = Map.of(winner1, new Amount(1_000), winner2, new Amount(2_000)); -// -// //when -// Map result = repository.calculateResult(dealer); -// -// //then -// Assertions.assertThat(result).isEqualTo(expected); -// } -// -// @Test -// @DisplayName("참여자가 블랙잭인 경우 1.5배의 수익을 얻는다.") -// void blackJackAmount() { -// final Dealer dealer = new Dealer(sum17Size3One); -// final Player blackJackPlayer = new Player(new Name("수달"), blackJack); -// final Player loser = new Player(new Name("레디"), sum10Size2); -// -// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); -// repository.put(blackJackPlayer, new BetAmount(10_000)); -// repository.put(loser, new BetAmount(2_000)); -// -// Map expected = Map.of(blackJackPlayer, new Amount(15_000), loser, new Amount(-2_000)); -// -// //when -// Map result = repository.calculateResult(dealer); -// -// //then -// Assertions.assertThat(result).isEqualTo(expected); -// } -// -// @Test -// @DisplayName("참가자와 딜러 모두 블랙잭인 경우 배팅 금액을 돌려받는다.") -// void playerAndDealerBlackJack() { -// final Dealer dealer = new Dealer(blackJack); -// final Player blackJackPlayer = new Player(new Name("수달"), blackJack); -// final Player loser = new Player(new Name("레디"), sum18Size2); -// -// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); -// repository.put(blackJackPlayer, new BetAmount(10_000)); -// repository.put(loser, new BetAmount(2_000)); -// -// Map expected = Map.of(blackJackPlayer, new Amount(0), loser, new Amount(-2_000)); -// -// //when -// Map result = repository.calculateResult(dealer); -// -// //then -// Assertions.assertThat(result).isEqualTo(expected); -// } -// -// @Test -// @DisplayName("딜러의 최종 수익을 계산한다.") -// void dealerAmount() { -// //given -// final Dealer dealer = new Dealer(sum19Size3Ace1); -// final Player winner1 = new Player(new Name("레디"), sum20Size3); -// final Player winner2 = new Player(new Name("제제"), sum21Size3); -// final Player loser1 = new Player(new Name("브라운"), sum17Size3One); -// -// BetAmountRepository repository = new BetAmountRepository(new HashMap<>()); -// repository.put(winner1, new BetAmount(10_000)); -// repository.put(winner2, new BetAmount(30_000)); -// repository.put(loser1, new BetAmount(500_000)); -// -// //when -// //TODO 이거 한번에 수행하는 게 더 좋을듯 -// repository.calculateResult(dealer); -// final Amount amount = repository.calculateDealerAmount(); -// final Amount expected = new Amount(460_000); -// -// //then -// Assertions.assertThat(amount).isEqualTo(expected); -// } -//} From 6b5c8e638c30e10170a64fa0850e9350fdc548ee Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 14 Mar 2024 21:12:43 +0900 Subject: [PATCH 24/40] =?UTF-8?q?refactor:=20Player=20equals=20&&=20hashCo?= =?UTF-8?q?de=20=EC=9E=AC=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/participant/Player.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 5fdc403b5f7..9fbb31be880 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -5,6 +5,7 @@ import constants.ErrorCode; import domain.BetAmount; import exception.ReservedPlayerNameException; +import java.util.Objects; public class Player extends Participant { @@ -15,7 +16,7 @@ protected Player(final Name name, final Hands hands, final BetAmount betAmount) this.betAmount = betAmount; } - public Player(final Name name, final Hands hands) { // TODO 이전 테스트를 위한 생성자 + protected Player(final Name name, final Hands hands) { super(name, hands); validate(name); this.betAmount = new BetAmount(10); @@ -42,6 +43,22 @@ public boolean canDeal() { return handsSum() < Hands.BLACK_JACK; } + @Override + public boolean equals(final Object target) { + if (this == target) { + return true; + } + if (!(target instanceof Player player)) { + return false; + } + return Objects.equals(getName(), player.getName()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getName()); + } + @Override public String toString() { return super.toString(); From e166122ebd01ce99cf366b03f259d8b70e01915c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 00:01:53 +0900 Subject: [PATCH 25/40] =?UTF-8?q?style:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=94=94=EC=8A=A4=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=84=A4=EC=9E=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/BetAmountTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java index 5d5c12d05bd..88897605e2b 100644 --- a/src/test/java/domain/BetAmountTest.java +++ b/src/test/java/domain/BetAmountTest.java @@ -17,7 +17,7 @@ void invalidBetAmount(long value) { } @ParameterizedTest - @DisplayName("배팅 금액이 10으로 나누어 떨어질 시 예외가 발생한다.") + @DisplayName("배팅 금액이 10으로 나누어 떨어지지 않을 시 예외가 발생한다.") @ValueSource(longs = {5, 13, 10001}) void invalidUnitBetAmount(long value) { Assertions.assertThatThrownBy(() -> new BetAmount(value)) From e580c16a0bcb8094ec1446f34b8e34c26419eac8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 00:30:54 +0900 Subject: [PATCH 26/40] =?UTF-8?q?feat:=20=EB=B0=B0=ED=8C=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=B4=201=EC=96=B5=EC=9D=84=20=EC=B4=88=EA=B3=BC?= =?UTF-8?q?=ED=95=A0=20=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=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 --- docs/README.md | 2 ++ src/main/java/domain/BetAmount.java | 8 +++++--- src/main/java/exception/OutOfRangeBetAmount.java | 10 ++++++++++ src/test/java/domain/BetAmountTest.java | 13 +++++++++++-- 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 src/main/java/exception/OutOfRangeBetAmount.java diff --git a/docs/README.md b/docs/README.md index 3b290e7925b..df1c2a59d88 100644 --- a/docs/README.md +++ b/docs/README.md @@ -45,6 +45,8 @@ * [x] 양의 정수가 아닐 시 예외가 발생한다. * [x] 10으로 나누어 떨어지지 않으면 예외가 발생한다. * 블랙잭시 1.5배를 해주기 위함 + * [x] 배팅 금액은 최대 100_000_000로 이를 초과시 예외가 발생한다. + * 건전한 플레이를 하기 위함
diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/BetAmount.java index 8c7f4e4506a..5bb53fa9e01 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/BetAmount.java @@ -2,12 +2,14 @@ import constants.ErrorCode; import exception.InvalidBetAmountException; +import exception.OutOfRangeBetAmount; import java.util.Objects; public class BetAmount { private static final int UNIT = 10; - private static final int MIN_RANGE = 0; + private static final int MIN_RANGE = 10; + private static final int MAX_RANGE = 100_000_000; private final long amount; @@ -45,8 +47,8 @@ private void validateUnit(final long value) { } private void validateRange(final long value) { - if (value <= MIN_RANGE) { - throw new InvalidBetAmountException(ErrorCode.INVALID_BET_AMOUNT); + if (value < MIN_RANGE || MAX_RANGE < value) { + throw new OutOfRangeBetAmount(ErrorCode.INVALID_BET_AMOUNT); } } diff --git a/src/main/java/exception/OutOfRangeBetAmount.java b/src/main/java/exception/OutOfRangeBetAmount.java new file mode 100644 index 00000000000..509a26fcc52 --- /dev/null +++ b/src/main/java/exception/OutOfRangeBetAmount.java @@ -0,0 +1,10 @@ +package exception; + +import constants.ErrorCode; + +public class OutOfRangeBetAmount extends CustomException { + + public OutOfRangeBetAmount(final ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java index 88897605e2b..287719432ae 100644 --- a/src/test/java/domain/BetAmountTest.java +++ b/src/test/java/domain/BetAmountTest.java @@ -1,8 +1,10 @@ package domain; import exception.InvalidBetAmountException; +import exception.OutOfRangeBetAmount; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -13,14 +15,21 @@ class BetAmountTest { @ValueSource(longs = {0, -1, -100000}) void invalidBetAmount(long value) { Assertions.assertThatThrownBy(() -> new BetAmount(value)) - .isInstanceOf(InvalidBetAmountException.class); + .isInstanceOf(OutOfRangeBetAmount.class); } @ParameterizedTest @DisplayName("배팅 금액이 10으로 나누어 떨어지지 않을 시 예외가 발생한다.") - @ValueSource(longs = {5, 13, 10001}) + @ValueSource(longs = {11, 53, 10001}) void invalidUnitBetAmount(long value) { Assertions.assertThatThrownBy(() -> new BetAmount(value)) .isInstanceOf(InvalidBetAmountException.class); } + + @Test + @DisplayName("배팅 금액이 1억을 초과하면 예외가 발생한다.") + void overBetAmount() { + Assertions.assertThatThrownBy(() -> new BetAmount(100_000_010)) + .isInstanceOf(OutOfRangeBetAmount.class); + } } From 930c3856305409fdf56b2ac952381ebbf4eac2c9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 00:33:43 +0900 Subject: [PATCH 27/40] =?UTF-8?q?refactor:=20controller=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EB=AA=85=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackJackController.java | 36 +++++++++++-------- src/main/java/controller/InputController.java | 12 +++---- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 0da470e0900..405a3cc4187 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -16,6 +16,8 @@ import java.util.Map; import view.OutputView; +//TODO 컨트롤러가 하는 일이 좀 많은듯...? +// GAME이라는 객체를 만들어 보는 것은 어떨까? public class BlackJackController { private final InputController inputController; @@ -27,16 +29,16 @@ public BlackJackController(final InputController inputController, final OutputVi } public void run() { - final Names names = inputController.getPlayers(); + final Names names = inputController.getNames(); final Dealer dealer = new Dealer(); - final List temp = new ArrayList<>(); + final List playerList = new ArrayList<>(); for (final Name name : names.getPlayerNames()) { - BetAmount betAmount = inputController.getBetAmount(name.getValue()); - temp.add(new Player(name, betAmount)); + final BetAmount betAmount = inputController.getBetAmount(name.getValue()); + playerList.add(new Player(name, betAmount)); } - final Players players = new Players(temp); + final Players players = new Players(playerList); initHands(players, dealer); dealWithPlayers(players, dealer); @@ -60,13 +62,8 @@ private void dealWithPlayers(final Players players, final Dealer dealer) { outputView.printDealerBlackJack(); return; } - for (Player player : players.getPlayers()) { - if (player.isBlackJack()) { - outputView.printBlackJack(); - continue; - } - deal(player, dealer); - } + players.getPlayers() + .forEach(player -> deal(player, dealer)); } private void initHands(final Players players, final Dealer dealer) { @@ -76,12 +73,15 @@ private void initHands(final Players players, final Dealer dealer) { private void printFinalResult(final Players players, final Dealer dealer) { outputView.printHandsResult(ParticipantsDto.of(dealer, players)); - Map finalResult = players.calculateResult(dealer); - Amount dealerAmount = dealer.calculateRevenue(finalResult); + final Map finalResult = players.calculateResult(dealer); + final Amount dealerAmount = dealer.calculateRevenue(finalResult); outputView.printGameResult(finalResult, dealerAmount); } private void deal(final Player player, final Dealer dealer) { + if (isBlackJack(player)) { + return; + } boolean handsChanged = false; boolean turnEnded = false; @@ -96,6 +96,14 @@ private void deal(final Player player, final Dealer dealer) { } } + private boolean isBlackJack(final Player player) { + if (player.isBlackJack()) { + outputView.printBlackJack(); + return true; + } + return false; + } + private void printHandsIfRequired(final Player player, final boolean handsChanged, final Answer answer) { if (shouldShowHands(handsChanged, answer)) { outputView.printHands(ParticipantDto.from(player)); diff --git a/src/main/java/controller/InputController.java b/src/main/java/controller/InputController.java index cecfcb18788..75b56caf381 100644 --- a/src/main/java/controller/InputController.java +++ b/src/main/java/controller/InputController.java @@ -18,12 +18,12 @@ public InputController(final InputView inputView, final OutputView outputView) { this.outputView = outputView; } - public Names getPlayers() { - Names playerNames; + public Names getNames() { + Names names; do { - playerNames = readPlayerNames(); - } while (playerNames == null); - return playerNames; + names = readNames(); + } while (names == null); + return names; } public Answer getAnswer(String name) { @@ -42,7 +42,7 @@ public BetAmount getBetAmount(String name) { return betAmount; } - private Names readPlayerNames() { + private Names readNames() { try { List rawNames = inputView.readNames(); return Names.from(rawNames); From c401e21abb5219530803dd2f4c3699cb8c61e039 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 00:34:47 +0900 Subject: [PATCH 28/40] =?UTF-8?q?refactor:=20Result=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20GameResult=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 --- .../domain/{Result.java => GameResult.java} | 22 +++++++++---------- src/main/java/domain/participant/Dealer.java | 10 ++++----- src/main/java/domain/participant/Hands.java | 6 ++--- .../java/domain/participant/Participant.java | 4 ++-- src/main/java/domain/participant/Players.java | 8 +++---- .../{ResultTest.java => GameResultTest.java} | 16 +++++++------- .../java/domain/participant/DealerTest.java | 10 ++++----- .../java/domain/participant/PlayersTest.java | 14 ++++++------ 8 files changed, 45 insertions(+), 45 deletions(-) rename src/main/java/domain/{Result.java => GameResult.java} (66%) rename src/test/java/domain/{ResultTest.java => GameResultTest.java} (83%) diff --git a/src/main/java/domain/Result.java b/src/main/java/domain/GameResult.java similarity index 66% rename from src/main/java/domain/Result.java rename to src/main/java/domain/GameResult.java index a62d4cd2def..a1955b807a3 100644 --- a/src/main/java/domain/Result.java +++ b/src/main/java/domain/GameResult.java @@ -5,33 +5,33 @@ import java.util.function.BiPredicate; import java.util.function.Function; -public enum Result { +public enum GameResult { - BLACK_JACK_WIN(Result::blackJackWinningCondition, BetAmount::blackJackWinAmount), - WIN(Result::winningCondition, BetAmount::winAmount), - TIE(Result::tieCondition, BetAmount::tieAmount), - LOSE(Result::loseCondition, BetAmount::loseAmount); + BLACK_JACK_WIN(GameResult::blackJackWinningCondition, BetAmount::blackJackWinAmount), + WIN(GameResult::winningCondition, BetAmount::winAmount), + TIE(GameResult::tieCondition, BetAmount::tieAmount), + LOSE(GameResult::loseCondition, BetAmount::loseAmount); private final BiPredicate condition; private final Function calculate; - Result(final BiPredicate condition, final Function calculate) { + GameResult(final BiPredicate condition, final Function calculate) { this.condition = condition; this.calculate = calculate; } - public Result reverse() { - if (Result.WIN.equals(this) || Result.BLACK_JACK_WIN.equals(this)) { + public GameResult reverse() { + if (GameResult.WIN.equals(this) || GameResult.BLACK_JACK_WIN.equals(this)) { return LOSE; } - if (Result.LOSE.equals(this)) { + if (GameResult.LOSE.equals(this)) { return WIN; } return TIE; } - public static Result calculateOf(final Hands hands, final Hands target) { - return Arrays.stream(Result.values()) + public static GameResult calculateOf(final Hands hands, final Hands target) { + return Arrays.stream(GameResult.values()) .filter(result -> result.condition.test(hands, target)) .findFirst() .orElseThrow(); diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index a5d30da547f..eae57c795ec 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -2,7 +2,7 @@ import domain.Amount; import domain.Answer; -import domain.Result; +import domain.GameResult; import domain.card.Card; import domain.card.CardDeck; import java.util.ArrayDeque; @@ -63,11 +63,11 @@ public int countAddedHands() { return handsSize() - INIT_HANDS_SIZE; } - public Map getDealerResult(final Players players) { - Map dealerResult = new EnumMap<>(Result.class); + public Map getDealerResult(final Players players) { + Map dealerResult = new EnumMap<>(GameResult.class); - for (Result value : players.getPlayersResult(this).values()) { - Result reversed = value.reverse(); + for (GameResult value : players.getPlayersResult(this).values()) { + GameResult reversed = value.reverse(); dealerResult.put(reversed, dealerResult.getOrDefault(reversed, 0) + 1); } return dealerResult; diff --git a/src/main/java/domain/participant/Hands.java b/src/main/java/domain/participant/Hands.java index 0cea0b74d42..89f6c1eb97e 100644 --- a/src/main/java/domain/participant/Hands.java +++ b/src/main/java/domain/participant/Hands.java @@ -1,6 +1,6 @@ package domain.participant; -import domain.Result; +import domain.GameResult; import domain.card.Card; import java.util.ArrayList; import java.util.List; @@ -56,8 +56,8 @@ public List getCards() { .toList(); } - public Result calculateResult(final Hands target) { - return Result.calculateOf(this, target); + public GameResult calculateResult(final Hands target) { + return GameResult.calculateOf(this, target); } private int calculateTotalByAce(final int total) { diff --git a/src/main/java/domain/participant/Participant.java b/src/main/java/domain/participant/Participant.java index 2749ecd524d..09e1fff645b 100644 --- a/src/main/java/domain/participant/Participant.java +++ b/src/main/java/domain/participant/Participant.java @@ -1,6 +1,6 @@ package domain.participant; -import domain.Result; +import domain.GameResult; import domain.card.Card; import java.util.List; import java.util.Objects; @@ -37,7 +37,7 @@ public int handsSize() { return hands.size(); } - public Result calculateResult(final Participant participant) { + public GameResult calculateResult(final Participant participant) { return hands.calculateResult(participant.getHands()); } diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index c9294a947cf..76192e449da 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,7 +1,7 @@ package domain.participant; import domain.Amount; -import domain.Result; +import domain.GameResult; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -24,8 +24,8 @@ public boolean isAllBust() { .allMatch(Player::isBust); } - public Map getPlayersResult(final Dealer dealer) { - final Map result = new LinkedHashMap<>(); + public Map getPlayersResult(final Dealer dealer) { + final Map result = new LinkedHashMap<>(); for (Player name : names) { result.put(name, name.calculateResult(dealer)); } @@ -36,7 +36,7 @@ public Map calculateResult(final Dealer dealer) { final Map playerAmountMap = new LinkedHashMap<>(); for (Player player : names) { - Result gameResult = player.calculateResult(dealer); + GameResult gameResult = player.calculateResult(dealer); playerAmountMap.put(player, gameResult.apply(player.getBetAmount())); } return playerAmountMap; diff --git a/src/test/java/domain/ResultTest.java b/src/test/java/domain/GameResultTest.java similarity index 83% rename from src/test/java/domain/ResultTest.java rename to src/test/java/domain/GameResultTest.java index 35effa14d25..a791abe776f 100644 --- a/src/test/java/domain/ResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -12,32 +12,32 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class ResultTest { +class GameResultTest { @DisplayName("카드 합이 같다면 무승부이다.") @Test void isTie() { - Assertions.assertThat(sum17Size3One.calculateResult(sum17Size3Two)).isEqualTo(Result.TIE); - Assertions.assertThat(sum20Size2.calculateResult(sum20Size3)).isEqualTo(Result.TIE); + Assertions.assertThat(sum17Size3One.calculateResult(sum17Size3Two)).isEqualTo(GameResult.TIE); + Assertions.assertThat(sum20Size2.calculateResult(sum20Size3)).isEqualTo(GameResult.TIE); } @Test @DisplayName("카드 합이 21이하이면서 21에 가까운 카드가 승리한다.") void isWin() { - Assertions.assertThat(sum21Size3.calculateResult(sum20Size2)).isEqualTo(Result.WIN); - Assertions.assertThat(sum20Size2.calculateResult(sum21Size3)).isEqualTo(Result.LOSE); + Assertions.assertThat(sum21Size3.calculateResult(sum20Size2)).isEqualTo(GameResult.WIN); + Assertions.assertThat(sum20Size2.calculateResult(sum21Size3)).isEqualTo(GameResult.LOSE); } @Test @DisplayName("카드 합이 21초과이면 패배한다.") void isLoseWhenCardSumGreater21() { - Assertions.assertThat(bustHands.calculateResult(sum20Size2)).isEqualTo(Result.LOSE); + Assertions.assertThat(bustHands.calculateResult(sum20Size2)).isEqualTo(GameResult.LOSE); } @Test @DisplayName("blackjack이 이긴다.") void isWinBlackJack() { - Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(Result.BLACK_JACK_WIN); - Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(Result.LOSE); + Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(GameResult.BLACK_JACK_WIN); + Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(GameResult.LOSE); } } diff --git a/src/test/java/domain/participant/DealerTest.java b/src/test/java/domain/participant/DealerTest.java index 4dd24fd6693..2b72441ac17 100644 --- a/src/test/java/domain/participant/DealerTest.java +++ b/src/test/java/domain/participant/DealerTest.java @@ -6,14 +6,14 @@ import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; -import static domain.Result.LOSE; -import static domain.Result.TIE; -import static domain.Result.WIN; +import static domain.GameResult.LOSE; +import static domain.GameResult.TIE; +import static domain.GameResult.WIN; import static org.junit.jupiter.api.Assertions.assertAll; import domain.Answer; import domain.BetAmount; -import domain.Result; +import domain.GameResult; import java.util.List; import java.util.Map; import org.assertj.core.api.Assertions; @@ -100,7 +100,7 @@ void dealerResult() { Dealer dealer = new Dealer(sum20Size3); // when - Map expected = Map.of(WIN, 2, LOSE, 1, TIE, 1); + Map expected = Map.of(WIN, 2, LOSE, 1, TIE, 1); // then Assertions.assertThat(dealer.getDealerResult(players)).isEqualTo(expected); diff --git a/src/test/java/domain/participant/PlayersTest.java b/src/test/java/domain/participant/PlayersTest.java index 8b8b656f605..1190ed21cf1 100644 --- a/src/test/java/domain/participant/PlayersTest.java +++ b/src/test/java/domain/participant/PlayersTest.java @@ -10,13 +10,13 @@ import static domain.HandsTestFixture.sum20Size2; import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; -import static domain.Result.LOSE; -import static domain.Result.TIE; -import static domain.Result.WIN; +import static domain.GameResult.LOSE; +import static domain.GameResult.TIE; +import static domain.GameResult.WIN; import domain.Amount; import domain.BetAmount; -import domain.Result; +import domain.GameResult; import java.util.List; import java.util.Map; import org.assertj.core.api.Assertions; @@ -64,7 +64,7 @@ void playerResult() { Dealer dealer = new Dealer(sum20Size3); //when & then - Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); + Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); Assertions.assertThat(players.getPlayersResult(dealer)).isEqualTo(expected); } @@ -80,8 +80,8 @@ void all() { Players players = new Players(List.of(winner1, winner2, loser)); //when - Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); - Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); + Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); + Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); //then Assertions.assertThat(players.getPlayersResult(bustDealer)).isEqualTo(expectedPlayerResult); From e5cc892cd82d3bd4bc67b42ad087fcb649c55cb1 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 00:45:13 +0900 Subject: [PATCH 29/40] =?UTF-8?q?refactor:=20Answer,=20Amount,=20BetAmount?= =?UTF-8?q?=20package=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/BlackJackController.java | 6 +++--- src/main/java/controller/InputController.java | 4 ++-- src/main/java/domain/GameResult.java | 2 ++ src/main/java/domain/{ => amount}/Amount.java | 2 +- src/main/java/domain/{ => amount}/BetAmount.java | 2 +- src/main/java/domain/{ => participant}/Answer.java | 2 +- src/main/java/domain/participant/Dealer.java | 3 +-- src/main/java/domain/participant/Player.java | 2 +- src/main/java/domain/participant/Players.java | 2 +- src/main/java/view/OutputView.java | 2 +- src/test/java/domain/AnswerTest.java | 1 + src/test/java/domain/BetAmountTest.java | 1 + src/test/java/domain/participant/DealerTest.java | 3 +-- src/test/java/domain/participant/PlayersTest.java | 4 ++-- 14 files changed, 19 insertions(+), 17 deletions(-) rename src/main/java/domain/{ => amount}/Amount.java (96%) rename src/main/java/domain/{ => amount}/BetAmount.java (98%) rename src/main/java/domain/{ => participant}/Answer.java (95%) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 405a3cc4187..372bbd14cb6 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -1,8 +1,8 @@ package controller; -import domain.Amount; -import domain.Answer; -import domain.BetAmount; +import domain.amount.Amount; +import domain.participant.Answer; +import domain.amount.BetAmount; import domain.participant.Dealer; import domain.participant.Name; import domain.participant.Names; diff --git a/src/main/java/controller/InputController.java b/src/main/java/controller/InputController.java index 75b56caf381..ca00c39625d 100644 --- a/src/main/java/controller/InputController.java +++ b/src/main/java/controller/InputController.java @@ -1,7 +1,7 @@ package controller; -import domain.Answer; -import domain.BetAmount; +import domain.participant.Answer; +import domain.amount.BetAmount; import domain.participant.Names; import exception.CustomException; import java.util.List; diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/GameResult.java index a1955b807a3..926a3bcdd69 100644 --- a/src/main/java/domain/GameResult.java +++ b/src/main/java/domain/GameResult.java @@ -1,5 +1,7 @@ package domain; +import domain.amount.Amount; +import domain.amount.BetAmount; import domain.participant.Hands; import java.util.Arrays; import java.util.function.BiPredicate; diff --git a/src/main/java/domain/Amount.java b/src/main/java/domain/amount/Amount.java similarity index 96% rename from src/main/java/domain/Amount.java rename to src/main/java/domain/amount/Amount.java index 17aef7518b0..15d899564d0 100644 --- a/src/main/java/domain/Amount.java +++ b/src/main/java/domain/amount/Amount.java @@ -1,4 +1,4 @@ -package domain; +package domain.amount; import java.util.Objects; diff --git a/src/main/java/domain/BetAmount.java b/src/main/java/domain/amount/BetAmount.java similarity index 98% rename from src/main/java/domain/BetAmount.java rename to src/main/java/domain/amount/BetAmount.java index 5bb53fa9e01..078859bce1b 100644 --- a/src/main/java/domain/BetAmount.java +++ b/src/main/java/domain/amount/BetAmount.java @@ -1,4 +1,4 @@ -package domain; +package domain.amount; import constants.ErrorCode; import exception.InvalidBetAmountException; diff --git a/src/main/java/domain/Answer.java b/src/main/java/domain/participant/Answer.java similarity index 95% rename from src/main/java/domain/Answer.java rename to src/main/java/domain/participant/Answer.java index dc53bfc33a4..0c110c0f7af 100644 --- a/src/main/java/domain/Answer.java +++ b/src/main/java/domain/participant/Answer.java @@ -1,4 +1,4 @@ -package domain; +package domain.participant; import constants.ErrorCode; import exception.InvalidCommandException; diff --git a/src/main/java/domain/participant/Dealer.java b/src/main/java/domain/participant/Dealer.java index eae57c795ec..a31b99cc618 100644 --- a/src/main/java/domain/participant/Dealer.java +++ b/src/main/java/domain/participant/Dealer.java @@ -1,7 +1,6 @@ package domain.participant; -import domain.Amount; -import domain.Answer; +import domain.amount.Amount; import domain.GameResult; import domain.card.Card; import domain.card.CardDeck; diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index 9fbb31be880..f7d12e67d4e 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -3,7 +3,7 @@ import static domain.participant.Dealer.DEALER_NAME; import constants.ErrorCode; -import domain.BetAmount; +import domain.amount.BetAmount; import exception.ReservedPlayerNameException; import java.util.Objects; diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index 76192e449da..b13eff9c244 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,6 +1,6 @@ package domain.participant; -import domain.Amount; +import domain.amount.Amount; import domain.GameResult; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 0c33697661d..283d448db2c 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -4,7 +4,7 @@ import static domain.participant.Dealer.THRESHOLD; import constants.ErrorCode; -import domain.Amount; +import domain.amount.Amount; import domain.participant.Player; import dto.DealerHandsDto; import dto.ParticipantDto; diff --git a/src/test/java/domain/AnswerTest.java b/src/test/java/domain/AnswerTest.java index ea61387a175..c4f61646564 100644 --- a/src/test/java/domain/AnswerTest.java +++ b/src/test/java/domain/AnswerTest.java @@ -1,5 +1,6 @@ package domain; +import domain.participant.Answer; import exception.InvalidCommandException; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/BetAmountTest.java b/src/test/java/domain/BetAmountTest.java index 287719432ae..476a1c9cbfc 100644 --- a/src/test/java/domain/BetAmountTest.java +++ b/src/test/java/domain/BetAmountTest.java @@ -1,5 +1,6 @@ package domain; +import domain.amount.BetAmount; import exception.InvalidBetAmountException; import exception.OutOfRangeBetAmount; import org.assertj.core.api.Assertions; diff --git a/src/test/java/domain/participant/DealerTest.java b/src/test/java/domain/participant/DealerTest.java index 2b72441ac17..70817e92d34 100644 --- a/src/test/java/domain/participant/DealerTest.java +++ b/src/test/java/domain/participant/DealerTest.java @@ -11,8 +11,7 @@ import static domain.GameResult.WIN; import static org.junit.jupiter.api.Assertions.assertAll; -import domain.Answer; -import domain.BetAmount; +import domain.amount.BetAmount; import domain.GameResult; import java.util.List; import java.util.Map; diff --git a/src/test/java/domain/participant/PlayersTest.java b/src/test/java/domain/participant/PlayersTest.java index 1190ed21cf1..6604016d9cd 100644 --- a/src/test/java/domain/participant/PlayersTest.java +++ b/src/test/java/domain/participant/PlayersTest.java @@ -14,8 +14,8 @@ import static domain.GameResult.TIE; import static domain.GameResult.WIN; -import domain.Amount; -import domain.BetAmount; +import domain.amount.Amount; +import domain.amount.BetAmount; import domain.GameResult; import java.util.List; import java.util.Map; From f22ec42f00d1c5e42f471f62c55c63d1b3e832a0 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 13:16:32 +0900 Subject: [PATCH 30/40] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=EC=97=90=20final=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/domain/CardTest.java | 2 +- src/test/java/domain/card/CardDeckTest.java | 4 +-- .../java/domain/participant/DealerTest.java | 20 +++++------ .../java/domain/participant/PlayersTest.java | 36 +++++++++---------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/test/java/domain/CardTest.java b/src/test/java/domain/CardTest.java index 39c5667e1de..bc362cfca08 100644 --- a/src/test/java/domain/CardTest.java +++ b/src/test/java/domain/CardTest.java @@ -12,7 +12,7 @@ class CardTest { @Test @DisplayName("중복없는 52장의 카드를 생성한다.") void generate() { - List values = Card.values(); + final List values = Card.values(); Assertions.assertThat(values).hasSize(52); Assertions.assertThat(Set.copyOf(values)).hasSize(52); diff --git a/src/test/java/domain/card/CardDeckTest.java b/src/test/java/domain/card/CardDeckTest.java index a7bf0c60bd5..f4ccfa4c8c6 100644 --- a/src/test/java/domain/card/CardDeckTest.java +++ b/src/test/java/domain/card/CardDeckTest.java @@ -13,7 +13,7 @@ class CardDeckTest { @Test void generate() { // given - CardDeck cardDeck = CardDeck.generate(DECK_SIZE); + final CardDeck cardDeck = CardDeck.generate(DECK_SIZE); // when && then Assertions.assertThat(cardDeck.size()).isEqualTo(52 * 6); @@ -23,7 +23,7 @@ void generate() { @DisplayName("카드가 없는데 카드를 뽑을 경우 예외가 발생한다.") void pop() { //given - CardDeck cardDeck = CardDeck.generate(1); + final CardDeck cardDeck = CardDeck.generate(1); //when int cardSize = 52; diff --git a/src/test/java/domain/participant/DealerTest.java b/src/test/java/domain/participant/DealerTest.java index 70817e92d34..1eb573b5406 100644 --- a/src/test/java/domain/participant/DealerTest.java +++ b/src/test/java/domain/participant/DealerTest.java @@ -90,16 +90,16 @@ void dealerNoDeal() { @Test void dealerResult() { // given - Player loser1 = new Player(new Name("레디"), sum18Size2); - Player loser2 = new Player(new Name("피케이"), sum18Size2); - Player winner = new Player(new Name("제제"), sum21Size3); - Player tier = new Player(new Name("브라운"), sum20Size3); + final Player loser1 = new Player(new Name("레디"), sum18Size2); + final Player loser2 = new Player(new Name("피케이"), sum18Size2); + final Player winner = new Player(new Name("제제"), sum21Size3); + final Player tier = new Player(new Name("브라운"), sum20Size3); - Players players = new Players(List.of(loser1, loser2, winner, tier)); - Dealer dealer = new Dealer(sum20Size3); + final Players players = new Players(List.of(loser1, loser2, winner, tier)); + final Dealer dealer = new Dealer(sum20Size3); // when - Map expected = Map.of(WIN, 2, LOSE, 1, TIE, 1); + final Map expected = Map.of(WIN, 2, LOSE, 1, TIE, 1); // then Assertions.assertThat(dealer.getDealerResult(players)).isEqualTo(expected); @@ -109,9 +109,9 @@ void dealerResult() { @DisplayName("처음 나눠준 카드 두장의 합이 21이라면 블랙잭이다.") void checkingBlackJack() { //given - Dealer dealer = new Dealer(sum20Size2); - Player blackJackPlayer = new Player(new Name("수달"), blackJack); - Player noBlackJackPlayer = new Player(new Name("레디"), sum18Size2); + final Dealer dealer = new Dealer(sum20Size2); + final Player blackJackPlayer = new Player(new Name("수달"), blackJack); + final Player noBlackJackPlayer = new Player(new Name("레디"), sum18Size2); //when && then assertAll(() -> Assertions.assertThat(dealer.isBlackJack()).isFalse(), diff --git a/src/test/java/domain/participant/PlayersTest.java b/src/test/java/domain/participant/PlayersTest.java index 6604016d9cd..9ae8ac9cf10 100644 --- a/src/test/java/domain/participant/PlayersTest.java +++ b/src/test/java/domain/participant/PlayersTest.java @@ -41,12 +41,12 @@ void isAllBustFalse() { @DisplayName("모든 참가자가 버스트되면 isAllBust가 True를 반환한다.") void isAllBustTrue() { //given - Player player1 = new Player(new Name("레디"), bustHands); - Player player2 = new Player(new Name("제제"), bustHands); - Player player3 = new Player(new Name("수달"), bustHands); - Player player4 = new Player(new Name("피케이"), bustHands); + final Player player1 = new Player(new Name("레디"), bustHands); + final Player player2 = new Player(new Name("제제"), bustHands); + final Player player3 = new Player(new Name("수달"), bustHands); + final Player player4 = new Player(new Name("피케이"), bustHands); - Players players = new Players(List.of(player1, player2, player3, player4)); + final Players players = new Players(List.of(player1, player2, player3, player4)); //when && then Assertions.assertThat(players.isAllBust()).isTrue(); @@ -56,15 +56,15 @@ void isAllBustTrue() { @DisplayName("참여자의 승패무를 판단한다.") void playerResult() { //given - Player loser = new Player(new Name("레디"), sum18Size2); - Player winner = new Player(new Name("제제"), sum21Size3); - Player tier = new Player(new Name("수달"), sum20Size3); + final Player loser = new Player(new Name("레디"), sum18Size2); + final Player winner = new Player(new Name("제제"), sum21Size3); + final Player tier = new Player(new Name("수달"), sum20Size3); - Players players = new Players(List.of(loser, winner, tier)); - Dealer dealer = new Dealer(sum20Size3); + final Players players = new Players(List.of(loser, winner, tier)); + final Dealer dealer = new Dealer(sum20Size3); //when & then - Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); + final Map expected = Map.of(loser, LOSE, winner, WIN, tier, TIE); Assertions.assertThat(players.getPlayersResult(dealer)).isEqualTo(expected); } @@ -72,16 +72,16 @@ void playerResult() { @DisplayName("딜러가 버스트일때 참여자가 버스트가 아니면 WIN") void all() { //given - Dealer bustDealer = new Dealer(bustHands); - Player winner1 = new Player(new Name("레디"), sum18Size2); - Player winner2 = new Player(new Name("브라운"), sum20Size2); - Player loser = new Player(new Name("제제"), bustHands); + final Dealer bustDealer = new Dealer(bustHands); + final Player winner1 = new Player(new Name("레디"), sum18Size2); + final Player winner2 = new Player(new Name("브라운"), sum20Size2); + final Player loser = new Player(new Name("제제"), bustHands); - Players players = new Players(List.of(winner1, winner2, loser)); + final Players players = new Players(List.of(winner1, winner2, loser)); //when - Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); - Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); + final Map expectedPlayerResult = Map.of(winner1, WIN, winner2, WIN, loser, LOSE); + final Map expectedDealerResult = Map.of(WIN, 1, LOSE, 2); //then Assertions.assertThat(players.getPlayersResult(bustDealer)).isEqualTo(expectedPlayerResult); From 353e923ced683dcd76eab1c2f3fc4eaf66ec67c1 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 13:30:21 +0900 Subject: [PATCH 31/40] =?UTF-8?q?refactor:=20Player=20=EC=9D=98=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8A=94=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=A0=9C=ED=95=9C=EC=9E=90=20=EB=94=94?= =?UTF-8?q?=ED=8F=B4=ED=8A=B8=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/domain/participant/Player.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/domain/participant/Player.java b/src/main/java/domain/participant/Player.java index f7d12e67d4e..48fd3197f7c 100644 --- a/src/main/java/domain/participant/Player.java +++ b/src/main/java/domain/participant/Player.java @@ -11,18 +11,17 @@ public class Player extends Participant { private final BetAmount betAmount; - protected Player(final Name name, final Hands hands, final BetAmount betAmount) { + Player(final Name name, final Hands hands, final BetAmount betAmount) { super(name, hands); this.betAmount = betAmount; } - protected Player(final Name name, final Hands hands) { + Player(final Name name, final Hands hands) { super(name, hands); validate(name); this.betAmount = new BetAmount(10); } - public Player(final Name name, final BetAmount betAmount) { super(name, Hands.createEmptyHands()); this.betAmount = betAmount; From 2fb500133db2d3940909c290ee711e4519a42dc0 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 13:34:50 +0900 Subject: [PATCH 32/40] =?UTF-8?q?refactor:=20betAmount=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/amount/BetAmount.java | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/domain/amount/BetAmount.java b/src/main/java/domain/amount/BetAmount.java index 078859bce1b..dd7d46a75ad 100644 --- a/src/main/java/domain/amount/BetAmount.java +++ b/src/main/java/domain/amount/BetAmount.java @@ -11,24 +11,23 @@ public class BetAmount { private static final int MIN_RANGE = 10; private static final int MAX_RANGE = 100_000_000; - private final long amount; + private final long value; - public BetAmount(final long amount) { - validate(amount); - this.amount = amount; + public BetAmount(final long value) { + validate(value); + this.value = value; } - public Amount loseAmount() { - return new Amount(-amount); + return new Amount(-value); } public Amount blackJackWinAmount() { - return new Amount(amount + (amount / 2)); + return new Amount(value + (value / 2)); } public Amount winAmount() { - return new Amount(amount); + return new Amount(value); } public Amount tieAmount() { @@ -60,16 +59,16 @@ public boolean equals(final Object target) { if (!(target instanceof BetAmount betAmount)) { return false; } - return Objects.equals(amount, betAmount.amount); + return Objects.equals(value, betAmount.value); } @Override public int hashCode() { - return Objects.hashCode(amount); + return Objects.hashCode(value); } @Override public String toString() { - return String.valueOf(amount); + return String.valueOf(value); } } From 28f5b8d28204d8e41839234c0be15b44db950213 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 13:59:16 +0900 Subject: [PATCH 33/40] =?UTF-8?q?refactor:=20=EC=B9=B4=EB=93=9C=EC=9D=98?= =?UTF-8?q?=20=ED=95=A9=EC=9D=B4=2021=EC=9D=B4=20=EB=90=9C=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EC=B6=9C=EB=A0=A5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BlackJackController.java | 4 ++-- src/main/java/view/OutputView.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 372bbd14cb6..cf676554f61 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -98,7 +98,7 @@ private void deal(final Player player, final Dealer dealer) { private boolean isBlackJack(final Player player) { if (player.isBlackJack()) { - outputView.printBlackJack(); + outputView.printBlackJack(player.getName()); return true; } return false; @@ -114,7 +114,7 @@ private boolean isTurnEnded(final Player player, final Answer answer) { if (player.canDeal()) { return !answer.isHit(); } - outputView.printDealEndMessage(player.isBust()); + outputView.printPlayerEndMessage(player.isBust()); return true; } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 283d448db2c..2b9baa666e3 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -69,20 +69,20 @@ public void printBust() { System.out.printf("BUST%n"); } - public void printBlackJack() { - System.out.printf("BLACK JACK!!!%n"); + public void printBlackJack(final String name) { + System.out.printf("%s 축하드립니다! BLACK JACK!!!%n", name); } public void printException(final ErrorCode errorCode) { System.out.printf(ERROR_FORM, ErrorCodeMessage.from(errorCode).getMessage()); } - public void printDealEndMessage(final boolean isBust) { + public void printPlayerEndMessage(final boolean isBust) { if (isBust) { printBust(); return; } - printBlackJack(); + System.out.println("카드의 합이 21이라 더 이상 카드를 받을 수 없습니다."); } public void printDealerBlackJack() { From b9f19af4e8b554801b3b827159f9336b8da9e024 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 13:59:41 +0900 Subject: [PATCH 34/40] =?UTF-8?q?refactor:=20=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=A0=9C=ED=95=9C=EC=9E=90=20protected=20?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=94=94=ED=8F=B4=ED=8A=B8=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/card/CardDeck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/domain/card/CardDeck.java b/src/main/java/domain/card/CardDeck.java index 90432e4fa5d..b23329a53cd 100644 --- a/src/main/java/domain/card/CardDeck.java +++ b/src/main/java/domain/card/CardDeck.java @@ -16,7 +16,7 @@ public CardDeck(final Deque cards) { this.cards = cards; } - protected static CardDeck generate(int size) { + static CardDeck generate(int size) { final List deck = new ArrayList<>(); for (int i = 0; i < size; i++) { From c48d7445fc9768144a304bc50c8ed8d347f50e64 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 14:24:18 +0900 Subject: [PATCH 35/40] =?UTF-8?q?feat:=20=EC=88=98=EC=9D=B5=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=EC=8B=9C=20=EC=84=B8=EC=9E=90=EB=A6=AC=20=EB=A7=88?= =?UTF-8?q?=EB=8B=A4=20=EC=89=BC=ED=91=9C=EB=A5=BC=20=EB=B6=99=EC=97=AC=20?= =?UTF-8?q?=EC=B6=9C=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/view/OutputView.java | 4 ++-- src/test/java/domain/GameResultTest.java | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 2b9baa666e3..00fe1b9271b 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -19,7 +19,7 @@ public class OutputView { private static final String LINE = System.lineSeparator(); private static final String FORM = "%s카드: %s%n"; private static final String TOTAL_SUM_FORM = "%s 카드: %s - 결과: %d%n"; - private static final String RESULT_FORM = "%s: %s%n"; + private static final String RESULT_FORM = "%s: %,d%n"; private static final String ERROR_FORM = "[ERROR] %s%n"; @@ -54,7 +54,7 @@ public void printHandsResult(final ParticipantsDto participantsDto) { public void printGameResult(final Map playerAmountMap, final Amount amount) { System.out.println("## 최종 수익"); - System.out.printf("딜러: %d%n", amount.getValue()); // TODO 숫자 세자리마다 쉼표 + System.out.printf("딜러: %,d%n", amount.getValue()); for (Entry entry : playerAmountMap.entrySet()) { System.out.printf(RESULT_FORM, entry.getKey().getName(), entry.getValue().getValue()); diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java index a791abe776f..bb2a5113ab5 100644 --- a/src/test/java/domain/GameResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -8,6 +8,7 @@ import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; +import java.text.DecimalFormat; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -40,4 +41,16 @@ void isWinBlackJack() { Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(GameResult.BLACK_JACK_WIN); Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(GameResult.LOSE); } + + @Test + @DisplayName("Test name") + void methodName() { + //given + + //when + long money = 100_000_000_000_000L; + String str = String.format("%,d", money); + System.out.println(str); + //then + } } From 8b9c0ca07fd140ea058eb0d524e9c3fc9baef1d1 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 14:57:00 +0900 Subject: [PATCH 36/40] =?UTF-8?q?refactor:=20players=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=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 --- .../java/controller/BlackJackController.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index cf676554f61..26a8c59fd5a 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -1,8 +1,8 @@ package controller; import domain.amount.Amount; -import domain.participant.Answer; import domain.amount.BetAmount; +import domain.participant.Answer; import domain.participant.Dealer; import domain.participant.Name; import domain.participant.Names; @@ -31,24 +31,30 @@ public BlackJackController(final InputController inputController, final OutputVi public void run() { final Names names = inputController.getNames(); final Dealer dealer = new Dealer(); - - final List playerList = new ArrayList<>(); - for (final Name name : names.getPlayerNames()) { - final BetAmount betAmount = inputController.getBetAmount(name.getValue()); - playerList.add(new Player(name, betAmount)); - } - - final Players players = new Players(playerList); + final Players players = registerPlayers(names); initHands(players, dealer); dealWithPlayers(players, dealer); + dealerTurn(players, dealer); + + printFinalResult(players, dealer); + } - if (!players.isAllBust()) { - dealer.deal(); - printDealerTurnMessage(dealer.countAddedHands()); + private void dealerTurn(final Players players, final Dealer dealer) { + if (players.isAllBust()) { + return; } + dealer.deal(); + printDealerTurnMessage(dealer.countAddedHands()); + } - printFinalResult(players, dealer); + private Players registerPlayers(final Names names) { + final List playerList = new ArrayList<>(); + for (final Name name : names.getPlayerNames()) { + final BetAmount betAmount = inputController.getBetAmount(name.getValue()); + playerList.add(new Player(name, betAmount)); + } + return new Players(playerList); } private void printDealerTurnMessage(final int turn) { From 6ca77d680bb85d51737af4570cec87f1225f71b1 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 16:59:17 +0900 Subject: [PATCH 37/40] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=EC=9D=98=20=EC=B1=85=EC=9E=84=EC=9D=84=20Game=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EB=A7=8C=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/BlackJackController.java | 88 ++++------------- src/main/java/domain/Game.java | 94 +++++++++++++++++++ src/main/java/domain/participant/Players.java | 8 +- 3 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 src/main/java/domain/Game.java diff --git a/src/main/java/controller/BlackJackController.java b/src/main/java/controller/BlackJackController.java index 26a8c59fd5a..6e680b54054 100644 --- a/src/main/java/controller/BlackJackController.java +++ b/src/main/java/controller/BlackJackController.java @@ -1,23 +1,19 @@ package controller; +import domain.Game; import domain.amount.Amount; import domain.amount.BetAmount; -import domain.participant.Answer; import domain.participant.Dealer; import domain.participant.Name; import domain.participant.Names; import domain.participant.Player; import domain.participant.Players; -import dto.DealerHandsDto; -import dto.ParticipantDto; import dto.ParticipantsDto; import java.util.ArrayList; import java.util.List; import java.util.Map; import view.OutputView; -//TODO 컨트롤러가 하는 일이 좀 많은듯...? -// GAME이라는 객체를 만들어 보는 것은 어떨까? public class BlackJackController { private final InputController inputController; @@ -33,19 +29,17 @@ public void run() { final Dealer dealer = new Dealer(); final Players players = registerPlayers(names); - initHands(players, dealer); - dealWithPlayers(players, dealer); - dealerTurn(players, dealer); + final Game game = new Game(dealer, players); + + initHands(game); + dealWithPlayers(game); + dealerTurn(game); printFinalResult(players, dealer); } - private void dealerTurn(final Players players, final Dealer dealer) { - if (players.isAllBust()) { - return; - } - dealer.deal(); - printDealerTurnMessage(dealer.countAddedHands()); + private void dealerTurn(final Game game) { + game.dealerTurn(outputView::printDealerTurnMessage); } private Players registerPlayers(final Names names) { @@ -57,24 +51,20 @@ private Players registerPlayers(final Names names) { return new Players(playerList); } - private void printDealerTurnMessage(final int turn) { - for (int i = 0; i < turn; i++) { - outputView.printDealerTurnMessage(); - } - } - - private void dealWithPlayers(final Players players, final Dealer dealer) { - if (dealer.isBlackJack()) { + private void dealWithPlayers(final Game game) { + if (game.isAlreadyEnd()) { outputView.printDealerBlackJack(); return; } - players.getPlayers() - .forEach(player -> deal(player, dealer)); + game.checkingPlayersBlackJack(outputView::printBlackJack); + game.dealWithPlayers( + inputController::getAnswer, + outputView::printHands, + outputView::printPlayerEndMessage); } - private void initHands(final Players players, final Dealer dealer) { - dealer.initHands(players); - outputView.printStartDeal(DealerHandsDto.from(dealer), ParticipantsDto.of(players)); + private void initHands(final Game game) { + game.initHands(outputView::printStartDeal); } private void printFinalResult(final Players players, final Dealer dealer) { @@ -83,48 +73,4 @@ private void printFinalResult(final Players players, final Dealer dealer) { final Amount dealerAmount = dealer.calculateRevenue(finalResult); outputView.printGameResult(finalResult, dealerAmount); } - - private void deal(final Player player, final Dealer dealer) { - if (isBlackJack(player)) { - return; - } - boolean handsChanged = false; - boolean turnEnded = false; - - while (!turnEnded) { - final Answer answer = inputController.getAnswer(player.getName()); - dealer.deal(player, answer); - - printHandsIfRequired(player, handsChanged, answer); - - handsChanged = true; - turnEnded = isTurnEnded(player, answer); - } - } - - private boolean isBlackJack(final Player player) { - if (player.isBlackJack()) { - outputView.printBlackJack(player.getName()); - return true; - } - return false; - } - - private void printHandsIfRequired(final Player player, final boolean handsChanged, final Answer answer) { - if (shouldShowHands(handsChanged, answer)) { - outputView.printHands(ParticipantDto.from(player)); - } - } - - private boolean isTurnEnded(final Player player, final Answer answer) { - if (player.canDeal()) { - return !answer.isHit(); - } - outputView.printPlayerEndMessage(player.isBust()); - return true; - } - - private boolean shouldShowHands(final boolean handsChanged, final Answer answer) { - return answer.isHit() || !handsChanged; - } } diff --git a/src/main/java/domain/Game.java b/src/main/java/domain/Game.java new file mode 100644 index 00000000000..ff12a57050e --- /dev/null +++ b/src/main/java/domain/Game.java @@ -0,0 +1,94 @@ +package domain; + +import domain.participant.Answer; +import domain.participant.Dealer; +import domain.participant.Participant; +import domain.participant.Player; +import domain.participant.Players; +import dto.DealerHandsDto; +import dto.ParticipantDto; +import dto.ParticipantsDto; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +public class Game { + + private final Dealer dealer; + private final Players players; + + public Game(final Dealer dealer, final Players players) { + this.dealer = dealer; + this.players = players; + } + + public void initHands(BiConsumer handsPrinter) { + dealer.initHands(players); + handsPrinter.accept(DealerHandsDto.from(dealer), ParticipantsDto.of(players)); + } + + public boolean isAlreadyEnd() { + return dealer.isBlackJack(); + } + + public void checkingPlayersBlackJack(Consumer blackJackPrinter) { + players.filter(Participant::isBlackJack) + .forEach(player -> blackJackPrinter.accept(player.getName())); + } + + public void dealWithPlayers(Function answerReader, + Consumer handsPrinter, + Consumer endMessagePrinter) { + players.forEach(player -> deal(player, answerReader, + handsPrinter, + endMessagePrinter + )); + } + + public void deal(final Player player, Function answerReader, + Consumer handsPrinter, + Consumer endMessagePrinter) { + if (player.isBlackJack()) { + return; + } + boolean handsChanged = false; + boolean turnEnded = false; + + while (!turnEnded) { + final Answer answer = answerReader.apply(player.getName()); + dealer.deal(player, answer); + printHandsIfRequired(player, handsChanged, answer, handsPrinter); + handsChanged = true; + turnEnded = isTurnEnded(player, answer, endMessagePrinter); + } + } + + public void dealerTurn(Runnable dealerTurnMessagePrinter) { + if (players.isAllBust()) { + return; + } + dealer.deal(); + for (int i = 0; i < dealer.countAddedHands(); i++) { + dealerTurnMessagePrinter.run(); + } + } + + private void printHandsIfRequired(final Player player, final boolean handsChanged, final Answer answer, + Consumer handsPrinter) { + if (shouldShowHands(handsChanged, answer)) { + handsPrinter.accept(ParticipantDto.from(player)); + } + } + + private boolean isTurnEnded(final Player player, final Answer answer, Consumer endMessagePrinter) { + if (player.canDeal()) { + return !answer.isHit(); + } + endMessagePrinter.accept(player.isBust()); + return true; + } + + private boolean shouldShowHands(final boolean handsChanged, final Answer answer) { + return answer.isHit() || !handsChanged; + } +} diff --git a/src/main/java/domain/participant/Players.java b/src/main/java/domain/participant/Players.java index b13eff9c244..bce0e099be4 100644 --- a/src/main/java/domain/participant/Players.java +++ b/src/main/java/domain/participant/Players.java @@ -1,11 +1,13 @@ package domain.participant; -import domain.amount.Amount; import domain.GameResult; +import domain.amount.Amount; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; public class Players { @@ -19,6 +21,10 @@ public void forEach(Consumer action) { names.forEach(action); } + public Stream filter(Predicate predicate) { + return names.stream().filter(predicate); + } + public boolean isAllBust() { return names.stream() .allMatch(Player::isBust); From 4721bfa74ae7e3ed382de84d6d6e7bac0ef9596d Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 17:05:25 +0900 Subject: [PATCH 38/40] =?UTF-8?q?style:=20=EC=A3=BC=EC=84=9D=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 --- src/main/java/constants/ErrorCode.java | 1 - src/main/java/view/message/ErrorCodeMessage.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/constants/ErrorCode.java b/src/main/java/constants/ErrorCode.java index 28769d16cc7..666205e8576 100644 --- a/src/main/java/constants/ErrorCode.java +++ b/src/main/java/constants/ErrorCode.java @@ -12,5 +12,4 @@ public enum ErrorCode { BLANK_VALUE, EMPTY_CARD, INVALID_COMMAND, - ; } diff --git a/src/main/java/view/message/ErrorCodeMessage.java b/src/main/java/view/message/ErrorCodeMessage.java index f630c425ce2..6e8a9d9457f 100644 --- a/src/main/java/view/message/ErrorCodeMessage.java +++ b/src/main/java/view/message/ErrorCodeMessage.java @@ -16,7 +16,7 @@ public enum ErrorCodeMessage { DUPLICATE_NAME(ErrorCode.DUPLICATE_NAME, "중복된 이름은 사용할 수 없습니다."), RESERVED_NAME(ErrorCode.RESERVED_NAME, "이름은 딜러일 수 없습니다."), BLANK_VALUE(ErrorCode.BLANK_VALUE, "이름은 공백일 수 없습니다."), - INVALID_BET_AMOUNT(ErrorCode.INVALID_BET_AMOUNT, "유효하지 않은 배팅 금액입니다."), // TODO 세분화 필요? + INVALID_BET_AMOUNT(ErrorCode.INVALID_BET_AMOUNT, "유효하지 않은 배팅 금액입니다."), EMPTY_CARD(ErrorCode.EMPTY_CARD, "뽑을 수 있는 카드가 없습니다."), INVALID_COMMAND(ErrorCode.INVALID_COMMAND, "y 또는 n을 입력해주세요"), ; From 7f672e480e5e187fd633e75a645c2cce0acb5929 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 17:06:02 +0900 Subject: [PATCH 39/40] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/GameResultTest.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java index bb2a5113ab5..a791abe776f 100644 --- a/src/test/java/domain/GameResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -8,7 +8,6 @@ import static domain.HandsTestFixture.sum20Size3; import static domain.HandsTestFixture.sum21Size3; -import java.text.DecimalFormat; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -41,16 +40,4 @@ void isWinBlackJack() { Assertions.assertThat(blackJack.calculateResult(sum20Size2)).isEqualTo(GameResult.BLACK_JACK_WIN); Assertions.assertThat(sum20Size2.calculateResult(blackJack)).isEqualTo(GameResult.LOSE); } - - @Test - @DisplayName("Test name") - void methodName() { - //given - - //when - long money = 100_000_000_000_000L; - String str = String.format("%,d", money); - System.out.println(str); - //then - } } From 5aa83c37230e6fc2d8dedf5a959e3f0d96cad377 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 15 Mar 2024 17:25:31 +0900 Subject: [PATCH 40/40] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EB=AA=A9?= =?UTF-8?q?=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 --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index df1c2a59d88..d57fe415174 100644 --- a/docs/README.md +++ b/docs/README.md @@ -82,6 +82,7 @@
* [x] 딜러의 최종 수익을 계산한다. + * [x] 수익을 출력시 세자리마다 쉼표를 찍는다. ex) 100,000 * [x] 참가자의 최종 수익을 계산한다. * [x] 참가자만 블랙잭인 경우 배팅 금액의 1.5배를 받는다. * [x] 참가자와 딜러 모두 블랙잭인 경우 배팅한 금액을 돌려받는다.