Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2단계 - 블랙잭 베팅] 리브(김민주) 미션 제출합니다. #695

Merged
merged 41 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
39a9f08
docs(README.md): 요구 사항 업데이트
Minjoo522 Mar 13, 2024
1758848
feat(Money): 베팅 금액의 원시값을 포장하는 Money 객체 구현
Minjoo522 Mar 13, 2024
48cf9fa
feat(InputView): 배팅 금액 입력 받는 기능 구현
Minjoo522 Mar 13, 2024
2dae152
feat(Money): getMoney 구현
Minjoo522 Mar 13, 2024
3714c5f
feat(Hit): Hit 상태를 표현하는 객체 구현
Minjoo522 Mar 13, 2024
4daf110
feat(BlackJack): BlackJack 상태를 표현하는 객체 구현
Minjoo522 Mar 13, 2024
629f779
feat(Bust): Bust 상태를 표현하는 객체 구현
Minjoo522 Mar 13, 2024
ebbbf67
feat(Stand): Stand 상태를 표현하는 객체 구현
Minjoo522 Mar 13, 2024
351d619
feat(State): 현재 소유한 카드의 총 점수를 계산하는 calculateScore() 메서드 추가
Minjoo522 Mar 13, 2024
1e0a610
feat(Participant): Dealer, Player의 중복 메서드 Participant로 이동
Minjoo522 Mar 13, 2024
0b7e558
refactor(State): state에서 List<Card> -> Hand를 반환하는 메서드로 변경
Minjoo522 Mar 13, 2024
4c98d73
feat(Money): 현재 금액에 전달 받은 숫자 곱하는 기능 구현
Minjoo522 Mar 13, 2024
ddffb0c
refactor(Participant): 불필요한 Hand 필드 제거
Minjoo522 Mar 13, 2024
4e88564
feat(bets): 플레이어의 베팅 금액을 저장하는 Bets 구현 및 BlackJackGame에서 사용
Minjoo522 Mar 13, 2024
8fed05d
feat(State): calculateProfit 제거 및 isBlackJack, isBust 추가
Minjoo522 Mar 13, 2024
a412a89
rename: 불필요한 클래스 제거
Minjoo522 Mar 13, 2024
222eb48
feat(ResultCommand, Referee, Rule): 블랙잭 승리 관련 조건 추가
Minjoo522 Mar 13, 2024
40fccda
feat(Bets): 플레이어의 베팅 금액을 모아둔 Bets 생성 및 Money의 validate Bets로 이동
Minjoo522 Mar 13, 2024
847eab2
feat(NameProfit): 플레이어의 이름, 수익금을 담는 NameProfit Dto 추가
Minjoo522 Mar 13, 2024
8aee5df
feat(OutputView, BlackJackGame): 딜러와 플레이어의 수익금 출력하는 기능 구현
Minjoo522 Mar 13, 2024
fe6f360
rename(state): state 관련 클래스 제거
Minjoo522 Mar 13, 2024
20388a4
refactor(Participant): Dealer와 Player에 중복 코드 추상 클래스로 이동
Minjoo522 Mar 13, 2024
608df98
rename(Bets, Money): 패키지 이동
Minjoo522 Mar 13, 2024
b758eaa
refactor(Referee): Rule -> Referee와 통합
Minjoo522 Mar 13, 2024
1a7335e
refactor(BlackJackGame): 최종 수익 출력 관련 메서드 분리
Minjoo522 Mar 13, 2024
3ede65e
docs(README.md): 요구 사항 완료 내역 체크
Minjoo522 Mar 13, 2024
d4d04c4
style(test, BlackJackGame): 불필요한 import 구문 및 파라미터 제거
Minjoo522 Mar 13, 2024
784df14
rename(ResultCommandDisplay): 사용하지 않는 display enum 제거
Minjoo522 Mar 14, 2024
eb4e010
rename(BetMoney): Money -> BetMoney로 이름 변경
Minjoo522 Mar 15, 2024
1342326
refactor(BetMoney): 각 player의 수익을 계산하는 calculatePlayerProfit에서 Map이 아…
Minjoo522 Mar 15, 2024
de58ed6
refactor(Players): 필요 없는 파라미터 제거
Minjoo522 Mar 15, 2024
cca88cf
refactor(BlackJackGame): Bets를 Players가 아닌 BlackJackGame이 담담하도록 변경
Minjoo522 Mar 15, 2024
9b85741
refactor(Profit): 당첨 수익금을 포장하는 Profit 객체 생성 및 사용
Minjoo522 Mar 15, 2024
342fbd0
feat(BetMoney): 1원 미만 1억 초과 금액을 베팅 금액으로 입력했을 때 예외가 발생하는 기능 구현
Minjoo522 Mar 15, 2024
af6a018
rename(ProfitStatement): NameProfit -> ProfitStatement로 변경
Minjoo522 Mar 15, 2024
797d6db
fit(BlackJackGame): 데이터 타입 변경 반영
Minjoo522 Mar 15, 2024
16acf7a
refactor(BetsTest): TestFixture 분리 및 ParameterizedTest 개별 테스트로 분리
Minjoo522 Mar 15, 2024
bf22dd7
refactor(Participant, Dealer): canHit을 추상 클래스에서 제거하고 Dealer에서 메서드 명을 …
Minjoo522 Mar 15, 2024
98c12c1
rename(Deck): distribute -> drawn 메서드명 변경
Minjoo522 Mar 15, 2024
d668349
refactor(test): 테스트 코드에 Fixture 추가 및 DisplayName 상세화
Minjoo522 Mar 15, 2024
ee98739
refactor(test): 예외 메시지가 변경되어도 테스트가 실패하지 않도록 수정
Minjoo522 Mar 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,22 +84,40 @@
- [x] OutputView, InputView 정적 클래스 ❌

