Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
143ebe7
docs: 컨벤션 및 기능 요구사항 작성
hyxrxn Mar 5, 2024
21dae3a
chore: remove gitkeep
hyxrxn Mar 5, 2024
1786e9f
feat(Card): 카드 점수 계산
hyxrxn Mar 5, 2024
76ef94b
feat(Deck): 덱에서 카드 한 장 드로우
hyxrxn Mar 5, 2024
3cd8593
feat(Deck): 비어있는 덱에서 드로우할 때 예외 처리
hyxrxn Mar 5, 2024
f61ae03
feat(Player): 플레이어 점수 계산
hyxrxn Mar 5, 2024
be2c348
feat(Dealer): 딜러의 점수에 따른 카드 드로우
hyxrxn Mar 5, 2024
cc38fcc
feat(Dealer): 주어진 점수에 따른 승패 판단
hyxrxn Mar 5, 2024
959c905
feat(Hand): Ace 점수를 유리한 방향으로 계산
hyxrxn Mar 5, 2024
4b04093
refactor(Player): 드로우 가능 여부 판단 메서드 위치 변경
hyxrxn Mar 5, 2024
a10af0c
feat(Name): 이름 생성 및 검증
hyxrxn Mar 5, 2024
48dc12d
feat(Players): 플레이어들 생성 및 검증
hyxrxn Mar 5, 2024
c305c41
feat(View): 콘솔 입출력
hyxrxn Mar 5, 2024
7ceb8ba
feat(CardDisplay): 카드의 모양과 수의 표현 방식 설정
hyxrxn Mar 6, 2024
9608caf
refactor(Player): 게임 상수 추출 및 드로우 조건 수정
hyxrxn Mar 6, 2024
4ec8b0e
feat(MatchResult): 게임 결과 판단
hyxrxn Mar 6, 2024
25353e0
feat(MatchResults): 게임 결과 저장
hyxrxn Mar 6, 2024
9e6d1f3
feat(Deck): Shape와 Number의 조합으로 한 세트 생성
hyxrxn Mar 6, 2024
9c16047
feat(Command): 사용자의 명령어 변환
hyxrxn Mar 6, 2024
25088ec
refactor(OutputView): 매개변수로 `Card`를 받도록 수정
hyxrxn Mar 7, 2024
de8d257
feat(Display): 플레이어의 결과 표현 방식 설정
hyxrxn Mar 7, 2024
a1666f1
feat(BlackJackGame): 게임 흐름 제어
hyxrxn Mar 7, 2024
fc78bad
feat(BlackJackMain): 의존성 설정 및 실행
hyxrxn Mar 7, 2024
a86d395
refactor(BlackJackGame): 메서드 분리
hyxrxn Mar 7, 2024
e836cbe
refactor(Players): 불필요한 래핑 제거
hyxrxn Mar 7, 2024
3cbf5c0
style(Shape): 불필요한 세미콜론 제거
hyxrxn Mar 7, 2024
efad4ef
refactor: 상수 추출
hyxrxn Mar 7, 2024
6e0a373
refactor(OutputView): 메서드 분리
hyxrxn Mar 7, 2024
86c80ac
refactor: 패키지 이동
hyxrxn Mar 7, 2024
3e0e9ee
test(Player): 드로우 가능 여부 판단
hyxrxn Mar 7, 2024
46cc05c
fix(Dealer): 카드를 가지고 있지 않은 경우 예외 처리
hyxrxn Mar 7, 2024
4f27bbd
refactor(Deck): 덱 생성 정적 메서드 추가
hyxrxn Mar 7, 2024
c245b03
refactor(Hand): 접근 제한자 변경
hyxrxn Mar 7, 2024
70db6d4
refactor(Deck): 메서드 분리
hyxrxn Mar 7, 2024
cace848
refactor(Display): 패키지 분리
hyxrxn Mar 7, 2024
a957752
style(Number): 파일 끝 공백 추가
hyxrxn Mar 7, 2024
d4da751
refactor: 메서드 순서 변경
hyxrxn Mar 7, 2024
d888faa
refactor: 패키지 이동
hyxrxn Mar 7, 2024
5729a1d
style: 불필요한 개행 삭제
hyxrxn Mar 7, 2024
1ca43df
style(Hand): 가독성을 위한 변수 위치 및 줄바꿈 수정
hyxrxn Mar 7, 2024
ce53b0d
refactor(MatchResult): 승리 조건 별 메서드 분리
hyxrxn Mar 7, 2024
8969a9a
test(MatchResult): 승리 조건 테스트 데이터 보강
hyxrxn Mar 7, 2024
1a0d96e
style: 테스트 클래스 접근제한자 삭제
hyxrxn Mar 7, 2024
4d35231
refactor(OutputView): 중복 코드 제거 및 메서드명 번경
hyxrxn Mar 7, 2024
23b3015
style: 개행 및 오타 수정
hyxrxn Mar 7, 2024
0155159
docs: 기능 구현 사항 추가
hyxrxn Mar 11, 2024
1800705
refactor(Card): this 사용 일관성 고려해 수정
hyxrxn Mar 11, 2024
76bed3c
refactor(InputView): 상수명 수정
hyxrxn Mar 11, 2024
33d8237
refactor(Display): 메서드명 수정
hyxrxn Mar 11, 2024
1f5d1ff
test(Card): 에이스 여부 확인
hyxrxn Mar 11, 2024
eb15bf0
refactor(Hand): 점수 계산 로직 수정
hyxrxn Mar 11, 2024
cf27355
refactor: 드로우 관련 메서드명 변경
hyxrxn Mar 11, 2024
543e4a1
refactor(Command): 클래스 내부 메서드로 No 여부 확인
hyxrxn Mar 11, 2024
8c510c9
refactor(Rank): 클래스명 변경
hyxrxn Mar 11, 2024
429555c
refactor(MatchResult): 메서드명 변경
hyxrxn Mar 11, 2024
7622c5f
refactor(Players): 메서드 간소화
hyxrxn Mar 11, 2024
560a034
refactor: 예외 메시지에서 상수 사용
hyxrxn Mar 11, 2024
948d569
refactor: 상호 참조 제외
hyxrxn Mar 11, 2024
b3cc95c
refactor: 예외 발생시 메시지 출력 후 종료
hyxrxn Mar 12, 2024
b9c0665
refactor(Display): 메서드 리턴 타입 변경
hyxrxn Mar 13, 2024
5c8c80d
refactor(OutputView): 상수 추출
hyxrxn Mar 13, 2024
61950f8
feat(Score): 점수 덧셈
hyxrxn Mar 13, 2024
a1b1c15
feat(Score): 버스트 여부 판단
hyxrxn Mar 13, 2024
3e1c8f8
feat(Score): 점수 대소 비교
hyxrxn Mar 13, 2024
c99ed8e
feat(Score): 에이스 보정 점수 계산
hyxrxn Mar 13, 2024
c551c57
refactor: Score 이용
hyxrxn Mar 13, 2024
28dd3a1
test(Deck): 덱 생성
hyxrxn Mar 13, 2024
dc16898
refactor(Score): 메서드명 번경
hyxrxn Mar 14, 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
53 changes: 51 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@

