diff --git a/README.md b/README.md index 5fa2560b46..2805ec1112 100644 --- a/README.md +++ b/README.md @@ -1 +1,46 @@ -# java-lotto-precourse +# ๐Ÿš€ ๋กœ๋˜ ๋ฏธ์…˜ + +## ๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ + +* **ํด๋ž˜์Šค์™€ ๊ฐ์ฒด:** ๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ๋ฌถ์–ด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ฐ์ฒด๋“ค์ด ํ˜‘๋ ฅํ•˜์—ฌ ํ•˜๋‚˜์˜ ํฐ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค. +* **ํ…Œ์ŠคํŠธ:** ํด๋ž˜์Šค์™€ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์˜๋„ํ•œ ๋Œ€๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” ์˜์—ญ์„ ํ™•๋ณดํ•ฉ๋‹ˆ๋‹ค. +* **ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜:** 2์ฃผ ์ฐจ ๊ณตํ†ต ํ”ผ๋“œ๋ฐฑ(indent depth, ํ•จ์ˆ˜ ๊ธธ์ด, `else` ์‚ฌ์šฉ ์ง€์–‘, `Enum` ์‚ฌ์šฉ ๋“ฑ)์„ ์ตœ๋Œ€ํ•œ ๋ฐ˜์˜ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค. + +--- + +## ๐Ÿ› ๏ธ ๊ธฐ๋Šฅ ๋ชฉ๋ก + +๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌํ•˜๊ณ , **๊ฐ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ์ปค๋ฐ‹**์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +### 1. ๋กœ๋˜ ๊ตฌ์ž… (Input & Purchase) + +* [ ] **๊ตฌ์ž… ๊ธˆ์•ก ์ž…๋ ฅ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ** + * ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋กœ๋˜ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. + * ์ž…๋ ฅ ๊ธˆ์•ก์ด **1,000์› ๋‹จ์œ„**์ธ์ง€ ๊ฒ€์ฆํ•œ๋‹ค. (์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์žฌ์ž…๋ ฅ) +* [ ] **๋กœ๋˜ ๋ฐœํ–‰ ๋ฐ ์ €์žฅ** + * ๊ตฌ์ž… ๊ธˆ์•ก์— ํ•ด๋‹นํ•˜๋Š” ๋กœ๋˜ ์ˆ˜๋Ÿ‰๋งŒํผ ์ค‘๋ณต ์—†๋Š” 1~45 ์‚ฌ์ด์˜ 6๊ฐœ ์ˆซ์ž๋กœ ๊ตฌ์„ฑ๋œ ๋กœ๋˜๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค. + * ๋ฐœํ–‰๋œ ๋กœ๋˜(`Lotto` ๊ฐ์ฒด)๋“ค์„ ์ €์žฅํ•œ๋‹ค. + +### 2. ๋ฐœํ–‰ ๊ฒฐ๊ณผ ์ถœ๋ ฅ (Output) + +* [ ] **๋ฐœํ–‰ ์ˆ˜๋Ÿ‰ ๋ฐ ๋ฒˆํ˜ธ ์ถœ๋ ฅ** + * ๊ตฌ๋งคํ•œ ๋กœ๋˜์˜ ์ด ์ˆ˜๋Ÿ‰์„ ์ถœ๋ ฅํ•œ๋‹ค. + * ๋ฐœํ–‰๋œ ๋ชจ๋“  ๋กœ๋˜ ๋ฒˆํ˜ธ๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ์š”๊ตฌ ์‚ฌํ•ญ ํ˜•์‹(`[n1, n2, n3, n4, n5, n6]`)์œผ๋กœ ์ถœ๋ ฅํ•œ๋‹ค. + +### 3. ๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ ๊ฒ€์ฆ (Winning Numbers Input) + +* [ ] **๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ** + * ์‰ผํ‘œ(`,`)๋กœ ๊ตฌ๋ถ„๋œ ๋‹น์ฒจ ๋ฒˆํ˜ธ 6๊ฐœ๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. + * ๋ฒˆํ˜ธ์˜ ๊ฐœ์ˆ˜, ๋ฒ”์œ„(1~45), ์ค‘๋ณต ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค. (์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์žฌ์ž…๋ ฅ) +* [ ] **๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ** + * ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ 1๊ฐœ๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. + * ๋ฒˆํ˜ธ์˜ ๋ฒ”์œ„(1~45), ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€์˜ ์ค‘๋ณต ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค. (์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์žฌ์ž…๋ ฅ) + +### 4. ๋‹น์ฒจ ํ†ต๊ณ„ ๋ฐ ์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ (Result & Calculation) + +* [ ] **๊ฐœ๋ณ„ ๋กœ๋˜ ๋‹น์ฒจ ํ™•์ธ ๋ฐ ํ†ต๊ณ„ ์ง‘๊ณ„** + * ๊ตฌ๋งคํ•œ ๋กœ๋˜์™€ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋‹น์ฒจ ๋“ฑ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ํ†ต๊ณ„๋ฅผ ์ง‘๊ณ„ํ•œ๋‹ค. (**Enum** ํ™œ์šฉ) +* [ ] **๋‹น์ฒจ ํ†ต๊ณ„ ์ถœ๋ ฅ** + * ๊ฐ ๋“ฑ์ˆ˜๋ณ„ ๋‹น์ฒจ ๊ฐœ์ˆ˜๋ฅผ ์š”๊ตฌ ์‚ฌํ•ญ ์ถœ๋ ฅ ํ˜•์‹์— ๋งž๊ฒŒ ์ถœ๋ ฅํ•œ๋‹ค. (5๋“ฑ๋ถ€ํ„ฐ 1๋“ฑ ์ˆœ์„œ) +* [ ] **์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ ๋ฐ ์ถœ๋ ฅ** + * ์ด ์ƒ๊ธˆ๊ณผ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ด์šฉํ•˜์—ฌ ์ˆ˜์ต๋ฅ ์„ ๊ณ„์‚ฐ \ No newline at end of file diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index 88fc5cf12b..2907b46128 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -1,8 +1,16 @@ package lotto; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class Lotto { + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + private static final int LOTTO_SIZE = 6; + private static final String ERROR_PREFIX = "[ERROR] "; + private final List numbers; public Lotto(List numbers) { @@ -11,10 +19,43 @@ public Lotto(List numbers) { } private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + validateSize(numbers); + validateRange(numbers); + validateDuplication(numbers); + } + + // (1) ๋ฒˆํ˜ธ ๊ฐœ์ˆ˜ ๊ฒ€์ฆ (๊ธฐ์กด ์ฝ”๋“œ) + private void validateSize(List numbers) { + if (numbers.size() != LOTTO_SIZE) { + throw new IllegalArgumentException(ERROR_PREFIX + "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); } } - // TODO: ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ -} + // (2) ๋ฒˆํ˜ธ ๋ฒ”์œ„ ๊ฒ€์ฆ + private void validateRange(List numbers) { + for (int number : numbers) { + validateSingleNumberRange(number); + } + } + + // ํ•จ์ˆ˜ ๊ธธ์ด 15๋ผ์ธ ๋ฏธ๋งŒ ์œ ์ง€ (๋‹จ์ผ ๋ฒˆํ˜ธ ๊ฒ€์ฆ ๋ถ„๋ฆฌ) + private void validateSingleNumberRange(int number) { + if (number < MIN_NUMBER || number > MAX_NUMBER) { + throw new IllegalArgumentException(ERROR_PREFIX + "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1๋ถ€ํ„ฐ 45 ์‚ฌ์ด์˜ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + // (3) ๋ฒˆํ˜ธ ์ค‘๋ณต ๊ฒ€์ฆ + private void validateDuplication(List numbers) { + Set uniqueNumbers = new HashSet<>(numbers); + if (uniqueNumbers.size() != LOTTO_SIZE) { + throw new IllegalArgumentException(ERROR_PREFIX + "๋กœ๋˜ ๋ฒˆํ˜ธ์— ์ค‘๋ณต๋œ ์ˆซ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค."); + } + } + + // ๋กœ๋˜ ๋ฒˆํ˜ธ ์กฐํšŒ๋ฅผ ์œ„ํ•œ Getter (์ถœ๋ ฅ ๋ฐ ๋‹น์ฒจ ํ™•์ธ์— ์‚ฌ์šฉ) + public List getNumbers() { + // ๋ถˆ๋ณ€์„ฑ์„ ์œ„ํ•ด Collections.unmodifiableList๋กœ ๊ฐ์‹ธ์„œ ๋ฐ˜ํ™˜ + return Collections.unmodifiableList(numbers); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/LottoController.java b/src/main/java/lotto/LottoController.java new file mode 100644 index 0000000000..7e6878ba62 --- /dev/null +++ b/src/main/java/lotto/LottoController.java @@ -0,0 +1,33 @@ +package lotto; + +import lotto.Lotto; +import lotto.LottoGenerator; +import lotto.LottoView; // ์ถ”๊ฐ€ + +import java.util.List; + +public class LottoController { + + // ... (๊ธฐ์กด ํ•„๋“œ: lottoValidator) + private final LottoGenerator lottoGenerator = new LottoGenerator(); // ์ถ”๊ฐ€ + private final LottoView lottoView = new LottoView(); // ์ถ”๊ฐ€ + + public void run() { + int lottoCount = getPurchaseAmount(); // 1๋‹จ๊ณ„ ๊ธฐ๋Šฅ ํ˜ธ์ถœ + + List purchasedLottos = buyLottos(lottoCount); // ์ƒˆ๋กœ ์ถ”๊ฐ€ + + lottoView.printLottoCount(lottoCount); // 3๋‹จ๊ณ„ ๊ธฐ๋Šฅ ํ˜ธ์ถœ + lottoView.printLottos(purchasedLottos); // 3๋‹จ๊ณ„ ๊ธฐ๋Šฅ ํ˜ธ์ถœ + + // ... (๋‹ค์Œ ๋‹จ๊ณ„) + } + + // (1) ๊ตฌ์ž… ๊ธˆ์•ก ์ž…๋ ฅ ๋ฐ ๊ฒ€์ฆ (๊ธฐ์กด ๋ฉ”์„œ๋“œ) + // ... getPurchaseAmount() ๋ฉ”์„œ๋“œ ์œ ์ง€ ... + + // (2) ๋กœ๋˜ ๋ฐœํ–‰ ๋ฐ ์ €์žฅ ๊ธฐ๋Šฅ (์ƒˆ๋กœ ์ถ”๊ฐ€) + private List buyLottos(int count) { + return lottoGenerator.generateLottos(count); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/LottoGenerator.java b/src/main/java/lotto/LottoGenerator.java new file mode 100644 index 0000000000..c2ae5316d7 --- /dev/null +++ b/src/main/java/lotto/LottoGenerator.java @@ -0,0 +1,31 @@ +package lotto; + +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.List; +import java.util.stream.Collectors; + +public class LottoGenerator { + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + private static final int LOTTO_SIZE = 6; + + // ๋กœ๋˜ ๋ฒˆํ˜ธ 6๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ •๋ ฌ๋œ List ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ + public List generateLottoNumbers() { + List numbers = Randoms.pickUniqueNumbersInRange(MIN_NUMBER, MAX_NUMBER, LOTTO_SIZE); + + // ์š”๊ตฌ์‚ฌํ•ญ: ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ๋ณด์—ฌ์ค€๋‹ค. + // Lotto ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์ €์žฅ + return numbers.stream() + .sorted() + .collect(Collectors.toList()); + } + + // ๊ตฌ๋งค ์ˆ˜๋Ÿ‰๋งŒํผ ๋กœ๋˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ List๋กœ ๋ฐ˜ํ™˜ + public List generateLottos(int count) { + // stream์„ ์‚ฌ์šฉํ•˜์—ฌ count๋งŒํผ Lotto ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฆฌ์ŠคํŠธ๋กœ ์ˆ˜์ง‘ + return java.util.stream.IntStream.range(0, count) + .mapToObj(i -> new Lotto(generateLottoNumbers())) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/LottoTest.java b/src/main/java/lotto/LottoTest.java new file mode 100644 index 0000000000..1f53f773c9 --- /dev/null +++ b/src/main/java/lotto/LottoTest.java @@ -0,0 +1,47 @@ +package lotto; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class LottoTest { + + @DisplayName("๋กœ๋˜ ๋ฒˆํ˜ธ์˜ ๊ฐœ์ˆ˜๊ฐ€ 6๊ฐœ๊ฐ€ ๋„˜์–ด๊ฐ€๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @Test + void createLottoByOverSize() { + assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 6, 7))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @DisplayName("๋กœ๋˜ ๋ฒˆํ˜ธ์— ์ค‘๋ณต๋œ ์ˆซ์ž๊ฐ€ ์žˆ์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @Test + void createLottoByDuplicatedNumber() { + assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 5))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @DisplayName("๋กœ๋˜ ๋ฒˆํ˜ธ์˜ ๋ฒ”์œ„(1~45)๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @ParameterizedTest + @MethodSource("invalidRangeProvider") + void createLottoByInvalidRange(List invalidNumbers) { + assertThatThrownBy(() -> new Lotto(invalidNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + static Stream invalidRangeProvider() { + return Stream.of( + Arguments.of(List.of(1, 2, 3, 4, 5, 46)), // 46 (์ดˆ๊ณผ) + Arguments.of(List.of(0, 2, 3, 4, 5, 6)) // 0 (๋ฏธ๋งŒ) + ); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/LottoView.java b/src/main/java/lotto/LottoView.java new file mode 100644 index 0000000000..9072c16892 --- /dev/null +++ b/src/main/java/lotto/LottoView.java @@ -0,0 +1,30 @@ +package lotto; + +import lotto.Lotto; + +import java.util.List; +import java.util.stream.Collectors; + +public class LottoView { + + // (1) ๋ฐœํ–‰๋œ ๋กœ๋˜ ์ˆ˜๋Ÿ‰ ์ถœ๋ ฅ + public void printLottoCount(int count) { + System.out.printf("%d๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.%n", count); + } + + // (2) ๋ฐœํ–‰๋œ ๋กœ๋˜ ๋ฒˆํ˜ธ ๋ชฉ๋ก ์ถœ๋ ฅ + public void printLottos(List lottos) { + for (Lotto lotto : lottos) { + printLottoNumbers(lotto); + } + } + + // ๋กœ๋˜ ํ•œ ์žฅ์˜ ๋ฒˆํ˜ธ๋ฅผ ์ถœ๋ ฅ ํ˜•์‹์— ๋งž๊ฒŒ ๋ณ€ํ™˜ ๋ฐ ์ถœ๋ ฅ (ํ•จ์ˆ˜ ๊ธธ์ด 15๋ผ์ธ ๋ฏธ๋งŒ ์œ ์ง€) + private void printLottoNumbers(Lotto lotto) { + String numbersString = lotto.getNumbers().stream() + .map(String::valueOf) // ์ˆซ์ž๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + .collect(Collectors.joining(", ", "[", "]")); // ์‰ผํ‘œ์™€ ๊ณต๋ฐฑ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๊ณ  ๋Œ€๊ด„ํ˜ธ๋กœ ๊ฐ์Œˆ + + System.out.println(numbersString); + } +} \ No newline at end of file