Skip to content

Commit

Permalink
[2단계 - 블랙잭 베팅] 우르(김현우) 미션 제출합니다. (#512)
Browse files Browse the repository at this point in the history
* feat : 점수가 블랙잭인지 확인

* feat : Cards의 합이 블랙잭인지 확인

* feat : Money VO 생성

* feat : 게임 결과에 따라 베팅액 결정 전략 추가

* feat : 참여자는 자신의 베팅 결과 상태를 결정할 수 있다

* fix : BigDecimal equals 수정

* feat : 참여자는 자신의 베팅 결과에 따라 베팅액 결과 금액을 반환한다.

* feat : CardTable은 승부에 따라 베팅액 결정 상태 요청을 Participant에게 보냄

* feat : CardTable 은 경기 결과에 따라 베팅 금액을 구해준다

* feat : 배팅 금액 받기

* feat : 배팅금액상태 결정 되지 않음

* feat : Participant 수익 출력

* feat : 돈 합하기

* feat : 딜러 수익 구하기

* feat : 참여자와 딜러의 전체 최종 수익 구하기

* refactor : interface method 이름 변경

* refactor : 참여자와 딜러 점수 비교하는 것을 Participant 에 위임

* feat : 처음 2장에서 승부가 나지 않을 상태 추가

* refactor : 딜러와 참여자 점수를 비교를 Participant 에 위임

* refactor : null이 아닌 승부가 나지 않은 상태인 TieState 로 초기화

* refactor : first, finalMatchWith 메서드 간단하게 작성

- 테스트 코드 다시 작성

* refactor : 조건문 삭제

* refactor : setter 삭제 후, 테스트 추가

* refactor : 아직 승부가 결정이 안된 상태 null object 넣기

* refactor : dealCardTo boolean 사용하지 않기 때문에 void 로 변경

* refactor : dealer 가 블랙잭이면 게임을 바로 끝내야해서 상태가 정해진 participant 는 hit 할 수 없음

* refactor : CardArea -> Hand 로 변경

* refactor : 도메인 용어로 메서드 네임, 상수 이름 변경

* feat : 처음 두 장을 받을 때, 보여주는 방식을 추상 메서드로 변경

* refactor : 카드를 보여주는 추상 메서드 존재하기 때문에 기존 코드 삭제

* test : final match 를 테스트 할 때, first match 도 실행

* test : dealer 얻은 결과 테스트 작성

* style : pr 제출 전 reformatting

* refactor : 객체 메시지 목록은 관용적인 getter보다 위에 위치

* refactor : 블랙잭 조건은 카드가 2장의 합이 21이어야함

* refactor : 점수 계산할 때 softHand일 경우 바로 score 리턴

* refactor : 패키지 이동

* feat : 배팅 상태 판단하는 클래스 추가

* refactor : BetResultFinder 가 베팅 결과 상태를 찾아서 Participant 가 돈을 계산

* test : 테스트 메서드 명 수정

* fix : DealerBust 에서 참여자가 블랙잭이 아니면서 3장 이상의 카드 합이 21일 때 진 걸로 결정

- 그래서 참여자가 블랙잭이 아니고, 합이 21이거나 hit 할 수 있는 상황 + 딜러가 버스트면 참여자가 이김

* refactor : @FunctionalInterface 추가 및 NULL object 삭제

* refactor : DealerBust 조건 변경 및 사용하지 않는 메서드 삭제

* refactor : 딜러와 참여자가 블랙잭이 아니더라도 나중에 점수가 같으면 무승부이다.

* style : 리뷰 요청 전 code formatting
  • Loading branch information
java-saeng authored Mar 15, 2023
1 parent 10779cd commit db4fc8f
Show file tree
Hide file tree
Showing 37 changed files with 1,382 additions and 485 deletions.
128 changes: 66 additions & 62 deletions src/main/java/controller/BlackJackController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import domain.player.Name;
import domain.player.Player;
import domain.player.dealer.Dealer;
import domain.player.dealer.DealerResult;
import domain.player.participant.Money;
import domain.player.participant.Participant;
import domain.player.participant.ParticipantResult;
import view.InputView;
import view.OutputView;

Expand All @@ -16,8 +15,6 @@
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.counting;

public class BlackJackController {

public void run() {
Expand All @@ -29,96 +26,103 @@ public void run() {
final Dealer dealer = createDealer();
final List<Player> players = createPlayers(participants, dealer);

deal(cardTable, players);

printStateAfterDeal(participants, dealer);
hittingPlayer(cardTable, participants, dealer);
printStateAfterHit(participants, dealer);
firstDeal(cardTable, players);
printStateAfterFirstDeal(participants, dealer);

final Map<Participant, ParticipantResult> participantsResult = cardTable.determineWinner(participants, dealer);
final Map<DealerResult, Long> scoreBoard = countDealerResult(participantsResult);

printPlayerScoreBoard(participants, participantsResult, scoreBoard);
}

private static List<Player> createPlayers(final List<Participant> participants, final Dealer dealer) {
List<Player> players = new ArrayList<>(participants);
players.add(dealer);
finalDeal(cardTable, participants, dealer);
printStateAfterFinalDeal(participants, dealer);

return players;
printPlayersMoneyBoard(cardTable, participants, dealer);
}

private static void deal(final CardTable cardTable, final List<Player> players) {
private void firstDeal(final CardTable cardTable, final List<Player> players) {
dealCard(cardTable, players);
dealCard(cardTable, players);
}

private static void dealCard(final CardTable cardTable, final List<Player> players) {
private void dealCard(final CardTable cardTable, final List<Player> players) {
players.forEach(cardTable::dealCardTo);
}

private static Dealer createDealer() {
return new Dealer();
private void printStateAfterFirstDeal(final List<Participant> participants, final Dealer dealer) {
OutputView.showDealtCardTo(participants);
OutputView.showStateOf(dealer);
OutputView.showStateOf(participants);
}

private static List<Participant> createParticipants() {
return InputView.readParticipantsName()
.stream()
.map(Name::new)
.map(Participant::new)
.collect(Collectors.toList());
private void finalDeal(final CardTable cardTable, final List<Participant> participants, final Dealer dealer) {
hitForParticipants(cardTable, participants);
hitForDealer(cardTable, dealer);
}

private static void printPlayerScoreBoard(final List<Participant> participants,
final Map<Participant, ParticipantResult> playersResult,
final Map<DealerResult, Long> scoreBoard) {
OutputView.showDealerScoreBoard(scoreBoard);
OutputView.showParticipantsScoreBoard(playersResult, participants);
private void hitForParticipants(final CardTable cardTable, final List<Participant> participants) {
participants.stream()
.filter(Participant::isNotBlackjack)
.forEach(participant -> hitForParticipant(cardTable, participant));

}

private static void printStateAfterHit(final List<Participant> participants, final Dealer dealer) {
private void hitForParticipant(final CardTable cardTable, final Participant participant) {
while (participant.canHit() && selectHitOrStand(participant)) {
cardTable.dealCardTo(participant);
OutputView.showStateOf(participant);
}
}

private void hitForDealer(final CardTable cardTable, final Dealer dealer) {
do {
OutputView.dealerOneMoreCard();
cardTable.dealCardTo(dealer);
} while (dealer.canHit());
}

private void printStateAfterFinalDeal(final List<Participant> participants, final Dealer dealer) {
OutputView.showPlayerStateResult(dealer);
OutputView.showParticipantsStateResult(participants);
}

private static void printStateAfterDeal(final List<Participant> participants, final Dealer dealer) {
OutputView.showDealtCardTo(participants);
OutputView.showStateOf(dealer);
OutputView.showStateOf(participants);
private void printPlayersMoneyBoard(final CardTable cardTable, final List<Participant> participants,
final Dealer dealer) {
printParticipantsMoneyBoard(cardTable, participants, dealer);
printDealerMoneyBoard(cardTable, participants, dealer);
}

private static Map<DealerResult, Long> countDealerResult(
final Map<Participant, ParticipantResult> playersResult) {
return playersResult.keySet()
.stream()
.collect(Collectors.groupingBy(participant -> playersResult.get(participant)
.convertToDealerResult(),
counting()));
private void printParticipantsMoneyBoard(final CardTable cardTable, final List<Participant> participants,
final Dealer dealer) {
final Map<Participant, Money> participantsResult = cardTable.determineParticipantsBettingMoney(participants,
dealer);
OutputView.showBettingMoneyBoard(participantsResult);
}

private void hittingPlayer(final CardTable cardTable, final List<Participant> participants, final Dealer dealer) {
hitForParticipants(cardTable, participants);
hitForDealer(cardTable, dealer);
private void printDealerMoneyBoard(final CardTable cardTable, final List<Participant> participants,
final Dealer dealer) {
final Money money = cardTable.determineDealerMoney(participants, dealer);
OutputView.showDealerMoneyBoard(money);
}

private void hitForDealer(final CardTable cardTable, final Dealer dealer) {
do {
OutputView.dealerOneMoreCard();
} while (cardTable.dealCardTo(dealer));
private List<Player> createPlayers(final List<Participant> participants, final Dealer dealer) {
List<Player> players = new ArrayList<>(participants);
players.add(dealer);

return players;
}

private void hitForParticipants(final CardTable cardTable, final List<Participant> participants) {
participants.forEach(participant -> hitForParticipant(cardTable, participant));
private Dealer createDealer() {
return new Dealer();
}

private void hitForParticipant(final CardTable cardTable, final Participant participant) {
while (inputHitOrStay(participant)) {
cardTable.dealCardTo(participant);
OutputView.showStateOf(participant);
}
private List<Participant> createParticipants() {
return InputView.readParticipantsName()
.stream()
.map(Name::new)
.map(name -> {
final int bettingMoney = InputView.readBettingMoney(name);
return new Participant(name, Money.wons(bettingMoney));
})
.collect(Collectors.toList());
}

private boolean inputHitOrStay(final Participant participant) {
return InputView.readMoreCard(participant).equals("y");
private boolean selectHitOrStand(final Participant participant) {
return InputView.readMoreCard(participant);
}
}
16 changes: 12 additions & 4 deletions src/main/java/domain/Score.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class Score {

private static final Score UPPER_LIMIT_SCORE = new Score(21);

private static final Score REMAIN_SCORE_ACE = new Score(10);
private static final Score SOFT_HAND_SCORE = new Score(10);

private final int value;

Expand Down Expand Up @@ -36,11 +36,11 @@ public boolean isGreaterThan(final Score other) {
return value > other.value;
}

public Score plusTenIfNotBurst() {
final Score plusScore = this.plus(REMAIN_SCORE_ACE);
public Score plusSoftHand() {
final Score plusScore = this.plus(SOFT_HAND_SCORE);

if (plusScore.isLessEqualThan(UPPER_LIMIT_SCORE)) {
return this.plus(REMAIN_SCORE_ACE);
return this.plus(SOFT_HAND_SCORE);
}

return this;
Expand All @@ -50,6 +50,14 @@ public Score plus(Score other) {
return new Score(value + other.value);
}

public boolean isSumTwentyOne() {
return this.equals(UPPER_LIMIT_SCORE);
}

public boolean isSame(final Score other) {
return this.equals(other);
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/domain/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ public CardValue cardValue() {

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof Card)) return false;
if (this == o) {
return true;
}
if (!(o instanceof Card)) {
return false;
}
final Card card = (Card) o;
return cardShape == card.cardShape && cardValue == card.cardValue;
}
Expand Down
41 changes: 19 additions & 22 deletions src/main/java/domain/cardtable/CardTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import domain.deck.CardDeck;
import domain.player.Player;
import domain.player.dealer.Dealer;
import domain.player.participant.Money;
import domain.player.participant.Participant;
import domain.player.participant.ParticipantResult;
import domain.player.participant.betresult.resultfinder.BetResultFinder;

import java.util.List;
import java.util.Map;
Expand All @@ -14,45 +15,41 @@
public class CardTable {

private final CardDeck cardDeck;
private final BetResultFinder betResultFinder;

private CardTable(final CardDeck cardDeck) {
this.cardDeck = cardDeck;
this.betResultFinder = new BetResultFinder();
}

public static CardTable readyToPlayBlackjack(final CardDeck cardDeck) {
return new CardTable(cardDeck);
}

public Map<Participant, ParticipantResult> determineWinner(final List<Participant> participants,
final Dealer dealer) {
public Map<Participant, Money> determineParticipantsBettingMoney(final List<Participant> participants,
final Dealer dealer) {

return participants.stream()
.collect(Collectors.toMap(
Function.identity(),
participant -> matchBetween(participant, dealer))
);
participant -> participant.determineBetMoney(
betResultFinder.findStateOf(participant, dealer))
));
}

private ParticipantResult matchBetween(final Participant participant, final Dealer dealer) {
if (participant.isBust()) {
return ParticipantResult.LOSER;
}
if (dealer.isBust()) {
return ParticipantResult.WINNER;
}
if (participant.score().isGreaterThan(dealer.score())) {
return ParticipantResult.WINNER;
}
if (participant.score().equals(dealer.score())) {
return ParticipantResult.DRAWER;
}
return ParticipantResult.LOSER;
public Money determineDealerMoney(final List<Participant> participants, final Dealer dealer) {

final Map<Participant, Money> participantsResultMoney = determineParticipantsBettingMoney(participants, dealer);

return participantsResultMoney.values()
.stream()
.reduce(Money.MIN, Money::plus)
.lose();
}

public boolean dealCardTo(Player player) {
public void dealCardTo(Player player) {
if (player.canHit()) {
player.hit(cardDeck.draw());
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package domain.area;
package domain.hand;

import domain.Score;
import domain.card.Card;

import java.util.ArrayList;
import java.util.List;

public class CardArea {
public class Hand {

private final List<Card> cards = new ArrayList<>();

Expand All @@ -21,8 +21,8 @@ public void addCard(final Card card) {
public Score calculate() {
Score score = score();

if (hasAce()) {
score = score.plusTenIfNotBurst();
if (isSoftHand()) {
return score.plusSoftHand();
}

return score;
Expand All @@ -35,7 +35,7 @@ private Score score() {

}

private boolean hasAce() {
private boolean isSoftHand() {
return cards.stream()
.anyMatch(card -> card.cardValue().isAce());
}
Expand All @@ -48,7 +48,15 @@ public boolean isBust() {
return calculate().isBust();
}

public boolean isBlackjack() {
return cards.size() == 2 && calculate().isSumTwentyOne();
}

public Card firstCard() {
return cards.get(0);
}

public Card secondCard() {
return cards.get(1);
}
}
Loading

0 comments on commit db4fc8f

Please sign in to comment.