블랙잭 미션 저장소

## 우아한테크코스 코드리뷰
## 페어와 지킬 컨벤션
1. 클래스 정의 다음 줄은 공백으로 한다.
2. test code에 사용하는 메서드는 `static import`한다.
Comment on lines +6 to +7
Copy link
Member

Choose a reason for hiding this comment

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

옹 이렇게 페어와 지킬 컨벤션을 작성해두는것도 좋은 거 같네요!!


- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
## 요구사항
### 카드
- [x] 카드는 모양과 수로 이루어져 있다.
- [x] 모양으로는 스페이드, 다이아, 하트, 클로버가 있다.
- [x] 수로는 Ace, King, Queen, Jack과 2 이상 10 이하의 정수가 있다.
- [x] 카드의 숫자 계산은 카드 숫자를 기본으로 한다.
- [x] Ace는 1 또는 11로 계산할 수 있다.
- [x] King, Queen, Jack은 각각 10으로 계산한다.

### 덱
- [x] 맨 위의 카드 한 장을 뽑는다.
- [x] 덱에 카드가 없는 경우, 예외를 발생한다.

### 플레이어
- [x] 덱에서 카드를 한 장 뽑는다.
- [x] 지금까지 뽑은 카드의 점수를 계산한다.

### 이름
- [x] 이름은 2글자 이상 5글자 이하이다.
- [x] 이름은 공백으로만 구성될 수 없다.

