-
Notifications
You must be signed in to change notification settings - Fork 8
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단계 미션 제출합니다. #4
base: byungjunkim3059
Are you sure you want to change the base?
Changes from 20 commits
2c1ca1a
ff1a0d5
35424f8
8aa0548
b72e864
6aa4b33
18a50a8
e3e7227
0871be7
a467680
e333a06
0bf9401
87cb353
6d63bc6
e320bfb
4f14501
ad70235
43fa46e
d7f85d7
5a0dcba
6e6be79
c57f353
5afd467
81233a8
4a90047
419da1c
a13c714
85e3dc7
c658279
382161d
0b25c44
152ff20
24261b2
08ef19f
1e6a152
28a34f0
aa4d654
f288e60
07bee19
255d747
678bb49
c4066ba
29d688f
1bf8d9f
d5bbcc5
9b19017
b74cf82
f5b4361
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,92 @@ | ||
# java-blackjack | ||
|
||
## 🚀 기능 요구 사항 | ||
|
||
## ✅ 1단계 - 블랙잭 구현 | ||
|
||
블랙잭 게임을 변형한 프로그램을 구현한다. 블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다. | ||
|
||
카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다. | ||
게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 얼마든지 카드를 계속 뽑을 수 있다. | ||
딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다. | ||
게임을 완료한 후 각 플레이어별로 승패를 출력한다. | ||
|
||
## 💻 실행 결과 | ||
``` | ||
게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리) | ||
pobi,jason | ||
|
||
딜러와 pobi, jason에게 2장을 나누었습니다. | ||
딜러: 3다이아몬드 | ||
pobi카드: 2하트, 8스페이드 | ||
jason카드: 7클로버, K스페이드 | ||
|
||
pobi는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n) | ||
y | ||
pobi카드: 2하트, 8스페이드, A클로버 | ||
pobi는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n) | ||
n | ||
pobi카드: 2하트, 8스페이드, A클로버 | ||
jason은 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n) | ||
n | ||
jason카드: 7클로버, K스페이드 | ||
|
||
딜러는 16이하라 한장의 카드를 더 받았습니다. | ||
|
||
딜러 카드: 3다이아몬드, 9클로버, 8다이아몬드 - 결과: 20 | ||
pobi카드: 2하트, 8스페이드, A클로버 - 결과: 21 | ||
jason카드: 7클로버, K스페이드 - 결과: 17 | ||
|
||
## 최종 승패 | ||
딜러: 1승 1패 | ||
pobi: 승 | ||
jason: 패 | ||
``` | ||
|
||
## ✅ 2단계 - 블랙잭 구현 | ||
|
||
- 1단계 미션이 어느정도 구현된 후에 공개할 예정 | ||
|
||
## 🖥️ 프로그래밍 요구 사항 | ||
- indent(인덴트, 들여쓰기) depth를 3를 넘지 않도록 구현한다. 2까지만 허용한다. ( 개인의 역량에 맞춰 1까지 허용하여 진행해볼 것을 추천 ) | ||
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. | ||
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. | ||
- 3항 연산자를 쓰지 않는다. | ||
- else 예약어를 쓰지 않는다. | ||
- else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. | ||
- 힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다. | ||
- 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다. | ||
- UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다. | ||
- 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. | ||
- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라. | ||
|
||
## 🔥 추가된 요구 사항 | ||
- Java 11 으로 변경한다. | ||
- 모든 원시 값과 문자열을 포장한다 [참고 글](https://tecoble.techcourse.co.kr/post/2020-05-29-wrap-primitive-type/) | ||
- 구현한 기능에 Test를 추가한다. 단, UI(System.out, System.in) 로직은 제외 | ||
- 배열 대신 컬렉션을 사용한다. | ||
- 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. | ||
- 딜러와 플레이어에서 발생하는 중복 코드를 제거해야 한다. | ||
- 일급 컬렉션을 쓴다. [참고 글](https://jojoldu.tistory.com/412) | ||
|
||
## 📚 과제 진행 요구 사항 | ||
- 미션은 해당 저장소를 Fork/Clone함으로부터 시작된다. | ||
- 기능을 구현하기 전에 java-baseball/docs/README.md 파일에 구현할 기능 목록을 정리해 추가한다. | ||
- Git의 커밋 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다. | ||
- 커밋 메시지 [컨벤션 가이드](https://gist.github.com/stephenparish/9941e89d80e2bc58a153)를 참고해 커밋 메시지를 작성한다. | ||
# 기능 목록 | ||
|
||
<hr> | ||
|
||
## view | ||
|
||
### inputView | ||
|
||
- [ ] 입력 | ||
- [x] 플레이어 목록 입력 | ||
- [ ] 플레이어가 카드를 받을지 여부(y/n) 입력 | ||
|
||
### outputView | ||
|
||
- [ ] 출력 | ||
- [x] 플레이어 이름 입력하기 문구 | ||
- [ ] 게임 시작 시 카드 2장 배분에 대한 문구 | ||
- [ ] 플레이어가 카드를 받을지 여부(y/n) 묻는 문구 | ||
- [ ] 참여자 카드 리스트 내의 카드 출력 (jason카드: 7클로버, K스페이드) | ||
- [ ] 딜러 카드 추가적으로 받았을 때 문구 | ||
|
||
- [ ] 결과 출력 | ||
- [ ] 점수 계산 결과 출력 | ||
- [ ] 최종 승패 출력 | ||
|
||
<hr> | ||
|
||
## domain | ||
|
||
### participant | ||
|
||
- [x] 참가자(클래스) | ||
|
||
- [x] 플레이어(참가자 상속) | ||
|
||
- [x] 플레이어 리스트 | ||
- [x] 플레이어 이름 목록 받아서 플레이어 리스트 생성 | ||
- [x] 플레이어 이름 중복 예외처리 | ||
- [x] 플레이어 리스트 반환 | ||
|
||
- [x] 딜러(참가자 상속) | ||
|
||
- [x] 참가자 리스트: 딜러와 플레이어 리스트 함께 저장하는 리스트 | ||
- [x] 참가자 리스트 반환 | ||
|
||
- [x] 카드 리스트: 딜러와 플레이어가 배분 받은 카드들 담는 리스트 | ||
- [x] 카드 리스트에 카드 추가 | ||
|
||
### carddeck | ||
|
||
- [x] 카드 심볼 상수(하트~스페이드) | ||
|
||
- [x] 카드 숫자 상수(에이스~잭,퀸,킹) | ||
|
||
- [x] 카드: 심볼(하트, 스페이드, 다이아몬드, 클로버)과 숫자(에이스~킹) 조합으로 이루어진 카드 | ||
|
||
- [x] 카드덱: 52가지 카드 담고 있는 하나의 카드덱 | ||
- [x] 카드덱에서 카드 추출하여 반환 | ||
|
||
- [x] 카드 숫자 변환기: 문자열 형태인 카드의 숫자를 수로 변환해주는 기능 | ||
- [x] 변환기 | ||
|
||
### 비즈니스 로직 | ||
|
||
- [x] 카드 배분 | ||
- [x] 게임 시작 시 카드 2장 씩 참가자들에 카드덱에서 추출하여 배분 | ||
- [x] 플레이어에 카드 1장 카드덱에서 추출하여 배분 | ||
|
||
- [x] 점수 계산 | ||
- [x] 카드 리스트에 있는 카드에 대해 최종 점수 계산하여 반환 | ||
|
||
- [ ] 최종 승패 판단 | ||
- [ ] 참여자들 최종 승패 | ||
|
||
<hr> | ||
|
||
## controller | ||
|
||
- [ ] 게임 매니저 | ||
- [ ] 게임 시작 | ||
- [ ] 참가자 생성 | ||
- [ ] 카드 배분 | ||
- [ ] 점수 계산 결과 출력 | ||
- [ ] 최종 승패 결과 출력 | ||
- [ ] 참가자 생성 | ||
- [ ] 플레이어 이름 입력 받기 | ||
- [ ] 플레이어 리스트 생성 | ||
- [ ] 플레이어 생성 | ||
- [ ] 딜러 생성 | ||
- [ ] 카드 배분 | ||
- [ ] 플레이어들에게 카드 추가 여부 묻기 (모든 플레이어에 대해, 각 플레이어 그만 추가할 때까지) | ||
- [ ] 딜러 카드 합 16이하 시 카드 추가 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import domain.CalculateScore; | ||
import domain.CardDistributor; | ||
import domain.carddeck.Card; | ||
import domain.carddeck.CardDeck; | ||
import domain.participant.Participant; | ||
import domain.participant.PlayerList; | ||
import view.outputview.OutputView; | ||
|
||
public class application { | ||
|
||
public static void main(String[] args) { | ||
OutputView outputView = new OutputView(); | ||
|
||
Participant participant = new Participant("kim"); | ||
CardDeck cardDeck = new CardDeck(); | ||
|
||
CardDistributor cardDistributor = new CardDistributor(); | ||
|
||
cardDistributor.distributeOneCard(cardDeck, participant); | ||
cardDistributor.distributeOneCard(cardDeck, participant); | ||
cardDistributor.distributeOneCard(cardDeck, participant); | ||
|
||
for (Card card : participant.getCardList().getCardList()) { | ||
System.out.println(card.toString()); | ||
} | ||
|
||
CalculateScore calculateScore = new CalculateScore(); | ||
System.out.println(calculateScore.calculator(participant)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package controller; | ||
|
||
public class gameManager { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package domain; | ||
|
||
import domain.carddeck.Card; | ||
import domain.carddeck.CardRank; | ||
import domain.carddeck.CardRankConverter; | ||
import domain.constants.Constant; | ||
import domain.participant.CardList; | ||
import domain.participant.Participant; | ||
|
||
import java.util.List; | ||
|
||
public class CalculateScore { | ||
|
||
private CardRankConverter cardRankConverter = new CardRankConverter(); | ||
|
||
|
||
public int calculator(Participant participant) { | ||
int sumExceptAce = calculatorExceptAce(participant); | ||
int sum = calculatorContainsAce(participant, sumExceptAce); | ||
participant.getCardList().setScore(sum); | ||
return sum; | ||
} | ||
|
||
private int calculatorExceptAce(Participant participant) { | ||
int sumExceptAce = 0; | ||
CardList cardList = participant.getCardList(); | ||
for (Card card : cardList.getCardList()) { | ||
CardRank cardRank = card.getCardRank(); | ||
sumExceptAce += this.cardRankConverter.converter(cardRank); | ||
} | ||
return sumExceptAce; | ||
} | ||
|
||
private int calculatorContainsAce(Participant participant, int sum) { | ||
CardList cardList = participant.getCardList(); | ||
for (Card card : cardList.getCardList()) { | ||
CardRank cardRank = card.getCardRank(); | ||
if (cardRank == CardRank.ACE) { | ||
sum = addOneOrEleven(sum); | ||
} | ||
} | ||
return sum; | ||
} | ||
|
||
private int addOneOrEleven(int sum) { | ||
sum += 1; | ||
if (sum + 11 <= Constant.TARGET_SCORE) { | ||
sum += 10; | ||
} | ||
return sum; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요 메서드 명을 calculateAceValue로 가는 것은 어떨까요?? |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 마지막 줄 개행 한 줄 추가해주세요!! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package domain; | ||
|
||
import domain.carddeck.Card; | ||
import domain.carddeck.CardDeck; | ||
import domain.participant.Participant; | ||
import domain.participant.ParticipantList; | ||
|
||
import java.util.List; | ||
|
||
public class CardDistributor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 카드를 나눠주는 것도 객체로 만들어 주셨네요!! public BackJack(List<Participant> participants, Dealer dealer) {
/// 딜러, 유저에게 2장씩 배분
} 왜 이런식으로 제안드리는지 한번 이유를 생각해보시고 댓글로 남겨주세요!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BlackJack이라는 객체를 만들어서 게임 시작의 경계를 분명히 하려는 의도가 아니신가 싶습니다. 궁금한 점이 있습니다! 답변 주시면 감사드리겠습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
카드를 나눠주는 것을 객체로 나눠서 만드는 것은 해당 책임을 지는 객체에게 위임하겠다는 의미입니다!! 장점
단점
지금 단계에서는 BlackJack에서 CardDistributor를 분리하여 추상화하는 것은 오버프로그래밍이지 않을까라는 생각입니다 ㅎㅎ |
||
|
||
private final int initialDistributionCount = 2; | ||
|
||
public void initialCardDistribution(CardDeck cardDeck, ParticipantList participantList) { | ||
List<Participant> participants = participantList.getParticipantList(); | ||
for (Participant participant : participants) { | ||
for (int i = 0; i < initialDistributionCount; i++) { | ||
Card card = cardDeck.getCardRandomly(); | ||
participant.getCardList().addCard(card); | ||
} | ||
} | ||
} | ||
|
||
public void distributeOneCard(CardDeck cardDeck, Participant participant) { | ||
Card card = cardDeck.getCardRandomly(); | ||
participant.getCardList().addCard(card); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. get으로 가져와서 직접 넣는 것은 participant의 card 구현체를 드러내는 것이기 때문에 |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package domain; | ||
|
||
import domain.participant.Dealer; | ||
import domain.participant.Player; | ||
|
||
public class ResultEvaluator { | ||
|
||
public void evaluator(Dealer dealer, Player player) { | ||
int dealerScore = dealer.getCardList().getScore(); | ||
int playerScore = player.getCardList().getScore(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package domain.carddeck; | ||
|
||
public class Card { | ||
|
||
private final CardSuit cardSuit; | ||
private final CardRank cardRank; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 객체를 너무 잘 만들어 주셨네요 👍👍👍 |
||
|
||
public Card(CardSuit cardSuit, CardRank cardRank) { | ||
this.cardSuit = cardSuit; | ||
this.cardRank = cardRank; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return this.cardRank.getValue() + this.cardSuit.getValue(); | ||
} | ||
|
||
public CardSuit getCardSuit() { | ||
return this.cardSuit; | ||
} | ||
|
||
public CardRank getCardRank() { | ||
return this.cardRank; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package domain.carddeck; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Random; | ||
|
||
public class CardDeck { | ||
|
||
List<Card> cardDeck; | ||
|
||
public CardDeck() { | ||
generateCardDeck(); | ||
} | ||
|
||
private void generateCardDeck() { | ||
CardSuit[] suits = CardSuit.values(); | ||
CardRank[] ranks = CardRank.values(); | ||
|
||
this.cardDeck = new ArrayList<Card>(); | ||
|
||
for (CardSuit suit : suits) { | ||
for (CardRank rank : ranks) { | ||
Card card = new Card(suit, rank); | ||
this.cardDeck.add(card); | ||
} | ||
} | ||
} | ||
|
||
public Card getCardRandomly() { | ||
Random random = new Random(); | ||
int randomIndex = random.nextInt(this.cardDeck.size()); | ||
Card randomCard = this.cardDeck.get(randomIndex); | ||
|
||
this.cardDeck.remove(randomIndex); | ||
|
||
return randomCard; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getCardRanomly를 호출할 때 마다 Random을 생성하지 말고 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package domain.carddeck; | ||
|
||
public enum CardRank { | ||
|
||
ACE("A"), TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), | ||
SIX("6"), SEVEN("7"), EIGHT("8"), NINE("9"), TEN("10"), | ||
JACK("J"), QUEEN("Q"), KING("K"); | ||
|
||
private final String value; | ||
|
||
CardRank(String value) { | ||
this.value = value; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CaculateScore가 하는 행위를 만들어주신 다른 객체에 포함시키면 좋을 것 같아요!!
그 판단을 "자신의 필드에 대한 책임을 객체 스스로 책임진다"는 원칙을 기준으로 찾아보시면 좋을 것 같습니다.