Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7be777d
docs: 연료 주입 요구 사항 작성
kworkbee Feb 11, 2022
f1985fb
refactor: Remove Unnecessary Files empty.txt's
kworkbee Feb 11, 2022
9ce23cd
test: RentCompanyTest 작성
kworkbee Feb 11, 2022
6d4d637
feat: Car / PassengerCar 작성
kworkbee Feb 11, 2022
1f44c48
feat: PassengerCar 상속받은 자동차 정의
kworkbee Feb 11, 2022
4b1ce8b
feat: RentCompany 정의
kworkbee Feb 11, 2022
41bbc18
refactor: Add final modifier into K5 / Avante for making distance imm…
kworkbee Feb 11, 2022
5a02cc7
docs: 연료 주입 요구사항 반영
kworkbee Feb 11, 2022
c8d9181
docs: update README.md
judy5050 Feb 14, 2022
18629ed
test: CardNumberTest 작성
judy5050 Feb 14, 2022
b1486aa
feat: Player 정의
judy5050 Feb 14, 2022
e8d2d78
feat: Score 정의
judy5050 Feb 14, 2022
151b0d4
feat: Suit 정의
judy5050 Feb 14, 2022
36af6d5
test: Deck 테스트코드 작성
MinChul-Son Feb 15, 2022
16699df
feat: Deck 클래스 구현
MinChul-Son Feb 15, 2022
a55c743
feat: Card 클래스 equals & hashCode 오버라이드
MinChul-Son Feb 15, 2022
fa5905d
refactor: CardNumber에서 사용하지 않는 Getter 제거
MinChul-Son Feb 15, 2022
3dd4f68
feat: Person의 추상 메서드 변경
MinChul-Son Feb 15, 2022
754087e
feat: 추상 메서드 오버라이드
MinChul-Son Feb 15, 2022
5c6ebe8
refactor: 불필요한 공백 및 public 키워드 제거
MinChul-Son Feb 15, 2022
9b05903
feat: Cards의 isNearTwentyOne 메서드 구현
MinChul-Son Feb 15, 2022
7c3352a
test: 도메인 테스트 구현
kworkbee Feb 16, 2022
c0e7999
test: 도메인 테스트 구현
kworkbee Feb 16, 2022
1d6d1ef
feat: 도메인 기능 구현
kworkbee Feb 16, 2022
0d26b30
feat: 도메인 기능 구현
kworkbee Feb 16, 2022
dfeecf4
feat: View / Controller
kworkbee Feb 16, 2022
fccc5fc
refactor: domain 패키지 이동
kworkbee Feb 17, 2022
eb50a57
feat: ResultView 뷰 로직 구현
judy5050 Feb 17, 2022
32ec9fe
feat: Players 이름 반환 및 카드 오픈 기능 구현
judy5050 Feb 17, 2022
b7e9073
feat: Player 카드 오픈 기능 구현
judy5050 Feb 17, 2022
d45db41
feat: Person 카드 오픈 및 NameDto 변환 기능 구현
judy5050 Feb 17, 2022
76af023
feat: GameController 구현
judy5050 Feb 17, 2022
316a510
feat: Dealer CardInfo 반환 기능 구현
judy5050 Feb 17, 2022
acb4123
feat: 카드 이름 반환 메서드 구현
judy5050 Feb 17, 2022
4da5a3a
style: 매직 넘버 변경
judy5050 Feb 17, 2022
2065276
feat: main 기능 구현
judy5050 Feb 17, 2022
15404c0
feat: CardInfo 구현
judy5050 Feb 17, 2022
d85d6e7
feat: NameInfo 구현
judy5050 Feb 17, 2022
e774da4
feat: PeopleController 구현
judy5050 Feb 17, 2022
66d3ef6
style: 코드라인 정렬
judy5050 Feb 17, 2022
502a5bd
refactor: Controller
kworkbee Feb 17, 2022
ec398cc
feat: Dto
kworkbee Feb 17, 2022
1193866
feat: View
kworkbee Feb 17, 2022
a09581c
feat: Cards
kworkbee Feb 17, 2022
14b4ec5
feat: Person (Player / Dealer)
kworkbee Feb 17, 2022
e7d4691
feat: Score / ScoreBoard
kworkbee Feb 17, 2022
ccb5359
test: 기능 요구 사항에 따른 테스트 구현
MinChul-Son Feb 18, 2022
05ce88d
feat: 컨트롤러 구현
MinChul-Son Feb 18, 2022
cd1e181
feat: 도메인 구현
MinChul-Son Feb 18, 2022
5e3663f
feat: DTO 구현
MinChul-Son Feb 18, 2022
e3f49f6
feat: View 구현
MinChul-Son Feb 18, 2022
a5158db
refactor: 누락된 커밋 반영
MinChul-Son Feb 18, 2022
007cf1c
refactor: 누락된 커밋 반영
MinChul-Son Feb 18, 2022
10c15b2
docs: 완료된 요구사항 리드미 반영
MinChul-Son Feb 18, 2022
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
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
# java-blackjack
# java-blackjack

