-
Notifications
You must be signed in to change notification settings - Fork 75
[김정호] 연료 주입, 블랙잭 (Step 1) #34
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
base: hoya-kim
Are you sure you want to change the base?
Changes from all commits
3b755f3
ff92f1c
7ab8c03
95fbf47
b2c2920
679cd13
1501e4f
eab1872
eb94b7d
f7ee342
361bb4e
3a7fe0c
648a2dc
8ac61f1
2e16386
b8bc27f
c808b5f
faa242d
18e892c
17e065d
6de51e6
ebb2b54
5a6a77f
42c5843
1f1471e
678b79a
24cd7d0
c10faf7
75b59e2
c2e535f
7f565e1
8441a30
259ea44
e079604
fa79f66
0b6eb9a
f2575e4
3ce951c
232fc23
2839a04
bebd646
e8f4aed
07c2a26
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 +1,82 @@ | ||
# java-blackjack | ||
# java-blackjack | ||
|
||
# 📌 연료 주입 | ||
|
||
## 기능 요구 사항 | ||
|
||
우리 회사는 렌터카를 운영하고 있다. | ||
|
||
현재 보유하고 있는 차량은 Sonata 2대, Avante 1대, K5 2대로 총 5대의 차량을 보유하고 있다. | ||
|
||
고객이 인터넷으로부터 예약할 때 여행할 목적지의 대략적인 이동거리를 입력 받는다. | ||
|
||
이 이동거리를 활용해 차량 별로 필요한 연료를 주입한다. 차량 별로 주입해야 할 연료량을 확인할 수 있는 보고서를 생성해야 한다. | ||
|
||
``` | ||
* Sonata : 10km/리터 | ||
* Avante : 15km/리터 | ||
* K5 : 13km/리터 | ||
``` | ||
|
||
## 프로그래밍 요구 사항 | ||
|
||
- 상속과 추상 메서드를 활용한다. | ||
- 위 요구사항을 `if/else` 절을 쓰지 않고 구현해야 한다. | ||
|
||
## 기능 구현 사항 | ||
|
||
- [x] `Car` 클래스 추상화 (`Car`) | ||
- [x] 주입해야할 연료량 계산 (`Car.getChargeQuantity()`) | ||
- [x] 파생 클래스 구현 | ||
|
||
- [x] `Sonata` 클래스 구현 (`Sonata`) | ||
- [x] 리터당 이동 거리 계산 (`Sonata.getDistancePerLiter()`) | ||
- [x] 여행하려는 거리 반환 (`Sonata.getTripDistance()`) | ||
- [x] 차종의 이름 반환 (`Sonata.getName()`) | ||
|
||
- [x] `Avante` 클래스 구현 (`Avante`) | ||
- [x] 리터당 이동 거리 계산 (`Avante.getDistancePerLiter()`) | ||
- [x] 여행하려는 거리 반환 (`Avante.getTripDistance()`) | ||
- [x] 차종의 이름 반환 (`Avante.getName()`) | ||
|
||
- [x] `K5` 클래스 구현 (`K5`) | ||
- [x] 리터당 이동 거리 계산 (`K5.getDistancePerLiter()`) | ||
- [x] 여행하려는 거리 반환 (`K5.getTripDistance()`) | ||
- [x] 차종의 이름 반환 (`K5.getName()`) | ||
|
||
--- | ||
|
||
# 📌 블랙잭 | ||
|
||
# 기능 요구 사항 | ||
|
||
블랙잭 게임을 변형한 프로그램을 구현한다. 블랙잭 게임은 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 숫자를 가지는 쪽이 이기는 게임이다. | ||
|
||
- 카드의 숫자 계산은 카드 숫자를 기본으로 하며, 예외로 Ace는 1 또는 11로 계산할 수 있으며, King, Queen, Jack은 각각 10으로 계산한다. | ||
- 게임을 시작하면 플레이어는 두 장의 카드를 지급 받으며, 두 장의 카드 숫자를 합쳐 21을 초과하지 않으면서 21에 가깝게 만들면 이긴다. 21을 넘지 않을 경우 원한다면 | ||
얼마든지 카드를 계속 뽑을 수 있다. | ||
- 딜러는 처음에 받은 2장의 합계가 16이하이면 반드시 1장의 카드를 추가로 받아야 하고, 17점 이상이면 추가로 받을 수 없다. | ||
- 게임을 완료한 후 각 플레이어별로 승패를 출력한다. | ||
|
||
## 프로그래밍 요구 사항 | ||
|
||
- 모든 엔티티를 작게 유지한다. | ||
- 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. | ||
- 딜러와 플레이어에서 발생하는 중복 코드를 제거해야 한다. | ||
|
||
## 기능 구현 사항 | ||
|
||
- [x] 사람 이름 입력받기(`InputView.getPlayerNames`) | ||
- [x] 카드는 문양값(`Suit`)과 숫자값(`Denomination`)을 가진다 (Card) | ||
- [x] 문양값(`Suit`)과 숫자값(`Denomination`)은 `enum`으로 구현한다 | ||
- [x] 카드리스트를 가진 일급 컬렉션 Deck 구현 | ||
- [x] 카드를 생성한다 (`Deck.setupCard()`) | ||
- [x] 카드를 섞는다 (`Deck.shuffle()`) | ||
- [x] 카드 한 장을 꺼낸다 (`Deck.popCard()`) | ||
- [x] `Dealer`는 `Player` 클래스로부터 상속을 받는다 | ||
- [x] 카드 숫자를 계산한다 (`Player.calculateScore()`) | ||
- [x] 딜러가 플레이어에게 카드 배분한다 (`Dealer.allocateCard()`) | ||
- [x] 딜러의 처음 받은 2장의 카드 합계가 16이하라면 카드 한 장을 추가로 받는다 (`Dealer.addOneMoreCard`) | ||
- [x] 카드 추가 여부 묻기 (`InputView.askAddCard()`) | ||
- [x] 우승자를 찾는다 (`Judgement.findWinner()`) | ||
- [x] 최종 승패 계산하기 (`Judgement.judgeResult()`) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package blackjack; | ||
|
||
import blackjack.controller.BlackjackGame; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
BlackjackGame blackjackGame = new BlackjackGame(); | ||
blackjackGame.play(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,88 @@ | ||||||||||
package blackjack.controller; | ||||||||||
|
||||||||||
import blackjack.domain.Dealer; | ||||||||||
import blackjack.domain.Judgement; | ||||||||||
import blackjack.domain.Player; | ||||||||||
import blackjack.view.InputView; | ||||||||||
import blackjack.view.OutputView; | ||||||||||
import java.util.ArrayList; | ||||||||||
import java.util.List; | ||||||||||
import java.util.stream.Collectors; | ||||||||||
|
||||||||||
public class BlackjackGame { | ||||||||||
|
||||||||||
private static final int THRESHOLD = 21; | ||||||||||
|
||||||||||
public void play() { | ||||||||||
List<String> playersName = getPlayerName(); | ||||||||||
Dealer dealer = new Dealer(); | ||||||||||
List<Player> players = playersName.stream().map(Player::new) | ||||||||||
.collect(Collectors.toList()); | ||||||||||
Comment on lines
+19
to
+20
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.
Suggested change
로또 미션에서 학습한 것 처럼 일급컬렉션을 만들어 객체의 행위를 정해보면 어떨까요? |
||||||||||
|
||||||||||
List<Player> allGamblers = getAllGamblers(dealer, players); | ||||||||||
allGamblers.forEach(dealer::allocateInitialCards); | ||||||||||
OutputView.printPlayersCard(allGamblers); | ||||||||||
|
||||||||||
betting(dealer, players); | ||||||||||
|
||||||||||
checkIfDealerGotMoreCard(dealer); | ||||||||||
|
||||||||||
Judgement judgement = new Judgement(allGamblers); | ||||||||||
OutputView.printGameResult(allGamblers, judgement.findWinners()); | ||||||||||
} | ||||||||||
|
||||||||||
private void betting(Dealer dealer, List<Player> players) { | ||||||||||
List<Player> alivePlayers = players; | ||||||||||
boolean isPlaying; | ||||||||||
do { | ||||||||||
isPlaying = isAnyOneGettingMoreCard(dealer, alivePlayers); | ||||||||||
alivePlayers = filterBustedPlayer(alivePlayers); | ||||||||||
} | ||||||||||
while (isPlaying); | ||||||||||
} | ||||||||||
|
||||||||||
private List<Player> filterBustedPlayer(List<Player> alive) { | ||||||||||
return alive.stream().filter(player -> player.calculateScore() <= THRESHOLD) | ||||||||||
.collect(Collectors.toList()); | ||||||||||
} | ||||||||||
|
||||||||||
private boolean isAnyOneGettingMoreCard(Dealer dealer, List<Player> players) { | ||||||||||
boolean isPlaying = false; | ||||||||||
for (Player player : players) { | ||||||||||
isPlaying = isPlayerGettingMoreCard(dealer, player); | ||||||||||
} | ||||||||||
return isPlaying; | ||||||||||
} | ||||||||||
|
||||||||||
private boolean isPlayerGettingMoreCard(Dealer dealer, Player player) { | ||||||||||
boolean answer = InputView.askAddCard(player); | ||||||||||
if (answer) { | ||||||||||
dealer.allocateCard(player); | ||||||||||
OutputView.printJoinedCardInfo(player); | ||||||||||
OutputView.printNextLine(); | ||||||||||
return true; | ||||||||||
} | ||||||||||
return false; | ||||||||||
} | ||||||||||
|
||||||||||
private List<String> getPlayerName() { | ||||||||||
List<String> playersName = InputView.getPlayersName(); | ||||||||||
OutputView.printInitialCardDistribute(playersName); | ||||||||||
return playersName; | ||||||||||
} | ||||||||||
|
||||||||||
private void checkIfDealerGotMoreCard(Dealer dealer) { | ||||||||||
if (dealer.addOneMoreCard()) { | ||||||||||
OutputView.printDealerReceived(); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
private List<Player> getAllGamblers(Dealer dealer, List<Player> players) { | ||||||||||
List<Player> allGamblers = new ArrayList<>(); | ||||||||||
allGamblers.add(dealer); | ||||||||||
allGamblers.addAll(players); | ||||||||||
return allGamblers; | ||||||||||
} | ||||||||||
|
||||||||||
|
||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,29 @@ | ||||||
package blackjack.domain; | ||||||
|
||||||
public class 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. 매 게임마다 카드를 새로 생성해야하는 것 보다 카드 static하게 만들어 보는 것은 어떨까요? |
||||||
|
||||||
private final Suit suit; | ||||||
private final Denomination denomination; | ||||||
|
||||||
public Card(Suit suit, Denomination denomination) { | ||||||
this.suit = suit; | ||||||
this.denomination = denomination; | ||||||
} | ||||||
|
||||||
public Suit getSuit() { | ||||||
return suit; | ||||||
} | ||||||
|
||||||
public Denomination getDenomination() { | ||||||
return denomination; | ||||||
} | ||||||
|
||||||
public String getDenomiationCountstring() { | ||||||
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.
Suggested change
|
||||||
return denomination.getCountString(); | ||||||
} | ||||||
|
||||||
public String getSuitName() { | ||||||
return suit.getName(); | ||||||
} | ||||||
|
||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package blackjack.domain; | ||
|
||
public class Dealer extends Player { | ||
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. 딜러와 플레이어의 공통행위를 추상화해보는 방식으로 수정하면 어떨까요? |
||
|
||
private static final int SCORE_THRESHOLD = 16; | ||
private static final String DEALER = "딜러"; | ||
private static final int TWICE = 2; | ||
|
||
private final Deck deck; | ||
|
||
public Dealer() { | ||
super(DEALER); | ||
this.deck = new Deck(); | ||
} | ||
|
||
public void allocateInitialCards(Player player) { | ||
for (int i = 0; i < TWICE; i++) { | ||
Card popped = deck.popCard(); | ||
player.receiveCard(popped); | ||
} | ||
} | ||
|
||
public void allocateCard(Player player) { | ||
Card popped = deck.popCard(); | ||
player.receiveCard(popped); | ||
|
||
} | ||
|
||
public boolean addOneMoreCard() { | ||
int score = calculateScore(); | ||
if (score <= SCORE_THRESHOLD) { | ||
cards.add(deck.popCard()); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package blackjack.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class Deck { | ||
|
||
private final List<Card> cards; | ||
|
||
public Deck() { | ||
cards = new ArrayList<>(); | ||
setupCard(); | ||
shuffle(); | ||
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. 덱을 구성하는 방식을 주입받아 생성하는 것은 어떨까요? |
||
} | ||
|
||
private void setupCard() { | ||
for (Suit suit : Suit.values()) { | ||
setDenomination(suit); | ||
} | ||
} | ||
|
||
private void setDenomination(Suit suit) { | ||
for (Denomination denomination : Denomination.values()) { | ||
cards.add(new Card(suit, denomination)); | ||
} | ||
} | ||
|
||
private void shuffle() { | ||
Collections.shuffle(cards); | ||
} | ||
|
||
public Card popCard() { | ||
Card popped = cards.remove(0); | ||
return new Card(popped.getSuit(), popped.getDenomination()); | ||
} | ||
|
||
public int getCardsCount() { | ||
return cards.size(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,37 @@ | ||||||||||
package blackjack.domain; | ||||||||||
|
||||||||||
public enum Denomination { | ||||||||||
ACE(1, "A"), | ||||||||||
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(10, "J"), | ||||||||||
QUEEN(10, "Q"), | ||||||||||
KING(10, "K"); | ||||||||||
|
||||||||||
private final int count; | ||||||||||
private final String countString; | ||||||||||
Comment on lines
+18
to
+19
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.
Suggested change
의미를 명확하게 변수명을 변경해보는 것은 어떨까요? |
||||||||||
|
||||||||||
Denomination(final int count, final String countString) { | ||||||||||
this.count = count; | ||||||||||
this.countString = countString; | ||||||||||
} | ||||||||||
|
||||||||||
public boolean isAce() { | ||||||||||
return this == ACE; | ||||||||||
} | ||||||||||
|
||||||||||
public int getCount() { | ||||||||||
return count; | ||||||||||
} | ||||||||||
|
||||||||||
public String getCountString() { | ||||||||||
return countString; | ||||||||||
} | ||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package blackjack.domain; | ||
|
||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
public class Judgement { | ||
|
||
private static final String DEALER = "딜러"; | ||
private static final int THRESHOLD = 21; | ||
private static final String WIN = "승"; | ||
private static final String LOSE = "패"; | ||
|
||
private Map<String, Integer> playerScores; | ||
private Map<String, String> playerResults; | ||
|
||
public Judgement(List<Player> players) { | ||
this.playerScores = new LinkedHashMap<>(); | ||
this.playerResults = new LinkedHashMap<>(); | ||
updatePlayersMap(players); | ||
|
||
} | ||
|
||
private void updatePlayersMap(List<Player> players) { | ||
players.forEach(player -> { | ||
playerScores.put(player.getName(), player.calculateScore()); | ||
}); | ||
} | ||
|
||
public Map<String, String> findWinners() { | ||
int dealerScore = playerScores.get(DEALER); | ||
playerScores.remove(DEALER); | ||
playerResults.put(DEALER, ""); | ||
playerScores.forEach((name, score) -> { | ||
playerResults.put(name, checkWinOrLose(dealerScore, score)); | ||
}); | ||
playerResults.put(DEALER, getDealerResult()); | ||
return Collections.synchronizedMap(new LinkedHashMap<>(playerResults)); | ||
} | ||
|
||
private String checkWinOrLose(int dealerScore, Integer score) { | ||
if (score > THRESHOLD) { | ||
return LOSE; | ||
} | ||
if (dealerScore > THRESHOLD || dealerScore <= score) { // 동점이면 플레이어가 이기게 설정 | ||
return WIN; | ||
} | ||
return LOSE; | ||
} | ||
|
||
private String getDealerResult() { | ||
long winCount = getCount(LOSE); | ||
long loseCount = getCount(WIN); | ||
return winCount + WIN + " " + loseCount + LOSE; | ||
} | ||
|
||
private long getCount(String indicator) { | ||
return playerResults.values().stream() | ||
.filter(result -> Objects.equals(result, indicator)).count(); | ||
} | ||
} |
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.
컨트롤러에 카드점수 상태를 판단하는 로직이 있는 것 보다 적절한 객체에 책임을 부여해보는 것은 어떨까요?
딜러와 플레이어가 카드를 들고 있는 손을 객체로 만들어 카드를 추가 여부와 카드를 카드 점수 상태를 관리해 보는 것은 어떨까요?