Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
111 changes: 111 additions & 0 deletions src/doc/TODOS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)
pobi,jason

pobi의 배팅 금액은?
10000

jason의 배팅 금액은?
20000

딜러와 pobi, jason에게 2장의 나누었습니다.
딜러: 3다이아몬드
pobi카드: 2하트, 8스페이드
jason카드: 7클로버, K스페이드

pobi는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)
y
pobi카드: 2하트, 8스페이드, A클로버
pobi는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)
n
jason은 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)
n
jason카드: 7클로버, K스페이드

딜러는 16이하라 한장의 카드를 더 받았습니다.

딜러 카드: 3다이아몬드, 9클로버, 8다이아몬드 - 결과: 20
pobi카드: 2하트, 8스페이드, A클로버 - 결과: 21
jason카드: 7클로버, K스페이드 - 결과: 17

## 최종 수익
딜러: 10000
pobi: 10000
jason: -20000

---

# 순서대로 정리

1. 플레이어 이름을 입력받는다.
- 플레이어의 이름은 쉼표로 구분(,)
- 이 때 딜러도 생성된다

2. 플레이어는 베팅 금액을 입력한다.

3. 카드기계는 카드를 두장씩 넘겨준다.
- 이 때 플레이어들은 카드덱에 카드를 두 장 지급받는다.(딜러 포함)
- 이 때, 딜러의 카드 합이 16 이하면 반드시 한 장 더뽑고, 17 이상이면 뽑지 않는다.
- 지급받은 카드들을 출력한다

4. 플레이어들은 한 장을 더 받을지를 계산해서, y나 n 으로 대답한다. 원하는 만큼 작업을 반복한다.

5. 최종 수익을 계산한다

### 카드 판별

1. 딜러
- 딜러는 2장 뽑았을 때 카드 합이 16 이하면 한장 더, 아니면 뽑지 않는다.

2. 플레이어는 21이 되면 1.5배를 돌려받는다. 대신 딜러또한 21이면 베팅금액만 돌려받는다.

---

# 도메인별 정리

# 플레이어

## 1. 상태

- 베팅 금액
- 카드 뭉치 (덱? 스택?)

## 2. 동작

- 베팅 금액을 설정해서 초기화된다. (이 때 카드뭉치는 비어있다)
- 손패의 합을 계산한다

# 딜러 (플레이어 상속?)

## 1. 상태

- 베팅 금액
- 카드 뭉치

## 2. 동작

- 플레이어의 동작들...
- 손패의 합이 16 이하인지 초과인지 계산하는 로직

# 카드

## 상태

- 이름
- 숫자 값

## 동작

- 게터매서드

# 카드 뭉치

## 상태

- 카드들

### 동작

- 카드들을 생성한다. (홀 카드)
- 카드들을 랜덤으로 셔플한다
- 셔플한 카드들을 리턴한다

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

public class Card {
private final Number number;
private final Shape shape;

public Card(Shape shape, Number number) {
this.number = number;
this.shape = shape;
}

public String getCardInfo(){
return number.getName() + shape.getName();
}

public Number getNumber() {
return number;
}
}
23 changes: 23 additions & 0 deletions src/main/java/card/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package card;

import java.util.*;

public class Deck {
private static final Deque<Card> cards = new ArrayDeque<>();

Choose a reason for hiding this comment

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

과연 LinkedList보다 ArrayDeque가 더 효율적이겠네요 🤔

static {
Arrays.stream(Shape.values()).forEach(
shape -> Arrays.stream(Number.values())
.forEach(number -> cards.add(new Card(shape, number)))
);
}
public void shuffle() {
List<Card> cardList = new ArrayList<>(cards);
Collections.shuffle(cardList);
cards.clear();
cards.addAll(cardList);
}
Comment on lines +13 to +18
Copy link

@deok-beom deok-beom Nov 24, 2023

Choose a reason for hiding this comment

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

이 로직을 보고 처음에 만들어지는 정렬된 카드 배열을 캐싱하면 어떨까 생각해보았습니다.
최초 초기화 블록에서 생성한 카드 뭉치를 별도로 저장해놓고 섞인 새로운 카드 뭉치가 필요할 때 복사해서 셔플만 하면 카드 뭉치를 다시 생성하는 시간을 아낄 수 있겠네요.
문제에서는 게임을 단 한 번밖에 진행하고 있어서 이러한 로직은 필요 없지만... 추후에 게임을 여러번 반복해서 진행하도록 패치한다면 실행 시간을 줄이는데 큰 도움이 될 것 같습니다. 👍


public Card getCard(){
return cards.pop();
}
}
33 changes: 33 additions & 0 deletions src/main/java/card/Number.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package card;