## 연료 주입

### 기능 요구사항

- [X] 각 보유 차량 (5대) 렌트할 때 대략적인 이동거리를 입력
- [X] 자동차 객체 생성 시 생성자에 이동거리 주입
- [X] 연료량 계산
- [X] 연료 주입에 필요한 연료량 보고서 생성

### 프로그래밍 요구사항

- [X] 상속 / 추상 메서드 활용
- [X] 조건문 X

### 블랙잭

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

### 프로그래밍 요구사항

- [x] 모든 엔티티를 작게 유지
- [x] 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않음
- [x] 딜러와 플레이어에서 발생하는 중복 코드를 제거해야 함
14 changes: 14 additions & 0 deletions src/main/java/blackjack/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package blackjack;

import blackjack.controller.GameController;

public class Application {


public static void main(String[] args) {

final GameController gameController = new GameController();
gameController.run();
}

}
82 changes: 82 additions & 0 deletions src/main/java/blackjack/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package blackjack.controller;

import static blackjack.domain.Dealer.DEALER_DRAW_LIMIT;

import blackjack.domain.Dealer;
import blackjack.domain.Deck;
import blackjack.domain.Players;
import blackjack.domain.ScoreBoard;
import blackjack.view.InputView;
import blackjack.view.ResultView;

public class GameController {

private final Players players;
private final Dealer dealer;
Comment on lines +14 to +15
Copy link

Choose a reason for hiding this comment

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

Controller는 상태를 가지면 안돼요. 👀
필요하다면 Controller의 메서드 안에서 객체를 직접 생성해서 사용해야해요. 😃

또한 Controller에 비즈니스 로직이 상당수 존재하는 것 같아요. 🙄
playersdealer를 상태로 가지는 새로운 객체(= BlackJack)를 만들어보면 어떨까요? 🤗


public GameController() {
this.players = Players.create(InputView.getNames());
this.dealer = new Dealer();
}

public void run() {
final Deck deck = Deck.create();

setUpPerson(deck);
play(deck);
showGameResult();
}

private void setUpPerson(final Deck deck) {
ResultView.margin();

players.initializeDeck(deck);
dealer.initializeDeck(deck);
Comment on lines +33 to +34
Copy link

Choose a reason for hiding this comment

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

players가 아니라 더 상위 클래스인 Persons로 dealer와 players들을 동시에 묶는다면 이 로직은 persons.initializeDeck(deck);으로 한 번만 호출하도록 바꿔볼 수 있을 것 같아요. 🤗


ResultView.shareCards(dealer.nameInfo().getPersonName(), players.nameInfos());
ResultView.openCardInfo(dealer.openCards(), players.openCards());
}

private void play(final Deck deck) {
ResultView.margin();

playersJudgment(deck);
dealerJudgment(deck);

ResultView.scoreboard(dealer.scoreInfo());
ResultView.scoreboard(players.scoreInfos());
}

private void showGameResult() {
ScoreBoard scoreBoard = players.match(dealer);
ResultView.matchResult(scoreBoard.dealerMatches(dealer),
scoreBoard.playerMatches());
}

private void playersJudgment(final Deck deck) {
while (players.hasActivePlayer()) {
activePlayerJudgement(deck);
}
}

private void activePlayerJudgement(final Deck deck) {
while (players.checkActivePlayerCanDrawCard() && InputView.drawChoice(
players.getActivePlayerNameInfo())) {
players.drawCardToActivePlayer(deck);
ResultView.playerCardsInfo(players.getActivePlayerCardInfo());
}
players.nextActivePlayer();
}

private void dealerJudgment(final Deck deck) {
ResultView.margin();

while (dealer.canDrawCard()) {
dealer.drawCard(deck);
ResultView.dealerDrawDecision(dealer.nameInfo(), DEALER_DRAW_LIMIT);
}

ResultView.margin();
}

}
45 changes: 45 additions & 0 deletions src/main/java/blackjack/domain/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package blackjack.domain;

