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단계 - 블랙잭 게임 실행] 저문(유정훈) 미션 제출합니다. #472

Merged
merged 43 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
69c8cf2
docs: 기능목록 초안 작성
mcodnjs Feb 28, 2023
7a5adac
feat: Name 생성 및 유효성 검증 추가
mcodnjs Feb 28, 2023
daf7e71
feat: Player 생성 로직 추가
mcodnjs Feb 28, 2023
73e5fe5
feat: Players 생성 로직 추가
mcodnjs Feb 28, 2023
fc0cafb
feat: Players의 Player 수 유효성 검증 추가
mcodnjs Feb 28, 2023
aeea695
feat: Players의 중복 Player 유효성 검증 추가
mcodnjs Feb 28, 2023
8b3c12a
feat: Card 생성자 구현
mcodnjs Feb 28, 2023
40ce6c5
feat: Deck 생성 로직 구현
mcodnjs Mar 2, 2023
e626287
feat: Participant가 카드를 받는 기능 구현
mcodnjs Mar 2, 2023
56d9a4d
feat: Card의 equals와 hashCode 재정의
mcodnjs Mar 2, 2023
f52efb3
feat: Participant의 모든 카드의 숫자 합을 반환하는 기능 구현
mcodnjs Mar 2, 2023
d7643bf
feat: BlackJackGame 초기 카드 배분 기능 구현
mcodnjs Mar 2, 2023
ccc0fe4
feat: CardMachine 구현 및 BlackJackGame 카드 배분 기능 구현
mcodnjs Mar 2, 2023
c638486
feat: 각 참가들의 승패 결과를 계산하는 기능 구현
mcodnjs Mar 2, 2023
cc7451f
feat: InputView, OutputView 구현(리팩터링 필요)
mcodnjs Mar 2, 2023
6360d9b
feat: OutputView 출력 로직 수정
mcodnjs Mar 2, 2023
c961cd6
refactor: View 전체 출력 로직 수정
mcodnjs Mar 3, 2023
38bc19c
feat: 승패 판단하는 로직 수정
mcodnjs Mar 3, 2023
4c9aa21
feat: Dealer의 첫번째 카드를 반환하는 로직 추가
mcodnjs Mar 3, 2023
909a867
feat: 재입력 로직 구현
mcodnjs Mar 3, 2023
94547aa
feat: Rank의 rankFormat 필드 추가
mcodnjs Mar 3, 2023
5c642cd
feat: Player 이름 입력에 대한 공백 유효성 검사 및 검사 순서 변경
mcodnjs Mar 3, 2023
fdbacf9
refactor: 하드 코딩된 값을 상수화
mcodnjs Mar 3, 2023
2bc1271
refactor: 전체 메서드 분리
mcodnjs Mar 3, 2023
00918a7
refactor: OutputView 공백 수정
mcodnjs Mar 3, 2023
d84dace
feat: View private생성자 추가
jeomxon Mar 3, 2023
a9f4a69
docs: 기능 목록 구현 최신화
jeomxon Mar 4, 2023
ebfab91
refactor: 매개변수 및 일부 변수 final 키워드 추가
jeomxon Mar 4, 2023
5a6226e
feat: BlackJackGameController에 ShufflingMachine을 인스턴스 변수로 사용
jeomxon Mar 4, 2023
c16b76e
refactor: 초기 카드를 나눠주는 메서드 리네이밍
jeomxon Mar 5, 2023
c3508fa
refactor: GameCommand에서 Null을 방지하기 위한 코드 수정
jeomxon Mar 5, 2023
33138b2
refactor: BlackJackGame의 생성자 주입을 통해 Dealer를 생성하도록 수정
jeomxon Mar 5, 2023
a0cb83a
refactor: Players 생성자 로직 변경
jeomxon Mar 5, 2023
311fb32
refactor: handOutInitCardsTo메서드 내부 로직 while로 변경
jeomxon Mar 5, 2023
52d41bf
refactor: 재입력 로직을 재귀에서 반복문으로 변경
jeomxon Mar 5, 2023
9e675af
refactor: 카드 받는 순서를 드러내기 위한 Participant의 카드를 가지는 변수의 자료구조 변경
jeomxon Mar 6, 2023
a1a1094
refactor: BlackJackGame의 boolean타입을 반환하는 메서드 리네이밍
jeomxon Mar 6, 2023
bf54b76
test: Name에 공백이 포함됐을 때 에외를 던지는 것을 확인하는 테스트 추가
jeomxon Mar 6, 2023
2185196
test: Participant의 isUnderThanBoundary에 대한 테스트 추가
jeomxon Mar 6, 2023
56785fb
refactor: BlackJackGameController 메서드 분리
jeomxon Mar 6, 2023
a6ec90f
fix: 전체적인 게임실행 로직 오류 수정
jeomxon Mar 6, 2023
15a0621
feat: 블랙잭 게임의 결과를 관리하는 GameResult객체 구현
jeomxon Mar 7, 2023
6f5c2ec
List미션 구현
jeomxon Mar 7, 2023
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
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,53 @@
## 우아한테크코스 코드리뷰

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