public enum Number {

ACE("ACE", 1),
TWO("2", 2),
THREE("3", 3),
FOUR("4", 4),
FIVE("5", 5),
SIX("6", 6),
SEVEN("7", 7),
EIGHT("8", 8),
NINE("9", 9),
JACK("잭", 10),
QUEEN("퀸", 10),
KING("킹", 10);

private final String name;
private final int value;

Number(String name, int value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public int getValue() {
return value;
}
}
18 changes: 18 additions & 0 deletions src/main/java/card/Shape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package card;

public enum Shape {
HEART("하트"),
SPADE("스페이드"),
CLOVER("클로버"),
DIAMOND("다이아몬드");

private final String name;

Shape(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
78 changes: 78 additions & 0 deletions src/main/java/console/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package console;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class InputView {
private final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private String getInput(){
try {
return br.readLine();
} catch (IOException e){
throw new IllegalArgumentException(e.getMessage());
}
}
public String[] getName() {
System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)");
String[] userNames = getInput().split(",");
try{
validate(userNames);
} catch (IllegalArgumentException e){
System.out.println(e.getMessage());
return getName();
}
return userNames;
}
private void validate(String[] userNames){
if (userNames.length == 0 || isDuplicatedNames(userNames) || isContainsBlank(userNames)){
throw new IllegalArgumentException("[Error] 잘못된 입력");
}
}

private boolean isContainsBlank(String[] userNames) {
return Arrays.stream(userNames)
.anyMatch(s -> s.trim().isEmpty());
}

private boolean isDuplicatedNames(String[] userNames) {
return Arrays.stream(userNames)
.distinct()
.count() == userNames.length;
}

private int getMoney(String name){
System.out.println(name + "의 배팅 금액은?");
String input = getInput();
try {
return Integer.parseInt(input);
} catch (NumberFormatException e){
System.out.println("[ERROR] 잘못된 입력");
return getMoney(name);
}
}

public boolean askUserForCardDecision(String name){
System.out.println(name + "는 한장의 카드를 더 받겠습니까?(예는 y, 아니오는 n)");
String input = getInput();
try {
checkInput(input);
return name.equals("y");
} catch (IllegalArgumentException e){
System.out.println("[ERROR] 잘못된 입력");
return askUserForCardDecision(name);
}
}

private void checkInput(String input) {
input = input.trim().toLowerCase();
if (input.isEmpty() || isNotValid(input)) {
throw new IllegalArgumentException();
}
}

private boolean isNotValid(String input) {
return !(input.equals("y") || input.equals("n"));
}
}
33 changes: 33 additions & 0 deletions src/main/java/console/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package console;

import card.Card;
import user.User;

import java.util.Arrays;
import java.util.Deque;

public class OutputView {
public void printNames(String[] usernames){
String names = getNames(usernames);
System.out.println(names);
}

private String getNames(String[] usernames) {
StringBuilder sb = new StringBuilder();
Arrays.stream(usernames).forEach(s -> sb.append(s).append(","));
return sb.substring(0, sb.length() - 1);
}

public void distributedTwoCards(String[] usernames){
System.out.println("딜러와 " + getNames(usernames) + "에게 2장의 나누었습니다.");
}

public void printUsersCardInfo(User user){
String name = user.getName();
StringBuilder sb = new StringBuilder();
Deque<Card> cardsInHand = user.getCardsInHand();
cardsInHand.forEach(card -> sb.append(card.getCardInfo()).append(", "));
String cardInfo = sb.substring(0, sb.length() - 2);
System.out.println(name + "카드: " + cardInfo);
}
}
10 changes: 10 additions & 0 deletions src/main/java/game/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package game;

import console.InputView;
import console.OutputView;

public class Controller {
private final InputView inputView = new InputView();
private final OutputView outputView = new OutputView();

}
26 changes: 26 additions & 0 deletions src/main/java/hand/Asset.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package hand;

public class Asset {
private int money;

public void setMoney(int money) {
this.money = money;
}

private void winMoney(int money){
this.money += money;
}

private void payMoney(int money){
this.money -= money;
}

public int getMoney() {
return money;
}

public void sendMoney(Asset asset, int money){
this.payMoney(money);
asset.winMoney(money);
}
}
Loading