## 딜러가 덱 생성을 하고, 쥐고 있으면서 경기 진행

- [x] 딜러와 플레이어 분리
- [x] 딜러에게 필요한 것
- [x] Deck
- [x] Hand
- [x] 딜러에게 필요한 역할
- [x] 덱 생성
- [x] 카드 분배
- [x] 플레이어에게 필요한 것
- [x] Name
- [x] Hand
- [x] 딜러에게 필요한 것
- [x] Deck
- [x] Hand
- [x] 딜러에게 필요한 역할
- [x] 덱 생성
- [x] 카드 분배
- [x] 플레이어에게 필요한 것
- [x] Name
- [x] Hand
- [x] 딜러, 플레이어가 생성될 때 카드를 먼저 넘기고 시작하면 안된다.(딜러가 나누어주어야 하니까)

### ACE 점수 계산

- [x] ACE가 0개일 때 0
- [x] ACE가 두 개 이상
- [x] 한 개를 제외한 모든 ACE는 1점
- [x] 나머지 한 개 ACE
- [x] 다른 카드 점수 합 + (ACE 개수 - 1)이 10보다 크면 1점, 아니면 11점
- [x] 한 개를 제외한 모든 ACE는 1점
- [x] 나머지 한 개 ACE
- [x] 다른 카드 점수 합 + (ACE 개수 - 1)이 10보다 크면 1점, 아니면 11점

---

# 2단계 - 블랙잭 배팅

- [x] 배팅 금액 전달 받기(Money)
- [x] 공백 ❌
- [x] 숫자 ❌
- [x] 음수 ❌
- [x] 입력 받은 배팅 금액 관리(BetMoney) -> 각 플레이어와 금액 정보

## 베팅 규칙

- [x] 21을 초과할 경우 베팅 금액을 모두 잃게 된다
- [x] 블랙잭 : 1.5배를 딜러에게 받는다
- [x] 딜러, 플레이어 동시에 블랙잭 : 플레이어는 베팅한 금액을 돌려 받음
- [x] 딜러가 버스트되기 전까지 `남아 있던` 플레이어들은 가지고 있는 패에 상관 없이 승리(돌려 받음)
69 changes: 43 additions & 26 deletions src/main/java/blackjack/BlackJackGame.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package blackjack;

import blackjack.dto.DealerResultCount;
import blackjack.dto.NameCards;
import blackjack.dto.NameCardsScore;
import blackjack.dto.PlayerNameFinalResult;
import blackjack.dto.NameProfit;
import blackjack.model.deck.Deck;
import blackjack.model.money.Bets;
import blackjack.model.money.Money;
import blackjack.model.participant.Dealer;
import blackjack.model.participant.Player;
import blackjack.model.participant.Players;
import blackjack.model.result.Referee;
import blackjack.model.result.Rule;
import blackjack.model.result.ResultCommand;
import blackjack.view.InputView;
import blackjack.view.OutputView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