### 플레이어들
- [x] 플레이어들의 이름은 중복될 수 없다.
- [x] 플레이어들의 인원수는 1명 이상 10명 이하이다.

### 딜러
- [x] 플레이어의 기능을 상속한다.
- [x] 17점 이상이 될 때까지 카드를 계속 뽑는다.

### 게임 결과
- [x] 게임 결과를 아래의 순서대로 올바르게 판단한다.
1. 플레이어의 점수가 21점을 초과하면 딜러가 승리한다.
2. 플레이어의 점수가 21점을 초과하지 않으면서 딜러의 점수가 21점을 초과하면 플레이어가 승리한다.
3. 딜러와 플레이어의 점수를 비교해 승패를 결정한다.
4. 점수가 같으면 무승부이다.
- [x] 각 플레이어별 게임 결과를 저장한다.

---

### 게임 흐름
- [x] (hit, stand) 21을 넘지 않을 경우 원한다면 카드를 계속 뽑을 수 있다.
- [x] 게임이 시작할 때 딜러와 플레이어는 두 장의 카드를 지급 받는다.
- [x] 플레이어의 카드는 모두에게 공개된다.
- [x] 딜러의 두 번째 카드는 공개되지 않는다.
- [x] 플레이어가 카드를 새로 뽑을 때마다 카드 현황을 공개한다.
- [x] 각 플레이어는 딜러와만 승패를 겨룬다.
- [x] 딜러는 모든 플레이어와 승패를 겨룬다.
- [x] 게임을 완료한 후 딜러를 포함한 모든 플레이어의 승패를 확인한다.
Empty file removed src/main/java/.gitkeep
Empty file.
19 changes: 19 additions & 0 deletions src/main/java/blackjack/BlackJackMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package blackjack;

import blackjack.game.BlackJackGame;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackJackMain {

public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
BlackJackGame blackJackGame = new BlackJackGame(inputView, outputView);
try {
blackJackGame.play();
} catch (Exception e) {
outputView.printExceptionMessage(e);
}
}
}
48 changes: 48 additions & 0 deletions src/main/java/blackjack/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package blackjack.card;

import blackjack.player.Score;
import java.util.Objects;

