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

[로또 미션] - 원태연, 이승용 미션 제출합니다. #1

Open
wants to merge 38 commits into
base: taeyeonroyce
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5363326
Docs: readme 작성
jelee2555 May 1, 2024
2f27c66
feat: 로또 번호 추가
jelee2555 May 1, 2024
ffec0c5
feat: 로또 검증 로직 추가
jelee2555 May 1, 2024
36e7a0d
feat: 로또 가격 추가
jelee2555 May 1, 2024
178bc0e
feat: 로또 가격 입력
jelee2555 May 1, 2024
6d2244c
feat: 로또 랜덤 생성 로직 추가
jelee2555 May 1, 2024
2e22419
fix: 로또 번호 범위 수정
TaeyeonRoyce May 2, 2024
ea1f133
refactor: 매직 넘버 제거
TaeyeonRoyce May 2, 2024
02117a5
feat: 로또 게임 관리 객체 추가
TaeyeonRoyce May 2, 2024
e527000
fix: 로또 금액 입력 시, 문자열 입력에 대한 예외 처리 적용
TaeyeonRoyce May 2, 2024
8dc6638
test: 로또 금액 테스트 추가
TaeyeonRoyce May 2, 2024
fe3c459
feat: 로또 발행 로직 추가
TaeyeonRoyce May 2, 2024
e0d1c0a
refactor: 값객체 record로 변환
TaeyeonRoyce May 2, 2024
28637cc
feat: 로또 결과 출력
TaeyeonRoyce May 2, 2024
b720de9
feat: 로또 오름차순 정렬 규칙 반영
TaeyeonRoyce May 2, 2024
5e69c08
refactor: 불필요한 static 제거
TaeyeonRoyce May 2, 2024
77f2eba
test: 객체 테스트 추가
TaeyeonRoyce May 2, 2024
c3d3def
refactor: 패키지 분리
TaeyeonRoyce May 2, 2024
20d6f2f
feat: 애플리케이션 추가
TaeyeonRoyce May 2, 2024
db3eb59
refactor: 테스트 패키지 이동
TaeyeonRoyce May 2, 2024
fad8541
docs: 2단계 요구사항 정리
TaeyeonRoyce May 2, 2024
ed40d83
feat: 로또 결과 순위 객체 추가
TaeyeonRoyce May 2, 2024
4e861b4
feat: 로또 결과 계산 로직 추가
TaeyeonRoyce May 2, 2024
314f607
feat: 로또 결과 추산 객체 추가
TaeyeonRoyce May 2, 2024
a0920b4
feat: 수익률 계산
TaeyeonRoyce May 2, 2024
3d0af72
feat: 당첨 번호 추첨 및 결과 출력
TaeyeonRoyce May 3, 2024
9fe9d10
fix: 당첨 로또 입력 오류 수정
kokodak May 5, 2024
98f1349
refactor: 로또 당첨 비교 로직 삭제
kokodak May 5, 2024
79d8b5f
feat: 당첨 로또 도메인 생성
kokodak May 5, 2024
9153d70
feat: 2등상 추가
kokodak May 5, 2024
5f25494
feat: 보너스 볼 입력 로직 구현
kokodak May 5, 2024
8255321
feat: 2등상 출력 형식 구현
kokodak May 5, 2024
92a593d
style: 컨벤션 수정
kokodak May 5, 2024
8eff1b4
feat: 2등을 위한 보너스 볼 추가 로직 구현
kokodak May 5, 2024
4bafa45
feat: 수동 구매를 위한 입력 로직 구현
kokodak May 5, 2024
018abad
feat: 수동 및 자동 구매 현황 출력 로직 구현
kokodak May 5, 2024
660447f
feat: 로또 수동 구매 로직 구현
kokodak May 5, 2024
b5212db
Merge pull request #1 from kokodak/kokodak
TaeyeonRoyce May 6, 2024
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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Lotto

- 크기가 6인 int List : numbers
- [x] 1 ~ 45 사이의 숫자
- [x] 중복되지 않아야 함
- [x] 크기가 6이어야 함

- [x] 로또 금액을 입력 받아야 함
- [x] 1000원 단위로 입력
- [x] 최소 1000원 이상
- [x] 로또 번호는 랜덤으로 설정
- [x] 숫자들끼리 중복되지 않도록
- [x] 1 ~ 45 사이
- [x] 출력 시 숫자들이 오름차순으로 정렬