## 사용자 스토리

블랙잭 게임을 변형한 프로그램을 구현한다. 블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다.

카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다.
게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다.
딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다.
게임을 완료한 후 각 플레이어별로 승패를 출력한다.

1. 게임에 참여할 사람의 이름 입력
2. 딜러와 플레이어에게 2장씩 카드를 나눠줌
3. 각 플레이어에게 카드 더 받을건지 물어봄
3-1. 플레이어가 "n"를 입력할 때까지 반복
4. 딜러의 카드가 17 이상이 될 때까지 카드를 더 받음
5. 딜러와 플레이어 카드 출력
6. 최종 승패 출력

## 기능목록

--

- 참가자 (플레이어 + 딜러)
- [x] 카드를 받아서 가지고 있음
- [x] 모든 카드의 숫자 합을 반환하는 기능
- 플레이어
- [x] validation: 플레이어 이름은 중복 불가
- [x] validation: 플레이어 이름의 길이 1글자 이상 5글자 이하
- [x] 쉼표 기준으로 분리
- [x] validation: 플레이어의 수는 최소 1명 최대 7명
- [x] 카드 2장을 받음
- [x] 매 턴마다 카드 숫자가 21 초과 인지 확인
- 카드를 받음
- 딜러
- [x] 카드 2장을 받음
- [x] 매 턴마다 카드 숫자가 16 초과 인지 확인
- 카드를 받음
- 게임
- [x] 참가자들에게 초기 카드 배분
- [x] 참가자들에게 각 턴마다 카드 배분
- [x] 딜러와 플레이어의 결과를 비교하여 승패 판단
- 카드
- [x] 카드 숫자 반환
- 덱
- [x] 모든 카드를 가짐

- ACE
- 가지고 있는 모든 카드의 합에 11을 더했을 경우
- 21보다 작거나 같으면 11로 적용
- 21보다 크면 1로 적용
12 changes: 12 additions & 0 deletions src/main/java/blackjack/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package blackjack;

import blackjack.controller.BlackJackGameController;
import blackjack.domain.card.ShufflingMachine;