import java.util.Objects;

public class Card {

private static final String CARD_NAME_FORMAT = "%s%s";

private final CardNumber cardNumber;
private final Suit suit;

public Card(final CardNumber cardNumber, final Suit suit) {
this.cardNumber = cardNumber;
this.suit = suit;
}

public boolean isAce() {
return cardNumber.isAce();
}

public String getCardName() {
return String.format(CARD_NAME_FORMAT, cardNumber.getInitial(), suit.getName());
}
Comment on lines +21 to +23
Copy link

Choose a reason for hiding this comment

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

View에 의존적인 코드인 것 같아요. 🤔
만약 카드의 출력을 K5가 아니라 KING5 같은 형태로 바꾼다면 어떻게 될까요? 👀
아마도 이 getCardName 메서드가 변경돼야 할 거예요. 🥲
MVC 패턴에 따라서 View와 Model을 적절히 분리해보셨으면 좋겠어요. 😃


public int getCardScore() {
return cardNumber.getScore();
}

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

@Override
public int hashCode() {
return Objects.hash(suit, cardNumber);
}
Comment on lines +29 to +44
Copy link

Choose a reason for hiding this comment

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

Card 객체의 동등성을 정의할 필요가 있나요? 🤔
만약 테스트 코드를 위한 equals & hashCode 정의라면 그 방법보다는 getter를 만들어서 상태 값이 실제 결과 값과 같은지 확인하는 테스트 코드로 변경하는 것이 좋다고 생각해요. 🤔

}
39 changes: 39 additions & 0 deletions src/main/java/blackjack/domain/CardNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package blackjack.domain;

public enum CardNumber {

ACE("A", 1),
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("J", 10),
QUEEN("Q", 10),
KING("K", 10);
Comment on lines +15 to +17
Copy link

Choose a reason for hiding this comment

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

이 상수들도 CardNumber라고 부를 수 있을까요? 🤔
CardValue 혹은 Denomination 는 어떨까요? 🤔


private final String initial;
private final int score;

CardNumber(final String initial, final int score) {
this.initial = initial;
this.score = score;
}

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

public int getScore() {
return this.score;
}

public String getInitial() {
return this.initial;
}

}
64 changes: 64 additions & 0 deletions src/main/java/blackjack/domain/Cards.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package blackjack.domain;

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

public class Cards {

private static final int ADDITION_ACE_SCORE = 10;
private static final int LIMITED_ACE_SCORE = 11;
private static final int REFERENCE_POINT = 21;
private static final String CARD_SIZE_ZERO_ERROR = "카드가 존재하지 않습니다.";
private static final int FRONT = 0;

private final List<Card> cards;

public Cards(final List<Card> cards) {
this.cards = cards;
}

public int size() {
return cards.size();
}

public int totalScore() {
final int score = cards.stream()
.mapToInt(Card::getCardScore)
.sum();

if (hasAce() && score <= LIMITED_ACE_SCORE) {
return score + ADDITION_ACE_SCORE;
}
return score;
}

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

private boolean hasAce() {
return cards.stream().anyMatch(Card::isAce);
}

public List<String> openCardOne() {
if (cards.isEmpty()) {
throw new RuntimeException(CARD_SIZE_ZERO_ERROR);
}
return Arrays.asList(cards.get(FRONT).getCardName());
}

public List<String> openCardAll() {
return cards.stream()
.map(Card::getCardName)
.collect(Collectors.toList());
}

public boolean isBust() {
return totalScore() > REFERENCE_POINT;
}

public boolean blackjack() {
return totalScore() == REFERENCE_POINT;
}
}
30 changes: 30 additions & 0 deletions src/main/java/blackjack/domain/Dealer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package blackjack.domain;

