Skip to content

Commit

Permalink
CardDeck 클래스 및 테스트 추가
Browse files Browse the repository at this point in the history
- 블랙잭 게임을 위한 `CardDeck` 클래스를 추가하였으며, 이는 카드 덱 생성, 카드 섞기, 카드 뽑기 등의 기능 포함하고 있음.
- `CardDeck`의 기능을 보장하기 위한 테스트를 추가하였음. 이에는 덱 생성, 섞기, 카드 뽑기 등의 상황에 대한 테스트가 포함됨.
  • Loading branch information
gunkim committed Apr 29, 2024
1 parent 8adb874 commit 585a138
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.github.gunkim.blackjack.domain;

import java.util.*;

public class CardDeck {
private static final int DEFAULT_CARD_SIZE = 52;

private final ArrayDeque<Card> cards;

CardDeck(Collection<Card> cards) {
validateCards(cards);
this.cards = new ArrayDeque<>(cards);
}

public static CardDeck shuffle() {
List<Card> shuffledCards = new ArrayList<>(Card.distinctCards());

Collections.shuffle(shuffledCards);
return new CardDeck(shuffledCards);
}

public Card draw() {
if (cards.isEmpty()) {
throw new IllegalStateException("No more cards in the deck");
}
return cards.remove();
}

private void validateCards(Collection<Card> cards) {
Objects.requireNonNull(cards, "cards must not be null");
checkForDuplicateCards(cards);
validateCardDeckSize(cards);
}

private void checkForDuplicateCards(Collection<Card> cards) {
var containsDuplicateCards = new HashSet<>(cards).size() != cards.size();
if (containsDuplicateCards) {
throw new IllegalArgumentException("cards must not contain duplicate cards");
}
}

private void validateCardDeckSize(Collection<Card> cards) {
if (cards.size() != DEFAULT_CARD_SIZE) {
throw new IllegalArgumentException(String.format("cards must contain %d cards", DEFAULT_CARD_SIZE));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.github.gunkim.blackjack.domain;

import io.github.gunkim.blackjack.domain.vo.CardNumber;
import io.github.gunkim.blackjack.domain.vo.CardSuit;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("카드 덱은")
class CardDeckTest {
@Test
@DisplayName("생성된다")
void shouldCreateCardDeck() {
List<Card> cards = Card.distinctCards();

assertDoesNotThrow(() -> new CardDeck(cards));
}

@Test
@DisplayName("섞인 채로 생성된다")
void shouldCreateShuffledDeck() {
CardDeck cardDeck = CardDeck.shuffle();

assertNotNull(cardDeck);
}

@Test
@DisplayName("중복된 카드가 없을 경우 생성된다")
void shouldCreateCardDeckWhenNotDuplicatedCards() {
List<Card> cards = Card.distinctCards();

assertDoesNotThrow(() -> new CardDeck(cards));
}

@Test
@DisplayName("중복된 카드가 있을 경우 생성되지 않는다")
void shouldFailToCreateCardDeckWhenDuplicatedCards() {
List<Card> cards = new ArrayList<>(Card.distinctCards());
cards.removeLast();
cards.add(cards.get(0));

assertThrows(IllegalArgumentException.class, () -> new CardDeck(cards));
}

@Test
@DisplayName("카드가 52장이 아닐 경우 예외가 발생한다")
void shouldThrowExceptionWhenCardCountIsNot52() {
List<Card> cards = List.of(new Card(CardSuit.CLUBS, CardNumber.A));

String actualErrorMessage = assertThrows(IllegalArgumentException.class, () -> new CardDeck(cards)).getMessage();
assertEquals(actualErrorMessage, "cards must contain 52 cards");
}

@Test
@DisplayName("덱에 카드가 남아 있다면 카드를 뽑을 수 있어야 한다")
void shouldDrawCardWhenDeckIsNotEmpty() {
CardDeck cardDeck = CardDeck.shuffle();
Card card = cardDeck.draw();

assertNotNull(card);
}

@Test
@DisplayName("덱에 카드가 비어 있다면 카드를 뽑을 수 없다")
void shouldThrowExceptionWhenCardDeckIsEmpty() {
CardDeck cardDeck = CardDeck.shuffle();
IntStream.range(0, 52).forEach(__ -> cardDeck.draw());

String actualErrorMessage = assertThrows(IllegalStateException.class, cardDeck::draw).getMessage();
assertEquals(actualErrorMessage, "No more cards in the deck");
}
}

0 comments on commit 585a138

Please sign in to comment.