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

[1단계 - 블랙잭 게임 실행] 재즈(함석명) 미션 제출합니다. #636

Merged
merged 39 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cc6c638
docs(README): 기능 요구 사항 작성
pricelees Mar 5, 2024
9c89c6f
feat: 카드 문양과 숫자에 대한 Enum 클래스 생성
pricelees Mar 5, 2024
b7011cb
feat(Deck): 모든 카드를 가지는 Deck 클래스 및 테스트 구현
pricelees Mar 5, 2024
1ab946f
style(DeckTest): 중복 코드 제거
pricelees Mar 6, 2024
54db712
feat(BlackJackGamer): 딜러와 플레이어의 공통 추상 클래스 생성
pricelees Mar 6, 2024
1432f2d
feat(Dealer): BlackJackGamer를 상속받는 딜러 클래스 생성과 메서드 재정의
pricelees Mar 6, 2024
56af966
feat(Player): BlackJackGamer를 상속받는 플레이어 클래스 생성과 메서드 재정의
pricelees Mar 6, 2024
af51dfa
feat(Name): 문자열 이름을 포장하는 클래스 생성
pricelees Mar 6, 2024
59f51bc
feat(Players): Player의 일급 컬렉션 생성
pricelees Mar 6, 2024
e75ea3b
refactor: 예외 메시지 추가 및 테스트 수정
pricelees Mar 6, 2024
939882c
test(NameTest): 정상 입력에 대한 테스트 추가
pricelees Mar 6, 2024
f050926
test(PlayersTest): 정상 입력에 대한 테스트 추가
pricelees Mar 6, 2024
9b0e50d
feat(Player): 딜러의 점수를 입력받아 플레이어의 승패 여부를 결정하는 기능 추가
pricelees Mar 7, 2024
ae70681
feat(Hand): 참여자의 카드 리스트에 대한 일급 컬렉션 생성
pricelees Mar 7, 2024
f6afbdc
refactor(BlackjackGamer): Hand를 사용하도록 수정
pricelees Mar 7, 2024
8d1b095
refactor(Dealer, Player): 생성자 및 메서드 수정
pricelees Mar 7, 2024
69e7124
feat(GameResult): 승,패를 표현하는 Enum 클래스 생성
pricelees Mar 7, 2024
1a9df2a
feat: DTO 생성 및 각 도메인에 DTO 생성 로직 추가
pricelees Mar 7, 2024
d74858c
refactor(Hand): 카드 숫자의 합계를 구하는 메서드 세분화 및 상수 추가
pricelees Mar 7, 2024
9fd5c3d
style(Dealer): 상수 추가 및 dto 생성 메서드명 수정
pricelees Mar 7, 2024
e0351cf
style(Player): 매직 넘버 상수화
pricelees Mar 7, 2024
da6b980
feat(Players): 전체 플레이어의 패를 초기화 하는 기능 및 dto 생성 기능 추가
pricelees Mar 7, 2024
6f1ef7b
feat(GameResult): 패배인지 확인하는 기능 및 getter 추가
pricelees Mar 7, 2024
23a4321
feat(InputView): 입력을 받아들이는 InputView 클래스 생성
pricelees Mar 7, 2024
38f9367
feat(OutputView): 출력을 담당하는 OutputView 클래스 생성
pricelees Mar 7, 2024
c3443d3
feat(BlackjackController): 블랙잭 게임 흐름을 제어하는 컨트롤러 클래스 생성
pricelees Mar 7, 2024
74bbc4c
style: 출력 요구사항에 맞춰 빈 줄 출력 포맷 수정
pricelees Mar 7, 2024
8250c40
feat(Application): 컨트롤러를 생성하고 호출하여 게임을 시작하는 클래스 생성
pricelees Mar 7, 2024
1b7ead1
docs(README): 기능 요구 사항 정리
pricelees Mar 8, 2024
094a0bf
refactor(BlackjackController): 명령어 상수를 별도의 view Enum으로 분리 및 사용
seokmyungham Mar 9, 2024
9397927
refactor(Card): 출력에 의존적인 CardNumber, CardShape을 수정하고 view 패키지에 Enum 추가
seokmyungham Mar 10, 2024
12715f4
refactor(GameResult): 기존 출력에 의존적이던 필드 문자열을 제거 및 view enum으로 분리
seokmyungham Mar 11, 2024
1375923
refactor: 기존 도메인 내에 존재하던 Dto 변환 로직을 Dto 내부로 이동 및 리팩토링
seokmyungham Mar 11, 2024
16372e1
refactor(Deck): 테스트 목적의 List<Card>를 파라미터로 받는 생성자 개방
seokmyungham Mar 11, 2024
93c8c4b
test(CardTest): eqauls&hashCode 테스트 추가
seokmyungham Mar 11, 2024
1ff95cb
refactor(PlayersTest): 가독성 향상을 위해 테스트 코드 리팩토링
seokmyungham Mar 11, 2024
ec048b0
test(PlayersTest): 경계 값 테스트를 위해 테스트케이스 수정
seokmyungham Mar 11, 2024
6659db2
feat(Command): 사용자 입력 명령어를 별도의 Enum 클래스로 분리
seokmyungham Mar 11, 2024
8f146b6
style(Players): getter 메서드의 위치를 맨 밑으로 이동
seokmyungham Mar 11, 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
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

