Skip to content
Open
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
3b755f3
docs: Update README.md
Hoya-kim Feb 11, 2022
ff92f1c
chore: 프로젝트 수행을 위한 기본 구성 파일 추가
Hoya-kim Feb 11, 2022
7ab8c03
feat: 요구 class 생성 및 제공된 템플릿 코드 작성
Hoya-kim Feb 11, 2022
95fbf47
feat: 테스트 코드 구현을 위한 메서드 시그니처 생성
Hoya-kim Feb 11, 2022
b2c2920
feat: Car의 파생클래스(Sonata, Avante, K5) 오버라이딩 메서드 구현
Hoya-kim Feb 11, 2022
679cd13
feat: RentCompany.generateReport 메서드 구현
Hoya-kim Feb 11, 2022
1501e4f
refactor: 파생 클래스 car name 상수처리
Hoya-kim Feb 11, 2022
eab1872
docs: Update README.md
Hoya-kim Feb 11, 2022
eb94b7d
refactor: 사용하지 않는 import문 제거
Hoya-kim Feb 11, 2022
f7ee342
docs: update README.md
LeahJiinLee Feb 14, 2022
361bb4e
김정호 님이 변경한 내용
LeahJiinLee Feb 14, 2022
3a7fe0c
chore: 프로젝트 수행을 위한 기본 구성 파일 추가
LeahJiinLee Feb 14, 2022
648a2dc
chore: 프로젝트 테스트를 위한 테스트 코드 추가
LeahJiinLee Feb 14, 2022
8ac61f1
chore: 프로젝트 수행을 위한 기본 구성 파일 추가
LeahJiinLee Feb 14, 2022
2e16386
feat: Dealer 객체 메소드 추가
LeahJiinLee Feb 14, 2022
b8bc27f
feat: enum 객체 작성
LeahJiinLee Feb 14, 2022
c808b5f
feat: Gambler 객체 기본 템플릿 작성
LeahJiinLee Feb 14, 2022
faa242d
feat: Player 객체 메소드 작성
LeahJiinLee Feb 14, 2022
18e892c
docs: Update README.md
LeahJiinLee Feb 14, 2022
17e065d
feat: enum 객체 작성
LeahJiinLee Feb 14, 2022
6de51e6
feat: Implement Card class
Hoya-kim Feb 15, 2022
ebb2b54
feat: Implement Deck class
Hoya-kim Feb 15, 2022
5a6a77f
feat: Gambler 추상 클래스 제거 및 Player, Dealer 재설계
Hoya-kim Feb 15, 2022
42c5843
feat: Player 점수 계산 메소드 구현
LeahJiinLee Feb 16, 2022
1f1471e
test(PlayerTest) : Player 테스트 코드 작성
LeahJiinLee Feb 16, 2022
678b79a
feat: Player 점수 계산 메소드 구현
LeahJiinLee Feb 16, 2022
24cd7d0
docs(README): 구현 완료한 기능 체크 표시
LeahJiinLee Feb 16, 2022
c10faf7
feat: Dealer의 카드 합이 16이하일 때 카드를 추가하는 메소드 구현
LeahJiinLee Feb 16, 2022
75b59e2
feat: Dealer의 카드 합이 16이하일 때 카드를 추가하는 메소드 구현
LeahJiinLee Feb 16, 2022
c2e535f
test: Dealer의 addOneMoreCard 기능 테스트 작성
LeahJiinLee Feb 16, 2022
7f565e1
feat: Dealer의 카드 합이 16이하일 때 카드를 추가하는 메소드 구현
LeahJiinLee Feb 16, 2022
8441a30
feat:Judgement 우승자 찾기 메소드 구현
LeahJiinLee Feb 16, 2022
259ea44
test: Judgement 우승자 찾기 기능 테스트 코드 작성
LeahJiinLee Feb 16, 2022
e079604
feat:Judgement 승패 찾기 메소드 수정 및 승패계산
LeahJiinLee Feb 16, 2022
fa79f66
test: Judgement 우승자 찾기 기능 테스트 코드 작성
LeahJiinLee Feb 16, 2022
0b6eb9a
test(JudgementTest): JudgeMent 테스트 코드 작성
LeahJiinLee Feb 16, 2022
f2575e4
test: Judgement 우승자 찾기 기능 테스트 코드 작성
LeahJiinLee Feb 16, 2022
3ce951c
docs(README): 구현 완료한 기능 체크 표시
LeahJiinLee Feb 16, 2022
232fc23
test: Judgement 우승자 찾기 기능 테스트 코드 작성
LeahJiinLee Feb 16, 2022
2839a04
feat: Implement InputView and OutputView
Hoya-kim Feb 17, 2022
bebd646
fix: static Scanner 객체로 인한 테스트 실패 이슈 해결
Hoya-kim Feb 17, 2022
e8f4aed
feat: Controller 및 블랙잭 application 구현완료
Hoya-kim Feb 17, 2022
07c2a26
chore: google convention에 따른 코드 정렬
Hoya-kim Feb 17, 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
83 changes: 82 additions & 1 deletion README.md
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()`)
11 changes: 11 additions & 0 deletions src/main/java/blackjack/Application.java
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();
}
}
88 changes: 88 additions & 0 deletions src/main/java/blackjack/controller/BlackjackGame.java
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 {
Copy link

Choose a reason for hiding this comment

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

컨트롤러에 카드점수 상태를 판단하는 로직이 있는 것 보다 적절한 객체에 책임을 부여해보는 것은 어떨까요?
딜러와 플레이어가 카드를 들고 있는 손을 객체로 만들어 카드를 추가 여부와 카드를 카드 점수 상태를 관리해 보는 것은 어떨까요?


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
Copy link

Choose a reason for hiding this comment

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

Suggested change
List<Player> players = playersName.stream().map(Player::new)
.collect(Collectors.toList());
Players players = playersName.stream().map(Player::new)
.collect(Collectors.toList());

로또 미션에서 학습한 것 처럼 일급컬렉션을 만들어 객체의 행위를 정해보면 어떨까요?


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;
}


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

public class Card {
Copy link

Choose a reason for hiding this comment

The 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() {
Copy link

Choose a reason for hiding this comment

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

Suggested change
public String getDenomiationCountstring() {
public String getDenomiationCountString() {

return denomination.getCountString();
}

public String getSuitName() {
return suit.getName();
}

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

public class Dealer extends Player {
Copy link

Choose a reason for hiding this comment

The 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;
}


}
41 changes: 41 additions & 0 deletions src/main/java/blackjack/domain/Deck.java
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();
Copy link

Choose a reason for hiding this comment

The 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();
}
}
37 changes: 37 additions & 0 deletions src/main/java/blackjack/domain/Denomination.java
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
Copy link

Choose a reason for hiding this comment

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

Suggested change
private final int count;
private final String countString;
private final int score;
private final String cardName;

의미를 명확하게 변수명을 변경해보는 것은 어떨까요?


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;
}
}
63 changes: 63 additions & 0 deletions src/main/java/blackjack/domain/Judgement.java
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();
}
}
Loading