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
14 changes: 11 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ version = '1.0-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(21) // JDK 21 사용
}
}

Expand All @@ -17,9 +17,17 @@ repositories {
}

dependencies {
implementation 'com.github.woowacourse-projects:mission-utils:1.2.0'
implementation 'com.github.woowacourse-projects:mission-utils:1.2.0' // 사용자 입력/출력용

//테스트를 위한 의존성 추가 gpt사용
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
testImplementation 'org.assertj:assertj-core:3.26.0'
}

test {
useJUnitPlatform()
useJUnitPlatform() // JUnit5 테스트 실행
}

tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // 인코딩 설정
}
5 changes: 4 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package lotto;

import lotto.controller.LottoController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
LottoController controller = new LottoController();
controller.run();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

117 changes: 117 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package lotto.controller;

import camp.nextstep.edu.missionutils.Console;
import camp.nextstep.edu.missionutils.Randoms;
import lotto.domain.Lotto;
import lotto.domain.LottoResult;

import java.util.List;
import java.util.stream.Collectors;

import lotto.view.OutputView;

public class LottoController {
private static final int LOTTO_PRICE = 1000;

public void run() {
int purchaseAmount = inputPurchaseAmount();
List<Lotto> purchasedLottos = purchaseLottos(purchaseAmount);

OutputView.printLottoCount(purchasedLottos.size());
OutputView.printLottos(purchasedLottos);

Lotto winningLotto = inputWinningLotto();
int bonusNumber = inputBonusNumber(winningLotto);

LottoResult result = LottoResult.of(purchasedLottos, winningLotto, bonusNumber);
OutputView.printStatistics(result, purchaseAmount);
}

private int inputPurchaseAmount() {
while (true) {
try {
OutputView.printMessage("구입금액을 입력해 주세요.");
String input = Console.readLine();
int amount = Integer.parseInt(input);
validatePurchaseAmount(amount);
return amount;
} catch (IllegalArgumentException e) {
OutputView.printError(e.getMessage());
}
}
}

private void validatePurchaseAmount(int amount) {
if (amount < LOTTO_PRICE || amount % LOTTO_PRICE != 0) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 1000원 단위여야 합니다.");
}
}

private List<Lotto> purchaseLottos(int amount) {
int count = amount / LOTTO_PRICE;
return java.util.stream.IntStream.range(0, count)
.mapToObj(i -> new Lotto(Randoms.pickUniqueNumbersInRange(1, 45, 6)))
.collect(Collectors.toList());
}

private Lotto inputWinningLotto() {
while (true) {
try {
OutputView.printMessage("당첨 번호를 입력해 주세요.");
String input = Console.readLine();
List<Integer> numbers = parseAndValidateWinningNumbers(input);
return new Lotto(numbers);
} catch (IllegalArgumentException e) {
OutputView.printError(e.getMessage());
}
}
}

private List<Integer> parseAndValidateWinningNumbers(String input) {
String[] tokens = input.split(",");
if (tokens.length != 6) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다.");
}
List<Integer> numbers = new java.util.ArrayList<>();
for (String token : tokens) {
int num = parseNumber(token.trim());
validateNumberRange(num);
if (numbers.contains(num)) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 중복될 수 없습니다.");
}
numbers.add(num);
}
return numbers;
}

private int parseNumber(String token) {
try {
return Integer.parseInt(token);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("[ERROR] 숫자를 올바르게 입력해 주세요.");
}
}

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

private int inputBonusNumber(Lotto winningLotto) {
while (true) {
try {
OutputView.printMessage("보너스 번호를 입력해 주세요.");
String input = Console.readLine();
int bonus = parseNumber(input.trim());
validateNumberRange(bonus);
if (winningLotto.contains(bonus)) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
return bonus;
} catch (IllegalArgumentException e) {
OutputView.printError(e.getMessage());
}
}
}
}
46 changes: 46 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lotto.domain;

import java.util.*;

