Skip to content

Commit

Permalink
[1단계 - 블랙잭 게임 실행] 카피(김상혁) 미션 제출합니다 (#672)
Browse files Browse the repository at this point in the history
* docs(README) : 구현 기능 목록 작성

* feat(Card) : 카드 숫자 유효성 검사 및 카드 생성

* feat(Cards) : 카드 처음 개수 검증

* feat(Cards) : 카드의 숫자 합이 최대 값을 초과하는지 확인

* feat(Player) : 카드 뽑기

* feat(Name) : 플레이어 이름 원시값 포장

* feat(Cards) : 카드 합이 최소 점수 조건보다 이하인지 확인

* refactor(Cards) : Cards 역할 분리

* refactor(Participant, Cards) : Participant 상속 및 Cards 추상화

* feat(Shape) : 카드 모양 추가

* feat(Score) : 점수 도메인 생성

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Cards) : Cards가 Participant를 관리하도록 변경

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Cards) : 카드 뽑는 기능을 Cards로 이동

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Rule) : 카드의 승무패를 결정하는 기능 구현

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Game) : 게임의 승패를 반영

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(InputView) : 이름 입력 받기

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(InputView) : 카드를 더 받을지 입력받기

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(OutputView) : 지급받은 카드 출력

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(OutputView) : 플레이어 카드 출력

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(OutputView) : 카드와 결과값 출력

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(ScoreBoard) : 점수 업데이트 및 조회

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(OutputView) : 최종 승패 출력

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Drawable) : canDraw 인터페이스로 분리

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Deck) : 카드 덱에서 뽑기

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Participant) : 사용하지 않는 클래스 삭제

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(ALL) : 패키지 구조 변경

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Deck) : 게임 시작 시 덱에서 두 장 뽑기

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* fix(Deck) : 덱 생성 범위 수정

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Cards) : 카드 받는 메서드 수정

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(OutputView) : 딜러 카드 뽑는 여부 출력

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* fix(RandomDrawStrategy) : 카드 뽑기 범위 수정

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Cards) : 최적합 구하기

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Rule) : ScoreBoard Rule에서 관리

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(View) : 출력 정리

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(Casino) : 뷰 및 도메인 호출

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat(BlackjackApplication) : 블랙잭 게임 시작

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* refactor(Score) : 중복 코드 제거

Co-authored-by: tkdgur0906 <tkdgur0906@naver.com>

* feat : 테스트 설명 어노테이션 추가

---------

Co-authored-by: ay-eonii <naayen@naver.com>
  • Loading branch information
tkdgur0906 and ay-eonii authored Mar 9, 2024
1 parent 4dd03d0 commit bd1af96
Show file tree
Hide file tree
Showing 25 changed files with 858 additions and 0 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,37 @@

블랙잭 미션 저장소

## 구현 기능 목록

### 카드

- [x] 숫자가 기본
- [ ] Ace는 1 또는 11
- [x] King, Queen, Jack은 각각 10
- [x] 모양은 스페이드, 다이아몬드, 하트, 클로버

### 게임

- [ ] 플레이어에게 두 장의 카드 지급
- [x] 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 우승
- [ ] 딜러는 처음에 2장 지급
- [x] 플레이 결과가 같다면 무승

### 플레이어

- [x] 21 이하일 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있음
- [x] 21을 초과한다면 카드를 뽑을 수 없음

### 딜러

- [ ] 처음에 2장 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 함
- [x] 17점 이상이면 추가로 받을 수 없음
- [x] 처음 카드는 한 장만 공개

### 출력

- [x] 게임을 완료한 후 각 플레이어별로 승패를 출력

## 우아한테크코스 코드리뷰

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
9 changes: 9 additions & 0 deletions src/main/java/BlackjackApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import manager.Casino;

public class BlackjackApplication {

public static void main(String[] args) {
Casino casino = new Casino();
casino.run();
}
}
15 changes: 15 additions & 0 deletions src/main/java/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package domain;

public class Name {

private final String name;

public Name(String name) {
this.name = name;
}

@Override
public String toString() {
return name;
}
}
25 changes: 25 additions & 0 deletions src/main/java/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package domain.card;

public class Card {

private final CardNumber cardNumber;
private final Shape shape;

public Card(int number, Shape shape) {
this.cardNumber = CardNumber.find(number);
this.shape = shape;
}

public boolean isAce() {
return cardNumber == CardNumber.ACE;
}

public int getCardNumber() {
return cardNumber.getValue();
}

@Override
public String toString() {
return cardNumber.getSign() + shape.getShape();
}
}
40 changes: 40 additions & 0 deletions src/main/java/domain/card/CardNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package domain.card;

public enum CardNumber {

ACE(1, "A"),
TWO(2, "2"),
THREE(3, "3"),
FOUR(4, "4"),
FIVE(5, "5"),
SIX(6, "6"),
SEVEN(7, "7"),
EIGHT(8, "8"),
NINE(9, "9"),
TEN(10, "10"),
JACK(10, "J"),
QUEEN(10, "Q"),
KING(10, "K");

private final int value;

private final String sign;

CardNumber(int value, String sign) {
this.value = value;
this.sign = sign;
}

public static CardNumber find(int random) {
CardNumber[] values = values();
return values[random - 1];
}

public int getValue() {
return value;
}

public String getSign() {
return sign;
}
}
55 changes: 55 additions & 0 deletions src/main/java/domain/card/Cards.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package domain.card;

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

