Skip to content
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

[로또 미션] 이현수 미션 제출합니다 #43

Open
wants to merge 2 commits into
base: 20hyeonsulee
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 13 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import model.LottoGame;
import view.InputView;
import view.OutputView;

public class Application {

public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
LottoGame lottoGame = new LottoGame(inputView, outputView);
lottoGame.play();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 main과 별도의 실행 클래스를 분리하는 이유가 있나요?
잘 몰라서 여쭤봅니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나름 관심사를 분리한다고 분리했던것 같습니다!

}
11 changes: 11 additions & 0 deletions src/main/java/model/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package model;

import java.util.List;

public record Lotto(List<LottoNumber> numbers) {

@Override
public String toString() {
return numbers.toString();
}
}
71 changes: 71 additions & 0 deletions src/main/java/model/LottoGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package model;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import view.InputView;
import view.OutputView;

public class LottoGame {

private final InputView inputView;
private final OutputView outputView;

private final Integer LOTTO_PRICE = 1_000;

public LottoGame(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void play() {
Integer price = inputView.readPrice();
Integer totalCount = price / LOTTO_PRICE;
Integer manualCount = inputView.readManualCount();
Integer autoCount = totalCount - manualCount;
List<Lotto> manualLottos = inputView.readManualLottos(manualCount);
List<Lotto> autoLottos = RandomLottoGenerator.generateLottoNumbers(autoCount);
outputView.printMyLottos(manualLottos, autoLottos);
Lotto winningLotto = inputView.readWinningLotto();
Integer bonusNumber = inputView.readBonusNumber();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

입력한 보너스 번호가 이미 뽑힌 번호 중에 있지 않은지에 대한 검증이 필요하다고 생각합니다

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오.. 맞네요 수정했습니다!

List<Lotto> myLottos = concatMyLottos(manualLottos, autoLottos);
Map<Rank, Integer> myResult = calculateResult(myLottos, winningLotto, bonusNumber);
outputView.printResult(myResult);
Integer profit = computeProfit(myResult);
outputView.printRateOfReturn(LOTTO_PRICE * totalCount, profit);
}

private Integer computeProfit(Map<Rank, Integer> result) {
return Arrays.stream(Rank.values())
.filter(it -> it.matchCount() >= 3)
.mapToInt(it -> result.getOrDefault(it, 0) * it.price())
.sum();
}

private Map<Rank, Integer> calculateResult(List<Lotto> myLottos, Lotto winningLotto, Integer bonusNumber) {
Map<Rank, Integer> result = new HashMap<>();
myLottos.stream().forEach(lotto -> {
Integer count = computeMatchCount(lotto, winningLotto);
Boolean containsBonusNumber = lotto.numbers().contains(bonusNumber);
Rank rank = Rank.of(count, containsBonusNumber);
result.put(rank, result.getOrDefault(rank, 0) + 1);
});
return result;
}

private Integer computeMatchCount(Lotto myLotto, Lotto winningLotto) {
return Math.toIntExact(myLotto.numbers().stream()
.filter(winningLotto.numbers()::contains)
.count());
}

private List<Lotto> concatMyLottos(List<Lotto> manualLottos, List<Lotto> autoLottos) {
return Stream.concat(
manualLottos.stream(),
autoLottos.stream()
).toList();
}
}
9 changes: 9 additions & 0 deletions src/main/java/model/LottoNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package model;

public record LottoNumber(int number) {

@Override
public String toString() {
return String.valueOf(number);
}
}
26 changes: 26 additions & 0 deletions src/main/java/model/RandomLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package model;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class RandomLottoGenerator {

public static List<Lotto> generateLottoNumbers(Integer count) {
return IntStream.range(0, count)
.mapToObj(i -> generateLottoNumber())
.toList();
}

private static Lotto generateLottoNumber() {
Set<LottoNumber> lottoNumbers = IntStream.generate(() -> ThreadLocalRandom.current().nextInt(1, 46))
.distinct()
.limit(6)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음부터 limit를 걸어버리면 예외처리를 생략해도 되는군요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어멋.. 생각해보니 제가 예외처리를 꼼꼼하게 못한것같네요.. ㅠ

.mapToObj(it -> new LottoNumber(it))
.collect(Collectors.toSet());
return new Lotto(new ArrayList<>(lottoNumbers));
}
}
43 changes: 43 additions & 0 deletions src/main/java/model/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package model;

import java.util.Arrays;

public enum Rank {
_LAST(0, 0, false),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

등수 외의 상수도 있으니 예외 대신 쓸수 있고 명확하네요!

_5TH(5_000, 3, false),
_4TH(50_000, 4, false),
_3TH(1_500_000, 5, false),
_2TH(30_000_000, 5, true),
_1TH(2_000_000_000, 6, false),
;

private final int price;
private final int matchCount;
private final boolean containsBonus;

Rank(int price, int matchCount, boolean containsBonus) {
this.price = price;
this.matchCount = matchCount;
this.containsBonus = containsBonus;
}

public static Rank of(int matchCount, boolean containsBonus) {
return Arrays.stream(Rank.values())
.filter(it -> it.matchCount == matchCount)
.filter(it -> matchCount == 5? it.containsBonus == containsBonus : true)
.findFirst()
.orElse(_LAST);
}

public int price() {
return price;
}

public int matchCount() {
return matchCount;
}

public boolean containsBonus() {
return containsBonus;
}
}
56 changes: 56 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package view;

import java.util.List;
import java.util.Scanner;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import model.Lotto;
import model.LottoNumber;

public class InputView {

private static final Scanner SCANNER = new Scanner(System.in);

public int readPrice() {
System.out.println("구입금액을 입력해 주세요.");
return readNextInt();
}

public int readBonusNumber() {
System.out.println("보너스 볼을 입력해 주세요.");
return readNextInt();
}

public List<Lotto> readManualLottos(Integer count) {
System.out.println("수동으로 구매할 번호를 입력해 주세요.");
return IntStream.range(0, count)
.mapToObj(i -> readLotto())
.toList();
}

public int readManualCount() {
System.out.println("수동으로 구매할 로또 수를 입력해 주세요.");
return readNextInt();
}

public Lotto readWinningLotto() {
System.out.println("지난 주 당첨 번호를 입력해 주세요.");
return readLotto();
}

private Lotto readLotto() {
String input = SCANNER.nextLine();
return new Lotto(
Stream.of(input.replace(" ","").split(","))
.map(it -> new LottoNumber(Integer.parseInt(it)))
.toList()
);
}

private int readNextInt() {
Integer input = SCANNER.nextInt();
SCANNER.nextLine();
return input;
}
}
39 changes: 39 additions & 0 deletions src/main/java/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package view;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import model.Lotto;
import model.Rank;

public class OutputView {

public void printMyLottos(List<Lotto> manual, List<Lotto> auto) {
System.out.println(String.format("수동으로 %d장, 자동으로 %d개를 구매했습니다.", manual.size(), auto.size()));
manual.stream().forEach(System.out::println);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오.. 그러고 보니 println을 스트림으로 써 볼 생각을 못했네요.

auto.stream().forEach(System.out::println);
}

public void printRateOfReturn(Integer price, Integer profit) {
Double rateOfReturn = ((double) profit / price) * 100.0d;
System.out.println(String.format("총 수익률은 %.2f입니다.", rateOfReturn));
}

public void printResult(Map<Rank, Integer> result) {
System.out.println("당첨 통계");
System.out.println("---------");
Arrays.stream(Rank.values())
.filter(rank -> rank.matchCount() != 0)
.forEach(rank -> printResult(rank, result.getOrDefault(rank, 0)));
}

private void printResult(Rank rank, Integer count) {
String bonus = rank.containsBonus()? ", 보너스 볼 일치": " ";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삼항연산자를 쓰지 말라는 조건이 있었습니다!
그래도 확실히 삼항연산자를 쓰는게 더 간결해지고 보기 편하네요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

으악! 수정하겠습니다

System.out.println(String.format("%d개 일치%s(%d원)- %d개",
rank.matchCount(),
bonus,
rank.price(),
count));
}
}