-
Notifications
You must be signed in to change notification settings - Fork 3
[로또만들기] 남지윤 3주차 미션 제출입니다. #2
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
base: main
Are you sure you want to change the base?
Changes from all commits
e0e8d35
630ba05
64333dd
9dfe302
1111dc5
4a0e378
5f491f5
49f64aa
f76663f
197f7ef
2bd7aeb
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 +1,53 @@ | ||
| # javascript-lotto-precourse | ||
| ✅ 입출력 | ||
| - 로또 구입 금액 입력(1000단위) ✅ | ||
| - 당첨 번호 입력 ✅ | ||
| - 보너스 번호 입력 ✅ | ||
| - 발행한 로또 개수 출력 ✅ | ||
| - 결과 출력 | ||
|
|
||
| ✅ 전처리 | ||
| - 당첨 번호 쉼표 기준 구분(앞 뒤로 공백제거, 숫자로 변환) ✅ | ||
| - 발행한 로또 개수 구하기 ✅ | ||
|
|
||
| ✅ 1등 ~ 5등 검사 | ||
| - (로또 개수만큼) 중복되지 않는 숫자 6개 뽑기, 오름차순 정렬 ✅ | ||
| - 1등 조건 검사, 개수 카운트 ✅ | ||
| - 2등 조건 검사, 개수 카운트 ✅ | ||
| - 3등 조건 검사, 개수 카운트 ✅ | ||
| - 4등 조건 검사, 개수 카운트 ✅ | ||
| - 5등 조건 검사, 개수 카운트 ✅ | ||
|
|
||
| ✅ 수익률 계산 | ||
| - 수익률 계산 (벌어들인 금액/구매 금액), 소수점 둘째 자리 반올림 ✅ | ||
|
|
||
| ✅ 예외처리 | ||
| - 입력 오류 : 입력 금액이 1000으로 나누어 떨어지지 않는 경우 ✅ | ||
| - 입력 오류 : 로또 구매 금액이 숫자가 경우 ✅ | ||
| - 입력 오류 : 숫자가 아니거나, 쉼표가 아닌 것이 입력된 경우 ✅ | ||
| - 입력 오류 : 숫자가 중복되는 경우 ✅ | ||
| - 입력 오류 : 로또 번호가 범위를 벗어나는 경우 ✅ | ||
| - 입력 오류 : 로또 번호가 6개가 아닌 경우 ✅ | ||
| - 입력 오류 : 보너스 번호가 이미 입력한 번호와 중복되는 경우 ✅ | ||
| - 입력 오류 : 보너스 번호가 숫자가 아닌 경우 ✅ | ||
|
|
||
| # 클래스 설계 | ||
| - Lotto 클래스 : 입력된 로또 번호 검증 및 관리 | ||
| - LottoGame 클래스 : 게임진행, 로또발행, 당첨내역, 예외처리 | ||
| - App 클래스 : 입출력 담당 | ||
|
|
||
| # 코드 흐름 | ||
| - App 로또 금액 입력받기 | ||
| -> LottoGame 로또 금액만큼 로또 발행 요청 | ||
| -> Lotto 로또 발행 (외부에서 수정 불가) | ||
| -> LottoGame 발행된 로또 저장 | ||
| -> App 로또출력 | ||
|
|
||
| - App 로또 번호, 보너스 입력받기 | ||
| -> LottoGame 로또 번호 전처리(,제거) | ||
| -> Lotto 유저 로또 검증, 발행 | ||
| -> LottoGame 유저 로또 저장 | ||
| -> LottoGame 로또 번호 당첨 여부 카운트 | ||
| -> App 당첨여부출력 | ||
|
|
||
| # MVC 구조 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,86 @@ | ||
| import { Console } from "@woowacourse/mission-utils"; | ||
| import LottoGame from "../src/LottoGame.js"; | ||
|
|
||
| class App { | ||
| async run() {} | ||
| async run() { | ||
| try { | ||
| const lottoGame = new LottoGame(); | ||
|
|
||
| //구입금액 입력 | ||
| const inputMoney = await this.getInputMoney(); | ||
| const ticketCount = inputMoney / 1000; | ||
|
|
||
| //구입한 로또 출력 | ||
| Console.print(`${ticketCount}개를 구매했습니다.`); | ||
| const winningLotto = lottoGame.creatLotto(ticketCount); | ||
| for (let lotto in winningLotto) { | ||
| Console.print(`[${winningLotto[lotto].join(", ")}]`); | ||
| } | ||
|
|
||
| //당첨번호 입력 | ||
| const userLotto = await this.getUserLotto(lottoGame); | ||
|
|
||
| //보너스번호 입력 | ||
| const inputBonus = await this.getBonusNumber(userLotto); | ||
|
|
||
| //결과 출력 | ||
| const rank = lottoGame.returnRank(userLotto, winningLotto, inputBonus); | ||
| Console.print("당첨 통계"); | ||
| Console.print("---"); | ||
| Console.print(`3개 일치 (5,000원) - ${rank.fifth}개`); | ||
| Console.print(`4개 일치 (50,000원) - ${rank.fourth}개`); | ||
| Console.print(`5개 일치 (1,500,000원) - ${rank.third}개`); | ||
| Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${rank.second}개`); | ||
| Console.print(`6개 일치 (2,000,000,000원) - ${rank.first}개`); | ||
| const earningRate = lottoGame.earningRate(inputMoney); | ||
| Console.print(`총 수익률은 ${earningRate}%입니다.`); | ||
|
|
||
| } catch (error) { | ||
| Console.print(error.message); | ||
| return Promise.reject(error); | ||
| } | ||
| } | ||
|
|
||
| // 재귀적으로 구입금액 입력 받기 | ||
| async getInputMoney() { | ||
| try { | ||
| const inputMoney = await Console.readLineAsync('구입금액을 입력해 주세요.'); | ||
| const moneyNum = Number(inputMoney); | ||
| if (isNaN(moneyNum) || inputMoney % 1000 !== 0 || !Number.isInteger(moneyNum)) { | ||
| throw new Error("[ERROR] IllegalArgumentException"); | ||
| } | ||
| return inputMoney; | ||
| } catch (error) { | ||
| Console.print(error.message); | ||
| return this.getInputMoney(); // 재귀적으로 다시 호출 | ||
| } | ||
| } | ||
|
|
||
| // 재귀적으로 당첨번호 입력 받기 | ||
| async getUserLotto(lottoGame) { | ||
| try { | ||
| const inputNumbers = await Console.readLineAsync('당첨 번호를 입력해 주세요.'); | ||
| const userLotto = lottoGame.preprocessUserLotto(inputNumbers); | ||
| return userLotto; | ||
| } catch (error) { | ||
| Console.print(error.message); | ||
| return this.getUserLotto(lottoGame); // 재귀적으로 다시 호출 | ||
| } | ||
| } | ||
|
|
||
| // 재귀적으로 보너스 번호 입력 받기 | ||
| async getBonusNumber(userLotto) { | ||
| try { | ||
| const inputBonus = await Console.readLineAsync('보너스 번호를 입력해 주세요.'); | ||
| if (userLotto.includes(Number(inputBonus))||isNaN(inputBonus)) { | ||
| throw new Error("[ERROR] 보너스 번호는 입력하지 않은 숫자이어야 합니다."); | ||
| } | ||
| return inputBonus; | ||
| } catch (error) { | ||
| Console.print(error.message); | ||
| return this.getBonusNumber(userLotto); // 재귀적으로 다시 호출 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export default App; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,8 @@ | ||
| import { Random } from "@woowacourse/mission-utils"; | ||
|
|
||
| //로또 번호 저장, 검증, 반환 | ||
| class Lotto { | ||
| #numbers; | ||
| #numbers; //받은 로또 번호리스트 | ||
|
|
||
| constructor(numbers) { | ||
| this.#validate(numbers); | ||
|
|
@@ -12,7 +15,9 @@ class Lotto { | |
| } | ||
| } | ||
|
|
||
| // TODO: 추가 기능 구현 | ||
| getNumbers(){ | ||
| return this.#numbers | ||
| } | ||
| } | ||
|
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. Lotto 클래스에서는 로또 티켓이 가진 고유의 성질들을 구현하시면 좋을 것 같아요. 저는 로또 번호 6를 랜덤으로 뽑는 것이라던지 당첨번호를 입력받을 때의 예외 처리를 이 부분에서 구현하였습니다. |
||
|
|
||
| export default Lotto; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import { Console, Random } from "@woowacourse/mission-utils"; | ||
| import Lotto from "../src/Lotto.js"; | ||
|
|
||
| class LottoGame{ | ||
| constructor(){ | ||
| this.winningLottos = [] | ||
| this.counts = {first : 0, second : 0, third: 0, fourth: 0, fifth: 0}; | ||
| } | ||
|
|
||
| //로또 발행 | ||
| creatLotto(num){ | ||
| for(let i = 0; i < num; i++){ | ||
| let numbers = Random.pickUniqueNumbersInRange(1, 45, 6); //중복되지 않는 숫자 6개 | ||
| this.winningLottos.push(new Lotto(numbers).getNumbers()); | ||
| } | ||
| this.winningLottos.sort((a,b) => a - b); | ||
| return this.winningLottos | ||
| } | ||
|
|
||
| // userLotto 전처리 | ||
| preprocessUserLotto(userNumbers) { | ||
| userNumbers = userNumbers.split(",").map(num => num.trim()).map(num => Number(num)); | ||
| const userLotto = new Lotto(userNumbers); | ||
| return userLotto.getNumbers().sort((a,b) => a - b); | ||
| } | ||
|
|
||
| // 일치하는 숫자 개수 계산 | ||
| calculateMatchingCount(userLotto, winningLotto) { | ||
| return userLotto.filter(num => winningLotto.includes(num)).length; | ||
| } | ||
|
|
||
| // 등수 판별 | ||
| getRank(matchingCount, bonusMatch) { | ||
| switch (matchingCount) { | ||
| case 6: return 'first'; | ||
| case 5: return bonusMatch ? 'third' : 'second'; | ||
| case 4: return 'fourth'; | ||
| case 3: return 'fifth'; | ||
| default: return null; | ||
| } | ||
| } | ||
|
|
||
| // 등수 반환 | ||
| returnRank(userLotto, winningLottos, bonusNumber){ | ||
| let matchingCount = 0; | ||
| let bonusMatch = userLotto.includes(bonusNumber); | ||
|
|
||
| for (let i = 0; i < winningLottos.length; i++) { | ||
| // 일치하는 번호 개수 계산 | ||
| matchingCount = this.calculateMatchingCount(userLotto, winningLottos[i]); | ||
|
|
||
| // 등수 판별 | ||
| let rank = this.getRank(matchingCount, bonusMatch); | ||
| if (rank) { | ||
| this.counts[rank] += 1; | ||
| } | ||
| } | ||
|
|
||
| return this.counts; | ||
| } | ||
|
|
||
|
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. 결과 출력하는 부분의 구현을 이부분에 해놓고 App에서는 함수 호출을 하면 위에 수익률 계산 하는 함수에 대한 결과를 바로 밑에서 볼 수 있어서 가독성이 좋을 것 같습니다! |
||
| //수익률 계산 (벌어들인 금액/구매 금액) | ||
| earningRate(money){ | ||
| const earnings = (this.counts.fifth * 5000) + | ||
| (this.counts.fourth * 50000) + | ||
| (this.counts.second * 1500000) + | ||
| (this.counts.third * 30000000) + | ||
| (this.counts.first * 2000000000); | ||
|
|
||
| const earningsRate = (earnings / money) * 100 ; | ||
| const roundedearningsRate = parseFloat(earningsRate.toFixed(1)); | ||
| return roundedearningsRate; | ||
| } | ||
| } | ||
|
|
||
| export default LottoGame; | ||
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.
App 클래스에서는 사용자와 맞닿아있는 인터페이스 (UI) 부분을 구현하는 게 가독성이 좋아보일 것 같아요. 사용자가 디폴트로 거쳐야 하는 기능의 UI만 골라서 구현하시면 코드가 훨씬 간결해질 것 같습니다! 저의 경우는 예외처리 및 결과 출력 부분 등 기능별로 파일을 여러개 만들어서 별도로 구현하였습니다