From 5ae3864bff8e3997cdad0f6c79263360b8bf0a10 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:29:19 +0900 Subject: [PATCH 01/20] =?UTF-8?q?docs(README):=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=A6=AC=EB=93=9C=EB=AF=B8=EC=97=90=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/README.md b/README.md index 5fa2560..32d00e9 100644 --- a/README.md +++ b/README.md @@ -1 +1,160 @@ # java-lotto-precourse + +## ๐Ÿš€ ๊ธฐ๋Šฅ ์š”๊ตฌ ์‚ฌํ•ญ + +๋กœ๋˜ ๊ฒŒ์ž„ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋กœ๋˜ ๊ฒŒ์ž„์€ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ทœ์น™์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค +``` +๋กœ๋˜ ๋ฒˆํ˜ธ์˜ ์ˆซ์ž ๋ฒ”์œ„๋Š” 1~45๊นŒ์ง€์ด๋‹ค. +1๊ฐœ์˜ ๋กœ๋˜๋ฅผ ๋ฐœํ–‰ํ•  ๋•Œ ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” 6๊ฐœ์˜ ์ˆซ์ž๋ฅผ ๋ฝ‘๋Š”๋‹ค. +๋‹น์ฒจ ๋ฒˆํ˜ธ ์ถ”์ฒจ ์‹œ ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ์ˆซ์ž 6๊ฐœ์™€ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ 1๊ฐœ๋ฅผ ๋ฝ‘๋Š”๋‹ค. +๋‹น์ฒจ์€ 1๋“ฑ๋ถ€ํ„ฐ 5๋“ฑ๊นŒ์ง€ ์žˆ๋‹ค. ๋‹น์ฒจ ๊ธฐ์ค€๊ณผ ๊ธˆ์•ก์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. +1๋“ฑ: 6๊ฐœ ๋ฒˆํ˜ธ ์ผ์น˜ / 2,000,000,000์› +2๋“ฑ: 5๊ฐœ ๋ฒˆํ˜ธ + ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ผ์น˜ / 30,000,000์› +3๋“ฑ: 5๊ฐœ ๋ฒˆํ˜ธ ์ผ์น˜ / 1,500,000์› +4๋“ฑ: 4๊ฐœ ๋ฒˆํ˜ธ ์ผ์น˜ / 50,000์› +5๋“ฑ: 3๊ฐœ ๋ฒˆํ˜ธ ์ผ์น˜ / 5,000์› +``` + +- ๋กœ๋˜ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅํ•˜๋ฉด ๊ตฌ์ž… ๊ธˆ์•ก์— ํ•ด๋‹นํ•˜๋Š” ๋งŒํผ ๋กœ๋˜๋ฅผ ๋ฐœํ–‰ํ•ด์•ผ ํ•œ๋‹ค. +- ๋กœ๋˜ 1์žฅ์˜ ๊ฐ€๊ฒฉ์€ 1,000์›์ด๋‹ค. +- ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. +- ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ๋งคํ•œ ๋กœ๋˜ ๋ฒˆํ˜ธ์™€ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋‹น์ฒจ ๋‚ด์—ญ ๋ฐ ์ˆ˜์ต๋ฅ ์„ ์ถœ๋ ฅํ•˜๊ณ  ๋กœ๋˜ ๊ฒŒ์ž„์„ ์ข…๋ฃŒํ•œ๋‹ค. +- ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ๊ฐ’์„ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ `IllegalArgumentException` ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , "[ERROR]"๋กœ ์‹œ์ž‘ํ•˜๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅ ํ›„ ๊ทธ ๋ถ€๋ถ„๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋‹ค์‹œ ๋ฐ›๋Š”๋‹ค. + - `Exception`์ด ์•„๋‹Œ `IllegalArgumentException`, `IllegalStateException` ๋“ฑ๊ณผ ๊ฐ™์€ ๋ช…ํ™•ํ•œ ์œ ํ˜•์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. + +## ์ž…์ถœ๋ ฅ ์š”๊ตฌ ์‚ฌํ•ญ + +### ์ž…๋ ฅ + +๋กœ๋˜ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅ ๋ฐ›๋Š”๋‹ค. ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„๋กœ ์ž…๋ ฅ ๋ฐ›์œผ๋ฉฐ 1,000์›์œผ๋กœ ๋‚˜๋ˆ„์–ด ๋–จ์–ด์ง€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•œ๋‹ค. + +``` +14000 +``` + +๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅ ๋ฐ›๋Š”๋‹ค. ๋ฒˆํ˜ธ๋Š” ์‰ผํ‘œ(,)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค. +``` +1,2,3,4,5,6 +``` + +๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅ ๋ฐ›๋Š”๋‹ค. +``` +7 +``` + +### ์ถœ๋ ฅ + +๋ฐœํ–‰ํ•œ ๋กœ๋˜ ์ˆ˜๋Ÿ‰ ๋ฐ ๋ฒˆํ˜ธ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ๋ณด์—ฌ์ค€๋‹ค. + +``` +8๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[1, 3, 5, 14, 22, 45] +``` + +๋‹น์ฒจ ๋‚ด์—ญ์„ ์ถœ๋ ฅํ•œ๋‹ค. + +``` +3๊ฐœ ์ผ์น˜ (5,000์›) - 1๊ฐœ +4๊ฐœ ์ผ์น˜ (50,000์›) - 0๊ฐœ +5๊ฐœ ์ผ์น˜ (1,500,000์›) - 0๊ฐœ +5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜ (30,000,000์›) - 0๊ฐœ +6๊ฐœ ์ผ์น˜ (2,000,000,000์›) - 0๊ฐœ +``` + +์ˆ˜์ต๋ฅ ์€ ์†Œ์ˆ˜์  ๋‘˜์งธ ์ž๋ฆฌ์—์„œ ๋ฐ˜์˜ฌ๋ฆผํ•œ๋‹ค. (ex. 100.0%, 51.5%, 1,000,000.0%) +``` +์ด ์ˆ˜์ต๋ฅ ์€ 62.5%์ž…๋‹ˆ๋‹ค. +``` + +์˜ˆ์™ธ ์ƒํ™ฉ ์‹œ ์—๋Ÿฌ ๋ฌธ๊ตฌ๋ฅผ ์ถœ๋ ฅํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, ์—๋Ÿฌ ๋ฌธ๊ตฌ๋Š” "[ERROR]"๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค. +``` +[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1๋ถ€ํ„ฐ 45 ์‚ฌ์ด์˜ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. +``` + +### ์‹คํ–‰ ๊ฒฐ๊ณผ ์˜ˆ์‹œ + +``` +๊ตฌ์ž…๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +8000 + +8๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[1, 3, 5, 14, 22, 45] + +๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +1,2,3,4,5,6 + +๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +7 + +๋‹น์ฒจ ํ†ต๊ณ„ + +3๊ฐœ ์ผ์น˜ (5,000์›) - 1๊ฐœ +4๊ฐœ ์ผ์น˜ (50,000์›) - 0๊ฐœ +5๊ฐœ ์ผ์น˜ (1,500,000์›) - 0๊ฐœ +5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜ (30,000,000์›) - 0๊ฐœ +6๊ฐœ ์ผ์น˜ (2,000,000,000์›) - 0๊ฐœ +์ด ์ˆ˜์ต๋ฅ ์€ 62.5%์ž…๋‹ˆ๋‹ค. +``` + +## ๐ŸŽฏ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ + +- JDK 17 ๋ฒ„์ „์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. JDK 17์—์„œ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ 0์  ์ฒ˜๋ฆฌํ•œ๋‹ค. +- ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์˜ ์‹œ์ž‘์ ์€ `Application`์˜ `main()`์ด๋‹ค. +- `build.gradle` ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ณ , ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. +- Java ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ๊ฐ€์ด๋“œ๋ฅผ ์ค€์ˆ˜ํ•˜๋ฉฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•œ๋‹ค. +- ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ `System.exit()`๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค. +- ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„์ด ์™„๋ฃŒ๋˜๋ฉด `ApplicationTest`์˜ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ์„ฑ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•  ๊ฒฝ์šฐ 0์  ์ฒ˜๋ฆฌํ•œ๋‹ค. +- ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ์—์„œ ๋‹ฌ๋ฆฌ ๋ช…์‹œํ•˜์ง€ ์•Š๋Š” ํ•œ ํŒŒ์ผ, ํŒจํ‚ค์ง€ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ด๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. +- indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ 3์ด ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. 2๊นŒ์ง€๋งŒ ํ—ˆ์šฉํ•œ๋‹ค. +- ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์„œ๋“œ)์˜ ๊ธธ์ด๊ฐ€ 15๋ผ์ธ์„ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. +- `else` ์˜ˆ์•ฝ์–ด๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. +- Java Enum์„ ์ ์šฉํ•œ๋‹ค. +- ๋„๋ฉ”์ธ ๋กœ์ง์— ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, UI(`System.out`, `System.in`, `Scanner`) ๋กœ์ง์€ ์ œ์™ธํ•œ๋‹ค. +- ํ•ต์‹ฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ์™€ UI๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋กœ์ง์„ ๋ถ„๋ฆฌํ•ด ๊ตฌํ˜„ํ•œ๋‹ค. + +## ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ + +- `camp.nextstep.edu.missionutils`์—์„œ ์ œ๊ณตํ•˜๋Š” `Randoms` ๋ฐ `Console` API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. + +List numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6); + +## Lotto ํด๋ž˜์Šค + +์ œ๊ณต๋œ `Lotto` ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•ด ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. + +- `numbers`์˜ ์ ‘๊ทผ ์ œ์–ด์ž์ธ `private`์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค. +- `Lotto`์— ํ•„๋“œ(์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜)๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋‹ค. +- `Lotto`์˜ ํŒจํ‚ค์ง€ ๋ณ€๊ฒฝ์€ ๊ฐ€๋Šฅํ•˜๋‹ค. + +```java +public class Lotto { + private final List numbers; + + public Lotto(List numbers) { + validate(numbers); + this.numbers = numbers; + } + + private void validate(List numbers) { + if (numbers.size() != 6) { + throw new IllegalArgumentException(); + } + } + + // TODO: ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ +} + From 16bc3ee5c2f3380dc6274a8353d3efb9097dd8f9 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:31:14 +0900 Subject: [PATCH 02/20] =?UTF-8?q?feat(view):=20inputview=20=EB=B0=8F=20out?= =?UTF-8?q?putview=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `InputView`: ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์‹œ ํ•œ ์ค„ ๋„์šฐ๊ธฐ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€๋…์„ฑ ๊ฐœ์„  - ๊ตฌ์ž… ๊ธˆ์•ก, ๋‹น์ฒจ ๋ฒˆํ˜ธ, ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ž…๋ ฅ ํ›„ ๊ฐœํ–‰ ์ถ”๊ฐ€ - `OutputView`: ๋‹น์ฒจ ๊ฒฐ๊ณผ ์ถœ๋ ฅ ํ˜•์‹ ์กฐ์ • - ๋‹น์ฒจ ๊ธˆ์•ก์„ ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ๋กœ ์ถœ๋ ฅํ•˜๋„๋ก ๊ฐœ์„  - ๋‹น์ฒจ ํ†ต๊ณ„ ์ถœ๋ ฅ ํ›„ ํ•œ ์ค„ ๋„์šฐ๊ธฐ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ --- src/main/java/lotto/view/InputView.java | 49 ++++++++++++++++++++++++ src/main/java/lotto/view/OutputView.java | 36 +++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 src/main/java/lotto/view/InputView.java create mode 100644 src/main/java/lotto/view/OutputView.java diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java new file mode 100644 index 0000000..76f4c95 --- /dev/null +++ b/src/main/java/lotto/view/InputView.java @@ -0,0 +1,49 @@ +package lotto.view; + +import camp.nextstep.edu.missionutils.Console; +import lotto.validator.InputValidator; +import lotto.validator.LottoValidator; + +import java.util.List; + +public class InputView { + public int readPurchaseAmount() { + while (true) { + try { + System.out.println("๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + int amount = InputValidator.validatePurchaseAmount(Console.readLine()); + System.out.println(); + return amount; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + public List readWinningNumbers() { + while (true) { + try { + System.out.println("๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + List numbers = InputValidator.validateLottoNumbers(Console.readLine()); + LottoValidator.validateLottoNumbers(numbers); + System.out.println(); + return numbers; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + public int readBonusNumber(List winningNumbers) { + while (true) { + try { + System.out.println("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + int bonusNumber = InputValidator.validateBonusNumber(Console.readLine()); + LottoValidator.validateBonusNumber(bonusNumber, winningNumbers); + return bonusNumber; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } +} diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java new file mode 100644 index 0000000..810e5cc --- /dev/null +++ b/src/main/java/lotto/view/OutputView.java @@ -0,0 +1,36 @@ +package lotto.view; + +import lotto.model.dto.LottoResultDto; +import lotto.model.entity.LottoTicket; +import lotto.enums.LottoRank; + +import java.text.NumberFormat; +import java.util.Locale; + +public class OutputView { + private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.KOREA); // โœ… ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ถ”๊ฐ€ + + public void printLottoTickets(LottoTicket lottoTicket) { + System.out.printf("%d๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.%n", lottoTicket.getTickets().size()); + lottoTicket.getTickets().forEach(lotto -> System.out.println(lotto.getNumbers())); + System.out.println(); // โœ… ๊ตฌ๋งคํ•œ ๋กœ๋˜ ์ถœ๋ ฅ ํ›„ ๊ฐœํ–‰ + } + + public void printResults(LottoResultDto result, int purchaseAmount) { + System.out.println("๋‹น์ฒจ ํ†ต๊ณ„"); + System.out.println("---"); + + for (LottoRank rank : LottoRank.values()) { + if (rank == LottoRank.NONE) continue; // NONE ๋“ฑ์ˆ˜๋Š” ์ถœ๋ ฅ ์•ˆ ํ•จ + + System.out.printf("%d๊ฐœ ์ผ์น˜%s (%s์›) - %d๊ฐœ%n", + rank.getMatchCount(), + rank == LottoRank.SECOND ? ", ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜" : "", + numberFormat.format(rank.getPrize()), // โœ… ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ถ”๊ฐ€ + result.resultMap().getOrDefault(rank, 0)); + } + + System.out.println(); // โœ… ๋‹น์ฒจ ํ†ต๊ณ„ ์ถœ๋ ฅ ํ›„ ๊ฐœํ–‰ + System.out.printf("์ด ์ˆ˜์ต๋ฅ ์€ %.1f%%์ž…๋‹ˆ๋‹ค.%n", result.getProfitRate(purchaseAmount)); + } +} From fc805fbf4f2237e65025ea713cd54d26619844a2 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:32:36 +0900 Subject: [PATCH 03/20] =?UTF-8?q?feat(controller):=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=20=ED=9D=90=EB=A6=84=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoController`: ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›์•„ ๊ฒŒ์ž„์„ ์ง„ํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ - `LottoService`๋ฅผ ํ†ตํ•ด ๋กœ๋˜ ๋ฒˆํ˜ธ ์ƒ์„ฑ ๋ฐ ๋‹น์ฒจ ๊ฒฐ๊ณผ ๊ณ„์‚ฐ - UI ๋กœ์ง์„ ์ตœ์†Œํ™”ํ•˜์—ฌ ์„œ๋น„์Šค ๊ณ„์ธต๊ณผ ๋ถ„๋ฆฌ --- .../lotto/controller/LottoController.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/lotto/controller/LottoController.java diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java new file mode 100644 index 0000000..65e5028 --- /dev/null +++ b/src/main/java/lotto/controller/LottoController.java @@ -0,0 +1,38 @@ +package lotto.controller; + +import java.util.List; +import lotto.model.dto.LottoResultDto; +import lotto.model.entity.LottoTicket; +import lotto.model.entity.WinningLotto; +import lotto.service.LottoService; +import lotto.view.InputView; +import lotto.view.OutputView; + +public class LottoController { + private final LottoService lottoService; + private final InputView inputView; + private final OutputView outputView; + + public LottoController(LottoService lottoService, InputView inputView, OutputView outputView) { + this.lottoService = lottoService; + this.inputView = inputView; + this.outputView = outputView; + } + + public void startGame() { + int purchaseAmount = inputView.readPurchaseAmount(); + LottoTicket lottoTicket = lottoService.purchaseLottoTickets(purchaseAmount); + outputView.printLottoTickets(lottoTicket); + + WinningLotto winningLotto = getWinningLotto(); + LottoResultDto result = lottoService.calculateResults(lottoTicket, winningLotto); + outputView.printResults(result, purchaseAmount); + } + + private WinningLotto getWinningLotto() { + List winningNumbers = inputView.readWinningNumbers(); // ๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ + int bonusNumber = inputView.readBonusNumber(winningNumbers); // ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ๋„˜๊ฒจ์คŒ + return new WinningLotto(winningNumbers, bonusNumber); + } + +} From 46963f5d734112cdf01fc55bfd07448028289362 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:33:06 +0900 Subject: [PATCH 04/20] =?UTF-8?q?feat(service):=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B0=8F=20=EB=A1=9C=EB=98=90=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=83=9D=EC=84=B1=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoService`: ๊ฒŒ์ž„ ์ง„ํ–‰์„ ์œ„ํ•œ ํ•ต์‹ฌ ๋กœ์ง ๊ตฌํ˜„ - ๊ตฌ์ž… ๊ธˆ์•ก์— ๋งž์ถฐ ๋กœ๋˜ ํ‹ฐ์ผ“ ์ƒ์„ฑ - ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋น„๊ตํ•˜์—ฌ ๊ฒฐ๊ณผ ๊ณ„์‚ฐ - UI ๋กœ์ง์„ ์ œ๊ฑฐํ•˜๊ณ  ์ˆœ์ˆ˜ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์œผ๋กœ ๋ถ„๋ฆฌ --- src/main/java/lotto/service/LottoService.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/lotto/service/LottoService.java diff --git a/src/main/java/lotto/service/LottoService.java b/src/main/java/lotto/service/LottoService.java new file mode 100644 index 0000000..d25e8b6 --- /dev/null +++ b/src/main/java/lotto/service/LottoService.java @@ -0,0 +1,25 @@ +package lotto.service; + +import lotto.enums.LottoPrice; +import lotto.model.dto.LottoResultDto; +import lotto.model.entity.LottoTicket; +import lotto.model.entity.WinningLotto; +import lotto.utils.LottoResultCalculator; + +public class LottoService { + public LottoTicket purchaseLottoTickets(int purchaseAmount) { + validatePurchaseAmount(purchaseAmount); + int ticketCount = purchaseAmount / LottoPrice.PRICE_PER_TICKET.getPrice(); + return new LottoTicket(ticketCount); + } + + private void validatePurchaseAmount(int purchaseAmount) { + if (purchaseAmount <= 0 || purchaseAmount % LottoPrice.PRICE_PER_TICKET.getPrice() != 0) { + throw new IllegalArgumentException("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public LottoResultDto calculateResults(LottoTicket lottoTicket, WinningLotto winningLotto) { + return LottoResultCalculator.calculateResults(lottoTicket, winningLotto); + } +} From 69e8af236d07d5a16fd19796a5b547be8bf84051 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:33:46 +0900 Subject: [PATCH 05/20] =?UTF-8?q?feat(entity):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8B=B9=EC=B2=A8=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoTicket`: ๋กœ๋˜ ํ‹ฐ์ผ“ ๊ฐ์ฒด๋กœ ์ƒ์„ฑ ํ›„ ๊ด€๋ฆฌ - ๋žœ๋ค์œผ๋กœ 6๊ฐœ์˜ ์ˆซ์ž๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Lotto ๊ฐ์ฒด๋กœ ์ €์žฅ - `WinningLotto`: ๋‹น์ฒจ ๋ฒˆํ˜ธ ๋ฐ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ๊ฒ€์ฆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ - LottoValidator๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ฆ ํ›„ ์ €์žฅ - ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๊ฐ€ ์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก ์ฒดํฌ --- src/main/java/lotto/Lotto.java | 20 ------------ src/main/java/lotto/model/entity/Lotto.java | 26 +++++++++++++++ .../java/lotto/model/entity/LottoTicket.java | 28 ++++++++++++++++ .../java/lotto/model/entity/WinningLotto.java | 32 +++++++++++++++++++ 4 files changed, 86 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/lotto/Lotto.java create mode 100644 src/main/java/lotto/model/entity/Lotto.java create mode 100644 src/main/java/lotto/model/entity/LottoTicket.java create mode 100644 src/main/java/lotto/model/entity/WinningLotto.java diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java deleted file mode 100644 index 88fc5cf..0000000 --- a/src/main/java/lotto/Lotto.java +++ /dev/null @@ -1,20 +0,0 @@ -package lotto; - -import java.util.List; - -public class Lotto { - private final List numbers; - - public Lotto(List numbers) { - validate(numbers); - this.numbers = numbers; - } - - private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - } - - // TODO: ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ -} diff --git a/src/main/java/lotto/model/entity/Lotto.java b/src/main/java/lotto/model/entity/Lotto.java new file mode 100644 index 0000000..886c3d0 --- /dev/null +++ b/src/main/java/lotto/model/entity/Lotto.java @@ -0,0 +1,26 @@ +package lotto.model.entity; + +import java.util.HashSet; +import java.util.List; + +public class Lotto { + private final List numbers; + + public Lotto(List numbers) { + validate(numbers); + this.numbers = List.copyOf(numbers); // ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + } + + private void validate(List numbers) { + if (numbers.size() != 6 || new HashSet<>(numbers).size() != 6) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + if (numbers.stream().anyMatch(num -> num < 1 || num > 45)) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1๋ถ€ํ„ฐ 45 ์‚ฌ์ด์˜ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public List getNumbers() { + return numbers; + } +} diff --git a/src/main/java/lotto/model/entity/LottoTicket.java b/src/main/java/lotto/model/entity/LottoTicket.java new file mode 100644 index 0000000..e07b50d --- /dev/null +++ b/src/main/java/lotto/model/entity/LottoTicket.java @@ -0,0 +1,28 @@ +package lotto.model.entity; + +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Collectors; + +public class LottoTicket { + private final List tickets; + + public LottoTicket(int count) { + this.tickets = IntStream.range(0, count) + .mapToObj(i -> generateLotto()) + .collect(Collectors.toList()); // โœ… Immutable List ๋Œ€์‹  ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ List ์‚ฌ์šฉ + } + + private Lotto generateLotto() { + List numbers = new ArrayList<>(Randoms.pickUniqueNumbersInRange(1, 45, 6)); // โœ… ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ List๋กœ ๋ณ€ํ™˜ + Collections.sort(numbers); + return new Lotto(numbers); + } + + public List getTickets() { + return tickets; + } +} diff --git a/src/main/java/lotto/model/entity/WinningLotto.java b/src/main/java/lotto/model/entity/WinningLotto.java new file mode 100644 index 0000000..36b4ed4 --- /dev/null +++ b/src/main/java/lotto/model/entity/WinningLotto.java @@ -0,0 +1,32 @@ +package lotto.model.entity; + + +import java.util.List; +import java.util.Set; +import lotto.validator.LottoValidator; + + +public class WinningLotto { + private final Set winningNumbers; + private final int bonusNumber; + + public WinningLotto(List numbers, int bonusNumber) { + LottoValidator.validateLottoNumbers(numbers); // ๋กœ๋˜ ๋ฒˆํ˜ธ ๊ฒ€์ฆ + this.winningNumbers = Set.copyOf(numbers); + + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + this.bonusNumber = bonusNumber; + } + + public int countMatchingNumbers(Lotto lotto) { + return (int) lotto.getNumbers().stream() + .filter(winningNumbers::contains) + .count(); + } + + public boolean hasBonusNumber(Lotto lotto) { + return winningNumbers.contains(bonusNumber); + } +} From 096c11cf99a9085cd85de99e3219bdc7d5a547b1 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:34:42 +0900 Subject: [PATCH 06/20] =?UTF-8?q?feat(validator):=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoValidator`: ๋กœ๋˜ ๋ฒˆํ˜ธ ๊ฒ€์ฆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ - 1~45 ๋ฒ”์œ„์˜ ์ˆซ์ž 6๊ฐœ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ - ์ค‘๋ณต๋œ ์ˆซ์ž๊ฐ€ ์—†๋Š”์ง€ ๊ฒ€์ฆ - `InputValidator`: ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ - ๊ตฌ์ž… ๊ธˆ์•ก์ด 1000์› ๋‹จ์œ„์ธ์ง€ ํ™•์ธ - ์ˆซ์ž๊ฐ€ ์•„๋‹Œ ๊ฐ’ ์ž…๋ ฅ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ - ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๊ฐ€ ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๊ฒน์น˜์ง€ ์•Š๋„๋ก ๊ฒ€์ฆ --- .../java/lotto/validator/InputValidator.java | 38 +++++++++++++++++++ .../java/lotto/validator/LottoValidator.java | 28 ++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/main/java/lotto/validator/InputValidator.java create mode 100644 src/main/java/lotto/validator/LottoValidator.java diff --git a/src/main/java/lotto/validator/InputValidator.java b/src/main/java/lotto/validator/InputValidator.java new file mode 100644 index 0000000..6d05613 --- /dev/null +++ b/src/main/java/lotto/validator/InputValidator.java @@ -0,0 +1,38 @@ +package lotto.validator; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class InputValidator { + public static int validatePurchaseAmount(String input) { + try { + int amount = Integer.parseInt(input.trim()); + if (amount <= 0 || amount % 1000 != 0) { + throw new IllegalArgumentException("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + return amount; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("[ERROR] ์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); + } + } + + public static List validateLottoNumbers(String input) { + try { + return Arrays.stream(input.split(",")) + .map(String::trim) + .map(Integer::parseInt) + .collect(Collectors.toList()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public static int validateBonusNumber(String input) { + try { + return Integer.parseInt(input.trim()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } +} diff --git a/src/main/java/lotto/validator/LottoValidator.java b/src/main/java/lotto/validator/LottoValidator.java new file mode 100644 index 0000000..c50736f --- /dev/null +++ b/src/main/java/lotto/validator/LottoValidator.java @@ -0,0 +1,28 @@ +package lotto.validator; + +import java.util.HashSet; +import java.util.List; + +public class LottoValidator { + private static final int LOTTO_SIZE = 6; + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + + public static void validateLottoNumbers(List numbers) { + if (numbers.size() != LOTTO_SIZE || new HashSet<>(numbers).size() != LOTTO_SIZE) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + if (numbers.stream().anyMatch(n -> n < MIN_NUMBER || n > MAX_NUMBER)) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public static void validateBonusNumber(int bonusNumber, List winningNumbers) { + if (bonusNumber < MIN_NUMBER || bonusNumber > MAX_NUMBER) { + throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } +} From da703b7831e0c61d8644309db9a901dafb3eca39 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:35:16 +0900 Subject: [PATCH 07/20] =?UTF-8?q?feat(enums):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=93=B1=EC=88=98=20=ED=8C=90=EB=B3=84=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoRank`: ๋‹น์ฒจ ๊ฐœ์ˆ˜ ๋ฐ ๋ณด๋„ˆ์Šค ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋“ฑ์ˆ˜ ๊ฒฐ์ • - 6๊ฐœ ์ผ์น˜ โ†’ 1๋“ฑ, 5๊ฐœ+๋ณด๋„ˆ์Šค โ†’ 2๋“ฑ, 5๊ฐœ ์ผ์น˜ โ†’ 3๋“ฑ ๋“ฑ - `findRank()`๋ฅผ ํ†ตํ•ด ์ ์ ˆํ•œ ๋“ฑ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ - ๋‹น์ฒจ ๊ธˆ์•ก์„ ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ๋กœ ์ถœ๋ ฅํ•˜๋„๋ก ๊ฐœ์„  --- src/main/java/lotto/enums/LottoPrice.java | 15 ++++++++ src/main/java/lotto/enums/LottoRank.java | 42 +++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/main/java/lotto/enums/LottoPrice.java create mode 100644 src/main/java/lotto/enums/LottoRank.java diff --git a/src/main/java/lotto/enums/LottoPrice.java b/src/main/java/lotto/enums/LottoPrice.java new file mode 100644 index 0000000..2dfb087 --- /dev/null +++ b/src/main/java/lotto/enums/LottoPrice.java @@ -0,0 +1,15 @@ +package lotto.enums; + +public enum LottoPrice { + PRICE_PER_TICKET(1000); + + private final int price; + + LottoPrice(int price) { + this.price = price; + } + + public int getPrice() { + return price; + } +} diff --git a/src/main/java/lotto/enums/LottoRank.java b/src/main/java/lotto/enums/LottoRank.java new file mode 100644 index 0000000..c367e0b --- /dev/null +++ b/src/main/java/lotto/enums/LottoRank.java @@ -0,0 +1,42 @@ +package lotto.enums; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public enum LottoRank { + FIRST(6, false, 2_000_000_000), + SECOND(5, true, 30_000_000), + THIRD(5, false, 1_500_000), + FOURTH(4, false, 50_000), + FIFTH(3, false, 5_000), + NONE(0, false, 0); + + private final int matchCount; + private final boolean requiresBonus; + private final int prize; + private static final Map RANK_MAP = Arrays.stream(values()) + .filter(rank -> !rank.requiresBonus) + .collect(Collectors.toMap(LottoRank::getMatchCount, rank -> rank)); + + LottoRank(int matchCount, boolean requiresBonus, int prize) { + this.matchCount = matchCount; + this.requiresBonus = requiresBonus; + this.prize = prize; + } + + public int getPrize() { + return prize; + } + + public int getMatchCount() { + return matchCount; + } + + public static LottoRank findRank(int matchCount, boolean hasBonus) { + if (hasBonus && matchCount == 5) { + return SECOND; + } + return RANK_MAP.getOrDefault(matchCount, NONE); + } +} From 910f32fcbf9f90e603a910d8c89397883f7defac Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:37:34 +0900 Subject: [PATCH 08/20] =?UTF-8?q?feat(util):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EA=B3=84=EC=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoResultCalculator`: ๋กœ๋˜ ๋‹น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์ถ”๊ฐ€ - `WinningLotto`์™€ ๋น„๊ตํ•˜์—ฌ ๋‹น์ฒจ ๋“ฑ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ `LottoResultDto`๋กœ ๋ฐ˜ํ™˜ - `EnumMap`์„ ์‚ฌ์šฉํ•˜์—ฌ `LottoRank`๋ณ„ ๋‹น์ฒจ ๊ฐœ์ˆ˜๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅ - `NumberUtil`: ์ด ์ˆ˜์ต๋ฅ ์„ ์†Œ์ˆ˜์  ๋‘˜์งธ ์ž๋ฆฌ์—์„œ ๋ฐ˜์˜ฌ๋ฆผํ•˜๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€ - `BigDecimal`์„ ํ™œ์šฉํ•˜์—ฌ ๋ฐ˜์˜ฌ๋ฆผ ์ •ํ™•๋„๋ฅผ ๋ณด์žฅ --- .../lotto/utils/LottoResultCalculator.java | 20 +++++++++++++++++++ src/main/java/lotto/utils/NumberUtil.java | 12 +++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/main/java/lotto/utils/LottoResultCalculator.java create mode 100644 src/main/java/lotto/utils/NumberUtil.java diff --git a/src/main/java/lotto/utils/LottoResultCalculator.java b/src/main/java/lotto/utils/LottoResultCalculator.java new file mode 100644 index 0000000..50adb21 --- /dev/null +++ b/src/main/java/lotto/utils/LottoResultCalculator.java @@ -0,0 +1,20 @@ +package lotto.utils; + +import lotto.enums.LottoRank; +import lotto.model.dto.LottoResultDto; +import lotto.model.entity.LottoTicket; +import lotto.model.entity.WinningLotto; + +import java.util.EnumMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class LottoResultCalculator { + public static LottoResultDto calculateResults(LottoTicket lottoTicket, WinningLotto winningLotto) { + Map results = lottoTicket.getTickets().stream() + .map(ticket -> LottoRank.findRank(winningLotto.countMatchingNumbers(ticket), winningLotto.hasBonusNumber(ticket))) + .collect(Collectors.groupingBy(rank -> rank, () -> new EnumMap<>(LottoRank.class), Collectors.summingInt(e -> 1))); + + return new LottoResultDto(results); + } +} diff --git a/src/main/java/lotto/utils/NumberUtil.java b/src/main/java/lotto/utils/NumberUtil.java new file mode 100644 index 0000000..af65b84 --- /dev/null +++ b/src/main/java/lotto/utils/NumberUtil.java @@ -0,0 +1,12 @@ +package lotto.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class NumberUtil { + public static double roundToTwoDecimalPlaces(double value) { + return new BigDecimal(value) + .setScale(2, RoundingMode.HALF_UP) + .doubleValue(); + } +} From 31ec78e38ef45f547bad01f755eb63456f5f5223 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:38:21 +0900 Subject: [PATCH 09/20] =?UTF-8?q?feat(dto):=20=EB=8B=B9=EC=B2=A8=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EA=B5=AC=EC=A1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LottoResultDto`: ๋‹น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ˆ˜์ต๋ฅ ์„ ๊ณ„์‚ฐํ•˜๋Š” DTO ๊ตฌํ˜„ - EnumMap์„ ์‚ฌ์šฉํ•˜์—ฌ `LottoRank`๋ณ„ ๋‹น์ฒจ ํšŸ์ˆ˜๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅ - ์ด ์ƒ๊ธˆ์„ ๊ณ„์‚ฐํ•˜์—ฌ ์ˆ˜์ต๋ฅ ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€ - UI์™€์˜ ์˜์กด์„ฑ์„ ์ค„์ด๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ --- .../java/lotto/model/dto/LottoResultDto.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/lotto/model/dto/LottoResultDto.java diff --git a/src/main/java/lotto/model/dto/LottoResultDto.java b/src/main/java/lotto/model/dto/LottoResultDto.java new file mode 100644 index 0000000..7eb9eeb --- /dev/null +++ b/src/main/java/lotto/model/dto/LottoResultDto.java @@ -0,0 +1,21 @@ +package lotto.model.dto; + +import java.util.EnumMap; +import java.util.Map; +import lotto.enums.LottoRank; +import lotto.utils.NumberUtil; + +public record LottoResultDto(Map resultMap) { + public LottoResultDto(Map resultMap) { + this.resultMap = new EnumMap<>(resultMap); + } + + public double getProfitRate(int purchaseAmount) { + int totalPrize = resultMap.entrySet().stream() + .mapToInt(entry -> entry.getKey().getPrize() * entry.getValue()) + .sum(); + + double profitRate = (double) totalPrize / purchaseAmount * 100; + return NumberUtil.roundToTwoDecimalPlaces(profitRate); + } +} \ No newline at end of file From 43a22da3cd994f60c0e6928fe2ecb96143961d73 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:39:06 +0900 Subject: [PATCH 10/20] =?UTF-8?q?chore(config):=20AppConfig=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DI ์ ์šฉ ๋ฐ ์˜์กด์„ฑ ์ฃผ์ž… --- src/main/java/lotto/Application.java | 6 ++++-- src/main/java/lotto/config/AppConfig.java | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/main/java/lotto/config/AppConfig.java diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922..26ccfb9 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,9 @@ package lotto; +import lotto.config.AppConfig; + public class Application { public static void main(String[] args) { - // TODO: ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„ + AppConfig.getLottoController().startGame(); } -} +} \ No newline at end of file diff --git a/src/main/java/lotto/config/AppConfig.java b/src/main/java/lotto/config/AppConfig.java new file mode 100644 index 0000000..80ef6f4 --- /dev/null +++ b/src/main/java/lotto/config/AppConfig.java @@ -0,0 +1,19 @@ +package lotto.config; + +import lotto.controller.LottoController; +import lotto.service.LottoService; +import lotto.view.InputView; +import lotto.view.OutputView; + +public class AppConfig { + private static final InputView INPUT_VIEW = new InputView(); + private static final OutputView OUTPUT_VIEW = new OutputView(); + private static final LottoService LOTTO_SERVICE = new LottoService(); + + private static final LottoController LOTTO_CONTROLLER = + new LottoController(LOTTO_SERVICE, INPUT_VIEW, OUTPUT_VIEW); + + public static LottoController getLottoController() { + return LOTTO_CONTROLLER; + } +} From 2264b6557befe495649bddf98562adc895d26ef5 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:39:36 +0900 Subject: [PATCH 11/20] =?UTF-8?q?feat(test):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoTest.java | 1 + src/test/java/lotto/enums/LottoRankTest.java | 17 ++++++ .../java/lotto/service/LottoServiceTest.java | 59 +++++++++++++++++++ .../lotto/validator/LottoValidatorTest.java | 41 +++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 src/test/java/lotto/enums/LottoRankTest.java create mode 100644 src/test/java/lotto/service/LottoServiceTest.java create mode 100644 src/test/java/lotto/validator/LottoValidatorTest.java diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 309f4e5..6d8e4a0 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -1,5 +1,6 @@ package lotto; +import lotto.model.entity.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/lotto/enums/LottoRankTest.java b/src/test/java/lotto/enums/LottoRankTest.java new file mode 100644 index 0000000..684cc8e --- /dev/null +++ b/src/test/java/lotto/enums/LottoRankTest.java @@ -0,0 +1,17 @@ +package lotto.enums; + +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +class LottoRankTest { + + @Test + void ๋‹น์ฒจ_๋“ฑ์ˆ˜_์ฐพ๊ธฐ_ํ…Œ์ŠคํŠธ() { + assertThat(LottoRank.findRank(6, false)).isEqualTo(LottoRank.FIRST); + assertThat(LottoRank.findRank(5, true)).isEqualTo(LottoRank.SECOND); + assertThat(LottoRank.findRank(5, false)).isEqualTo(LottoRank.THIRD); + assertThat(LottoRank.findRank(4, false)).isEqualTo(LottoRank.FOURTH); + assertThat(LottoRank.findRank(3, false)).isEqualTo(LottoRank.FIFTH); + assertThat(LottoRank.findRank(2, false)).isEqualTo(LottoRank.NONE); + } +} diff --git a/src/test/java/lotto/service/LottoServiceTest.java b/src/test/java/lotto/service/LottoServiceTest.java new file mode 100644 index 0000000..5266c3e --- /dev/null +++ b/src/test/java/lotto/service/LottoServiceTest.java @@ -0,0 +1,59 @@ +package lotto.service; + +import lotto.model.dto.LottoResultDto; +import lotto.model.entity.Lotto; +import lotto.model.entity.LottoTicket; +import lotto.model.entity.WinningLotto; +import lotto.enums.LottoRank; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class LottoServiceTest { + private LottoService lottoService; + + @BeforeEach + void setUp() { + lottoService = new LottoService(); + } + + @Test + void ๋กœ๋˜_ํ‹ฐ์ผ“_๊ตฌ๋งค_ํ…Œ์ŠคํŠธ() { + // given + int purchaseAmount = 5000; // 1000์› ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด 5๊ฐœ ๊ตฌ๋งค + + // when + LottoTicket lottoTicket = lottoService.purchaseLottoTickets(purchaseAmount); + + // then + assertThat(lottoTicket.getTickets()).hasSize(5); + } + + @Test + void ๋กœ๋˜_๊ฒฐ๊ณผ_๊ณ„์‚ฐ_ํ…Œ์ŠคํŠธ() { + // given + LottoTicket lottoTicket = new LottoTicket(2); // 2๊ฐœ์˜ ๋กœ๋˜ ํ‹ฐ์ผ“ ์ƒ์„ฑ + List tickets = List.of( + new Lotto(List.of(1, 2, 3, 4, 5, 6)), // ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋™์ผํ•œ ๋กœ๋˜ + new Lotto(List.of(10, 11, 12, 13, 14, 15)) // ๋‹น์ฒจ๋˜์ง€ ์•Š๋Š” ๋กœ๋˜ + ); + + // LottoTicket ๋‚ด๋ถ€์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ต์ฒดํ•˜์—ฌ ํ…Œ์ŠคํŠธ์— ๋งž์ถค + lottoTicket.getTickets().clear(); + lottoTicket.getTickets().addAll(tickets); + + WinningLotto winningLotto = new WinningLotto(List.of(1, 2, 3, 4, 5, 6), 7); + + // when + LottoResultDto getResultDto = lottoService.calculateResults(lottoTicket, winningLotto); + + // then + Map resultMap = getResultDto.resultMap(); + assertThat(resultMap.get(LottoRank.FIRST)).isEqualTo(1); // ์ฒซ ๋ฒˆ์งธ ๋กœ๋˜๊ฐ€ 6๊ฐœ ์ผ์น˜ + assertThat(resultMap.get(LottoRank.NONE)).isEqualTo(1); // ๋‘ ๋ฒˆ์งธ ๋กœ๋˜๋Š” ๋‹น์ฒจ๋˜์ง€ ์•Š์Œ + } +} diff --git a/src/test/java/lotto/validator/LottoValidatorTest.java b/src/test/java/lotto/validator/LottoValidatorTest.java new file mode 100644 index 0000000..abebd87 --- /dev/null +++ b/src/test/java/lotto/validator/LottoValidatorTest.java @@ -0,0 +1,41 @@ +package lotto.validator; + +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; + +class LottoValidatorTest { + + @Test + void ๋กœ๋˜_๋ฒˆํ˜ธ_์œ ํšจ์„ฑ_๊ฒ€์‚ฌ_์ •์ƒ() { + // given + List validNumbers = List.of(1, 2, 3, 4, 5, 6); + + // when & then (์˜ˆ์™ธ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์•ผ ํ•จ) + LottoValidator.validateLottoNumbers(validNumbers); + } + + @Test + void ๋กœ๋˜_๋ฒˆํ˜ธ_๊ฐœ์ˆ˜_์˜ค๋ฅ˜() { + // given + List invalidNumbers = List.of(1, 2, 3, 4, 5); // 5๊ฐœ๋งŒ ์žˆ์Œ + + // when & then + assertThatThrownBy(() -> LottoValidator.validateLottoNumbers(invalidNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + void ๋ณด๋„ˆ์Šค_๋ฒˆํ˜ธ_์ค‘๋ณต_์˜ค๋ฅ˜() { + // given + List winningNumbers = List.of(1, 2, 3, 4, 5, 6); + int duplicateBonusNumber = 3; // ๋‹น์ฒจ ๋ฒˆํ˜ธ์— ํฌํ•จ๋จ + + // when & then + assertThatThrownBy(() -> LottoValidator.validateBonusNumber(duplicateBonusNumber, winningNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } +} \ No newline at end of file From d8c7f00c4adbef4e824bb4f11b217ec70613ea05 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:53:07 +0900 Subject: [PATCH 12/20] =?UTF-8?q?fix(view):=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `OutputView`: ๋‹น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๋‚ฎ์€ ๋“ฑ์ˆ˜(3๊ฐœ ์ผ์น˜)๋ถ€ํ„ฐ ๋†’์€ ๋“ฑ์ˆ˜(6๊ฐœ ์ผ์น˜) ์ˆœ์œผ๋กœ ์ถœ๋ ฅํ•˜๋„๋ก ๋ณ€๊ฒฝ - ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฐœ์„ : Indent depth 2 ์ดํ•˜ ์œ ์ง€ ๋ฐ ๋ฉ”์„œ๋“œ ๊ธธ์ด 15์ค„ ์ดํ•˜๋กœ ์ œํ•œ - `formatLottoRank()` ๋ฉ”์„œ๋“œ ๋ถ„๋ฆฌํ•˜์—ฌ ์ถœ๋ ฅ ์ฝ”๋“œ ๋‹จ์ˆœํ™” - `printResults()`์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๋˜ ๋“ฑ์ˆ˜ ์ •๋ ฌ ๋ฐ ์ถœ๋ ฅ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ€๋…์„ฑ ๊ฐœ์„  --- src/main/java/lotto/view/InputView.java | 1 + src/main/java/lotto/view/OutputView.java | 34 +++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java index 76f4c95..14a2150 100644 --- a/src/main/java/lotto/view/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -40,6 +40,7 @@ public int readBonusNumber(List winningNumbers) { System.out.println("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); int bonusNumber = InputValidator.validateBonusNumber(Console.readLine()); LottoValidator.validateBonusNumber(bonusNumber, winningNumbers); + System.out.println(); return bonusNumber; } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java index 810e5cc..ec8d09b 100644 --- a/src/main/java/lotto/view/OutputView.java +++ b/src/main/java/lotto/view/OutputView.java @@ -1,36 +1,40 @@ package lotto.view; +import java.util.Comparator; import lotto.model.dto.LottoResultDto; -import lotto.model.entity.LottoTicket; import lotto.enums.LottoRank; +import lotto.model.entity.LottoTicket; import java.text.NumberFormat; +import java.util.Arrays; import java.util.Locale; +import java.util.stream.Collectors; public class OutputView { - private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.KOREA); // โœ… ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ถ”๊ฐ€ + private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.KOREA); public void printLottoTickets(LottoTicket lottoTicket) { System.out.printf("%d๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.%n", lottoTicket.getTickets().size()); lottoTicket.getTickets().forEach(lotto -> System.out.println(lotto.getNumbers())); - System.out.println(); // โœ… ๊ตฌ๋งคํ•œ ๋กœ๋˜ ์ถœ๋ ฅ ํ›„ ๊ฐœํ–‰ + System.out.println(); } public void printResults(LottoResultDto result, int purchaseAmount) { System.out.println("๋‹น์ฒจ ํ†ต๊ณ„"); System.out.println("---"); - - for (LottoRank rank : LottoRank.values()) { - if (rank == LottoRank.NONE) continue; // NONE ๋“ฑ์ˆ˜๋Š” ์ถœ๋ ฅ ์•ˆ ํ•จ - - System.out.printf("%d๊ฐœ ์ผ์น˜%s (%s์›) - %d๊ฐœ%n", - rank.getMatchCount(), - rank == LottoRank.SECOND ? ", ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜" : "", - numberFormat.format(rank.getPrize()), // โœ… ์ฒœ ๋‹จ์œ„ ์ฝค๋งˆ ์ถ”๊ฐ€ - result.resultMap().getOrDefault(rank, 0)); - } - - System.out.println(); // โœ… ๋‹น์ฒจ ํ†ต๊ณ„ ์ถœ๋ ฅ ํ›„ ๊ฐœํ–‰ + System.out.print(formatLottoRank(result)); System.out.printf("์ด ์ˆ˜์ต๋ฅ ์€ %.1f%%์ž…๋‹ˆ๋‹ค.%n", result.getProfitRate(purchaseAmount)); } + + private String formatLottoRank(LottoResultDto result) { + return Arrays.stream(LottoRank.values()) + .filter(rank -> rank != LottoRank.NONE) + .sorted(Comparator.comparingInt(LottoRank::getMatchCount)) + .map(rank -> String.format("%d๊ฐœ ์ผ์น˜%s (%s์›) - %d๊ฐœ%n", + rank.getMatchCount(), + rank == LottoRank.SECOND ? ", ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜" : "", + numberFormat.format(rank.getPrize()), + result.resultMap().getOrDefault(rank, 0))) + .collect(Collectors.joining()); + } } From f0f7978a7367f9dec88587633eb007e78c4dcbb2 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:22:41 +0900 Subject: [PATCH 13/20] =?UTF-8?q?refactor(view):=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=9E=AC?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `getValidatedInput()` ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ค‘๋ณต๋œ `while (true)` ๋ฐ˜๋ณต ๋กœ์ง ์ œ๊ฑฐ - `InputValidator`์˜ ๊ฒ€์ฆ ๋ฉ”์„œ๋“œ๋ฅผ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•ด ๋™์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋„๋ก ๋ณ€๊ฒฝ --- src/main/java/lotto/view/InputView.java | 51 ++++++++++++------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java index 14a2150..cecff6b 100644 --- a/src/main/java/lotto/view/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -2,49 +2,46 @@ import camp.nextstep.edu.missionutils.Console; import lotto.validator.InputValidator; -import lotto.validator.LottoValidator; import java.util.List; public class InputView { public int readPurchaseAmount() { - while (true) { - try { - System.out.println("๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); - int amount = InputValidator.validatePurchaseAmount(Console.readLine()); - System.out.println(); - return amount; - } catch (IllegalArgumentException e) { - System.out.println(e.getMessage()); - } - } + return getValidatedInput( + "๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + InputValidator::validatePurchaseAmount + ); } public List readWinningNumbers() { - while (true) { - try { - System.out.println("๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); - List numbers = InputValidator.validateLottoNumbers(Console.readLine()); - LottoValidator.validateLottoNumbers(numbers); - System.out.println(); - return numbers; - } catch (IllegalArgumentException e) { - System.out.println(e.getMessage()); - } - } + return getValidatedInput( + "๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + InputValidator::validateWinningNumbers + ); } public int readBonusNumber(List winningNumbers) { + return getValidatedInput( + "๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + input -> InputValidator.validateBonusNumber(input, winningNumbers) + ); + } + + private T getValidatedInput(String message, InputFunction validator) { while (true) { try { - System.out.println("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); - int bonusNumber = InputValidator.validateBonusNumber(Console.readLine()); - LottoValidator.validateBonusNumber(bonusNumber, winningNumbers); + System.out.println(message); + T value = validator.apply(Console.readLine()); System.out.println(); - return bonusNumber; + return value; } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); } } } -} + + @FunctionalInterface + private interface InputFunction { + R apply(T t); + } +} \ No newline at end of file From 9f588a60cf37dc24824cb861189eb9e818ba5759 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:23:09 +0900 Subject: [PATCH 14/20] =?UTF-8?q?refactor(validator):=20=EB=A1=9C=EB=98=90?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B5=9C=EC=A0=81=ED=99=94=20=EB=B0=8F=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `validateNumberRange()` ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฒ”์œ„ ๊ฒ€์ฆ ๋กœ์ง์„ ์ผ๊ด„ ์ฒ˜๋ฆฌ - `parseInteger()` ๋ฐ `parseIntegerList()` ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ผ๊ด„ ์ ์šฉ - `validateBonusNumber()` ๋ฐ `validateWinningNumbers()`์—์„œ ์ค‘๋ณต๋œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ œ๊ฑฐ ๋ฐ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ --- .../java/lotto/validator/InputValidator.java | 64 ++++++++---- .../lotto/validator/InputValidatorTest.java | 99 +++++++++++++++++++ .../lotto/validator/LottoValidatorTest.java | 41 -------- 3 files changed, 145 insertions(+), 59 deletions(-) create mode 100644 src/test/java/lotto/validator/InputValidatorTest.java delete mode 100644 src/test/java/lotto/validator/LottoValidatorTest.java diff --git a/src/main/java/lotto/validator/InputValidator.java b/src/main/java/lotto/validator/InputValidator.java index 6d05613..f6c98d5 100644 --- a/src/main/java/lotto/validator/InputValidator.java +++ b/src/main/java/lotto/validator/InputValidator.java @@ -1,38 +1,66 @@ package lotto.validator; import java.util.Arrays; +import java.util.HashSet; import java.util.List; -import java.util.stream.Collectors; public class InputValidator { + private static final int LOTTO_SIZE = 6; + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + public static int validatePurchaseAmount(String input) { + int amount = parseInteger(input); + if (amount <= 0 || amount % 1000 != 0) { + throw new IllegalArgumentException("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + return amount; + } + + public static List validateWinningNumbers(String input) { + List numbers = parseIntegerList(input); + validateLottoNumbers(numbers); + return numbers; + } + + public static int validateBonusNumber(String input, List winningNumbers) { + int bonusNumber = parseInteger(input); + validateNumberRange(bonusNumber, "[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + return bonusNumber; + } + + private static void validateLottoNumbers(List numbers) { + if (numbers.size() != LOTTO_SIZE || new HashSet<>(numbers).size() != LOTTO_SIZE) { + throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + numbers.forEach(n -> validateNumberRange(n, "[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.")); + } + + private static void validateNumberRange(int number, String errorMessage) { + if (number < MIN_NUMBER || number > MAX_NUMBER) { + throw new IllegalArgumentException(errorMessage); + } + } + + private static int parseInteger(String input) { try { - int amount = Integer.parseInt(input.trim()); - if (amount <= 0 || amount % 1000 != 0) { - throw new IllegalArgumentException("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - return amount; + return Integer.parseInt(input); } catch (NumberFormatException e) { throw new IllegalArgumentException("[ERROR] ์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); } } - public static List validateLottoNumbers(String input) { + private static List parseIntegerList(String input) { try { return Arrays.stream(input.split(",")) .map(String::trim) .map(Integer::parseInt) - .collect(Collectors.toList()); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - } - - public static int validateBonusNumber(String input) { - try { - return Integer.parseInt(input.trim()); + .toList(); } catch (NumberFormatException e) { - throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + throw new IllegalArgumentException("[ERROR] ์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); } } -} +} \ No newline at end of file diff --git a/src/test/java/lotto/validator/InputValidatorTest.java b/src/test/java/lotto/validator/InputValidatorTest.java new file mode 100644 index 0000000..7582d8b --- /dev/null +++ b/src/test/java/lotto/validator/InputValidatorTest.java @@ -0,0 +1,99 @@ +package lotto.validator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +import java.util.List; + +class InputValidatorTest { + + @Test + @DisplayName("์ •์ƒ์ ์ธ ๊ตฌ์ž… ๊ธˆ์•ก ๊ฒ€์ฆ") + void validatePurchaseAmount_valid() { + int amount = InputValidator.validatePurchaseAmount("5000"); + assertThat(amount).isEqualTo(5000); + } + + @Test + @DisplayName("๊ตฌ์ž… ๊ธˆ์•ก์ด 1000์› ๋‹จ์œ„๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validatePurchaseAmount_invalid() { + assertThatThrownBy(() -> InputValidator.validatePurchaseAmount("5500")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("์ˆซ์ž๊ฐ€ ์•„๋‹Œ ๊ฐ’์ด ์ž…๋ ฅ๋  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validatePurchaseAmount_nonNumeric() { + assertThatThrownBy(() -> InputValidator.validatePurchaseAmount("abcd")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); + } + + @Test + @DisplayName("์ •์ƒ์ ์ธ ๋‹น์ฒจ ๋ฒˆํ˜ธ ๊ฒ€์ฆ") + void validateWinningNumbers_valid() { + List numbers = InputValidator.validateWinningNumbers("1,2,3,4,5,6"); + assertThat(numbers).containsExactly(1, 2, 3, 4, 5, 6); + } + + @Test + @DisplayName("๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ 6๊ฐœ๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateWinningNumbers_invalidSize() { + assertThatThrownBy(() -> InputValidator.validateWinningNumbers("1,2,3,4,5")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("์ค‘๋ณต๋œ ๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ ํฌํ•จ๋  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateWinningNumbers_duplicate() { + assertThatThrownBy(() -> InputValidator.validateWinningNumbers("1,2,3,4,5,5")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("1~45 ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ ํฌํ•จ๋  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateWinningNumbers_outOfRange() { + assertThatThrownBy(() -> InputValidator.validateWinningNumbers("1,2,3,4,5,46")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("์ •์ƒ์ ์ธ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ๊ฒ€์ฆ") + void validateBonusNumber_valid() { + List winningNumbers = List.of(1, 2, 3, 4, 5, 6); + int bonusNumber = InputValidator.validateBonusNumber("7", winningNumbers); + assertThat(bonusNumber).isEqualTo(7); + } + + @Test + @DisplayName("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๊ฐ€ ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateBonusNumber_duplicate() { + List winningNumbers = List.of(1, 2, 3, 4, 5, 6); + assertThatThrownBy(() -> InputValidator.validateBonusNumber("5", winningNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๊ฐ€ 1~45 ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateBonusNumber_outOfRange() { + List winningNumbers = List.of(1, 2, 3, 4, 5, 6); + assertThatThrownBy(() -> InputValidator.validateBonusNumber("50", winningNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + @DisplayName("์ˆซ์ž๊ฐ€ ์•„๋‹Œ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ž…๋ ฅ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void validateBonusNumber_nonNumeric() { + List winningNumbers = List.of(1, 2, 3, 4, 5, 6); + assertThatThrownBy(() -> InputValidator.validateBonusNumber("abc", winningNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] ์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/validator/LottoValidatorTest.java b/src/test/java/lotto/validator/LottoValidatorTest.java deleted file mode 100644 index abebd87..0000000 --- a/src/test/java/lotto/validator/LottoValidatorTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package lotto.validator; - -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.List; - -class LottoValidatorTest { - - @Test - void ๋กœ๋˜_๋ฒˆํ˜ธ_์œ ํšจ์„ฑ_๊ฒ€์‚ฌ_์ •์ƒ() { - // given - List validNumbers = List.of(1, 2, 3, 4, 5, 6); - - // when & then (์˜ˆ์™ธ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์•ผ ํ•จ) - LottoValidator.validateLottoNumbers(validNumbers); - } - - @Test - void ๋กœ๋˜_๋ฒˆํ˜ธ_๊ฐœ์ˆ˜_์˜ค๋ฅ˜() { - // given - List invalidNumbers = List.of(1, 2, 3, 4, 5); // 5๊ฐœ๋งŒ ์žˆ์Œ - - // when & then - assertThatThrownBy(() -> LottoValidator.validateLottoNumbers(invalidNumbers)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - - @Test - void ๋ณด๋„ˆ์Šค_๋ฒˆํ˜ธ_์ค‘๋ณต_์˜ค๋ฅ˜() { - // given - List winningNumbers = List.of(1, 2, 3, 4, 5, 6); - int duplicateBonusNumber = 3; // ๋‹น์ฒจ ๋ฒˆํ˜ธ์— ํฌํ•จ๋จ - - // when & then - assertThatThrownBy(() -> LottoValidator.validateBonusNumber(duplicateBonusNumber, winningNumbers)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } -} \ No newline at end of file From 313a3fdd54919a8f1b8dea50172f76afb841451f Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:25:32 +0900 Subject: [PATCH 15/20] =?UTF-8?q?refactor(entity):=20`WinningLotto`=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=20=EB=B3=80=EA=B2=BD=20(=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=EC=99=80=20=EC=9D=BC=EC=B9=98?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `WinningLotto`๊ฐ€ `String`์ด ์•„๋‹Œ `List`๋ฅผ ์ง์ ‘ ๋ฐ›๋„๋ก ์ˆ˜์ • - ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๊ฒ€์ฆ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต ๊ฒ€์ฆ์„ ์ œ๊ฑฐ - ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด๊ณ , `InputValidator`์—์„œ ๋ชจ๋“  ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์ฑ…์ž„ ๋ถ„๋ฆฌ --- src/main/java/lotto/model/entity/WinningLotto.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/lotto/model/entity/WinningLotto.java b/src/main/java/lotto/model/entity/WinningLotto.java index 36b4ed4..de1747b 100644 --- a/src/main/java/lotto/model/entity/WinningLotto.java +++ b/src/main/java/lotto/model/entity/WinningLotto.java @@ -1,22 +1,14 @@ package lotto.model.entity; - import java.util.List; import java.util.Set; -import lotto.validator.LottoValidator; - public class WinningLotto { private final Set winningNumbers; private final int bonusNumber; public WinningLotto(List numbers, int bonusNumber) { - LottoValidator.validateLottoNumbers(numbers); // ๋กœ๋˜ ๋ฒˆํ˜ธ ๊ฒ€์ฆ this.winningNumbers = Set.copyOf(numbers); - - if (winningNumbers.contains(bonusNumber)) { - throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } this.bonusNumber = bonusNumber; } @@ -27,6 +19,6 @@ public int countMatchingNumbers(Lotto lotto) { } public boolean hasBonusNumber(Lotto lotto) { - return winningNumbers.contains(bonusNumber); + return lotto.getNumbers().contains(bonusNumber); } -} +} \ No newline at end of file From 329dfa77bc7effb723d45a4ebd7a1c84bf1429f8 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:27:20 +0900 Subject: [PATCH 16/20] =?UTF-8?q?refactor(domain):=20`WinningLotto`?= =?UTF-8?q?=EB=A5=BC=20`entity`=EC=97=90=EC=84=9C=20`domain`=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `WinningLotto`๋Š” DB ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹Œ ํ•ต์‹ฌ ๋„๋ฉ”์ธ ๊ฐ์ฒด์ด๋ฏ€๋กœ `domain` ํŒจํ‚ค์ง€๋กœ ์ด๋™ - ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด์ด๋ฏ€๋กœ `entity`๋ณด๋‹ค `domain`์ด ๋” ์ ์ ˆ - ORM ๋„์ž… ์‹œ `entity` ํŒจํ‚ค์ง€๋ฅผ JPA ์—”ํ‹ฐํ‹ฐ ๊ด€๋ฆฌ ์šฉ๋„๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅ - ํŒจํ‚ค์ง€ ๋ณ€๊ฒฝ์œผ๋กœ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์ฝ”๋“œ ๋ช…ํ™•์„ฑ ํ–ฅ์ƒ --- src/main/java/lotto/controller/LottoController.java | 4 ++-- src/main/java/lotto/model/{entity => domain}/Lotto.java | 2 +- .../java/lotto/model/{entity => domain}/LottoTicket.java | 2 +- .../java/lotto/model/{entity => domain}/WinningLotto.java | 2 +- src/main/java/lotto/service/LottoService.java | 4 ++-- src/main/java/lotto/utils/LottoResultCalculator.java | 4 ++-- src/main/java/lotto/view/OutputView.java | 2 +- src/test/java/lotto/LottoTest.java | 2 +- src/test/java/lotto/service/LottoServiceTest.java | 6 +++--- 9 files changed, 14 insertions(+), 14 deletions(-) rename src/main/java/lotto/model/{entity => domain}/Lotto.java (96%) rename src/main/java/lotto/model/{entity => domain}/LottoTicket.java (96%) rename src/main/java/lotto/model/{entity => domain}/WinningLotto.java (95%) diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 65e5028..1f51110 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -2,8 +2,8 @@ import java.util.List; import lotto.model.dto.LottoResultDto; -import lotto.model.entity.LottoTicket; -import lotto.model.entity.WinningLotto; +import lotto.model.domain.LottoTicket; +import lotto.model.domain.WinningLotto; import lotto.service.LottoService; import lotto.view.InputView; import lotto.view.OutputView; diff --git a/src/main/java/lotto/model/entity/Lotto.java b/src/main/java/lotto/model/domain/Lotto.java similarity index 96% rename from src/main/java/lotto/model/entity/Lotto.java rename to src/main/java/lotto/model/domain/Lotto.java index 886c3d0..d49ef10 100644 --- a/src/main/java/lotto/model/entity/Lotto.java +++ b/src/main/java/lotto/model/domain/Lotto.java @@ -1,4 +1,4 @@ -package lotto.model.entity; +package lotto.model.domain; import java.util.HashSet; import java.util.List; diff --git a/src/main/java/lotto/model/entity/LottoTicket.java b/src/main/java/lotto/model/domain/LottoTicket.java similarity index 96% rename from src/main/java/lotto/model/entity/LottoTicket.java rename to src/main/java/lotto/model/domain/LottoTicket.java index e07b50d..0f422c3 100644 --- a/src/main/java/lotto/model/entity/LottoTicket.java +++ b/src/main/java/lotto/model/domain/LottoTicket.java @@ -1,4 +1,4 @@ -package lotto.model.entity; +package lotto.model.domain; import camp.nextstep.edu.missionutils.Randoms; import java.util.ArrayList; diff --git a/src/main/java/lotto/model/entity/WinningLotto.java b/src/main/java/lotto/model/domain/WinningLotto.java similarity index 95% rename from src/main/java/lotto/model/entity/WinningLotto.java rename to src/main/java/lotto/model/domain/WinningLotto.java index de1747b..8b21a7c 100644 --- a/src/main/java/lotto/model/entity/WinningLotto.java +++ b/src/main/java/lotto/model/domain/WinningLotto.java @@ -1,4 +1,4 @@ -package lotto.model.entity; +package lotto.model.domain; import java.util.List; import java.util.Set; diff --git a/src/main/java/lotto/service/LottoService.java b/src/main/java/lotto/service/LottoService.java index d25e8b6..fb67c38 100644 --- a/src/main/java/lotto/service/LottoService.java +++ b/src/main/java/lotto/service/LottoService.java @@ -2,8 +2,8 @@ import lotto.enums.LottoPrice; import lotto.model.dto.LottoResultDto; -import lotto.model.entity.LottoTicket; -import lotto.model.entity.WinningLotto; +import lotto.model.domain.LottoTicket; +import lotto.model.domain.WinningLotto; import lotto.utils.LottoResultCalculator; public class LottoService { diff --git a/src/main/java/lotto/utils/LottoResultCalculator.java b/src/main/java/lotto/utils/LottoResultCalculator.java index 50adb21..4c7a9d8 100644 --- a/src/main/java/lotto/utils/LottoResultCalculator.java +++ b/src/main/java/lotto/utils/LottoResultCalculator.java @@ -2,8 +2,8 @@ import lotto.enums.LottoRank; import lotto.model.dto.LottoResultDto; -import lotto.model.entity.LottoTicket; -import lotto.model.entity.WinningLotto; +import lotto.model.domain.LottoTicket; +import lotto.model.domain.WinningLotto; import java.util.EnumMap; import java.util.Map; diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java index ec8d09b..603645b 100644 --- a/src/main/java/lotto/view/OutputView.java +++ b/src/main/java/lotto/view/OutputView.java @@ -3,7 +3,7 @@ import java.util.Comparator; import lotto.model.dto.LottoResultDto; import lotto.enums.LottoRank; -import lotto.model.entity.LottoTicket; +import lotto.model.domain.LottoTicket; import java.text.NumberFormat; import java.util.Arrays; diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 6d8e4a0..ab43f7f 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -1,6 +1,6 @@ package lotto; -import lotto.model.entity.Lotto; +import lotto.model.domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/lotto/service/LottoServiceTest.java b/src/test/java/lotto/service/LottoServiceTest.java index 5266c3e..cb9e3d0 100644 --- a/src/test/java/lotto/service/LottoServiceTest.java +++ b/src/test/java/lotto/service/LottoServiceTest.java @@ -1,9 +1,9 @@ package lotto.service; import lotto.model.dto.LottoResultDto; -import lotto.model.entity.Lotto; -import lotto.model.entity.LottoTicket; -import lotto.model.entity.WinningLotto; +import lotto.model.domain.Lotto; +import lotto.model.domain.LottoTicket; +import lotto.model.domain.WinningLotto; import lotto.enums.LottoRank; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 20b94d038a373bc00a4f077b9ed88afa8eb35a87 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:31:37 +0900 Subject: [PATCH 17/20] =?UTF-8?q?remove(validator):=20`LottoValidator`=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20`InputValidator`=EB=A1=9C=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=9D=BC=EC=9B=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/lotto/validator/LottoValidator.java | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/main/java/lotto/validator/LottoValidator.java diff --git a/src/main/java/lotto/validator/LottoValidator.java b/src/main/java/lotto/validator/LottoValidator.java deleted file mode 100644 index c50736f..0000000 --- a/src/main/java/lotto/validator/LottoValidator.java +++ /dev/null @@ -1,28 +0,0 @@ -package lotto.validator; - -import java.util.HashSet; -import java.util.List; - -public class LottoValidator { - private static final int LOTTO_SIZE = 6; - private static final int MIN_NUMBER = 1; - private static final int MAX_NUMBER = 45; - - public static void validateLottoNumbers(List numbers) { - if (numbers.size() != LOTTO_SIZE || new HashSet<>(numbers).size() != LOTTO_SIZE) { - throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - if (numbers.stream().anyMatch(n -> n < MIN_NUMBER || n > MAX_NUMBER)) { - throw new IllegalArgumentException("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - } - - public static void validateBonusNumber(int bonusNumber, List winningNumbers) { - if (bonusNumber < MIN_NUMBER || bonusNumber > MAX_NUMBER) { - throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” 1~45 ๋ฒ”์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - if (winningNumbers.contains(bonusNumber)) { - throw new IllegalArgumentException("[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); - } - } -} From 4f120336e5ceab0c50a5b708ab34a29970f7f854 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:49:14 +0900 Subject: [PATCH 18/20] =?UTF-8?q?refactor(enum,domain):=20=EC=83=81?= =?UTF-8?q?=EC=88=98=ED=99=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/enums/LottoRank.java | 4 +++- src/main/java/lotto/model/domain/LottoTicket.java | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/lotto/enums/LottoRank.java b/src/main/java/lotto/enums/LottoRank.java index c367e0b..4935d57 100644 --- a/src/main/java/lotto/enums/LottoRank.java +++ b/src/main/java/lotto/enums/LottoRank.java @@ -12,6 +12,8 @@ public enum LottoRank { FIFTH(3, false, 5_000), NONE(0, false, 0); + private static final int BONUS_CRITERIA = 5; + private final int matchCount; private final boolean requiresBonus; private final int prize; @@ -34,7 +36,7 @@ public int getMatchCount() { } public static LottoRank findRank(int matchCount, boolean hasBonus) { - if (hasBonus && matchCount == 5) { + if (hasBonus && matchCount == BONUS_CRITERIA) { return SECOND; } return RANK_MAP.getOrDefault(matchCount, NONE); diff --git a/src/main/java/lotto/model/domain/LottoTicket.java b/src/main/java/lotto/model/domain/LottoTicket.java index 0f422c3..7488ca2 100644 --- a/src/main/java/lotto/model/domain/LottoTicket.java +++ b/src/main/java/lotto/model/domain/LottoTicket.java @@ -9,15 +9,18 @@ public class LottoTicket { private final List tickets; + private static final int LOTTO_MIN_NUMBER = 1; // ๐ŸŽฏ ๋กœ๋˜ ๋ฒˆํ˜ธ ์ตœ์†Œ๊ฐ’ + private static final int LOTTO_MAX_NUMBER = 45; // ๐ŸŽฏ ๋กœ๋˜ ๋ฒˆํ˜ธ ์ตœ๋Œ€๊ฐ’ + private static final int LOTTO_SIZE = 6; public LottoTicket(int count) { this.tickets = IntStream.range(0, count) .mapToObj(i -> generateLotto()) - .collect(Collectors.toList()); // โœ… Immutable List ๋Œ€์‹  ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ List ์‚ฌ์šฉ + .collect(Collectors.toList()); } private Lotto generateLotto() { - List numbers = new ArrayList<>(Randoms.pickUniqueNumbersInRange(1, 45, 6)); // โœ… ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ List๋กœ ๋ณ€ํ™˜ + List numbers = new ArrayList<>(Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER, LOTTO_SIZE)); Collections.sort(numbers); return new Lotto(numbers); } From 00980d29d7eefca3e19a3b8c0c40799e38ba87ed Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:52:07 +0900 Subject: [PATCH 19/20] =?UTF-8?q?refactor(view):=20`OutputView`=20?= =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B0=80=EB=8F=85=EC=84=B1=20=ED=96=A5=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `NUMBER_FORMAT`์œผ๋กœ ์ƒ์ˆ˜ ๋„ค์ด๋ฐ ๋ณ€๊ฒฝํ•˜์—ฌ ์ปจ๋ฒค์…˜ ์ค€์ˆ˜ - `Arrays.stream()` ๋Œ€์‹  `List.of().stream()` ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ณ€ํ™˜ ์ œ๊ฑฐ - `formatLottoRankString()` ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ ๋ฐ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ - `printProfitRate()` ๋ฉ”์„œ๋“œ ๋ถ„๋ฆฌํ•˜์—ฌ `printResults()` ๊ฐ€๋…์„ฑ ๊ฐœ์„  --- src/main/java/lotto/view/OutputView.java | 30 +++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java index 603645b..1797ac5 100644 --- a/src/main/java/lotto/view/OutputView.java +++ b/src/main/java/lotto/view/OutputView.java @@ -1,17 +1,17 @@ package lotto.view; import java.util.Comparator; +import java.util.stream.Stream; import lotto.model.dto.LottoResultDto; import lotto.enums.LottoRank; import lotto.model.domain.LottoTicket; import java.text.NumberFormat; -import java.util.Arrays; import java.util.Locale; import java.util.stream.Collectors; public class OutputView { - private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.KOREA); + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.KOREA); public void printLottoTickets(LottoTicket lottoTicket) { System.out.printf("%d๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.%n", lottoTicket.getTickets().size()); @@ -23,18 +23,26 @@ public void printResults(LottoResultDto result, int purchaseAmount) { System.out.println("๋‹น์ฒจ ํ†ต๊ณ„"); System.out.println("---"); System.out.print(formatLottoRank(result)); - System.out.printf("์ด ์ˆ˜์ต๋ฅ ์€ %.1f%%์ž…๋‹ˆ๋‹ค.%n", result.getProfitRate(purchaseAmount)); + printProfitRate(result, purchaseAmount); } private String formatLottoRank(LottoResultDto result) { - return Arrays.stream(LottoRank.values()) + return Stream.of(LottoRank.values()) .filter(rank -> rank != LottoRank.NONE) - .sorted(Comparator.comparingInt(LottoRank::getMatchCount)) - .map(rank -> String.format("%d๊ฐœ ์ผ์น˜%s (%s์›) - %d๊ฐœ%n", - rank.getMatchCount(), - rank == LottoRank.SECOND ? ", ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜" : "", - numberFormat.format(rank.getPrize()), - result.resultMap().getOrDefault(rank, 0))) + .sorted(Comparator.comparingInt(LottoRank::getMatchCount).reversed()) + .map(rank -> formatLottoRankString(rank, result)) .collect(Collectors.joining()); } -} + + private String formatLottoRankString(LottoRank rank, LottoResultDto result) { + return String.format("%d๊ฐœ ์ผ์น˜%s (%s์›) - %d๊ฐœ%n", + rank.getMatchCount(), + rank == LottoRank.SECOND ? ", ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜" : "", + NUMBER_FORMAT.format(rank.getPrize()), + result.resultMap().getOrDefault(rank, 0)); + } + + private void printProfitRate(LottoResultDto result, int purchaseAmount) { + System.out.printf("์ด ์ˆ˜์ต๋ฅ ์€ %.1f%%์ž…๋‹ˆ๋‹ค.%n", result.getProfitRate(purchaseAmount)); + } +} \ No newline at end of file From 86eac65f68fbbdf54db371743c6584f09e9b5375 Mon Sep 17 00:00:00 2001 From: kim nan seul <154604350+seulnan@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:56:59 +0900 Subject: [PATCH 20/20] =?UTF-8?q?fix(view):=20`OutputView`=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95=20(3?= =?UTF-8?q?=EA=B0=9C=20=E2=86=92=206=EA=B0=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/view/OutputView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java index 1797ac5..4c0edca 100644 --- a/src/main/java/lotto/view/OutputView.java +++ b/src/main/java/lotto/view/OutputView.java @@ -29,7 +29,7 @@ public void printResults(LottoResultDto result, int purchaseAmount) { private String formatLottoRank(LottoResultDto result) { return Stream.of(LottoRank.values()) .filter(rank -> rank != LottoRank.NONE) - .sorted(Comparator.comparingInt(LottoRank::getMatchCount).reversed()) + .sorted(Comparator.comparingInt(LottoRank::getMatchCount)) .map(rank -> formatLottoRankString(rank, result)) .collect(Collectors.joining()); }