public class Lotto {
private final List<Integer> numbers;

public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = new ArrayList<>(numbers);
Collections.sort(this.numbers);
}

private void validate(List<Integer> numbers) {
if (numbers == null || numbers.size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다.");
}
Set<Integer> set = new HashSet<>(numbers);
if (set.size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다.");
}
for (int num : numbers) {
if (num < 1 || num > 45) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
}
}

public boolean contains(int number) {
return numbers.contains(number);
}

public int countMatch(Lotto other) {
int count = 0;
for (int num : numbers) {
if (other.contains(num)) {
count++;
}
}
return count;
}

public List<Integer> getNumbers() {
return Collections.unmodifiableList(numbers);
}
}
54 changes: 54 additions & 0 deletions src/main/java/lotto/domain/LottoRank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package lotto.domain;

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;

LottoRank(int matchCount, boolean requiresBonus, int prize) {
this.matchCount = matchCount;
this.requiresBonus = requiresBonus;
this.prize = prize;
}

public static LottoRank 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 String toDisplayString() {
return switch (this) {
case FIRST -> "6개 일치 (2,000,000,000원)";
case SECOND -> "5개 일치, 보너스 볼 일치 (30,000,000원)";
case THIRD -> "5개 일치 (1,500,000원)";
case FOURTH -> "4개 일치 (50,000원)";
case FIFTH -> "3개 일치 (5,000원)";
default -> "";
};
}
}
40 changes: 40 additions & 0 deletions src/main/java/lotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package lotto.domain;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;

public class LottoResult {
private final Map<LottoRank, Integer> rankCount = new EnumMap<>(LottoRank.class);
private final int totalPrize;

private LottoResult(Map<LottoRank, Integer> rankCount, int totalPrize) {
this.rankCount.putAll(rankCount);
this.totalPrize = totalPrize;
}

public static LottoResult of(List<Lotto> purchased, Lotto winning, int bonusNumber) {
Map<LottoRank, Integer> counts = new EnumMap<>(LottoRank.class);
for (LottoRank rank : LottoRank.values()) {
counts.put(rank, 0);
}

int prizeSum = 0;
for (Lotto lotto : purchased) {
int matchCount = lotto.countMatch(winning);
boolean bonusMatch = lotto.contains(bonusNumber);
LottoRank rank = LottoRank.valueOf(matchCount, bonusMatch);
counts.put(rank, counts.get(rank) + 1);
prizeSum += rank.getPrize();
}
return new LottoResult(counts, prizeSum);
}

public int getCount(LottoRank rank) {
return rankCount.getOrDefault(rank, 0);
}

public int getTotalPrize() {
return totalPrize;
}
}
45 changes: 45 additions & 0 deletions src/main/java/lotto/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package lotto.view;

import lotto.domain.Lotto;
import lotto.domain.LottoRank;
import lotto.domain.LottoResult;

import java.util.List;

public class OutputView {
public static void printMessage(String message) {
System.out.println(message);
}

public static void printError(String errorMessage) {
System.out.println(errorMessage);
}

public static void printLottoCount(int count) {
System.out.printf("%d개를 구매했습니다.%n", count);
}

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

public static void printStatistics(LottoResult result, int purchaseAmount) {
System.out.println();
System.out.println("당첨 통계");
System.out.println("---");
printRankCount(LottoRank.FIFTH, result);
printRankCount(LottoRank.FOURTH, result);
printRankCount(LottoRank.THIRD, result);
printRankCount(LottoRank.SECOND, result);
printRankCount(LottoRank.FIRST, result);

double rate = ((double) result.getTotalPrize() / purchaseAmount) * 100;
System.out.printf("총 수익률은 %.1f%%입니다.%n", Math.round(rate * 10) / 10.0);
}

private static void printRankCount(LottoRank rank, LottoResult result) {
System.out.printf("%s - %d개%n", rank.toDisplayString(), result.getCount(rank));
}
}
Loading