- [x] 당첨 번호를 입력 받는다
- 당첨 결과를 계산한다.
- [x] 일치한 개수에 따라 순위와 당첨금이 결정된다.
- [x] 수익률을 계산한다
- [x] 당첨 통계를 출력한다.
13 changes: 13 additions & 0 deletions src/main/java/LottoApplication.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 LottoApplication {

public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
LottoGame lottoGame = new LottoGame(inputView, outputView);
lottoGame.run();
}
}
47 changes: 47 additions & 0 deletions src/main/java/model/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public record Lotto(List<LottoNumber> numbers) {

public static final int LOTTO_SIZE = 6;

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

public static Lotto from(List<Integer> numbers) {
List<LottoNumber> lottoNumbers = numbers.stream()
.map(LottoNumber::new)
.toList();
return new Lotto(lottoNumbers);
}

private void validate(List<LottoNumber> numbers) {
validateSize(numbers);
validateDuplication(numbers);
}

private void validateSize(List<LottoNumber> numbers) {
if (numbers.size() != LOTTO_SIZE) {
throw new IllegalArgumentException("로또는 6개의 숫자로 이루어져야 합니다.");
}
}

private void validateDuplication(List<LottoNumber> numbers) {
long duplicatedSize = numbers.stream().distinct().count();
if (numbers.size() != duplicatedSize) {
throw new IllegalArgumentException("로또는 중복되지 않는 6개의 숫자로 이루어져야 합니다.");
}
}

@Override
public List<LottoNumber> numbers() {
return List.copyOf(numbers);
}
}
80 changes: 80 additions & 0 deletions src/main/java/model/LottoGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package model;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import view.InputView;
import view.OutputView;
import view.dto.LottoResponse;
import view.dto.LottoStatisticsResponse;

public class LottoGame {

private final InputView inputView;
private final OutputView outputView;

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

public void run() {
LottoPrice price = LottoPrice.valueOf(inputView.readLottoPrice());
int lottoAmount = price.divideByUnit();
final int manualLottoCount = inputView.readManualLottoCount();
final int automaticLottoCount = lottoAmount - manualLottoCount;

if (lottoAmount < manualLottoCount) {
throw new IllegalArgumentException("로또 구매 금액이 부족합니다.");
}

List<Lotto> lottos = publishLotto(manualLottoCount, automaticLottoCount);
printPublishedResult(lottos, manualLottoCount, automaticLottoCount);

WinningLotto winningLotto = readWinningLotto();

ResultStatistics resultStatistics = calculateResultStatistics(lottos, winningLotto);
LottoStatisticsResponse response = LottoStatisticsResponse.from(resultStatistics);
outputView.printResultStatistics(response);
}

private List<Lotto> publishLotto(int manualLottoCount, int automaticLottoCount) {
List<Lotto> lottos = new ArrayList<>();

inputView.readManualLottoNumbers(manualLottoCount).stream()
.map(manualLottoNumber -> {
List<Integer> numbers = Stream.of(manualLottoNumber.replace(" ", "").split(","))
.map(Integer::parseInt)
.toList();
return Lotto.from(numbers);
})
.forEach(lottos::add);

IntStream.range(0, automaticLottoCount)
.mapToObj(i -> RandomLottoGenerator.generateLotto())
.forEach(lottos::add);

return lottos;
}

private void printPublishedResult(List<Lotto> lottos, int manualLottoCount, int automaticLottoCount) {
List<LottoResponse> results = lottos.stream().map(LottoResponse::from).toList();
outputView.printLotto(results, manualLottoCount, automaticLottoCount);
}

private WinningLotto readWinningLotto() {
List<LottoNumber> winningNumbers = inputView.readWinningNumbers().stream()
.map(LottoNumber::valueOf)
.toList();
final LottoNumber bonusNumber = new LottoNumber(inputView.readBonusNumber());
return new WinningLotto(new Lotto(winningNumbers), bonusNumber);
}

private ResultStatistics calculateResultStatistics(List<Lotto> lottos, WinningLotto winningLotto) {
List<Rank> ranks = lottos.stream()
.map(winningLotto::match)
.toList();
return ResultStatistics.from(ranks);
}
}
30 changes: 30 additions & 0 deletions src/main/java/model/LottoNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package model;

public record LottoNumber(int number) implements Comparable<LottoNumber> {

public static final int MIN_VALUE = 1;
public static final int MAX_VALUE = 45;

public LottoNumber {
validateRange(number);
}

public static LottoNumber valueOf(String number) {
try {
return new LottoNumber(Integer.parseInt(number));
} catch (NumberFormatException exception) {
throw new IllegalArgumentException("로또 번호는 숫자여야 합니다.");
}
}

private void validateRange(int number) {
if (number < MIN_VALUE || number > MAX_VALUE) {
throw new IllegalArgumentException("로또 번호는 1부터 45 사이여야 합니다.");
}
}

@Override
public int compareTo(LottoNumber other) {
return Integer.compare(number, other.number);
}
}
40 changes: 40 additions & 0 deletions src/main/java/model/LottoPrice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package model;