블랙잭 미션 저장소

## 우아한테크코스 코드리뷰
## 기능 요구 사항

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

- [x] 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 쪽이 승리한다.
- [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다.
- [x] 이후 플레이어와 딜러의 카드를 출력한다.
- [x] 단, 딜러의 카드는 하나만 출력한다.
- [x] 플레이어는 카드의 숫자 합이 21을 초과하지 않는다면 카드를 원하는 만큼 다시 뽑을 수 있다.
- [x] 새로 받을 때 마다 해당 플레이어의 카드를 출력한다.
- [x] 플레이어가 카드를 다 받으면 딜러의 카드를 확인한다.
- [x] 딜러의 카드 합이 17 이상이 될 때 까지 카드를 받는다.
- [x] 딜러와 플레이어의 카드, 결과와 최종 승패를 출력한다.

### 카드

- [x] 클로버, 스페이드, 하트, 다이아몬드 모양을 가진다.
- [x] 카드는 2부터 10까지의 숫자와 Ace, King, Queen, Jack으로 이루어져 있다.
- [x] King, Queen, Jack은 10으로 계산한다.
- [x] ACE는 1 또는 11로 계산할 수 있다.

### 딜러, 플레이어 공통

- [x] 최소 1글자, 최대 5글자의 이름을 가진다.
- [x] ACE 카드를 가지는 경우, 일단 11로 계산한 뒤, 합이 21을 초과하면 1로 계산한다.
- [x] 현재 가진 카드 숫자의 합을 기준으로 카드를 더 받을 수 있는지 결정한다.
- [x] 딜러는 숫자의 합이 16 이하이면 카드를 더 받을 수 있다.
- [x] 플레이어는 숫자의 합이 21 이하이면 카드를 더 받을 수 있다.

### 플레이어

- [x] 플레이어의 이름은 중복될 수 없다.
- [x] 플레이어는 최소 2명부터 최대 8명까지 가능하다.
- [x] 딜러의 점수를 입력받아 승,패를 결정한다.
- [x] 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다.
- [x] 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우 패배한다.
- [x] 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다.
- [x] 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 크면 승리한다.
11 changes: 11 additions & 0 deletions src/main/java/blackjack/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package blackjack;

import blackjack.controller.BlackjackController;

public class Application {

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

import blackjack.domain.card.Deck;
import blackjack.domain.gamer.Dealer;
import blackjack.domain.gamer.GameResult;
import blackjack.domain.gamer.Name;
import blackjack.domain.gamer.Player;
import blackjack.domain.gamer.Players;
import blackjack.dto.DealerInitialHandDto;
import blackjack.dto.DealerResultDto;
import blackjack.dto.GamerHandDto;
import blackjack.dto.GamersHandDto;
import blackjack.dto.PlayerGameResultsDto;
import blackjack.view.InputView;
import blackjack.view.OutputView;
import blackjack.view.object.Command;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class BlackjackController {

private final InputView inputView;
private final OutputView outputView;

public BlackjackController() {
this.inputView = new InputView();
this.outputView = new OutputView();
}

public void run() {
Players players = getPlayers();
Dealer dealer = new Dealer();
Deck deck = new Deck();
deck.shuffle();

setUpInitialHands(players, deck, dealer);
distributeCardToPlayers(players, deck);
distributeCardToDealer(dealer, deck);
printAllGamerScores(dealer, players);
printResult(dealer, players);
}

private Players getPlayers() {
List<String> playerNames = inputView.receivePlayerNames();

return new Players(playerNames);
}

private void setUpInitialHands(Players players, Deck deck, Dealer dealer) {
players.initAllPlayersCard(deck);
dealer.initCard(deck);
printInitialHands(players, dealer);
}

private void printInitialHands(Players players, Dealer dealer) {
DealerInitialHandDto dealerInitialHandDto = DealerInitialHandDto.fromDealer(dealer);
GamersHandDto playersInitialHandDto = GamersHandDto.fromPlayers(players);

outputView.printInitialHands(dealerInitialHandDto, playersInitialHandDto);
}

private void distributeCardToPlayers(Players players, Deck deck) {
for (Player player : players.getPlayers()) {
distributeCardToPlayer(deck, player);
}
}

private void distributeCardToPlayer(Deck deck, Player player) {
while (canDistribute(player)) {
player.addCard(deck.draw());
outputView.printPlayerHand(GamerHandDto.fromBlackjackGamer(player));
}
}

private boolean canDistribute(Player player) {
return player.canReceiveCard() && Command.isHit(getCommand(player));
}

private Command getCommand(Player player) {
return inputView.receiveCommand(player.getName().value());
}

private void distributeCardToDealer(Dealer dealer, Deck deck) {
while (dealer.canReceiveCard()) {
dealer.addCard(deck.draw());
outputView.printDealerMessage(dealer.getName().value());
}
}

private void printAllGamerScores(Dealer dealer, Players players) {
outputView.printEmptyLine();
outputView.printScore(GamerHandDto.fromBlackjackGamer(dealer), dealer.getScore());
printPlayersScores(players);
}

private void printPlayersScores(Players players) {
for (Player player : players.getPlayers()) {
outputView.printScore(GamerHandDto.fromBlackjackGamer(player), player.getScore());
}
}

private void printResult(Dealer dealer, Players players) {
Map<Name, GameResult> playerGameResults = players.collectPlayerGameResults(dealer.getScore());
PlayerGameResultsDto playerGameResultsDto = PlayerGameResultsDto.fromPlayerGameResults(playerGameResults);
List<GameResult> playerResults = new ArrayList<>(playerGameResultsDto.resultMap().values());
DealerResultDto dealerResultDto = DealerResultDto.fromPlayerResults(playerResults);

outputView.printResult(dealerResultDto, playerGameResultsDto);
}
}
47 changes: 47 additions & 0 deletions src/main/java/blackjack/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package blackjack.domain.card;

import java.util.Objects;

public class Card {

private final CardShape cardShape;
private final CardNumber cardNumber;

public Card(CardShape cardShape, CardNumber cardNumber) {
this.cardShape = cardShape;
this.cardNumber = cardNumber;
}

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

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

public CardShape getCardShape() {
return cardShape;
}

public CardNumber getCardNumber() {
return cardNumber;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Card card = (Card) o;
return cardShape == card.cardShape && cardNumber == card.cardNumber;
}

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

public enum CardNumber {

ACE(11),
TWO(2),
THREE( 3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(10),
QUEEN(10),
KING(10);

private final int value;

CardNumber(int value) {
this.value = value;
}

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

public enum CardShape {

HEART,
CLOVER,
SPADE,
DIAMOND
}
36 changes: 36 additions & 0 deletions src/main/java/blackjack/domain/card/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package blackjack.domain.card;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

public class Deck {

private final LinkedList<Card> cards;

public Deck() {
this.cards = Arrays.stream(CardShape.values())
.flatMap(cardShape -> Arrays.stream(CardNumber.values())
.map(number -> new Card(cardShape, number)))
.collect(Collectors.toCollection(LinkedList::new));
}

public Deck(LinkedList<Card> cards) {
this.cards = cards;
}

public void shuffle() {
Collections.shuffle(cards);
}

public Card draw() {
return cards.poll();
}

public List<Card> getCards() {
return new ArrayList<>(cards);
}
}
47 changes: 47 additions & 0 deletions src/main/java/blackjack/domain/gamer/BlackjackGamer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package blackjack.domain.gamer;

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

import blackjack.domain.card.Card;
import blackjack.domain.card.Deck;
import blackjack.dto.CardDto;
import blackjack.dto.GamerHandDto;

public abstract class BlackjackGamer {

private final Name name;
private final Hand hand;

public BlackjackGamer(Name name) {
this.name = name;
this.hand = new Hand(new ArrayList<>());
}

public abstract boolean canReceiveCard();

public void initCard(Deck deck) {
addCard(deck.draw());
addCard(deck.draw());
}

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

public Card getFirstCard() {
return hand.getFirstCard();
}

public int getScore() {
return hand.calculateScore();
}

public Name getName() {
return name;
}

public Hand getHand() {
return hand;
}
}
16 changes: 16 additions & 0 deletions src/main/java/blackjack/domain/gamer/Dealer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package blackjack.domain.gamer;

public class Dealer extends BlackjackGamer {

private static final String DEFAULT_DEALER_NAME = "딜러";
private static final int DEALER_DRAW_THRESHOLD = 16;

public Dealer() {
super(new Name(DEFAULT_DEALER_NAME));
}

@Override
public boolean canReceiveCard() {
return getScore() <= DEALER_DRAW_THRESHOLD;
}
}
11 changes: 11 additions & 0 deletions src/main/java/blackjack/domain/gamer/GameResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package blackjack.domain.gamer;

public enum GameResult {

WIN,
LOSE;

public static boolean isLose(GameResult gameResult) {
return LOSE == gameResult;
}
}
Loading