public class BlackJackGame {
Expand All @@ -29,16 +31,15 @@ public BlackJackGame(InputView inputView, OutputView outputView) {
public void run() {
final Dealer dealer = new Dealer(new Deck());
final Players players = registerPlayers();
final Referee referee = new Referee(new Rule(dealer));
final Referee referee = new Referee(dealer);
final Bets bets = registerBets(players);

registerInitialCards(dealer, players);
outputView.printDistributionSubject(players.getNames());
printInitialCards(dealer, players);

playPlayersTurn(players, dealer);
playDealerTurn(dealer);

printFinalResult(dealer, players, referee);
playParticipantsTurn(players, dealer);
printFinalCardsAndScores(dealer, players);
printResultProfits(referee, players, bets);
}

private Players registerPlayers() {
Expand All @@ -51,9 +52,23 @@ private Players registerPlayers() {
}
}

private Bets registerBets(final Players players) {
return players.createBets(this::readBetMoney);
}

private int readBetMoney(final String name) {
try {
return inputView.readBetMoney(name);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return readBetMoney(name);
}
}

private void registerInitialCards(final Dealer dealer, final Players players) {
dealer.receiveInitialCards(dealer.distributeInitialCard());
players.receiveInitialCards(dealer::distributeInitialCard);
outputView.printDistributionSubject(players.getNames());
}

private void printInitialCards(final Dealer dealer, final Players players) {
Expand All @@ -72,6 +87,11 @@ private List<NameCards> createDealerPlayersNameCards(final Dealer dealer, final
.toList();
}

private void playParticipantsTurn(final Players players, final Dealer dealer) {
playPlayersTurn(players, dealer);
playDealerTurn(dealer);
}

private void playPlayersTurn(final Players players, final Dealer dealer) {
players.playEachPlayerTurns(this::playPlayerTurn, dealer);
}
Expand Down Expand Up @@ -106,11 +126,6 @@ private void playDealerTurn(final Dealer dealer) {
}
}

private void printFinalResult(final Dealer dealer, final Players players, final Referee referee) {
printFinalCardsAndScores(dealer, players);
printFinalResultCommand(referee, players);
}

private void printFinalCardsAndScores(final Dealer dealer, final Players players) {
outputView.println();
NameCardsScore dealerNameCardsScore = new NameCardsScore(OutputView.DEALER_NAME, dealer.openCards(),
Expand All @@ -120,19 +135,21 @@ private void printFinalCardsAndScores(final Dealer dealer, final Players players
outputView.printFinalCardsAndScore(playerNameCardsScore);
}

private void printFinalResultCommand(final Referee referee, final Players players) {
printDealerFinalResultCount(referee, players);
List<PlayerNameFinalResult> playerNameFinalResults = players.stream()
.map(player -> PlayerNameFinalResult.from(player, referee.judgePlayerResult(player)))
.toList();
outputView.printFinalResults(playerNameFinalResults);
private void printResultProfits(final Referee referee, final Players players, final Bets bets) {
final Map<Player, ResultCommand> playerResultCommands = players.matchPlayerResultCommands(referee, players);
printDealerResultProfit(playerResultCommands, bets);
printPlayersResultProfit(playerResultCommands, bets);
}

private void printDealerFinalResultCount(final Referee referee, final Players players) {
List<DealerResultCount> dealerResults = referee.judgeDealerResult(players)
.entrySet().stream()
.map(dealerResult -> new DealerResultCount(dealerResult.getKey(), dealerResult.getValue()))
.toList();
outputView.printDealerFinalResult(dealerResults);
private void printDealerResultProfit(final Map<Player, ResultCommand> playerResultCommands,
final Bets bets) {
final Money dealerProfit = bets.calculateDealerProfit(playerResultCommands);
outputView.printDealerProfit(dealerProfit.getMoney());
}

private void printPlayersResultProfit(final Map<Player, ResultCommand> playerResultCommands, final Bets bets) {
final Map<Player, Money> playerProfits = bets.calculatePlayersProfit(playerResultCommands);
final List<NameProfit> nameProfits = NameProfit.createNameProfits(playerProfits);
outputView.printPlayersProfit(nameProfits);
}
}
7 changes: 0 additions & 7 deletions src/main/java/blackjack/dto/DealerResultCount.java

This file was deleted.

19 changes: 19 additions & 0 deletions src/main/java/blackjack/dto/NameProfit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package blackjack.dto;

import blackjack.model.money.Money;
import blackjack.model.participant.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public record NameProfit(String name, int profit) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

장부나 정산서 처럼 금액을 핸들링한다는 느낌의 네이밍이면 좋을 것 같아요 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProfitStatement로 변경하였습니다. 좋은 의견 감사합니다!😊


public static List<NameProfit> createNameProfits(final Map<Player, Money> playerProfit) {
final List<NameProfit> nameProfits = new ArrayList<>();
for (Player player : playerProfit.keySet()) {
final int profit = playerProfit.get(player).getMoney();
nameProfits.add(new NameProfit(player.getName(), profit));
}
return nameProfits;
}
}
11 changes: 0 additions & 11 deletions src/main/java/blackjack/dto/PlayerNameFinalResult.java

This file was deleted.

46 changes: 46 additions & 0 deletions src/main/java/blackjack/model/money/Bets.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package blackjack.model.money;

import blackjack.model.participant.Player;
import blackjack.model.result.ResultCommand;
import java.util.LinkedHashMap;
import java.util.Map;

public class Bets {
private final Map<Player, Money> bets;

public Bets() {
this.bets = new LinkedHashMap<>();
}

public void addBet(final Player player, final int money) {
validatePositiveMoney(money);
bets.put(player, new Money(money));
}

private void validatePositiveMoney(final int money) {
if (money <= 0) {
throw new IllegalArgumentException("0원 이하의 금액을 베팅할 수 없습니다.");
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Money 가 유효한 범위인지는 원시값 포장을 해두었으니 돈이 생성될 때 검증하는게 더 안전하지 않을까요?

Bets 가 아닌 다른 곳에서 Money 를 생성하게되면 음수가 생성될 수도 있을 것 같아요~ 🤔

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

패배했을 경우 -1 이기 때문에 열어두셨군요.
그렇다면 배팅 머니와 / 정산 머니를 나눠도 좋을 것 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

베팅 머니와, 정산 머니를 나누어 BetMoney, Profit으로 만들어주고,
BetMoney에서 유효성 검증을 하도록 변경하였습니다. 😆


public Map<Player, Money> calculatePlayersProfit(final Map<Player, ResultCommand> result) {
final Map<Player, Money> playersProfit = new LinkedHashMap<>();
for (Player player : result.keySet()) {
playersProfit.put(player, calculatePlayerProfit(result, player));
}
return playersProfit;
}

private Money calculatePlayerProfit(final Map<Player, ResultCommand> result, final Player player) {
final double multiplier = result.get(player).getRate();
return bets.get(player).multiply(multiplier);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시그니처에 Map 을 넘겨주지 않고 rate 를 바로 넘겨주면 좋을 것 같아요. 계산이 필요한 플레이어 외에 다른 플레이어의 정보를 꺼내 올 수 있는 여지를 막도록요! ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바로 반영하였습니다! ☺️

public Money calculateDealerProfit(final Map<Player, ResultCommand> result) {
final Map<Player, Money> playersProfit = calculatePlayersProfit(result);
final int playerTotalProfit = playersProfit.values().stream()
.mapToInt(Money::getMoney)
.sum();
return new Money(playerTotalProfit).multiply(-1);
}
}
36 changes: 36 additions & 0 deletions src/main/java/blackjack/model/money/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package blackjack.model.money;

import java.util.Objects;

public class Money {
private final int money;

public Money(final int money) {
this.money = money;
}

public Money multiply(final double multiplier) {
return new Money((int) (money * multiplier));
}

public int getMoney() {
return money;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Money money1 = (Money) o;
return money == money1.money;
}

@Override
public int hashCode() {
return Objects.hash(money);
}
}
3 changes: 2 additions & 1 deletion src/main/java/blackjack/model/participant/Dealer.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public Card distributeCard() {
}

public List<Card> openFirstCard() {
return List.of(hand.getFirstCard());
final List<Card> cards = hand.getCards();
return List.of(cards.get(0));
}
}
4 changes: 0 additions & 4 deletions src/main/java/blackjack/model/participant/Hand.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,4 @@ public boolean hasSameSizeWith(Hand other) {
public List<Card> getCards() {
return List.copyOf(cards);
}

public Card getFirstCard() {
return cards.get(0);
}
}
10 changes: 8 additions & 2 deletions src/main/java/blackjack/model/participant/Participant.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@

public abstract class Participant {

protected final Hand hand;
protected Hand hand;

public Participant() {
this.hand = new Hand();
}

public void receiveInitialCards(final List<Card> cards) {
hand.add(cards);
for (Card card : cards) {
hand.add(card);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

손에 카드를 추가하는 형태로 변경하셨군요 좋습니다 👍🏻

}
}

public void draw(final Card card) {
Expand All @@ -33,6 +35,10 @@ public boolean isBust() {
return hand.isBust();
}

public boolean isBlackJack() {
return hand.isBlackJack();
}

public boolean hasManyCardsThan(Participant other) {
return hand.hasManyThan(other.hand);
}
Expand Down
Loading