Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# java-lotto-precourse

## 기능 요구사항

### 1. 입력 기능
- 로또 구입 금액 입력받기 (1,000원 단위 검증)
- 당첨 번호 6개 입력받기 (쉼표 구분)
- 보너스 번호 입력받기

### 2.로또 발행 기능
- 구입 금액에 따른 로또 개수 계산
- 1~45 범위에서 중복 없는 6개 번호 생성
- 로또 번호 오름차순 정렬 및 출력

### 3.당첨 처리 기능
- 구매 로또와 당첨 번호 비교
- 당첨 등수 판정 (1등~5등)
- 당첨 내역 집계

### 4.결과 출력 기능
- 당첨 통계 출력
- 수익률 계산 및 출력

### 5.예외 처리 기능
- 입력값 검증 및 예외 처리
- 에러 메시지 출력
166 changes: 164 additions & 2 deletions src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,169 @@
package lotto;

import camp.nextstep.edu.missionutils.Console;
import camp.nextstep.edu.missionutils.Randoms;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
System.out.println("구입금액을 입력해 주세요.");
int purchaseAmount = readPurchaseAmount();

List<Lotto> lottos = generateLottos(purchaseAmount);
printLottos(lottos);

System.out.println("당첨 번호를 입력해 주세요.");
List<Integer> winningNumbers = readWinningNumbers();

System.out.println("보너스 번호를 입력해 주세요.");
int bonusNumber = readBonusNumber(winningNumbers);

Map<Rank, Integer> results = checkWinnings(lottos, winningNumbers, bonusNumber);
printResults(results, purchaseAmount);
}

private static int readPurchaseAmount() {
while (true) {
try {
return parsePurchaseAmount(Console.readLine());
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

private static List<Integer> readWinningNumbers() {
while (true) {
try {
return parseWinningNumbers(Console.readLine());
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

private static int readBonusNumber(List<Integer> winningNumbers) {
while (true) {
try {
return parseBonusNumber(Console.readLine(), winningNumbers);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

private static Map<Rank, Integer> checkWinnings(List<Lotto> lottos, List<Integer> winningNumbers, int bonusNumber) {
Map<Rank, Integer> results = new HashMap<>();

for (Rank rank : Rank.values()) {
results.put(rank, 0);
}

for (Lotto lotto : lottos) {
Rank rank = lotto.checkRank(winningNumbers, bonusNumber);
results.put(rank, results.get(rank) + 1);
}

return results;
}

private static void printResults(Map<Rank, Integer> results, int purchaseAmount) {
System.out.println("당첨 통계");
System.out.println("---");
System.out.println("3개 일치 (5,000원) - " + results.get(Rank.FIFTH) + "개");
System.out.println("4개 일치 (50,000원) - " + results.get(Rank.FOURTH) + "개");
System.out.println("5개 일치 (1,500,000원) - " + results.get(Rank.THIRD) + "개");
System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원) - " + results.get(Rank.SECOND) + "개");
System.out.println("6개 일치 (2,000,000,000원) - " + results.get(Rank.FIRST) + "개");

double profitRate = calculateProfitRate(results, purchaseAmount);
System.out.println("총 수익률은 " + String.format("%.1f", profitRate) + "%입니다.");
}

private static double calculateProfitRate(Map<Rank, Integer> results, int purchaseAmount) {
int totalPrize = 0;
for (Rank rank : results.keySet()) {
totalPrize += rank.getPrize() * results.get(rank);
}
return (double) totalPrize / purchaseAmount * 100;
}

private static List<Lotto> generateLottos(int purchaseAmount) {
int count = purchaseAmount / 1000;
System.out.println(count + "개를 구매했습니다.");

List<Lotto> lottos = new ArrayList<>();
for (int i = 0; i < count; i++) {
List<Integer> numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6);
lottos.add(new Lotto(numbers));
}
return lottos;
}

private static void printLottos(List<Lotto> lottos) {
for (Lotto lotto : lottos) {
System.out.println(lotto.toString());
}
System.out.println();
}

private static int parsePurchaseAmount(String input) {
try {
int amount = Integer.parseInt(input);
if (amount % 1000 != 0) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위로 입력해야 합니다.");
}
return amount;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 숫자여야 합니다.");
}
}

private static List<Integer> parseWinningNumbers(String input) {
String[] parts = input.split(",");
if (parts.length != 6) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다.");
}

try {
List<Integer> numbers = Arrays.stream(parts)
.map(String::trim)
.map(Integer::parseInt)
.toList();

for (int number : numbers) {
if (number < 1 || number > 45) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
}

if (new HashSet<>(numbers).size() != 6) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 중복될 수 없습니다.");
}

return numbers;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 숫자여야 합니다.");
}
}

private static int parseBonusNumber(String input, List<Integer> winningNumbers) {
try {
int bonusNumber = Integer.parseInt(input);
if (bonusNumber < 1 || bonusNumber > 45) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
if (winningNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
return bonusNumber;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 숫자여야 합니다.");
}
}
}
}
40 changes: 38 additions & 2 deletions src/main/java/lotto/Lotto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package lotto;

import java.util.List;
import java.util.Collections;
import java.util.HashSet;

public class Lotto {
private final List<Integer> numbers;
Expand All @@ -14,7 +16,41 @@ private void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다.");
}

for (int number : numbers) {
if (number < 1 || number > 45) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
}

if (new HashSet<>(numbers).size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다.");
}
}

@Override
public String toString() {
List<Integer> sortedNumbers = numbers.stream().sorted().toList();
return sortedNumbers.toString();
}

// TODO: 추가 기능 구현
}
public List<Integer> getNumbers() {
return numbers;
}

public Rank checkRank(List<Integer> winningNumbers, int bonusNumber) {
int matchCount = countMatches(winningNumbers);
boolean bonusMatch = numbers.contains(bonusNumber);
return Rank.valueOf(matchCount, bonusMatch);
}

private int countMatches(List<Integer> winningNumbers) {
int count = 0;
for (int number : numbers) {
if (winningNumbers.contains(number)) {
count++;
}
}
return count;
}
}
51 changes: 51 additions & 0 deletions src/main/java/lotto/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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 valueOf(int matchCount, boolean bonusMatch) {
if (matchCount == 6) {
return FIRST;
}
if (matchCount == 5 && bonusMatch) {
return SECOND;
}
if (matchCount == 5) {
return THIRD;
}
if (matchCount == 4) {
return FOURTH;
}
if (matchCount == 3) {
return FIFTH;
}
return NONE;
}

public int getPrize() {
return prize;
}

public int getMatchCount() {
return matchCount;
}

public boolean isBonusMatch() {
return bonusMatch;
}
}