Skip to content
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# java-lotto-precourse

# 기능 목록

1. 입출력

- 입력 : 구입 금액, 당첨 번호 목록, 보너스 번호
- 출력 : 구입한 로또 개수와 내용물, 당첨 개수와 수익

2. 로또 게임 관리자

- 잘못된 입력 시 무한 루프
- 입력, 처리 및 계산, 결과 출력 관장

3. 게임 관련 객체들

- 로또(변경 제한), 게임, 플레이어 객체

4. 로또 게임 관련 계산 처리기

- 로또 당첨 계산
- 수익 계산

5. 예외처리 검증기
6. 출력 메세지 관리
7. 우승 종류 관리
12 changes: 11 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package lotto;

import lotto.config.AppConfig;
import lotto.controller.LottoController;

public class Application {
static LottoController lottoController;

public static void main(String[] args) {
// TODO: 프로그램 구현
new Application().run();
}

public void run() {
lottoController = AppConfig.getLottoController();
lottoController.startGame();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

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

import lotto.controller.LottoController;
import lotto.service.LottoService;
import lotto.view.LottoView;

public class AppConfig {
private static final LottoView lottoView = new LottoView();
private static final LottoService lottoService = new LottoService();

public static LottoController getLottoController() {
return new LottoController(lottoView, lottoService);
}
}
102 changes: 102 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package lotto.controller;

import java.util.List;
import java.util.Set;
import lotto.model.Game;
import lotto.model.Lotto;
import lotto.model.Player;
import lotto.service.LottoService;
import lotto.util.MajorErrorMessage;
import lotto.util.Validator;
import lotto.util.Validator.dataType;
import lotto.view.LottoView;

public class LottoController {
final LottoView lottoView;
final LottoService lottoService;


public void startGame() {
boolean buyContinue = true;
boolean setGameContinue = true;

while (buyContinue) {
buyContinue = buyStep();
}
while (setGameContinue) {
setGameContinue = setGameStep();
}

resultStep();
}

public boolean buyStep() {
try {
Player player = setLottoMoney();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

서비스가 있음에도 모델을 컨트롤러 내부에 두신 이유가 있나요?
제 생각에는 컨트롤러 내부에 있는 로직들은 서비스에 분리하는게 컨트롤러에 부담을 줄이고 관심사를 분리하는데 용이할 것 같습니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

구현할 당시에는 로또 서비스는 로또만 다루게 해야지~~ 단순히 생각했다가 최종 제출 때 살짝 아차한 부분이긴 합니다ㅋㅋ 아무래도 서비스가 있는한 다른 모델들을 서비스 내부에서 다루게하는게 좋겠죠?

attemptLottoPurchase(player);
lottoService.setPlayer(player);
return false;
} catch (IllegalArgumentException e) {
lottoView.outputCaughtError(e.getMessage());
return true;
}
}

public boolean setGameStep() {
try {
Game gameStep = setJackpot();
gameStep = setBonus(gameStep);

lottoService.setGame(gameStep);
return false;
} catch (Exception e) {
lottoView.outputCaughtError(MajorErrorMessage.LOTTONUM_WRONG.getMessage() + e.getMessage());
return true;
}
}

public void resultStep() {
int[] lottoResultTypes = lottoService.calculateLottoResultType();
float lottoResultProfitPercent = lottoService.calculateLottoResultProfit(lottoResultTypes);
lottoView.outputLottoResult(lottoResultTypes, lottoResultProfitPercent);
}

Player setLottoMoney() {
try {
String inputLine = lottoView.inputPurchaseMoney();
return Player.setLottoMoney(Validator.isSingleInputType(inputLine, dataType.NUMBER));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Validator가 값을 다시 뱉으니 가독성이 떨어지는 것 같아요!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

글쿤요 따로 분리하겠슴다

} catch (Exception e) {
throw new IllegalArgumentException(MajorErrorMessage.MONEY_WRONG.getMessage() + e.getMessage());
}
}

void attemptLottoPurchase(Player player) {
try {
player.buyLotto();
lottoView.outputPurchasedLottoNum(player.getPurchasedLottoNum());
player.getPurchasedLottoList().forEach(lotto -> lottoView.outputPurchasedLottoDetail(lotto.getNumbers()));
} catch (Exception e) {
throw new IllegalArgumentException(MajorErrorMessage.LOTTONUM_WRONG.getMessage() + e.getMessage());
}
}

Game setJackpot() {
String inputLine = lottoView.inputJackpotNumber();
List<Integer> jackpotNumbers = Validator.isMultipleInputType(inputLine, dataType.NUMBER, ",");
Validator.isListItemInRange(Lotto.getLottoRangeStart(), Lotto.getLottoRangeEnd(), jackpotNumbers);
Set<Integer> jackpotNumberSet = Validator.isListItemDuplicated(jackpotNumbers);
return Game.setJackpot(jackpotNumberSet);
}

Game setBonus(Game game) {
String inputLine = lottoView.inputBonusNumber();
int bonusNumber = Validator.isSingleInputType(inputLine, dataType.NUMBER);
game.setBonus(bonusNumber);
return game;
}

public LottoController(LottoView lottoView, LottoService lottoService) {
this.lottoView = lottoView;
this.lottoService = lottoService;
}
}
33 changes: 33 additions & 0 deletions src/main/java/lotto/model/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lotto.model;

import java.util.Set;
import lotto.util.DetailErrorMessage;

public class Game {
private Set<Integer> jackpotNumbers;
private Integer bonus;

Game(Set<Integer> jackpotNumbers) {
this.jackpotNumbers = jackpotNumbers;
}

//static factory pattern
public static Game setJackpot(Set<Integer> jackpotNumbers) {
return new Game(jackpotNumbers);
}

public void setBonus(int bonus) {
if (jackpotNumbers.contains(bonus)) {
throw new IllegalArgumentException(DetailErrorMessage.DUPLICATED.getMessage());
}
this.bonus = bonus;
}

public Set<Integer> getJackpotNumbers() {
return jackpotNumbers;
}

public Integer getBonus() {
return bonus;
}
}
34 changes: 34 additions & 0 deletions src/main/java/lotto/model/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package lotto.model;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.List;
import lotto.util.Validator;

public class Lotto {
private final List<Integer> numbers;
static final int LOTTO_RANGE_START = 1;
static final int LOTTO_RANGE_END = 45;
static final int LOTTO_BALL_COUNT = 6;

public Lotto(List<Integer> numbers) {
Validator.isLength(numbers.size());
Validator.isListItemDuplicated(numbers);
this.numbers = numbers;
}

public static Lotto buyNew() {
return new Lotto(Randoms.pickUniqueNumbersInRange(LOTTO_RANGE_START, LOTTO_RANGE_END, LOTTO_BALL_COUNT));
}

public List<Integer> getNumbers() {
return numbers;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

전반적으로 모델의 역할이 약한 것 같아요...!
List가 private final으로만 선언되어서 배열 전체를 반환할 경우 외부에서 배열 내부의 값을 수정하는 문제가 발생할 수 있을 것 같아요
또 배열을 만들어서 내뱉는 역할만 한다면 모델이라고 보기 어려운 측면이 있을 것 같아요

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

모델에 대해 전에 공부햇을때 dto에 가까운 넘도 모델이라구 해서 걍 이놈도 모델처리해버렸습니당 또 배열 반환 수정이 문제군요..오호.. 그럼 얕은복사한 배열을 돌려쥬면 문제가 안되겠죠??

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

얕은 복사를 한다면 모델의 안정성은 지키겠지만, 모델의 필드를 외부에서 관리하도록 내버려두는게 바람직한 방향은 아니라고 생각합니다ㅎㅎ


public static int getLottoRangeStart() {
return LOTTO_RANGE_START;
}

public static int getLottoRangeEnd() {
return LOTTO_RANGE_END;
}
}
50 changes: 50 additions & 0 deletions src/main/java/lotto/model/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package lotto.model;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import lotto.util.DetailErrorMessage;

public class Player {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

로또에서 Player라는 객체를 만드신 맥락이 궁금해요! 문제를 어떻게 해석하시고 객체를 어떻게 정의하셨나요??

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

로또를 사서 여러장을 가지고 있다가 추첨 결과에 따라 그 사람이 상품을 탈테니 그걸 고려하구 플레이어 모델을 만들었습니당~~

final int purchaseMoney;
int profitMoney;
List<Lotto> purchasedLottoList;

public static Player setLottoMoney(int purchaseMoney) {
if (purchaseMoney <= 0) {
throw new IllegalArgumentException(DetailErrorMessage.ZERO_NEGATIVE.getMessage());
}
if (purchaseMoney % 1000 > 0) {
throw new IllegalArgumentException(DetailErrorMessage.NOT_MULTIPLE.getMessage());
}
return new Player(purchaseMoney);
}

Player(int purchaseMoney) {
this.purchaseMoney = purchaseMoney;
purchasedLottoList = new ArrayList<>();
}

public void buyLotto() {
int howMuch = purchaseMoney / 1000;
IntStream.range(0, howMuch).forEach((i) -> {
purchasedLottoList.add(Lotto.buyNew());
});
}

public List<Lotto> getPurchasedLottoList() {
return purchasedLottoList;
}

public int getPurchasedLottoNum() {
return purchasedLottoList.size();
}

public void setProfitMoney(int profitMoney) {
this.profitMoney = profitMoney;
}

public float getProfitPercent() {
return (float) (profitMoney * 100) / purchaseMoney;
}
}
60 changes: 60 additions & 0 deletions src/main/java/lotto/service/LottoService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package lotto.service;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
import lotto.model.Game;
import lotto.model.Player;
import lotto.util.GamePrize;

public class LottoService {
private Game game;
private Player player;
private static final int PRIZE_LENGTH = GamePrize.values().length;

public void setGame(Game game) {
this.game = game;
}

public void setPlayer(Player player) {
this.player = player;
}

public int[] calculateLottoResultType() {
int[] resultList = new int[PRIZE_LENGTH];
player.getPurchasedLottoList().forEach(lotto -> updateResultList(resultList, lotto.getNumbers()));
return resultList;
}

public float calculateLottoResultProfit(int[] resultList) {
int[] prizeMoneyList = Arrays.stream(GamePrize.values()).mapToInt(GamePrize::getPrizeMoney).toArray();
int earnedMoney = IntStream.range(0, PRIZE_LENGTH).map(i -> resultList[i] * prizeMoneyList[i]).sum();
player.setProfitMoney(earnedMoney);
return player.getProfitPercent();
}

void updateResultList(int[] resultList, List<Integer> singleLotto) {
if (checkPrizeIndex(singleLotto) > -1) {
resultList[checkPrizeIndex(singleLotto)]++;
}
}

int checkPrizeIndex(List<Integer> singleLotto) {
Set<Integer> jackpotNumbers = game.getJackpotNumbers();
//일치하는 로또 공 개수 셈
int matchingLottoBall = (int) singleLotto.stream().filter(jackpotNumbers::contains).count();
if (matchingLottoBall == 6) {
if (hasBonusMatch(singleLotto)) {
return GamePrize.PRIZE_2ND.getIndex();
}
return GamePrize.PRIZE_1ST.getIndex();
}
return matchingLottoBall - 3;
}

boolean hasBonusMatch(List<Integer> singleLotto) {
int bonus = game.getBonus();
return singleLotto.contains(bonus);
}
}
24 changes: 24 additions & 0 deletions src/main/java/lotto/util/DetailErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.util;

public enum DetailErrorMessage {
BLANK("빈칸 입력됨"),
NOT_NUMBER("수 외의 문자 입력됨"),
NOT_ALPHABET("알파벳 외의 문자 입력됨"),
NOT_COMMA(", 외의 구분자 입력됨"),
NOT_LENGTH("6개 아님"),
NOT_RANGE("1부터 45까지의 숫자 아님"),
DUPLICATED("중복된 번호 입력됨"),
NOT_MULTIPLE("1000의 배수 아님"),
ZERO_NEGATIVE("0 또는 음수 입력됨"),
DEV_TYPE_WRONG("개발 오류, 지원되지 않는 자료형입니다.");

private String message;

DetailErrorMessage(String message) {
this.message = message;
}

public String getMessage() {
return " : " + message;
}
}
Loading