diff --git a/README.md b/README.md index 5fa2560b46..2f6c9440d0 100644 --- a/README.md +++ b/README.md @@ -1 +1,38 @@ # java-lotto-precourse + +## 구현할 기능 목록 + +### 입력 기능 +- 구입 금액 입력받기 + - 1,000원 단위로 입력 + - 숫자가 아닌 경우 예외 처리 + - 1,000원으로 나누어떨어지지 않으면 예외 처리 +- 당첨 번호 입력받기 + - 쉼표로 구분하여 6개 입력 + - 숫자가 아닌 경우 예외 처리 + - 중복된 숫자가 있으면 예외 처리 + - 1~45 범위 벗어나면 예외 처리 +- 보너스 번호 입력받기 + - 숫자가 아닌 경우 예외 처리 + - 1~45 범위 벗어나면 예외 처리 + - 당첨 번호와 중복되면 예외 처리 + +### 로또 생성 기능 +- 1~45 사이 중복없는 6개 번호 생성 +- 구입 금액에 맞춰 로또 개수만큼 생성 +- 생성된 로또 번호 오름차순 정렬 + +### 당첨 확인 기능 +- 당첨 번호와 일치하는 개수 확인 +- 보너스 번호 일치 여부 확인 +- 등수 판별 + - 6개 일치: 1등 (2,000,000,000원) + - 5개 일치 + 보너스: 2등 (30,000,000원) + - 5개 일치: 3등 (1,500,000원) + - 4개 일치: 4등 (50,000원) + - 3개 일치: 5등 (5,000원) + +### 출력 기능 +- 구매한 로또 개수 및 번호 출력 +- 당첨 통계 출력 (등수별 당첨 개수) +- 수익률 계산 및 출력 (소수점 둘째 자리에서 반올림) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922ba4..86b021f865 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,104 @@ package lotto; +import camp.nextstep.edu.missionutils.Console; +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.*; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + try { + int amount = readAmount(); + List lottos = generateLottos(amount); + printLottos(lottos); + + List winningNumbers = readWinningNumbers(); + int bonusNumber = readBonusNumber(winningNumbers); + + Map result = checkWinning(lottos, winningNumbers, bonusNumber); + printResult(result, amount); + } catch (Exception e) { + System.out.println("[ERROR]"); + } + } + + private static int readAmount() { + System.out.println("구입금액을 입력해 주세요."); + int amount = Integer.parseInt(Console.readLine()); + if (amount % 1000 != 0) { + throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); + } + return amount; + } + + private static List generateLottos(int amount) { + int count = amount / 1000; + System.out.println(count + "개를 구매했습니다."); + + List lottos = new ArrayList<>(); + for (int i = 0; i < count; i++) { + List numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6); + lottos.add(new Lotto(numbers)); + } + return lottos; + } + + private static void printLottos(List lottos) { + for (Lotto lotto : lottos) { + System.out.println(lotto.getNumbers()); + } + System.out.println(); + } + + private static List readWinningNumbers() { + System.out.println("당첨 번호를 입력해 주세요."); + String input = Console.readLine(); + String[] parts = input.split(","); + List numbers = new ArrayList<>(); + for (String part : parts) { + numbers.add(Integer.parseInt(part.trim())); + } + return numbers; + } + + private static int readBonusNumber(List winningNumbers) { + System.out.println("보너스 번호를 입력해 주세요."); + int bonus = Integer.parseInt(Console.readLine()); + if (winningNumbers.contains(bonus)) { + throw new IllegalArgumentException("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); + } + return bonus; + } + + private static Map checkWinning(List lottos, List winningNumbers, int bonusNumber) { + Map result = new HashMap<>(); + for (Rank rank : Rank.values()) { + result.put(rank, 0); + } + + for (Lotto lotto : lottos) { + int matchCount = lotto.countMatch(winningNumbers); + boolean bonusMatch = lotto.contains(bonusNumber); + Rank rank = Rank.of(matchCount, bonusMatch); + result.put(rank, result.get(rank) + 1); + } + return result; + } + + private static void printResult(Map result, int amount) { + System.out.println("당첨 통계"); + System.out.println("---"); + System.out.println("3개 일치 (5,000원) - " + result.get(Rank.FIFTH) + "개"); + System.out.println("4개 일치 (50,000원) - " + result.get(Rank.FOURTH) + "개"); + System.out.println("5개 일치 (1,500,000원) - " + result.get(Rank.THIRD) + "개"); + System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원) - " + result.get(Rank.SECOND) + "개"); + System.out.println("6개 일치 (2,000,000,000원) - " + result.get(Rank.FIRST) + "개"); + + long totalPrize = 0; + for (Rank rank : result.keySet()) { + totalPrize += (long) rank.getPrize() * result.get(rank); + } + double rate = (double) totalPrize / amount * 100; + System.out.printf("총 수익률은 %.1f%%입니다.%n", rate); } } diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index 88fc5cf12b..f6ba9da63c 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -1,20 +1,42 @@ package lotto; +import java.util.HashSet; import java.util.List; +import java.util.stream.Collectors; public class Lotto { private final List numbers; public Lotto(List numbers) { validate(numbers); - this.numbers = numbers; + this.numbers = numbers.stream().sorted().collect(Collectors.toList()); } private void validate(List numbers) { if (numbers.size() != 6) { throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다."); } + if (numbers.size() != new HashSet<>(numbers).size()) { + throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다."); + } + for (int number : numbers) { + if (number < 1 || number > 45) { + throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } + } + + public int countMatch(List winningNumbers) { + return (int) numbers.stream() + .filter(winningNumbers::contains) + .count(); } - // TODO: 추가 기능 구현 + public boolean contains(int number) { + return numbers.contains(number); + } + + public List getNumbers() { + return numbers; + } } diff --git a/src/main/java/lotto/Rank.java b/src/main/java/lotto/Rank.java new file mode 100644 index 0000000000..1dab24e002 --- /dev/null +++ b/src/main/java/lotto/Rank.java @@ -0,0 +1,42 @@ +package lotto; + +public enum Rank { + 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 bonusMatch; + private final int prize; + + Rank(int matchCount, boolean bonusMatch, int prize) { + this.matchCount = matchCount; + this.bonusMatch = bonusMatch; + this.prize = prize; + } + + public static Rank of(int matchCount, boolean bonusMatch) { + for (Rank rank : values()) { + if (rank.matchCount == matchCount) { + if (rank == SECOND && bonusMatch) { + return SECOND; + } + if (rank != SECOND) { + return rank; + } + } + } + return NONE; + } + + public int getPrize() { + return prize; + } + + public int getMatchCount() { + return matchCount; + } +}