-
Notifications
You must be signed in to change notification settings - Fork 1.1k
3단계 - 로또(2등) #4214
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
3단계 - 로또(2등) #4214
Changes from all commits
1f93118
451d4f9
8cafa4c
e3bef8b
0403d84
a5caacf
e1bfb3b
cd5f4b8
030f472
4be4d31
57ce83b
f75bfde
ac909b4
d148e86
17845eb
73ec000
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,22 +1,19 @@ | ||
| package lotto; | ||
|
|
||
| import lotto.model.PurchaseAmount; | ||
| import lotto.model.Lotto; | ||
| import lotto.model.LottoResults; | ||
| import lotto.model.Lottos; | ||
| import lotto.model.*; | ||
| import lotto.view.InputView; | ||
| import lotto.view.OutputView; | ||
|
|
||
| public class LottoApplication { | ||
| public static void main(String[] args) { | ||
| PurchaseAmount purchaseAmount = InputView.readBudgetInput(); | ||
| Lotto winningLotto = InputView.readWinningLottoInput(); | ||
| Money purchaseAmount = InputView.readPurchaseAmountInput(); | ||
| WinningLotto winningLotto = InputView.readWinningLottoInput(); | ||
|
|
||
| OutputView.printPurchaseCount(purchaseAmount.countLottoTickets()); | ||
| Lottos lottos = purchaseAmount.buyLottos(); | ||
| OutputView.printBoughtLottos(lottos); | ||
|
|
||
| LottoResults result = lottos.calculateResults(winningLotto); | ||
| LottoResults result = lottos.match(winningLotto); | ||
| OutputView.printResults(result, purchaseAmount); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,68 +1,54 @@ | ||
| package lotto.model; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.*; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.IntStream; | ||
|
|
||
| public class Lotto { | ||
| private final List<LottoNumber> numbers; | ||
| private final static int LOTTO_NUMBER_SIZE = 6; | ||
| private final static List<Integer> rangedInts = IntStream.rangeClosed(1, 45).boxed().collect(Collectors.toList()); | ||
| private final Set<LottoNumber> numbers; | ||
|
|
||
| public Lotto() { | ||
| this(generateRandomNumbers()); | ||
| } | ||
|
|
||
| public Lotto(int... numbers) { | ||
| this(Arrays.stream(numbers).boxed().collect(Collectors.toList())); | ||
| this(Arrays.stream(numbers).mapToObj(LottoNumber::of).collect(Collectors.toSet())); | ||
| } | ||
|
|
||
| public Lotto(List<Integer> numbers) { | ||
| public Lotto(Set<LottoNumber> numbers) { | ||
| checkValidity(numbers); | ||
| Collections.sort(numbers); | ||
| this.numbers = numbers.stream().map(LottoNumber::new).collect(Collectors.toList()); | ||
| } | ||
|
|
||
| public List<LottoNumber> value() { | ||
| return Collections.unmodifiableList(this.numbers); | ||
| this.numbers = numbers; | ||
| } | ||
|
|
||
| public int countMatchNumbers(Lotto lotto) { | ||
| int matchCount = 0; | ||
| for (LottoNumber number : this.numbers) { | ||
| matchCount += addMatchCount(number, lotto); | ||
| } | ||
| return matchCount; | ||
| return Math.toIntExact(this.numbers.stream().filter(lotto::contains).count()); | ||
| } | ||
|
|
||
| private void checkValidity(List<Integer> numbers) { | ||
| if (numbers.size() != 6) { | ||
| throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
| } | ||
| if (hasDuplicated(numbers)) { | ||
| throw new IllegalArgumentException("로또 번호는 중복될 수 없습니다."); | ||
| } | ||
| public boolean matchesBonusNumber(LottoNumber bonusNumber) { | ||
| return contains(bonusNumber); | ||
| } | ||
|
|
||
| private boolean hasDuplicated(List<Integer> numbers) { | ||
| long distinctCount = numbers.stream().distinct().count(); | ||
| return distinctCount != numbers.size(); | ||
| @Override | ||
| public String toString() { | ||
| List<LottoNumber> lottoNumbers = new ArrayList<>(this.numbers); | ||
| Collections.sort(lottoNumbers); | ||
| return lottoNumbers.toString(); | ||
| } | ||
|
|
||
| private int addMatchCount(LottoNumber number, Lotto lotto) { | ||
| if (lotto.contains(number)) { | ||
| return 1; | ||
| } | ||
| return 0; | ||
| public boolean contains(LottoNumber number) { | ||
| return numbers.contains(number); | ||
| } | ||
|
|
||
| private boolean contains(LottoNumber number) { | ||
| return numbers.contains(number); | ||
| private void checkValidity(Set<LottoNumber> numbers) { | ||
| if (numbers.size() != LOTTO_NUMBER_SIZE) { | ||
| throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| private static List<Integer> generateRandomNumbers() { | ||
| List<Integer> array = IntStream.rangeClosed(1, 45).boxed().collect(Collectors.toList()); | ||
| Collections.shuffle(array); | ||
| return array.subList(0, 6); | ||
| private static Set<LottoNumber> generateRandomNumbers() { | ||
| Collections.shuffle(rangedInts); | ||
| return rangedInts.subList(0, LOTTO_NUMBER_SIZE).stream().map(LottoNumber::of).collect(Collectors.toSet()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,19 +1,22 @@ | ||||||
| package lotto.model; | ||||||
|
|
||||||
| import java.util.Map; | ||||||
| import java.util.Objects; | ||||||
| import java.util.concurrent.ConcurrentHashMap; | ||||||
| import java.util.stream.IntStream; | ||||||
|
|
||||||
| public class LottoNumber { | ||||||
| private final int number; | ||||||
| public class LottoNumber implements Comparable<LottoNumber> { | ||||||
|
Contributor
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. 상황
위 요구사항을 서버에서 생성되는 LottoNumber의 인스턴스의 갯수는? 동시에 생성되는 인스턴스 갯수가 너무 많다. 힌트 : Map과 같은 곳에 인스턴스를 생성한 후 재사용하는 방법을 찾아본다. |
||||||
| private final static Map<Integer, LottoNumber> CACHE; | ||||||
|
|
||||||
|
Contributor
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.
Suggested change
문자열을 받는 생성자를 추가할 경우 의미있을까? |
||||||
| public LottoNumber(int number) { | ||||||
| if (!isValid(number)) { | ||||||
| throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||||||
| } | ||||||
| this.number = number; | ||||||
| static { | ||||||
| CACHE = new ConcurrentHashMap<>(); | ||||||
| IntStream.rangeClosed(1, 45).forEach(i -> CACHE.put(i, new LottoNumber(i))); | ||||||
| } | ||||||
|
Comment on lines
+11
to
14
Contributor
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. 👍 |
||||||
|
|
||||||
| private boolean isValid(int number) { | ||||||
| return number >= 1 && number <= 45; | ||||||
| private final int number; | ||||||
|
|
||||||
| private LottoNumber(int number) { | ||||||
| this.number = number; | ||||||
| } | ||||||
|
|
||||||
| public int getNumber() { | ||||||
|
|
@@ -36,4 +39,24 @@ public int hashCode() { | |||||
| public String toString() { | ||||||
| return String.valueOf(number); | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public int compareTo(LottoNumber another) { | ||||||
| return Integer.compare(this.number, another.number); | ||||||
| } | ||||||
|
|
||||||
| private static boolean isValid(int number) { | ||||||
| return CACHE.containsKey(number); | ||||||
| } | ||||||
|
|
||||||
| public static LottoNumber of(int number) { | ||||||
| if (!isValid(number)) { | ||||||
| throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||||||
| } | ||||||
| return CACHE.get(number); | ||||||
| } | ||||||
|
|
||||||
| public static LottoNumber of(String input) { | ||||||
| return of(Integer.parseInt(input)); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,59 +1,56 @@ | ||
| package lotto.model; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
|
|
||
| public class LottoResults { | ||
| private final Map<Integer, Integer> matchCounts; | ||
| private final Map<Prize, Integer> prizeCounts; | ||
|
|
||
| public LottoResults() { | ||
| this(new HashMap<>()); | ||
| } | ||
|
|
||
| public LottoResults(Map<Integer, Integer> matchCounts) { | ||
| this.matchCounts = matchCounts; | ||
| public LottoResults(Map<Prize, Integer> prizeCounts) { | ||
| this.prizeCounts = prizeCounts; | ||
| } | ||
|
|
||
| public void updateMatchCount(int matchCount) { | ||
| if (matchCount < 3) { | ||
| return; | ||
| } | ||
| matchCounts.put(matchCount, matchCounts.getOrDefault(matchCount, 0) + 1); | ||
| public void update(Prize prize) { | ||
| prizeCounts.put(prize, prizeCounts.getOrDefault(prize, 0) + 1); | ||
| } | ||
|
|
||
| public Money getTotalPrizeValue() { | ||
| return new Money(prizeCounts.entrySet().stream() | ||
| .mapToLong(entry -> (long) entry.getValue() * entry.getKey().value()) | ||
| .sum()); | ||
| } | ||
|
|
||
| public long getPrizeValue() { | ||
| return matchCounts.entrySet().stream() | ||
| .mapToLong(entry -> (long) entry.getValue() * Prize.fromMatchCount(entry.getKey()).value()) | ||
| .sum(); | ||
| public double getReturnRate(Money purchaseAmount) { | ||
| Money totalPrize = getTotalPrizeValue(); | ||
| return calculateReturnRate(purchaseAmount, totalPrize); | ||
| } | ||
|
|
||
| public double getReturnRate(PurchaseAmount purchaseAmount) { | ||
| long totalPrize = getPrizeValue(); | ||
| return purchaseAmount.getReturnRate(totalPrize); | ||
| private double calculateReturnRate(Money purchaseAmount, Money totalPrize) { | ||
| if (purchaseAmount.isZero()) { | ||
| return 0; | ||
| } | ||
| double rate = totalPrize.divideBy(purchaseAmount); | ||
| return Math.floor(rate * 100) / 100.0; | ||
| } | ||
|
|
||
| public Integer getMatchCount(int matchCount) { | ||
| return matchCounts.getOrDefault(matchCount, 0); | ||
| public Integer getPrizeCount(Prize prize) { | ||
| return prizeCounts.getOrDefault(prize, 0); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| LottoResults that = (LottoResults) o; | ||
| return Objects.equals(matchCounts, that.matchCounts); | ||
| return Objects.equals(prizeCounts, that.prizeCounts); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hashCode(matchCounts); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "LottoResults{" + | ||
| "matchCounts=" + matchCounts + | ||
| '}'; | ||
| return Objects.hashCode(prizeCounts); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,41 @@ | ||
| package lotto.model; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| public class Lottos { | ||
| private final List<Lotto> lottos; | ||
|
|
||
| public Lottos(int count) { | ||
| this(new ArrayList<>()); | ||
| for (int i = 0; i < count; i++) { | ||
| lottos.add(new Lotto()); | ||
| } | ||
| this(createLottos(count)); | ||
| } | ||
|
|
||
| public Lottos(List<Lotto> lottos) { | ||
| this.lottos = lottos; | ||
| } | ||
|
|
||
| public LottoResults calculateResults(Lotto winningLotto) { | ||
| LottoResults results = new LottoResults(); | ||
|
|
||
| for (Lotto lotto : lottos) { | ||
| int matchCount = lotto.countMatchNumbers(winningLotto); | ||
| results.updateMatchCount(matchCount); | ||
| } | ||
|
|
||
| return results; | ||
| } | ||
|
|
||
| private void addMatchCount(int matchCount, List<Integer> results) { | ||
| if (matchCount >= 3 && matchCount <= 6) { | ||
| int idx = matchCount - 3; | ||
| results.set(idx, results.get(idx) + 1); | ||
| public LottoResults match(WinningLotto winningLotto) { | ||
| LottoResults lottoResults = new LottoResults(); | ||
| for (Lotto lotto : this.lottos) { | ||
| lottoResults.update(winningLotto.calculatePrize(lotto)); | ||
| } | ||
| return lottoResults; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| StringBuilder sb = new StringBuilder(); | ||
| for (Lotto lotto : lottos) { | ||
| sb.append(lotto.value().toString()).append("\n"); | ||
| sb.append(lotto.toString()).append("\n"); | ||
| } | ||
| return sb.toString(); | ||
| } | ||
|
|
||
| private static List<Lotto> createLottos(int count) { | ||
| List<Lotto> lottos = new ArrayList<>(); | ||
| for (int i = 0; i < count; i++) { | ||
| lottos.add(new Lotto()); | ||
| } | ||
| return lottos; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,41 +2,45 @@ | |
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class PurchaseAmount { | ||
| private final int amount; | ||
| public class Money { | ||
|
Contributor
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. 👍 |
||
| private final long amount; | ||
|
|
||
| public PurchaseAmount(int amount) { | ||
| public Money(int amount) { | ||
| this((long) amount); | ||
| } | ||
|
|
||
| public Money(long amount) { | ||
| if (!isValid(amount)) { | ||
| throw new IllegalArgumentException("예산은 0 이상이며 1000원 단위로만 설정 가능합니다."); | ||
| } | ||
| this.amount = amount; | ||
| } | ||
|
|
||
| public int countLottoTickets() { | ||
| return amount / 1_000; | ||
| return Math.toIntExact(amount / 1_000L); | ||
| } | ||
|
|
||
| public Lottos buyLottos() { | ||
| return new Lottos(countLottoTickets()); | ||
| } | ||
|
|
||
| public double getReturnRate(Long totalPrize) { | ||
| if (amount == 0) { | ||
| return 0; | ||
| } | ||
| double rate = (double) totalPrize / amount; | ||
| return Math.floor(rate * 100) / 100.0; | ||
| public boolean isZero() { | ||
| return amount == 0; | ||
| } | ||
|
|
||
| public double divideBy(Money money) { | ||
| return (double) this.amount / money.amount; | ||
| } | ||
|
|
||
| private boolean isValid(int amount) { | ||
| private boolean isValid(Long amount) { | ||
| return amount >= 0 && amount % 1000 == 0; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| PurchaseAmount purchaseAmount = (PurchaseAmount) o; | ||
| return amount == purchaseAmount.amount; | ||
| Money money = (Money) o; | ||
| return amount == money.amount; | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
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.
👍