-
Notifications
You must be signed in to change notification settings - Fork 10
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
[로또 게임 과제] 정건우 제출합니다 #17
base: main
Are you sure you want to change the base?
Changes from all commits
b5efec7
911d97b
2d4a209
d37310d
be2892d
32df54b
c8ec053
8bbdd81
7816e9f
4ed9c12
9fb463d
facb0f5
32db404
b2c68f9
6b9eb5e
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 |
---|---|---|
@@ -1,7 +1,12 @@ | ||
package lotto; | ||
|
||
import lotto.controller.InstanceManager; | ||
import lotto.view.LottoGame; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
// TODO: 프로그램 구현 | ||
InstanceManager instanceManager = new InstanceManager(); | ||
LottoGame lottoGame = instanceManager.lottoGame(); | ||
lottoGame.start(); | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package lotto.controller; | ||
|
||
import lotto.model.LottoMachineModel; | ||
import lotto.model.WinningResultModel; | ||
import lotto.view.ConsoleInput; | ||
import lotto.view.LottoGame; | ||
|
||
public class InstanceManager { | ||
private final ConsoleInput consoleInput; | ||
private final LottoMachineModel lottoMachine; | ||
private final WinningResultModel winningResult; | ||
|
||
public InstanceManager() { | ||
this.consoleInput = new ConsoleInput(); | ||
this.lottoMachine = new LottoMachineModel(); | ||
this.winningResult = new WinningResultModel(); | ||
} | ||
|
||
public LottoGame lottoGame() { | ||
return new LottoGame(consoleInput, lottoMachine, winningResult); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package lotto.model; | ||
|
||
import camp.nextstep.edu.missionutils.Randoms; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class LottoMachineModel { | ||
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. Model은 데이터를 담는 객체를 말합니다. model 보다는 domain에 가까워 보입니다. |
||
private static final int LOTTO_NUMBER_MIN = 1; | ||
private static final int LOTTO_NUMBER_MAX = 45; | ||
private static final int LOTTO_NUMBERS_COUNT = 6; | ||
|
||
public List<LottoModel> generateLottos(int count) { | ||
List<LottoModel> lottos = new ArrayList<>(); | ||
for (int i = 0; i < count; i++) { | ||
List<Integer> numbers = Randoms.pickUniqueNumbersInRange(LOTTO_NUMBER_MIN, LOTTO_NUMBER_MAX, LOTTO_NUMBERS_COUNT); | ||
lottos.add(new LottoModel(numbers)); | ||
} | ||
return lottos; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package lotto.model; | ||
|
||
// cannot reslove symbol -> gradle rebuild로 해결 | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
public class LottoModel { | ||
private final List<Integer> numbers; | ||
|
||
public LottoModel(List<Integer> numbers) { | ||
validate(numbers); | ||
this.numbers = numbers; | ||
} | ||
|
||
private void validate(List<Integer> numbers) { | ||
if (numbers.size() != 6) { | ||
throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
} | ||
Set<Integer> numberSet = new HashSet<>(); | ||
for (int number : numbers) { | ||
if (number < 1 || number > 45) { | ||
throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||
} | ||
if (!numberSet.add(number)) { | ||
throw new IllegalArgumentException("로또 번호는 중복될 수 없습니다."); | ||
} | ||
} | ||
} | ||
|
||
// TODO: 추가 기능 구현 | ||
public List<Integer> getNumbers() { | ||
return numbers; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package lotto.model; | ||
|
||
public enum RankEnum { | ||
FIRST(6, 2_000_000_000), | ||
SECOND(5, 30_000_000), | ||
THIRD(5, 1_500_000), | ||
FOURTH(4, 50_000), | ||
FIFTH(3, 5_000), | ||
MISS(0, 0); | ||
|
||
private final int matchCount; | ||
private final int prize; | ||
|
||
RankEnum(int matchCount, int prize) { | ||
this.matchCount = matchCount; | ||
this.prize = prize; | ||
} | ||
|
||
public int getMatchCount() { | ||
return matchCount; | ||
} | ||
|
||
public int getPrize() { | ||
return prize; | ||
} | ||
|
||
public static RankEnum valueOf(int matchCount, boolean matchBonus) { | ||
if (matchCount == 6) { | ||
return FIRST; | ||
} | ||
if (matchCount == 5 && matchBonus) { | ||
return SECOND; | ||
} | ||
if (matchCount == 5) { | ||
return THIRD; | ||
} | ||
if (matchCount == 4) { | ||
return FOURTH; | ||
} | ||
if (matchCount == 3) { | ||
return FIFTH; | ||
} | ||
return MISS; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package lotto.model; | ||
|
||
|
||
import java.util.EnumMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.HashSet; | ||
|
||
public class WinningResultModel { | ||
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. model이 비즈니스 로직을 수행하네요. 물론 그러지 말라는 법은 없지만 mvc 패턴에서는 컨트롤러가 사용자로부터의 입력에 대한 응답으로 모델 및/또는 뷰를 업데이트하는 로직을 포함합니다. |
||
private final Map<RankEnum, Integer> result = new EnumMap<>(RankEnum.class); | ||
|
||
public WinningResultModel() { | ||
for (RankEnum rank : RankEnum.values()) { | ||
result.put(rank, 0); | ||
} | ||
} | ||
|
||
public void checkWinning(List<LottoModel> purchasedLottos, Set<Integer> winningNumbers, int bonusNumber) { | ||
for (LottoModel lotto : purchasedLottos) { | ||
Set<Integer> intersection = new HashSet<>(lotto.getNumbers()); | ||
intersection.retainAll(winningNumbers); | ||
int matchCount = intersection.size(); | ||
boolean matchBonus = lotto.getNumbers().contains(bonusNumber); | ||
|
||
RankEnum rank = RankEnum.valueOf(matchCount, matchBonus); | ||
result.put(rank, result.get(rank) + 1); | ||
} | ||
} | ||
|
||
public void printWinningResult() { | ||
System.out.println("당첨 통계\n---"); | ||
System.out.printf("3개 일치 (5,000원) - %d개%n", result.get(RankEnum.FIFTH)); | ||
System.out.printf("4개 일치 (50,000원) - %d개%n", result.get(RankEnum.FOURTH)); | ||
System.out.printf("5개 일치 (1,500,000원) - %d개%n", result.get(RankEnum.THIRD)); | ||
System.out.printf("5개 일치, 보너스 볼 일치 (30,000,000원) - %d개%n", result.get(RankEnum.SECOND)); | ||
System.out.printf("6개 일치 (2,000,000,000원) - %d개%n", result.get(RankEnum.FIRST)); | ||
} | ||
|
||
public double calculateProfitRate(int purchaseAmount) { | ||
int totalWinnings = result.entrySet().stream() | ||
.mapToInt(entry -> entry.getKey().getPrize() * entry.getValue()) | ||
.sum(); | ||
return ((double) totalWinnings / purchaseAmount) * 100; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package lotto.view; | ||
|
||
import camp.nextstep.edu.missionutils.Console; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
public class ConsoleInput { | ||
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 int getPurchaseAmount() { | ||
System.out.println("구입금액을 입력해 주세요."); | ||
String input = Console.readLine(); | ||
int purchaseAmount; | ||
try { | ||
purchaseAmount = Integer.parseInt(input); | ||
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. 예를 들면 정수가 아닌 입력은 잘못된 입력형식이라고 생각할 수 있어 입력단에서 처리하는게 나쁘지 않아보입니다. |
||
} catch (NumberFormatException e) { | ||
throw new IllegalArgumentException("구입 금액은 숫자여야 합니다."); | ||
} | ||
if (purchaseAmount % 1000 != 0) { | ||
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. 다만 구매 금액이 1000원단위가 아닌것은 잘못된 입력보다는 잘못된 "구매금액"아닐까요? 그렇다면 구매금액 객체를 관리하는 비즈니스 로직단에서 처리하는게 어떨까요? |
||
throw new IllegalArgumentException("구입 금액은 1,000원 단위여야 합니다."); | ||
} | ||
return purchaseAmount; | ||
} | ||
|
||
public Set<Integer> getWinningNumbers() { | ||
System.out.println("당첨 번호를 입력해 주세요."); | ||
String input = Console.readLine(); | ||
String[] split = input.split(","); | ||
if (split.length != 6) { | ||
throw new IllegalArgumentException("당첨 번호는 6개여야 합니다."); | ||
} | ||
|
||
Set<Integer> winningNumbers = new HashSet<>(); | ||
for (String number : split) { | ||
int num; | ||
try { | ||
num = Integer.parseInt(number); | ||
} catch (NumberFormatException e) { | ||
throw new IllegalArgumentException("당첨 번호는 숫자여야 합니다."); | ||
} | ||
if (num < 1 || num > 45) { | ||
throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||
} | ||
winningNumbers.add(num); | ||
} | ||
if (winningNumbers.size() != 6) { | ||
throw new IllegalArgumentException("당첨 번호는 중복되지 않는 6개의 숫자여야 합니다."); | ||
} | ||
return winningNumbers; | ||
} | ||
|
||
public int getBonusNumber(Set<Integer> winningNumbers) { | ||
System.out.println("보너스 번호를 입력해 주세요."); | ||
String input = Console.readLine(); | ||
int bonusNumber; | ||
try { | ||
bonusNumber = Integer.parseInt(input); | ||
} catch (NumberFormatException e) { | ||
throw new IllegalArgumentException("보너스 번호는 숫자여야 합니다."); | ||
} | ||
if (bonusNumber < 1 || bonusNumber > 45) { | ||
throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||
} | ||
if (winningNumbers.contains(bonusNumber)) { | ||
throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복되지 않아야 합니다."); | ||
} | ||
return bonusNumber; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package lotto.view; | ||
|
||
import lotto.model.LottoModel; | ||
import lotto.model.LottoMachineModel; | ||
import lotto.model.WinningResultModel; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
public class LottoGame { | ||
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. 전반적인 흐름을 관리하는 것으로 보아 view보단 controller가 좀더 어울리네요 |
||
|
||
private static final int LOTTO_PRICE = 1000; | ||
private final ConsoleInput consoleInput; | ||
private final LottoMachineModel lottoMachine; | ||
private final WinningResultModel winningResult; | ||
|
||
public LottoGame(ConsoleInput consoleInput, LottoMachineModel lottoMachine, WinningResultModel winningResult) { | ||
this.consoleInput = consoleInput; | ||
this.lottoMachine = lottoMachine; | ||
this.winningResult = winningResult; | ||
} | ||
|
||
public void start() { | ||
try { | ||
int purchaseAmount = getPurchaseAmount(); | ||
List<LottoModel> purchasedLottos = generateLottos(purchaseAmount); | ||
printPurchasedLottos(purchasedLottos); | ||
|
||
Set<Integer> winningNumbers = getWinningNumbers(); | ||
int bonusNumber = getBonusNumber(winningNumbers); | ||
|
||
checkAndPrintWinningResult(purchasedLottos, winningNumbers, bonusNumber, purchaseAmount); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println("[ERROR] " + e.getMessage()); | ||
} | ||
} | ||
|
||
private int getPurchaseAmount() { | ||
return consoleInput.getPurchaseAmount(); | ||
} | ||
|
||
private List<LottoModel> generateLottos(int purchaseAmount) { | ||
int numberOfLottos = purchaseAmount / LOTTO_PRICE; | ||
return lottoMachine.generateLottos(numberOfLottos); | ||
} | ||
|
||
private void printPurchasedLottos(List<LottoModel> lottos) { | ||
System.out.printf("%d개를 구매했습니다.%n", lottos.size()); | ||
for (LottoModel lotto : lottos) { | ||
System.out.println(lotto.getNumbers()); | ||
} | ||
} | ||
|
||
private Set<Integer> getWinningNumbers() { | ||
return consoleInput.getWinningNumbers(); | ||
} | ||
|
||
private int getBonusNumber(Set<Integer> winningNumbers) { | ||
return consoleInput.getBonusNumber(winningNumbers); | ||
} | ||
|
||
private void checkAndPrintWinningResult(List<LottoModel> purchasedLottos, Set<Integer> winningNumbers, int bonusNumber, int purchaseAmount) { | ||
winningResult.checkWinning(purchasedLottos, winningNumbers, bonusNumber); | ||
winningResult.printWinningResult(); | ||
|
||
double profitRate = winningResult.calculateProfitRate(purchaseAmount); | ||
System.out.printf("총 수익률은 %.1f%%입니다.%n", profitRate); | ||
} | ||
} |
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.
마치 스프링 컨테이너 역할을 하는 클래스를 만들었군요 좋습니다.