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 {

Choose a reason for hiding this comment

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

  • 너무 많은 책임이 있는 것 같아요객체의 역할을 나누어 책임을 분리 시켜보는 것이 어떨까요?
  • BalckjackGame 의 책임들을 어떻게 테스트를 해볼 수 있을까요?


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());

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) {

Choose a reason for hiding this comment

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

해당 메서드의 테스트가 있으면 좋을 것 같아요

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;
}
Comment on lines +49 to +55

Choose a reason for hiding this comment

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

스크린샷 2022-02-19 오전 12 27 02

플레이어가 원할 때 까지 받아야할 것 같은데 받고 버스트가 아닌데 다음 사람으로 넘어가는 것 같아요 ~
로직을 수정해보아요


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;
}
Comment on lines +57 to +66

Choose a reason for hiding this comment

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

프로그래밍 요구 사항 중 하나인 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다. 를 지켜보아요


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;
}
Comment on lines +80 to +85

Choose a reason for hiding this comment

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

Dealer 와 Players 의 두 상태 값을 갖는 객체를 만들어 보는 것이 어떨까요?



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

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() {
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 {

Choose a reason for hiding this comment

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

연료주입에서 배웠던 추상 클래스를 활용해보면 어떨까요?
Player 의 상속을 받았을 때 어떤 단점이 있으며
추상 클래스를 활용함으로써 어떤 장점이 있을까요?


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

}
Comment on lines +16 to +27

Choose a reason for hiding this comment

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

테스트하기 어려운 요소들을 어떻게 테스트를 해볼 수 있을까요?

사이즈 확인 테스트는 제외


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

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));
}
}
Comment on lines +17 to +27

Choose a reason for hiding this comment

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

만약 게임이 한판만에 끝나는게 아니라 계속 게임을 다시 할 수 있다면
Card 의 객체는 계속 생성될 것 같아요
객체의 생성을 어떻게 줄여볼 수 있을까요?


private void shuffle() {
Collections.shuffle(cards);
}
Comment on lines +29 to +31

Choose a reason for hiding this comment

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

Deck 의 객체를 테스트할 때 shuffle 을 통해 카드가 섞이게 된다면 테스트가 어려울 것 같은데요
어떻게 테스트를 해볼 수 있을까요?


public Card popCard() {
Card popped = cards.remove(0);
return new Card(popped.getSuit(), popped.getDenomination());
}
Comment on lines +33 to +36

Choose a reason for hiding this comment

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

카드 객체를 새롭게 만든 이유가 있을까요?


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"),

Choose a reason for hiding this comment

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

해당 enum 객체를 본다면 ACE 의 점수는 1만 있는 것 같아요
ACE 의 점수를 어떻게 표기하면 좋을까요?

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;

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;
Comment on lines +16 to +17

Choose a reason for hiding this comment

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

두 상태 값을 일급컬렉션으로 만들어보는 것은 어떨까요?


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