Skip to content

Commit

Permalink
[1단계 - 블랙잭 게임 실행] 우르(김현우) 미션 제출합니다. (#391)
Browse files Browse the repository at this point in the history
* docs : 기능 명세 작성

* feat : cardValue 추가

* feat : 카드 서브클래스 추가

* docs : 기능 명세 추가

* feat : CardArea 생성

* docs : 기능 명세 추가

* feat: 카드 추가 기능 구현

* feat : 카드 영역을 딜러 카드 영역과 참가자 카드 영역으로 나눔

* feat : 카드 점수 계산 기능 구현

* feat : 카드를 더 받을 수 있는 상태인지 확인하는 기능 추가

* feat : 카드를 더 받을 것인지 결정하는 기능 추가

* refactor : 카드 모양을 enum으로 설정

* feat : 카드 전체 생성 기능 추가

* feat : 카드 뽑기 기능 추가

* feat : 참가자 이름 구현

* feat : 참가자 카드 영역 Hit 여부 구현

* refactor : 패키지 구조 수정

* fix : 카드값 계산 오류 수정

* feat : 버스트 여부 확인

* refactor : Player를 부모로 두고 Dealer와 Participant를 가지게끔 변경

* refactor : CardArea 를 구체 클래스로 변경

- DealerCardArea, ParticipantCardArea 제거

* feat : 블랙잭 게임 완성

* feat : 출력 메세지 변환

* refactor: 게임 통계 로직 변경

* refactor : 첫 번째 카드를 보여주는 행위는 CardArea 가 적합하다고 생각하여 옮김

* refactor : Dealer 최대 점수 상수화

* refactor : enhanced-for 문 flatMap으로 수정

* refactor : state != STAY 를 풀어서 작성

- null 이거나 hit 상태일 경우 hit를 할 수 있음
- 그래서 null 과 hit 상태를 모두 나타내기 위해 연산을 풀어서 작성
- hit 상태를 State에게 직접 물어봄

* refactor : 패키지명 participant -> player 로 변경

* refactor : dealer name 은 고정적으로 딜러다

* feat : DealerResult 추가

- DealerResult는 ParticipantResult 반대

* refactor : OutputView 변경

* refactor : 패키지 변경

- Dealer 관련은 domain.player.dealer
- Participant 관련은 domain.player.participant

* refactor : CardDeck의 자료구조 List -> Stack 으로 변경

- 테스트 코드에서만 사용하는 메서드 삭제

* style : pr 제출 전 reformatting

* fix : y 또는 n 을 입력하지 않을 경우 재입력 로직 추가

* mission : mini mission ArrayList 구현하기

* docs : readme 위치 변경

* refactor : 블랙잭 규칙 중 burst -> bust 변경

* refactor : Player에 이미 점수 계산하는 메서드가 있어서 변경

- Name은 하위 클래스에서 사용하지 않기 때문에 접근제어자 protected -> private 변경

* style : 개행 추가

* refactor : 딜러에서 첫 번째 카드를 보여주는 메서드 추가

- OutputView에서
"딜러의 cardArea에서 첫 번재 카드를 뽑는다"보다는 "딜러는 첫번째 카드를 보여준다" 가 자연스러워 보임

* refactor : State 삭제

* feat : cardArea를 생성하는 CardTable 추가

* feat : 점수를 관리하는 Score 객체 추가

* feat : 점수 관련 로직에서 int 가 아닌 Score 로 변경

* feat : 블랙잭 게임 결과를 CardTable에서 알려준다

* refactor : 블랙잭 게임 결과를 CardTable 로 책임을 위임하면서 코드 변경

* fix : 점수 출력을 위한 getter 메서드 추가

* refactor : 매직넘버 상수로 변경

* refactor : 값 객체의 변수 이름을 value 로 변경

* refactor : 카드 나눠주는 행위를 Controller에서 하지 않고 CardTable로 위임

- 도메인 룰은 Participant 1장 -> Dealer 1장 -> Participant 1 -> Dealer 1장 임
- 현재 코드는 Participant 2장 한번에 주고 -> Dealer 2장 한번에 주기 때문에 도메인 룰 위반
- 카드 나눠주는 행위도 도메인 룰이기 때문에 CardTable에 위임
- CardArea 생성자를 삭제하고 나서의 코드 수정

* refactor : 카드를 나눠줄 수 있으면 true를 반환

* refactor : 카드 나눠주는 행위를 CardTable 에 위임

* style : 제출 전 reformatting

* minimission : ArrayList, LinkedList 구현하기

* feat : Score에서 Ace 계산하기

- Ace 가 하나이상 존재하면서 더할 때 버스트가 아닐 경우에는 11을 더해줌
- 그 외는 1로 더하기

* refactor : CardArea 에서 카드 값 계산 로직 수정

* refactor : int 로 비교하지 않고 Score 에 있는 연산 사용

* style : 제출 전 code reformatting

---------

Co-authored-by: shin-mallang <[email protected]>
java-saeng and shin-mallang authored Mar 7, 2023
1 parent b467f6f commit 10779cd
Showing 34 changed files with 2,428 additions and 0 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -5,3 +5,45 @@
## 우아한테크코스 코드리뷰

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)

## 도메인

### 카드 값

- [x] `2~10`, `A`, `K`, `Q`, `J` 가 있다.
- [x] `K`, `Q`, `J` 는 10으로 계산된다.

### 카드

- [x] `다이아`, `클로버`, `하트`, `스페이드` 카드가 있다.
- [x] `카드 값`을 가진다.