public class Application {

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

import java.util.Map;
import java.util.Optional;

import blackjack.domain.game.BlackJackGame;
import blackjack.domain.card.ShufflingMachine;
import blackjack.domain.game.GameResult;
import blackjack.domain.game.ResultType;
import blackjack.domain.participant.Dealer;
import blackjack.domain.participant.Player;
import blackjack.domain.participant.Players;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackJackGameController {

private static final String YES_COMMAND = "y";
private static final String NO_COMMAND = "n";
private static final int DEALER_DRAWING_BOUNDARY = 16;
private static final int PLAYER_BUST_BOUNDARY = 21;

private final ShufflingMachine shufflingMachine;

public BlackJackGameController(final ShufflingMachine shufflingMachine) {
this.shufflingMachine = shufflingMachine;
}

public void run() {
final BlackJackGame blackJackGame = generateBlackJackGame();
final Dealer dealer = blackJackGame.getDealer();
final Players players = blackJackGame.getPlayers();

final Map<Player, ResultType> playerResult = playBlackJackGame(blackJackGame, dealer, players);

Choose a reason for hiding this comment

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

BlackJackGame에서 dealer, players를 빼내서 프로세스를 진행하는것보다, BlackJackGame에서 관리할 순 없는걸까요?!

final GameResult gameResult = new GameResult(playerResult);

printFinalResult(dealer, players, gameResult);
}

private BlackJackGame generateBlackJackGame() {
Optional<BlackJackGame> blackJackGame;
do {
blackJackGame = checkNames();

Choose a reason for hiding this comment

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

checkName인데, Return값이 있는게 어색하게 느껴져요.
내부 구현을 봤을 땐, create & get의 느낌이 더 강한것 같아요.

Copy link
Author

Choose a reason for hiding this comment

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

네이밍 수정하였습니다!

} while (blackJackGame.isEmpty());
return blackJackGame.get();
}

private Optional<BlackJackGame> checkNames() {
try {
final String inputNames = InputView.readNames();
return Optional.of(new BlackJackGame(new Dealer(), inputNames));
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return Optional.empty();
}
}

private Map<Player, ResultType> playBlackJackGame(final BlackJackGame blackJackGame, final Dealer dealer,
final Players players) {
blackJackGame.handOutCards(shufflingMachine);

OutputView.printInitCard(players.getPlayers(), dealer.getFirstCard());
handOutCardToPlayers(blackJackGame, players);
handOutCardToDealer(blackJackGame, dealer);

return blackJackGame.makePlayerResult();
}

private void printFinalResult(final Dealer dealer, final Players players, final GameResult gameResult) {
OutputView.printCardsWithSum(players.getPlayers(), dealer);
OutputView.printFinalResult(gameResult.getPlayerResult(), gameResult.findDealerResult());
}

private void handOutCardToPlayers(final BlackJackGame blackJackGame, final Players players) {
for (final Player player : players.getPlayers()) {
handOutCardToEachPlayer(blackJackGame, player);
}
}
Comment on lines +74 to +78

Choose a reason for hiding this comment

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

depth 2를 피하기위함이라면, dpeth2 까지는 괜찮아보여요.
또한, players를 꺼내서 다른 게산로직에 넣는게 어색해보여요.


private void handOutCardToEachPlayer(final BlackJackGame blackJackGame, final Player player) {
boolean command = true;
while (player.isUnderThanBoundary(PLAYER_BUST_BOUNDARY) && command) {
final String playerAnswer = inputGameCommandToGetOneMoreCard(player);
command = isCardHandedOutByCommand(blackJackGame, player, playerAnswer);
}
}

private String inputGameCommandToGetOneMoreCard(final Player player) {
Optional<String> gameCommand;
do {
gameCommand = checkGameCommand(player);
} while (gameCommand.isEmpty());
return gameCommand.get();
}

private Optional<String> checkGameCommand(final Player player) {
try {
final String gameCommand = InputView.readGameCommandToGetOneMoreCard(player.getName());
validateCorrectCommand(gameCommand);
return Optional.of(gameCommand);
} catch (final IllegalArgumentException e) {
System.out.println(e.getMessage());
return Optional.empty();
}
}

private boolean isCardHandedOutByCommand(final BlackJackGame blackJackGame, final Player player,
final String playerAnswer) {
if (playerAnswer.equals(YES_COMMAND)) {
blackJackGame.handOutCardTo(shufflingMachine, player);
OutputView.printParticipantCards(player.getName(), player.getCards());
return true;
}
OutputView.printParticipantCards(player.getName(), player.getCards());
return false;
}

private void handOutCardToDealer(final BlackJackGame blackJackGame, final Dealer dealer) {
while (dealer.isUnderThanBoundary(DEALER_DRAWING_BOUNDARY)) {
blackJackGame.handOutCardTo(shufflingMachine, dealer);
OutputView.printDealerReceiveOneMoreCard();
}
}

private void validateCorrectCommand(final String gameCommand) {
if (!(YES_COMMAND.equals(gameCommand) || NO_COMMAND.equals(gameCommand))) {
throw new IllegalArgumentException("y 또는 n만 입력 가능합니다.");
}
}
}
35 changes: 35 additions & 0 deletions src/main/java/blackjack/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package blackjack.domain.card;

import java.util.Objects;

public class Card {

private final Rank rank;
private final Suit suit;

public Card(final Rank rank, final Suit suit) {
this.rank = rank;
this.suit = suit;
}

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

@Override
public int hashCode() {
return Objects.hash(rank, suit);
}

public Rank getRank() {
return this.rank;
}

public Suit getSuit() {
return this.suit;
}
}
41 changes: 41 additions & 0 deletions src/main/java/blackjack/domain/card/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package blackjack.domain.card;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Deck {

private static final Map<Integer, Card> deck = new HashMap<>();

static {
makeDeck();
}

private Deck() {
}

private static void makeDeck() {
int count = 0;
for (final Rank rank : Rank.values()) {
count = addCardsToDeck(rank, count);
}
}

private static int addCardsToDeck(final Rank rank, int count) {
for (final Suit suit : Suit.values()) {
deck.put(count, new Card(rank, suit));
count++;
}
return count;
}

public static Card from(final int index) {
return deck.get(index);
}

public static List<Integer> getKeys() {
return new ArrayList<>(deck.keySet());
}
}
25 changes: 25 additions & 0 deletions src/main/java/blackjack/domain/card/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package blackjack.domain.card;

public enum Rank {
ACE(1, "A"), DEUCE(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 rankFormat;

Rank(final int value, final String rankFormat) {
this.value = value;
this.rankFormat = rankFormat;
}

public int getValue() {
return this.value;
}

public String getRankFormat() {
return this.rankFormat;
}
}
23 changes: 23 additions & 0 deletions src/main/java/blackjack/domain/card/ShufflingMachine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package blackjack.domain.card;

import java.util.Collections;
import java.util.List;

public class ShufflingMachine {

private final List<Integer> keys;

public ShufflingMachine() {
this.keys = shuffleDeck();
}

private List<Integer> shuffleDeck() {
final List<Integer> keys = Deck.getKeys();
Collections.shuffle(keys);
return keys;
}

public Integer draw() {
return keys.remove(0);
}
}
18 changes: 18 additions & 0 deletions src/main/java/blackjack/domain/card/Suit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package blackjack.domain.card;

public enum Suit {
HEART("하트"),
DIAMOND("다이아몬드"),
SPADE("스페이드"),
CLOVER("클로버");

private final String value;

Suit(final String value) {
this.value = value;
}

public String getValue() {
return this.value;
}
}
Loading