-
Notifications
You must be signed in to change notification settings - Fork 0
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
레디 step1 미션 제출 #6
base: main
Are you sure you want to change the base?
Changes from all commits
e504ca0
3ed10c0
42a28a9
8972ef5
3a7d4d4
d719d08
a83c06d
3a1cd48
acf6680
68fa548
fbf514f
6017614
ac2aa22
aa6549c
9450f3b
b533c94
b458bdf
63ec5fb
50e902d
52dcb84
ba0dd83
56eaa06
ee77777
a5255e3
9575be9
e4d4369
51f5aea
3a0ddb4
9b1e7a4
546c4e9
9fd7e9c
3c2ce48
eb08c75
a1f0915
3595593
e26d988
bbd54df
57572c0
ef45b28
8f1e9b8
755f99a
d8f2ad4
4f080a1
f6438d3
649014a
7593784
cbee98a
0909ae6
c96930e
b188bdf
62493d6
4df9b26
7b0d3d7
75d216b
72b3f45
6238248
5a87d7c
72a3a20
9414fb4
2d2154e
356674b
da599d2
0198084
781f8e8
162927e
02211ea
2d96eec
32b1496
d0c0451
23bdf69
4e2a246
4ab6363
987be12
8c64ab9
88665a8
7977057
995d864
2d822e9
405ac6b
dfaae33
aaf03ab
017e6a0
36094c8
ad35da3
5e142b0
cc6a91f
d5564b4
2b02cdb
b23548c
8e95a70
2a8dfdc
3de3d0b
21ec566
f2d25ec
96cdc3b
fec95ee
41b1df7
4347c8c
1713750
167957a
e9374bc
19b71c6
80e13e4
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 |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# 블랙잭 규칙 | ||
|
||
## 참여자 | ||
|
||
**승** | ||
|
||
* (딜러 카드 합 < 참여자 카드 합) && 참여자가 버스트가 아닌 경우 | ||
* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 > 참여자 카드 수) && 참여자가 버스트가 아닌 경우 | ||
* 딜러가 버스트인 경우 && 참여자가 버스트가 아닌 경우 | ||
|
||
**무** | ||
|
||
* (딜러 카드 합 == 참여자 카드 합) && (딜러 카드 수 == 참여자 카드 수) && 참여자가 버스트가 아닌 경우 | ||
|
||
**패** | ||
|
||
* 참여자가 버스트인 경우 | ||
* (딜러 카드 합 > 참여자 카드 합) | ||
|
||
<br> | ||
|
||
# 기능 요구 사항 | ||
|
||
* [x] 참여자 이름 입력 받는다. | ||
* [x] 양 끝 공백을 제거한다. | ||
* [x] 참여자는 쉼표(,)로 구분한다. | ||
* [x] null 이나 공백인 경우 예외가 발생한다. | ||
* [x] 쉼표로 시작시 예외가 발생한다. ex) ,pobi,jason | ||
* [x] 쉼표로 끝날시 예외가 발생한다. ex) pobi,jason, | ||
* [x] 쉼표가 연속으로 올시 예외가 발생한다. ex) pobi,,jason | ||
* [x] 참여자 이름이 중복시 예외가 발생한다. | ||
* [x] 총 참여자의 수는 2이상 8이하여야 한다. | ||
|
||
<br> | ||
|
||
* [x] 딜러가 카드 2장을 분배하다. | ||
* [x] 카드는 총 6벌을 둔다. (52 * 6) | ||
* [x] 딜러의 카드를 출력한다. (1장) | ||
* [x] 참여자의 카드를 출력한다. (2장) | ||
|
||
<br> | ||
|
||
* [x] 참여자는 hit(y) / stay(n)를 선택한다. | ||
* [x] y, n 가 아닐시 예외가 발생한다. | ||
* [x] 참여자가 hit을 하는 경우 현재 가지고 있는 카드를 출력한다. | ||
* [x] 참여자가 hit을 한 적 없이 stay를 하는 경우 현재 가지고 있는 카드를 출력한다. | ||
* [x] 카드 합이 블랙잭인 경우 블랙잭 메시지를 출력한다. | ||
* [x] 카드 합이 21 초과시 버스트 메시지를 출력한다. | ||
|
||
<br> | ||
|
||
* [x] 딜러의 카드의 합을 계산한다. | ||
* [x] 카드 내의 ACE 가 포함된 경우 | ||
* ACE: 11 | ||
* 11로 했을 때 카드의 합이 21을 초과한 경우 1로 계산 | ||
* [x] 17 이상이 될때까지 카드를 받는다. | ||
|
||
<br> | ||
|
||
* [x] 모든 참여자의 카드의 합을 계산한다. | ||
* [x] 딜러의 승패무를 확인한다. | ||
* [x] 참여자의 승패무를 확인한다. | ||
* [x] 게임 결과를 출력한다. | ||
|
||
--- | ||
|
||
## 리팩터링 목록 | ||
|
||
~~추상 클래스 활용~~ | ||
|
||
* [x] 카드덱이 비었을때 꺼낸 경우 예외 발생 | ||
* [x] createEmptyPacket 메서드명 수정 | ||
* [x] 참가자의 이름 딜러 불가 | ||
* [x] Name 객체 포장하기 | ||
* [x] Result 함수형 프로그래밍 사용 | ||
* [x] TestFixture 사용 | ||
* [x] 패키지 정리 | ||
* [x] 메서드 컨벤션 작성 및 확인 | ||
* [x] final 컨벤션 통일 | ||
* [x] CardDeck 생성자 닫기 | ||
|
||
<br> | ||
|
||
* [x] 예외 시 재입력 기능 | ||
* [x] 예외 메시지 상수화 | ||
* 커스텀 예외 구현 | ||
* [x] CardDeck 웨어하우스로 바라보기 | ||
* [ ] ~~컨트롤러 메서드 수정하기~~ | ||
* [x] ~~Participant 추상 클래스 대신 클래스로 변경하기~~ | ||
* 추상 클래스를 유지하고 추상 메서드 추가 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package application; | ||
|
||
import controller.BlackJackController; | ||
import controller.InputController; | ||
import java.util.Scanner; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
final Scanner scanner = new Scanner(System.in); | ||
final InputView inputView = new InputView(scanner); | ||
final OutputView outputView = new OutputView(); | ||
final InputController inputController = new InputController(inputView, outputView); | ||
final BlackJackController blackJackController = new BlackJackController(inputController, outputView); | ||
blackJackController.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package constants; | ||
|
||
public enum ErrorCode { | ||
|
||
NOT_EXIST_MESSAGE, | ||
INVALID_SEPARATOR, | ||
INVALID_INPUT, | ||
INVALID_SIZE, | ||
DUPLICATE_NAME, | ||
RESERVED_NAME, | ||
BLANK_VALUE, | ||
EMPTY_CARD, | ||
INVALID_COMMAND, | ||
; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package controller; | ||
|
||
import domain.Answer; | ||
import domain.participant.Dealer; | ||
import domain.participant.Player; | ||
import domain.participant.Players; | ||
import dto.DealerHandsDto; | ||
import dto.ParticipantDto; | ||
import dto.ParticipantsDto; | ||
import view.OutputView; | ||
|
||
public class BlackJackController { | ||
|
||
private final InputController inputController; | ||
private final OutputView outputView; | ||
|
||
|
||
public BlackJackController(final InputController inputController, final OutputView outputView) { | ||
this.inputController = inputController; | ||
this.outputView = outputView; | ||
} | ||
|
||
public void run() { | ||
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. 메서드 길이가 10라인을 넘었네요 |
||
final Players players = inputController.getPlayers(); | ||
final Dealer dealer = new Dealer(); | ||
|
||
initHands(players, dealer); | ||
dealWithPlayers(players, dealer); | ||
|
||
if (!players.isAllBust()) { | ||
dealer.deal(); | ||
printDealerTurnMessage(dealer.countAddedHands()); | ||
} | ||
|
||
printFinalResult(players, dealer); | ||
} | ||
|
||
private void printDealerTurnMessage(final int turn) { | ||
for (int i = 0; i < turn; i++) { | ||
outputView.printDealerTurnMessage(); | ||
} | ||
} | ||
|
||
private void dealWithPlayers(final Players players, final Dealer dealer) { | ||
for (Player player : players.getPlayers()) { | ||
deal(player, dealer); | ||
} | ||
} | ||
|
||
private void initHands(final Players players, final Dealer dealer) { | ||
dealer.initHands(players); | ||
outputView.printStartDeal(DealerHandsDto.from(dealer), ParticipantsDto.of(players)); | ||
} | ||
|
||
private void printFinalResult(final Players players, final Dealer dealer) { | ||
outputView.printHandsResult(ParticipantsDto.of(dealer, players)); | ||
outputView.printGameResult(dealer.getDealerResult(players), players.getPlayersResult(dealer)); | ||
} | ||
|
||
private void deal(final Player player, final Dealer dealer) { | ||
boolean handsChanged = false; | ||
boolean turnEnded = false; | ||
|
||
while (!turnEnded) { | ||
final Answer answer = inputController.getAnswer(player.getName()); | ||
dealer.deal(player, answer); | ||
|
||
printHandsIfRequired(player, handsChanged, answer); | ||
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. 21 이상이면 카드를 받을 수 없는 것은 예제와 다르게 구현하셨는데, 저는 이 부분이 생기면서 로직이 좀 복잡해진 듯 합니다. 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. 오오 잘 캐치해주셨어요! 어떤건 예제대로 하고 어떤건 또 멋대로 구현하여 혼란을 줄 수도 있을거 같은데 이유를 설명해보자면;;; 그리고 변경된 경우에만 출력하는 기능은 예제 보고 규칙을 파악하여 그냥 신나서 구현했던 거 같아요 ㅎㅎㅎ |
||
|
||
handsChanged = true; | ||
turnEnded = isTurnEnded(player, answer); | ||
} | ||
} | ||
|
||
private void printHandsIfRequired(final Player player, final boolean handsChanged, final Answer answer) { | ||
if (shouldShowHands(handsChanged, answer)) { | ||
outputView.printHands(ParticipantDto.from(player)); | ||
} | ||
} | ||
Comment on lines
+75
to
+79
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.
직역하면 메서드 이름에 행위를 드러내더라도 의도가 조금 섞이도록 하는게 좋을 것 같아요 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. 네이밍 어려워요ㅜㅜ 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 boolean isTurnEnded(final Player player, final Answer answer) { | ||
if (player.canDeal()) { | ||
return !answer.isHit(); | ||
} | ||
outputView.printDealEndMessage(player.isBust()); | ||
return true; | ||
} | ||
|
||
private boolean shouldShowHands(final boolean handsChanged, final Answer answer) { | ||
return answer.isHit() || !handsChanged; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package controller; | ||
|
||
import domain.Answer; | ||
import domain.participant.Players; | ||
import exception.CustomException; | ||
import java.util.List; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
public class InputController { | ||
|
||
private final InputView inputView; | ||
private final OutputView outputView; | ||
|
||
public InputController(final InputView inputView, final OutputView outputView) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
} | ||
|
||
public Players getPlayers() { | ||
Players players; | ||
do { | ||
players = readPlayers(); | ||
} while (players == null); | ||
return players; | ||
} | ||
|
||
public Answer getAnswer(String name) { | ||
Answer answer; | ||
do { | ||
answer = readAnswer(name); | ||
} while (answer == null); | ||
return answer; | ||
} | ||
|
||
private Players readPlayers() { | ||
try { | ||
List<String> rawNames = inputView.readNames(); | ||
return Players.from(rawNames); | ||
} catch (CustomException exception) { | ||
outputView.printException(exception.getErrorCode()); | ||
return null; | ||
} | ||
} | ||
|
||
private Answer readAnswer(String name) { | ||
try { | ||
String value = inputView.readAnswer(name); | ||
return Answer.from(value); | ||
} catch (CustomException exception) { | ||
outputView.printException(exception.getErrorCode()); | ||
return null; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package domain; | ||
|
||
import constants.ErrorCode; | ||
import exception.InvalidCommandException; | ||
import java.util.Arrays; | ||
|
||
public enum Answer { | ||
|
||
HIT("y"), | ||
STAY("n"); | ||
|
||
private final String value; | ||
|
||
Answer(final String value) { | ||
this.value = value; | ||
} | ||
|
||
public static Answer from(final String value) { | ||
return Arrays.stream(Answer.values()) | ||
.filter(answer -> answer.value.equals(value)) | ||
.findFirst() | ||
.orElseThrow(() -> new InvalidCommandException(ErrorCode.INVALID_COMMAND)); | ||
} | ||
|
||
public boolean isHit() { | ||
return HIT.equals(this); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package domain; | ||
|
||
import domain.participant.Hands; | ||
import java.util.Arrays; | ||
import java.util.function.BiPredicate; | ||
|
||
public enum Result { | ||
|
||
WIN("승", Result::winningCondition), | ||
TIE("무", Result::tieCondition), | ||
LOSE("패", Result::loseCondition); | ||
|
||
private final String value; | ||
private final BiPredicate<Hands, Hands> condition; | ||
|
||
Result(final String value, final BiPredicate<Hands, Hands> condition) { | ||
this.value = value; | ||
this.condition = condition; | ||
} | ||
|
||
public Result reverse() { | ||
if (Result.WIN.equals(this)) { | ||
return LOSE; | ||
} | ||
if (Result.LOSE.equals(this)) { | ||
return WIN; | ||
} | ||
return TIE; | ||
} | ||
|
||
public static Result calculateOf(final Hands hands, final Hands target) { | ||
return Arrays.stream(Result.values()) | ||
.filter(result -> result.condition.test(hands, target)) | ||
.findFirst() | ||
.orElseThrow(); | ||
} | ||
|
||
private static boolean winningCondition(final Hands hands, final Hands target) { | ||
return (!hands.isBust() && target.isBust()) | ||
|| (hands.sum() > target.sum() && !hands.isBust()) | ||
|| (hands.sum() == target.sum() && hands.size() < target.size() && !hands.isBust()); | ||
} | ||
|
||
private static boolean tieCondition(final Hands hands, final Hands target) { | ||
return hands.sum() == target.sum() && hands.size() == target.size() && !hands.isBust(); | ||
} | ||
|
||
private static boolean loseCondition(final Hands hands, final Hands target) { | ||
return hands.isBust() || hands.sum() < target.sum() || !target.isBust(); | ||
} | ||
|
||
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.
개인적으로
승
과무
에참여자가 버스트가 아닌 경우
가 맨 앞에 가있거나, 다른 방식으로 언급이 되면 더 좋을 것 같아요~맨 뒤에 같은 말이 반복되어 가독성이 조금 떨어진다고 느껴집니다.
그리고
딜러 카드 합 == 참여자 카드 합
인데딜러 카드 수 < 참여자 카드 수
인 경우는 어떻게 되나요?언급이 되어 있지 않아 여쭤봅니다!
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.
딜러 카드 합 == 참여자 카드 합 && 딜러 카드 수 < 참여자 카드 수 라면 "패"조건이네요 작성을 놓쳤네요😅