import blackjack.dto.CardInfo;
import blackjack.dto.MatchInfo;
Copy link

Choose a reason for hiding this comment

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

불필요한 import문은 제거해주세요! 🙏

import java.util.ArrayList;

public class Dealer extends Person {

public static final int DEALER_DRAW_LIMIT = 16;
private static final String DEALER_NAME = "딜러";

public Dealer(final String userName,final Cards cards) {
Copy link

Choose a reason for hiding this comment

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

습관적으로 코드를 자동 정렬하는 습관을 들이시면 좋아요. 🤗
mac의 경우 ⌘ + ⌥+ L 단축키로 코드 자동 정렬을 할 수 있어요. 😉

super(userName, cards);
}
Comment on lines +12 to +14
Copy link

Choose a reason for hiding this comment

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

Dealer의 이름은 항상 딜러로 고정되니까 생성자 파라미터로 userName을 받을 필요 없지 않을까요? 🤔

Suggested change
public Dealer(final String userName,final Cards cards) {
super(userName, cards);
}
public Dealer(final Cards cards) {
super(DEALER_NAME, cards);
}


public Dealer() {
this(DEALER_NAME, new Cards(new ArrayList<>()));
}

@Override
public boolean canDrawCard() {
return cards.totalScore() <= DEALER_DRAW_LIMIT;
}

@Override
public CardInfo openCards() {
Copy link

Choose a reason for hiding this comment

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

추가로 도메인 객체의 리턴 값을 DTO로 바로 변환하여 반환하는 것 또한 View에 의존적인 코드라고 생각돼요. 🤔
반환 타입은 List 형태로 전달해보면 어떨까요? 🤔

return new CardInfo(userName, cards.openCardOne());
}

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

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

public class Deck {

private static final int REMOVE_INDEX = 0;
private final List<Card> cards;
Comment on lines +12 to +13
Copy link

Choose a reason for hiding this comment

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

상수와 상태(= 인스턴스 변수)는 한 줄 띄어서 가독성을 높여주세요! 🙏


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

public static Deck create() {
final List<Card> cards = createEntireCards();
Collections.shuffle(cards);
return new Deck(cards);
}

public Card drawCard() {
if (cards.isEmpty()) {
throw new RuntimeException("더 이상 카드를 뽑을 수 없습니다.");
Copy link

Choose a reason for hiding this comment

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

덱이 빈 경우에 대해서 예외 처리 👍

하지만 RuntimeException의 하위 (예외) 클래스는 100개가 넘는다고 해요. 👀
지금처럼 예외 처리로 RuntimeException을 던지게 되면, 이 예외를 catch하는 경우 해당 예외뿐만이 아니라 예상치 못했던 에러까지 잡히는 문제가 발생해요.🙂
즉, 예상치 못한 에러가 예외 처리돼버려서 애플리케이션에 결함을 발견하지 못할 수도 있어요. 🥲
구체적인 예외 클래스를 사용해서 예외 처리하도록 변경해주세요! 🙏

image

}
return cards.remove(REMOVE_INDEX);
}

public int deckSize() {
return cards.size();
}

private static List<Card> createEntireCards() {
return Arrays.stream(CardNumber.values())
.flatMap(Deck::createEntireSuitCards)
.collect(Collectors.toCollection(LinkedList::new));
}

private static Stream<Card> createEntireSuitCards(final CardNumber cardNumber) {
return Arrays.stream(Suit.values())
.map(suit -> new Card(cardNumber, suit));
}
Comment on lines +36 to +45
Copy link

Choose a reason for hiding this comment

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

Deck으로 쓰이는 카드들은 카드의 형태와 갯수들이 정해져있고 재사용할 확률이 높다고 생각해요. 😃
미리 만들어뒀다가 필요한 시점에 재사용해보면 어떨까요? 🤗

참고 자료

}
Loading