public record LottoPrice(int price) {

public static final int MIN_PRICE = 0;
public static final int PRICE_UNIT = 1_000;

public LottoPrice {
validate(price);
}

public static LottoPrice valueOf(String price) {
try {
return new LottoPrice(Integer.parseInt(price));
} catch (NumberFormatException numberFormatException) {
throw new IllegalArgumentException("로또 금액은 숫자여야 합니다.");
}
}

private void validate(int price) {
validateRange(price);
validateUnit(price);
}

private void validateRange(int price) {
if (price < MIN_PRICE) {
throw new IllegalArgumentException("로또 금액은 0원 보다 작을 수 없습니다.");
}
}

private void validateUnit(int price) {
if (price % PRICE_UNIT != 0) {
throw new IllegalArgumentException("로또 금액은 1000원 단위여야 합니다.");
}
}

public int divideByUnit() {
return price() / PRICE_UNIT;
}
}
24 changes: 24 additions & 0 deletions src/main/java/model/RandomLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package model;

import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class RandomLottoGenerator {

public static final Random RANDOM = new Random();

public static Lotto generateLotto() {
Set<Integer> numbers = new HashSet<>();
while (numbers.size() < Lotto.LOTTO_SIZE) {
int randomNumber = RANDOM.nextInt(LottoNumber.MIN_VALUE, LottoNumber.MAX_VALUE);
numbers.add(randomNumber);
}

List<LottoNumber> lottoNumbers = numbers.stream()
.map(LottoNumber::new)
.toList();
return new Lotto(lottoNumbers);
}
}
44 changes: 44 additions & 0 deletions src/main/java/model/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package model;

import java.util.Arrays;

public enum Rank {

_LAST_PRIZE(0, false, 0),
_5TH_PRIZE(3, false, 5_000),
_4TH_PRIZE(4, false, 50_000),
_3RD_PRIZE(5, false, 1_500_000),
_2ND_PRIZE(5, true, 30_000_000),
_1ST_PRIZE(6, false, 2_000_000_000),
;

private final int matchCount;
private final boolean containsBonus;
private final int prize;

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

public static Rank of(int matchCount, boolean matchBonus) {
return Arrays.stream(Rank.values())
.filter(rank -> rank.matchCount == matchCount)
.filter(rank -> rank.containsBonus == matchBonus)
.findFirst()
.orElse(_LAST_PRIZE);
}

public int matchCount() {
return matchCount;
}

public boolean containsBonus() {
return containsBonus;
}

public int prize() {
return prize;
}
}
33 changes: 33 additions & 0 deletions src/main/java/model/ResultStatistics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package model;

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

public class ResultStatistics {

private final Map<Rank, Integer> ranksByCount;
private final int purchaseAmount;

private ResultStatistics(Map<Rank, Integer> ranksByCount, int purchaseAmount) {
this.ranksByCount = ranksByCount;
this.purchaseAmount = purchaseAmount;
}

public static ResultStatistics from(List<Rank> ranks) {
Map<Rank, Integer> ranksByCount = ranks.stream()
.collect(Collectors.toMap(rank -> rank, rank -> 1, Integer::sum));
return new ResultStatistics(ranksByCount, ranks.size() * LottoPrice.PRICE_UNIT);
}

public int countOf(Rank rank) {
return ranksByCount.getOrDefault(rank, 0);
}

public double calculateProfitRate() {
int totalWinningPrize = ranksByCount.entrySet().stream()
.mapToInt(entry -> entry.getKey().prize() * entry.getValue())
.sum();
return ((float) (totalWinningPrize * 100) / purchaseAmount) / 100.0;
}
}
36 changes: 36 additions & 0 deletions src/main/java/model/WinningLotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package model;

import static model.Rank._2ND_PRIZE;

import java.util.List;

public record WinningLotto(Lotto lotto, LottoNumber bonusNumber) {

public WinningLotto {
validate(lotto, bonusNumber);
}

public static WinningLotto from(List<Integer> numbers, int bonusNumber) {
return new WinningLotto(Lotto.from(numbers), new LottoNumber(bonusNumber));
}

private void validate(Lotto lotto, LottoNumber bonusNumber) {
validateDuplication(lotto, bonusNumber);
}

private void validateDuplication(Lotto lotto, LottoNumber bonusNumber) {
if (lotto.numbers().contains(bonusNumber)) {
throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
}

public Rank match(Lotto other) {
int matchCount = (int) other.numbers().stream()
.filter(lotto.numbers()::contains)
.count();
if (matchCount == _2ND_PRIZE.matchCount()) {
return Rank.of(matchCount, other.numbers().contains(bonusNumber));
}
return Rank.of(matchCount, false);
}
}
Loading