public class Cards {

private static final int INIT_CARD_SIZE = 2;
protected static final int MAX_SCORE = 21;

protected final List<Card> cards;

public Cards(List<Card> cards) {
validate(cards);
this.cards = new ArrayList<>(cards);
}

private void validate(List<Card> cards) {
if (cards.size() != INIT_CARD_SIZE) {
throw new IllegalArgumentException("처음 지급받는 카드는 두 장이어야 합니다.");
}
}

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

public int bestSum() {
long countAce = countAce();
int sum = sum();
while (sum + 10 <= MAX_SCORE && countAce > 0) {
sum += 10;
countAce--;
}
return sum;
}

public int sum() {
return cards.stream()
.mapToInt(Card::getCardNumber)
.sum();
}

private long countAce() {
return cards.stream()
.filter(Card::isAce)
.count();
}

public List<String> getCards() {
return cards.stream()
.map(Card::toString)
.toList();
}
}
21 changes: 21 additions & 0 deletions src/main/java/domain/card/DealerCards.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package domain.card;

import java.util.List;

public class DealerCards extends Cards implements Drawable {

private static final int MIN_SCORE = 16;

public DealerCards(List<Card> cards) {
super(cards);
}

@Override
public boolean canDraw() {
return bestSum() <= MIN_SCORE;
}

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

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Deck {

private final List<Card> deck;
private final DrawStrategy strategy;

public Deck(DrawStrategy strategy) {
this.deck = createDeck();
this.strategy = strategy;
}

private List<Card> createDeck() {
return IntStream.range(1, 14)
.boxed()
.flatMap(cardNumber -> IntStream.range(0, 4)
.mapToObj(index -> new Card(cardNumber, Shape.getShapeByIndex(index))))
.collect(Collectors.toList());
}

public List<Card> drawInitialHands() {
return List.of(draw(), draw());
}

public Card draw() {
int randomNumber = strategy.generateNumber(deck.size());
Card card = deck.get(randomNumber);
deck.remove(randomNumber);
return card;
}
}
6 changes: 6 additions & 0 deletions src/main/java/domain/card/DrawStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package domain.card;

public interface DrawStrategy {

int generateNumber(int size);
}
6 changes: 6 additions & 0 deletions src/main/java/domain/card/Drawable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package domain.card;

public interface Drawable {

boolean canDraw();
}
24 changes: 24 additions & 0 deletions src/main/java/domain/card/PlayerCards.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package domain.card;

import domain.Name;

import java.util.List;

public class PlayerCards extends Cards implements Drawable {

private final Name name;

public PlayerCards(Name name, List<Card> cards) {
super(cards);
this.name = name;
}

@Override
public boolean canDraw() {
return bestSum() <= MAX_SCORE;
}

public Name getPlayerName() {
return name;
}
}
11 changes: 11 additions & 0 deletions src/main/java/domain/card/RandomDrawStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package domain.card;

import java.util.Random;

public class RandomDrawStrategy implements DrawStrategy {

@Override
public int generateNumber(int size) {
return new Random().nextInt(size);
}
}
24 changes: 24 additions & 0 deletions src/main/java/domain/card/Shape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package domain.card;

public enum Shape {

SPADE("스페이드"),
DIAMONDS("다이아몬드"),
HEART("하트"),
CLUB("클로버");

private final String shape;

Shape(String shape) {
this.shape = shape;
}

public static Shape getShapeByIndex(int random) {
Shape[] values = values();
return values[random];
}

public String getShape() {
return shape;
}
}
50 changes: 50 additions & 0 deletions src/main/java/domain/game/Rule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package domain.game;

import domain.card.Cards;
import domain.card.DealerCards;
import domain.card.PlayerCards;
import domain.score.ScoreBoard;
import domain.score.Status;

import java.util.List;

public class Rule {

private static final int STANDARD = 21;

private final ScoreBoard scoreBoard;

public Rule(ScoreBoard scoreBoard) {
this.scoreBoard = scoreBoard;
}

public Status decideStatus(Cards targetCards, Cards otherCards) {
if (targetCards.bestSum() > STANDARD) {
return Status.LOSE;
}

if (otherCards.bestSum() > STANDARD) {
return Status.WIN;
}

if (otherCards.bestSum() < targetCards.bestSum()) {
return Status.WIN;
}

if (otherCards.bestSum() > targetCards.bestSum()) {
return Status.LOSE;
}
return Status.TIE;
}

public void decideResult(DealerCards dealer, List<PlayerCards> players) {
players.forEach(player -> decideResult(dealer, player));
}

private void decideResult(DealerCards dealer, PlayerCards player) {
Status dealerStatus = decideStatus(dealer, player);
Status playerStatus = decideStatus(player, dealer);
scoreBoard.updateDealerScore(dealerStatus);
scoreBoard.updatePlayerScore(player.getPlayerName(), playerStatus);
}
}
Loading

0 comments on commit bd1af96

Please sign in to comment.