-
Notifications
You must be signed in to change notification settings - Fork 0
로또 미션 [SangBeom-Hahn] #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2df0cb9
389c255
e94adef
a14f592
4b3305b
ca99ae6
d8c2c32
5e30c1e
4e63004
6fe1833
c06ea29
1e752fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # 요구사항 명세서 | ||
| ## [카테고리] | ||
| 1. 사용자 | ||
| 2. 로또 발행기 | ||
| 3. 결과 비교기 | ||
| 4. 시스템 | ||
|
|
||
| ## [카테고리 별 요구사항 내용] | ||
| ### 1. 사용자 | ||
| - 로또 구입 금액을 입력한다. | ||
| - 당첨 번호 추첨 시 중복되지 않는 6개의 숫자와 보너스 번호를 1개를 입력한다. | ||
|
|
||
|
|
||
| ### 2. 로또 발행기 | ||
| - 1개의 로또를 발행할 때 중복되지 않는 6개의 숫자를 뽑는다. | ||
| - 로또 구입 금액에 해당하는 만큼 로또를 발행한다. | ||
|
|
||
|
|
||
| ### 3. 결과 비교기 | ||
| - 당첨 번호를 입력 받아 발행한 로또와 비교한다. | ||
|
|
||
|
|
||
| ### 4. 시스템 | ||
| - 당첨 내역과 수익률을 출력하고 로또 게임을 종료한다. | ||
| - 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고 "[ERROR]"로 시작하는 에러 메세지를 출력 후 종료한다. | ||
|
|
||
| # 기능 목록 | ||
| ### 1. 입력 기능 | ||
| - 사용자가 입력하는 금액을 입력 받는 기능 | ||
| - 사용자가 입력하는 당첨 번호, 보너스 번호를 입력 받는 기능 | ||
|
|
||
|
|
||
| ### 2. 출력 기능 | ||
| - 발행한 로또 내역 출력 기능 | ||
| - 당첨 통계와 수익률 출력 기능 | ||
|
|
||
|
|
||
| ### 3. 게임 로직 기능 | ||
| - 로또 발행 기능 | ||
| - 당첨 통계 기능 | ||
| - 수익률 계산 기능 | ||
|
|
||
|
|
||
| ### 4. 검증 기능 | ||
| - 입력 검증 | ||
| - 사용자가 입력한 금액이 1000원 단위로 1000의 배수인지 검증 | ||
| - 사용자가 입력한 당첨 번호가 정수 1 ~ 45인지 검증 | ||
| - 사용자가 입력한 당첨 번호가 숫자 6개인지 검증 | ||
| - 사용자가 입력한 보너스 번호가 정수 1 ~ 45인지 검증 | ||
| - 사용자가 입력한 보너스 번호가 숫자 1개인지 검증 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| package lotto; | ||
|
|
||
| import lotto.controller.Controller; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| new Controller().run(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package lotto.controller; | ||
|
|
||
| import lotto.domain.Lotto.AnswerLotto; | ||
| import lotto.domain.Lotto.Lotto; | ||
| import lotto.domain.user.User; | ||
| import lotto.service.ResultService; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import static camp.nextstep.edu.missionutils.Console.readLine; | ||
| import static lotto.domain.Lotto.LottoGenerator.generateLottos; | ||
| import static lotto.domain.Lotto.MoneyGenerator.generateMoney; | ||
|
|
||
| public class Controller { | ||
| private User user; | ||
| private ResultService resultService; | ||
|
|
||
| public Controller() { | ||
| this.resultService = new ResultService(); | ||
| } | ||
|
|
||
| public void run() { | ||
| System.out.println("구입금액을 입력해 주세요."); | ||
| int money = generateMoney(); | ||
|
|
||
| buyLotto(money); | ||
|
|
||
| List<Lotto> lottos = user.getLottos(); | ||
| System.out.println(lottos.size() + "개를 구매했습니다."); | ||
| for (Lotto lotto : lottos) { | ||
| System.out.println(lotto); | ||
| } | ||
|
Comment on lines
+31
to
+35
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| System.out.println("당첨 번호를 입력해 주세요."); | ||
| String answerNumbers = readLine(); | ||
| System.out.println("보너스 번호를 입력해 주세요."); | ||
| int bonusLottoNumber = Integer.parseInt(readLine()); | ||
| List<Integer> answerLottoNumbers = Stream.of(answerNumbers.split(",")) | ||
| .map(Integer::valueOf).collect(Collectors.toList()); | ||
| AnswerLotto answerLotto = new AnswerLotto(answerLottoNumbers, bonusLottoNumber); | ||
|
|
||
| Map<String, Integer> statistics = resultService.getStatistics(lottos, answerLotto.getAnswerNumbers(), answerLotto.getBonusNumber()); | ||
| double returnRate = resultService.getReturnRate(money); | ||
|
|
||
| System.out.println("당첨 통계"); | ||
| System.out.println("---"); | ||
| System.out.println("3개 일치 (5,000원)" + "-" + statistics.get("THREE") + "개"); | ||
| System.out.println("4개 일치 (50,000원)" + "-" + statistics.get("FOUR") + "개"); | ||
| System.out.println("5개 일치 (1,500,000원)" + "-" + statistics.get("FIVE") + "개"); | ||
| System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원)" + "-" + statistics.get("FIVEPLUSBONUS") + "개"); | ||
| System.out.println("6개 일치 (2,000,000,000원)" + "-" + statistics.get("SIX") + "개"); | ||
| System.out.println(String.format("총 수익률은 %.1f입니다.", returnRate)); | ||
|
Comment on lines
+37
to
+55
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리팩토링 하신다고 했으니까 이 부분은 피드백 생략할게요 |
||
| } | ||
|
|
||
| private void buyLotto(int money) { | ||
| user = new User(generateLottos(money)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,50 @@ | ||||||||||||||||||
| package lotto.domain.Lotto; | ||||||||||||||||||
|
|
||||||||||||||||||
| import java.util.List; | ||||||||||||||||||
|
|
||||||||||||||||||
| public class AnswerLotto { | ||||||||||||||||||
| private List<Integer> answerNumbers; | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||
| private int bonusNumber; | ||||||||||||||||||
|
|
||||||||||||||||||
| public AnswerLotto(List<Integer> answerNumbers, Integer bonusNumber) { | ||||||||||||||||||
| validateLottoSize(answerNumbers); | ||||||||||||||||||
| validateLottoHasDuplicate(answerNumbers); | ||||||||||||||||||
| validateLottoNumbersRange(answerNumbers); | ||||||||||||||||||
| this.answerNumbers = answerNumbers; | ||||||||||||||||||
| this.bonusNumber = bonusNumber; | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+9
to
+15
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||
|
|
||||||||||||||||||
| private void validateLottoSize(List<Integer> numbers) { | ||||||||||||||||||
| if (numbers.size() != 6) { | ||||||||||||||||||
| throw new IllegalArgumentException("정답 로또 번호가 6자리가 아닙니다."); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| private void validateLottoHasDuplicate(List<Integer> numbers) { | ||||||||||||||||||
| if (hasDuplicate(numbers)) { | ||||||||||||||||||
| throw new IllegalArgumentException("로또 번호에 중복된 번호가 있습니다."); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| private boolean hasDuplicate(List<Integer> numbers) { | ||||||||||||||||||
| return numbers.stream().distinct().count() != 6; | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+29
to
+31
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| private void validateLottoNumbersRange(List<Integer> numbers) { | ||||||||||||||||||
| if (isNotInRange(numbers)) { | ||||||||||||||||||
| throw new IllegalArgumentException("로또 번호 중에 1 ~ 45가 아닌 것이 있습니다."); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| private boolean isNotInRange(List<Integer> numbers) { | ||||||||||||||||||
| return numbers.stream().anyMatch(number -> number < 1 || number > 45); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| public List<Integer> getAnswerNumbers() { | ||||||||||||||||||
| return answerNumbers; | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. immutable |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| public int getBonusNumber() { | ||||||||||||||||||
| return bonusNumber; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package lotto.domain.Lotto; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class Lotto { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AnswerLotto 피드백 동일 |
||
| private final List<Integer> numbers; | ||
|
|
||
| public Lotto(List<Integer> numbers) { | ||
| validateLottoSize(numbers); | ||
| validateLottoHasDuplicate(numbers); | ||
| validateLottoNumbersRange(numbers); | ||
| this.numbers = numbers; | ||
| } | ||
|
|
||
| private void validateLottoSize(List<Integer> numbers) { | ||
| if (numbers.size() != 6) { | ||
| throw new IllegalArgumentException("로또 번호가 6자리가 아닙니다."); | ||
| } | ||
| } | ||
|
|
||
| private void validateLottoHasDuplicate(List<Integer> numbers) { | ||
| if (hasDuplicate(numbers)) { | ||
| throw new IllegalArgumentException("로또 번호에 중복된 번호가 있습니다."); | ||
| } | ||
| } | ||
|
|
||
| private boolean hasDuplicate(List<Integer> numbers) { | ||
| return numbers.stream().distinct().count() != 6; | ||
| } | ||
|
|
||
| private void validateLottoNumbersRange(List<Integer> numbers) { | ||
| if (isNotInRange(numbers)) { | ||
| throw new IllegalArgumentException("로또 번호 중에 1 ~ 45가 아닌 것이 있습니다."); | ||
| } | ||
| } | ||
|
|
||
| private boolean isNotInRange(List<Integer> numbers) { | ||
| return numbers.stream().anyMatch(number -> number < 1 || number > 45); | ||
| } | ||
|
|
||
| public List<Integer> getNumbers() { | ||
| return numbers; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return numbers.toString(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package lotto.domain.Lotto; | ||
|
|
||
| import camp.nextstep.edu.missionutils.Randoms; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class LottoGenerator { | ||
| private LottoGenerator() { | ||
| } | ||
|
|
||
| public static List<Lotto> generateLottos(int money) { | ||
| List<Lotto> lottos = new ArrayList<>(); | ||
| final int quantity = money / 1000; | ||
|
|
||
| for (int i = 0; i < quantity; i++) { | ||
| lottos.add(generateLotto()); | ||
| } | ||
|
|
||
| return lottos; | ||
| } | ||
|
Comment on lines
+12
to
+21
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구매한 money를 넘기는게 아니라 1000원 단위로 구매한 |
||
|
|
||
| private static Lotto generateLotto() { | ||
| return new Lotto(getLottoNumbers()); | ||
| } | ||
|
|
||
| private static List<Integer> getLottoNumbers() { | ||
| return Randoms.pickUniqueNumbersInRange(1, 45, 6); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package lotto.domain.Lotto; | ||
|
|
||
| import static camp.nextstep.edu.missionutils.Console.readLine; | ||
|
|
||
| public class MoneyGenerator { | ||
| private MoneyGenerator() { | ||
| } | ||
|
|
||
| public static int generateMoney() { | ||
| int money = inputMoney(); | ||
| validateMoney(money); | ||
| return money; | ||
| } | ||
|
|
||
| private static int inputMoney() { | ||
| String inputMoney = readLine(); | ||
| return convertMoneyTypeStringToInt(inputMoney); | ||
| } | ||
|
|
||
| private static int convertMoneyTypeStringToInt(String inputMoney) { | ||
| return Integer.parseInt(inputMoney); | ||
| } | ||
|
Comment on lines
+9
to
+22
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inputMony에서 |
||
| private static void validateMoney(int money) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에 라인과 개행 |
||
| validateMoneyIsPositive(money); | ||
| validateMoneyIsMultiplesOfPrice(money); | ||
| } | ||
|
|
||
| private static void validateMoneyIsPositive(int money) { | ||
| if (money < 0) { | ||
| throw new IllegalArgumentException("구입금액은 음수를 입력할 수 없습니다."); | ||
| } | ||
| } | ||
|
|
||
| private static void validateMoneyIsMultiplesOfPrice(int money) { | ||
| if (isNotMultiplesOfPrice(money)) { | ||
| throw new IllegalArgumentException("구입금액은 1000의 배수여야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| private static boolean isNotMultiplesOfPrice(int money) { | ||
| return (money / 1000) < 0 || (money % 1000) > 0; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package lotto.domain.user; | ||
|
|
||
| import lotto.domain.Lotto.Lotto; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class User { | ||
| private List<Lotto> lottos; | ||
|
|
||
| public User(List<Lotto> lottos) { | ||
| this.lottos = lottos; | ||
| } | ||
|
|
||
| public List<Lotto> getLottos() { | ||
| return lottos; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. immutable |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package lotto.service; | ||
|
|
||
| import lotto.domain.Lotto.Lotto; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public class ResultService { | ||
| private Map<Integer, String> collectMap = new HashMap<>(){{ | ||
| put(3, "THREE"); | ||
| put(4, "FOUR"); | ||
| put(5, "FIVE"); | ||
| put(6, "SIX"); | ||
| }}; | ||
| private Map<String, Integer> statisticCollectCntMap = new HashMap<>(){{ | ||
| put("THREE", 0); | ||
| put("FOUR", 0); | ||
| put("FIVE", 0); | ||
| put("FIVEPLUSBONUS", 0); | ||
| put("SIX", 0); | ||
| }}; | ||
|
Comment on lines
+9
to
+22
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| public Map<String, Integer> getStatistics(List<Lotto> userLottos, List<Integer> answerNumbers, int bonusNumber) { | ||
| int bonusCnt; | ||
| int collectCnt; | ||
|
|
||
| for (Lotto userLotto : userLottos) { | ||
| List<Integer> eachLottoNumbers = userLotto.getNumbers(); | ||
| bonusCnt = isContainsBonusNumber(eachLottoNumbers, bonusNumber); | ||
| collectCnt = getCollectCnt(eachLottoNumbers, answerNumbers); | ||
|
|
||
| try { | ||
| if (bonusCnt == 1 && collectCnt == 5) { | ||
| statisticCollectCntMap.compute("FIVEPLUSBONUS", (k, v) -> Integer.valueOf(v + 1)); | ||
| } else { | ||
| statisticCollectCntMap.compute(collectMap.get(collectCnt), (k, v) -> Integer.valueOf(v + 1)); | ||
| } | ||
| } catch (NullPointerException e) { | ||
|
|
||
| } | ||
|
Comment on lines
+33
to
+41
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NPE를 잡는 이유가 있나요?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Map에 없는 키를 get하면 NPE가 발생합니다. https://codechacha.com/ko/java-how-to-update-value-of-key-from-hashmap/ |
||
| } | ||
|
|
||
| return statisticCollectCntMap; | ||
| } | ||
|
|
||
| private int isContainsBonusNumber(List<Integer> eachLottoNumbers, Integer bonusNumber) { | ||
| if (eachLottoNumbers.contains(bonusNumber)) { | ||
| return 1; | ||
| } | ||
| return 0; | ||
| } | ||
|
Comment on lines
+47
to
+52
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1줄로 개선 |
||
|
|
||
| private int getCollectCnt(List<Integer> eachLottoNumbers, List<Integer> answerNumbers) { | ||
| eachLottoNumbers.retainAll(answerNumbers); | ||
| return eachLottoNumbers.size(); | ||
| } | ||
|
|
||
| public double getReturnRate(int money) { | ||
| return (double) 100 * ( | ||
| statisticCollectCntMap.get("THREE") * 5000 + | ||
| statisticCollectCntMap.get("FOUR") * 50000 + | ||
| statisticCollectCntMap.get("FIVE") * 1500000 + | ||
| statisticCollectCntMap.get("FIVEPLUSBONUS") * 30000000 + | ||
| statisticCollectCntMap.get("SIX") * 2000000000 | ||
| ) / money; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tab 컨벤션 4칸