public class Card {

private final Shape shape;
private final Rank rank;

public Card(Shape shape, Rank rank) {
this.shape = shape;
this.rank = rank;
}

public boolean isAce() {
return rank == Rank.ACE;
}

public Score getScore() {
return rank.getScore();
}

public Shape getShape() {
return shape;
}

public Rank getRank() {
return rank;
}

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

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class Deck {

private final Queue<Card> cards;

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

public static Deck createShuffledFullDeck() {
List<Card> cards = new LinkedList<>();
for (Shape shape : Shape.values()) {
cards.addAll(createNumberCardsOf(shape));
}
Collections.shuffle(cards);
return new Deck(cards);
}

static List<Card> createNumberCardsOf(Shape shape) {
List<Card> cards = new ArrayList<>();
for (Rank rank : Rank.values()) {
cards.add(new Card(shape, rank));
}
return cards;
}

public Card draw() {
if (cards.isEmpty()) {
throw new IllegalStateException("[ERROR] 덱이 비어있습니다.");
}
return cards.poll();
}

int size() {
return cards.size();
}
}
30 changes: 30 additions & 0 deletions src/main/java/blackjack/card/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package blackjack.card;

import blackjack.player.Score;

public enum Rank {

ACE(1),
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 Score score;

Rank(int score) {
this.score = new Score(score);
}

Score getScore() {
return this.score;
}
}
9 changes: 9 additions & 0 deletions src/main/java/blackjack/card/Shape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package blackjack.card;

public enum Shape {

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

import blackjack.card.Deck;
import blackjack.player.Dealer;
import blackjack.player.Player;
import blackjack.player.Players;
import blackjack.view.InputView;
import blackjack.view.OutputView;
import java.util.List;

public class BlackJackGame {

private final InputView inputView;
private final OutputView outputView;

public BlackJackGame(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void play() {
Deck deck = Deck.createShuffledFullDeck();
Dealer dealer = new Dealer();

Players players = createPlayers();
initializeGame(deck, dealer, players);
proceedPlayersTurn(deck, players);
proceedDealerTurn(deck, dealer);

showCardsWithScore(dealer, players);
showMatchResult(dealer, players);
}

private Players createPlayers() {
outputView.printNamesRequest();
List<String> names = inputView.readNames();
Players players = new Players(names);
outputView.printNewLine();
return players;
}

private void initializeGame(Deck deck, Dealer dealer, Players players) {
players.doInitialDraw(deck);
dealer.doInitialDraw(deck);
outputView.printInitializeBlackJack(players.getNames());
showInitialCard(dealer, players);
}

private void showInitialCard(Dealer dealer, Players players) {
outputView.printDealerFirstCard(dealer.getFirstCard());

for (Player player : players.getPlayers()) {
outputView.printPlayerCards(player.getName(), player.getCards());
}
outputView.printNewLine();
}

private void proceedPlayersTurn(Deck deck, Players players) {
for (Player player : players.getPlayers()) {
proceedPlayerTurn(deck, player);
}
outputView.printNewLine();
}

private void proceedPlayerTurn(Deck deck, Player player) {
Command command = askPlayerToDrawMore(player);
if (command.isNo()) {
return;
}
player.drawCard(deck);
outputView.printPlayerCards(player.getName(), player.getCards());

if (player.hasDrawableScore()) {
proceedPlayerTurn(deck, player);
}
}

private Command askPlayerToDrawMore(Player player) {
outputView.printDrawMoreCardRequest(player.getName());
String input = inputView.readCommand();
return Command.from(input);
}

private void proceedDealerTurn(Deck deck, Dealer dealer) {
while (dealer.hasDrawableScore()) {
dealer.drawCard(deck);
outputView.printDealerDrawCard();
outputView.printNewLine();
}
}

private void showCardsWithScore(Dealer dealer, Players players) {
outputView.printDealerCardsWithScore(dealer.getCards(), dealer.getScore());
for (Player player : players.getPlayers()) {
outputView.printPlayerCardsWithScore(player.getName(), player.getCards(), player.getScore());
}
outputView.printNewLine();
}

private void showMatchResult(Dealer dealer, Players players) {
MatchResults matchResults = calculateMatchResults(dealer, players);
outputView.printResultStart();
showDealerResult(matchResults);
showPlayersResult(players, matchResults);
}

private MatchResults calculateMatchResults(Dealer dealer, Players players) {
MatchResults matchResults = new MatchResults();
for (Player player : players.getPlayers()) {
matchResults.addResult(player.getName(), player.getScore(), dealer.getScore());
}
return matchResults;
}

private void showDealerResult(MatchResults matchResults) {
outputView.printDealerResult(
matchResults.getResultCount(MatchResult.DEALER_WIN),
matchResults.getResultCount(MatchResult.TIE),
matchResults.getResultCount(MatchResult.PLAYER_WIN)
);
}

private void showPlayersResult(Players players, MatchResults matchResults) {
for (Player player : players.getPlayers()) {
String playerName = player.getName();
MatchResult result = matchResults.getResultByName(playerName);
outputView.printPlayerResult(playerName, result);
}
}
}
26 changes: 26 additions & 0 deletions src/main/java/blackjack/game/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blackjack.game;

import java.util.Arrays;
import java.util.Objects;

public enum Command {
YES("y"),
NO("n");

private final String value;

Command(String value) {
this.value = value;
}

public static Command from(String value) {
return Arrays.stream(values())
.filter(command -> command.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하지 않는 명령어입니다."));
}

public boolean isNo() {
return Objects.equals(value, Command.NO.value);
}
}
Loading