### 카드 영역
- [x] 딜러 카드 영역과 참가자 카드 영역으로 나뉜다.
- [x] 카드들을 가진다.
- [x] 카드를 더 받을 수 있는 상태인지 확인한다.
- [x] 카드를 더 받을 것인지 결정한다.
- [x] 카드 현숫자를 계산한다.
- [X] `A` 는 1 또는 11로 계산될 수 있다.
- [x] 카드를 추가할 수 있다.
- [x] 처음에 카드 2장을 받아 생성된다.

### 카드 덱

- [x] 전체 카드를 가진다.
- [x] 카드를 한장씩 준다.

## refactoring

### 카드 테이블
- [x] `카드 영역`을 생성해준다.
- [x] `딜러``참여자`의 승부 결과를 알려줄 수 있다.

### 점수
- [x] 21점을 초과하는지 확인한다.
- [x] 21점 미만인지 확인한다.
- [x] 점수끼리 대소비교를 할 수 있다.
- [x] 작거나 같다.
- [x] 크다.
- [x] 작다.

7 changes: 7 additions & 0 deletions src/main/java/BlackJackApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import controller.BlackJackController;

public class BlackJackApplication {
public static void main(String[] args) {
new BlackJackController().run();
}
}
124 changes: 124 additions & 0 deletions src/main/java/controller/BlackJackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package controller;

import domain.cardtable.CardTable;
import domain.deck.CardDeck;
import domain.player.Name;
import domain.player.Player;
import domain.player.dealer.Dealer;
import domain.player.dealer.DealerResult;
import domain.player.participant.Participant;
import domain.player.participant.ParticipantResult;
import view.InputView;
import view.OutputView;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

public class BlackJackController {

public void run() {

final CardDeck cardDeck = CardDeck.shuffledFullCardDeck();
final CardTable cardTable = CardTable.readyToPlayBlackjack(cardDeck);

final List<Participant> participants = createParticipants();
final Dealer dealer = createDealer();
final List<Player> players = createPlayers(participants, dealer);

deal(cardTable, players);

printStateAfterDeal(participants, dealer);
hittingPlayer(cardTable, participants, dealer);
printStateAfterHit(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);

return players;
}

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

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

private static Dealer createDealer() {
return new Dealer();
}

private static List<Participant> createParticipants() {
return InputView.readParticipantsName()
.stream()
.map(Name::new)
.map(Participant::new)
.collect(Collectors.toList());
}

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 static void printStateAfterHit(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 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 hittingPlayer(final CardTable cardTable, final List<Participant> participants, final Dealer dealer) {
hitForParticipants(cardTable, participants);
hitForDealer(cardTable, dealer);
}

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

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

private void hitForParticipant(final CardTable cardTable, final Participant participant) {
while (inputHitOrStay(participant)) {
cardTable.dealCardTo(participant);
OutputView.showStateOf(participant);
}
}

private boolean inputHitOrStay(final Participant participant) {
return InputView.readMoreCard(participant).equals("y");
}
}
69 changes: 69 additions & 0 deletions src/main/java/domain/Score.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package domain;

import java.util.Objects;

public class Score {

public static final Score MIN = new Score(0);

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

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

private final int value;

public Score(final int value) {
this.value = value;
}

public boolean isBust() {
return this.isGreaterThan(UPPER_LIMIT_SCORE);
}

public boolean canMoreCard() {
return this.isLessThan(UPPER_LIMIT_SCORE);
}

public boolean isLessThan(final Score other) {
return value < other.value;
}

public boolean isLessEqualThan(final Score other) {
return value <= other.value;
}

public boolean isGreaterThan(final Score other) {
return value > other.value;
}

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

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

return this;
}

public Score plus(Score other) {
return new Score(value + other.value);
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Score score = (Score) o;
return value == score.value;
}

@Override
public int hashCode() {
return Objects.hash(value);
}

public int value() {
return value;
}
}
54 changes: 54 additions & 0 deletions src/main/java/domain/area/CardArea.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package domain.area;

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

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

public class CardArea {

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

public List<Card> cards() {
return new ArrayList<>(cards);
}

public void addCard(final Card card) {
cards.add(card);
}

public Score calculate() {
Score score = score();

if (hasAce()) {
score = score.plusTenIfNotBurst();
}

return score;
}

private Score score() {
return cards.stream()
.map(card -> new Score(card.cardValue().value()))
.reduce(Score.MIN, (Score::plus));

}

private boolean hasAce() {
return cards.stream()
.anyMatch(card -> card.cardValue().isAce());
}

public boolean canMoreCard() {
return calculate().canMoreCard();
}

public boolean isBust() {
return calculate().isBust();
}

public Card firstCard() {
return cards.get(0);
}
}
35 changes: 35 additions & 0 deletions src/main/java/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package domain.card;

import java.util.Objects;

public class Card {

private final CardShape cardShape;
private final CardValue cardValue;

public Card(final CardShape cardShape, final CardValue cardValue) {
this.cardShape = cardShape;
this.cardValue = cardValue;
}

public CardShape cardShape() {
return cardShape;
}

public CardValue cardValue() {
return this.cardValue;
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof Card)) return false;
final Card card = (Card) o;
return cardShape == card.cardShape && cardValue == card.cardValue;
}

@Override
public int hashCode() {
return Objects.hash(cardShape, cardValue);
}
}
9 changes: 9 additions & 0 deletions src/main/java/domain/card/CardShape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package domain.card;

public enum CardShape {
DIAMOND,
CLOVER,
HEART,
SPADE,
;
}
34 changes: 34 additions & 0 deletions src/main/java/domain/card/CardValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package domain.card;

public enum CardValue {

ACE(1),

TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),

KING(10),
QUEEN(10),
JACK(10);

private final int value;

CardValue(final int value) {
this.value = value;
}

public int value() {
return value;
}

public boolean isAce() {
return this == ACE;
}
}
Loading

0 comments on commit 10779cd

Please sign in to comment.