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

[로또] 육종호 미션 제출 합니다 #629

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f011fde
구현 기능 목록 업데이트
yook-jongho Nov 5, 2023
cb61623
로또번호 생성 기능 - 지정 범위 내 원하는 개수의 숫자 무작위 생성 및 중복 불가 기능 추가
yook-jongho Nov 5, 2023
a68afe7
로또 번호 생성 기능- 생성된 번호 오름차순 정렬 기능
yook-jongho Nov 5, 2023
df7cb4b
수익률 계산 및 소수점 둘째 자리 반올림
yook-jongho Nov 5, 2023
2303c85
구현 기능 목록 업데이트
yook-jongho Nov 5, 2023
2bea852
로또 번호 당첨 갯수
yook-jongho Nov 5, 2023
90fae62
입력 메세지 상수화 및 입력 클래스 추가
yook-jongho Nov 5, 2023
914bc47
출력메세지 상수화
yook-jongho Nov 5, 2023
78bc78b
출력 클래스 구현
yook-jongho Nov 5, 2023
1d13256
c출력 클래스 구현 - 발행한 로또 수량 및 번호리스트
yook-jongho Nov 5, 2023
ecbbbbf
출력 클래스 구현 - 수익률 및 당첨 내역
yook-jongho Nov 5, 2023
793bd9a
style: view 구현(input,output)
yook-jongho Nov 7, 2023
3005ba8
style: eslint 및 prettier 적용
yook-jongho Nov 7, 2023
473d900
컨트롤러에 입출력 기능 추가
yook-jongho Nov 7, 2023
91b4463
Lotto class의 기능(번호 생성, 정렬, 수익률) model로 이전
yook-jongho Nov 7, 2023
48da45e
createLotto 함수 리펙토링
yook-jongho Nov 7, 2023
83d373c
createLotto 함수에 정렬기능 추가, sortAscending함수 삭제
yook-jongho Nov 7, 2023
f4b19a2
fix: Resolve Error module not found by modifying import statements
yook-jongho Nov 7, 2023
be85ddd
feat: Implement controller functionality for MVC
yook-jongho Nov 7, 2023
0acf3ec
refactor: Refactor LottoService class
yook-jongho Nov 7, 2023
1389c4b
chore: Remove all functions from lotto class
yook-jongho Nov 7, 2023
2d5fbb3
refactor: Move existing Lotto class to the model
yook-jongho Nov 7, 2023
26aa9f5
feat: Add funct buylotto & inputwinningNum to controller
yook-jongho Nov 7, 2023
254f7d2
refactor: app class
yook-jongho Nov 8, 2023
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
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class Lotto {

#validate(numbers) {
if (numbers.length !== 6) {
throw new Error("[ERROR] 로또 번호는 6개여야 합니다.");
throw new Error('[ERROR] 로또 번호는 6개여야 합니다.');
}
}

Expand All @@ -237,3 +237,31 @@ class Lotto {
- **Git의 커밋 단위는 앞 단계에서 `docs/README.md`에 정리한 기능 목록 단위**로 추가한다.
- [커밋 메시지 컨벤션](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 가이드를 참고해 커밋 메시지를 작성한다.
- 과제 진행 및 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고한다.

## 구현 기능 목록

### 1. 도메인 로직

- 로또번호 생성 기능
- 지정 범위 내에서 원하는 개수의 숫자를 무작위로 생성하는 기능
- 무작위로 생성된 숫자가 중복되지 않는 기능
- 생성된 번호 오름차순 정렬 기능
- 수익률 계산 및 소수점 둘째 자리 반올림
- 로또 번호 당첨 및 수익금 통계

### 2. UI 담당

- 입력
- 구입금액
- 당첨 번호
- 보너스 번호
- 출력
- 발행한 로또 수량 및 번호
- 수익률 및 당첨 내역
- 에러 문구 `예시) [ERROR] 숫자가 잘못된 형식입니다.`

### 3. 기타

- 에러 처리
- 구입 금액 입력 시 천원 단위 확인
- 당첨 번호와 보너스 번호 입력 시, 중복 입력 체크
17 changes: 11 additions & 6 deletions __tests__/LottoTest.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import Lotto from "../src/Lotto.js";
import Lotto from '../src/Model/Lotto';

describe("로또 클래스 테스트", () => {
test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => {
describe('로또 클래스 테스트', () => {
test('로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.', () => {
expect(() => {
new Lotto([1, 2, 3, 4, 5, 6, 7]);
}).toThrow("[ERROR]");
}).toThrow('[ERROR]');
});

// TODO: 이 테스트가 통과할 수 있게 구현 코드 작성
test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => {
test('로또 번호에 중복된 숫자가 있으면 예외가 발생한다.', () => {
expect(() => {
new Lotto([1, 2, 3, 4, 5, 5]);
}).toThrow("[ERROR]");
}).toThrow('[ERROR]');
});

// 아래에 추가 테스트 작성 가능
test('로또 번호에 1~45가 아닌 숫자가 있으면 예외가 발생한다.', () => {
expect(() => {
new Lotto([1, 2, 3, 46, 57, 58]);
}).toThrow('[ERROR]');
});
});
16 changes: 15 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import Controller from './Controller/Controller.js';

class App {
async play() {}
constructor() {
this.controller = new Controller();
// this.play();
}

async play() {
await this.controller.buyLotto();
await this.controller.inputWinningNum();
this.controller.winningStatement();
}
}

export default App;

const app = new App();
app.play();
49 changes: 49 additions & 0 deletions src/Controller/Controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Console } from '@woowacourse/mission-utils';
import Input from '../View/Input.js';
import Output from '../View/Output.js';
import Lotto from '../Model/Lotto.js';
import LottoService from '../Model/LottoService.js';

class Controller {
#amount;
#lottoList = [];
#winnginNum;
#bonusNum;
#matchHistory;
#rateOfReturn;

constructor() {
this.input = new Input();
this.output = new Output();
this.lottoService = new LottoService();
}

async buyLotto() {
this.#amount = await this.input.inputPurchase();
let buy = this.#amount;
while (buy > 0) {
this.#lottoList.push(this.lottoService.createLotto());
buy -= 1000;
}
this.output.purchaseHistory(this.#lottoList);
}

async inputWinningNum() {
const userInput = await this.input.inputWinningNum();
this.#winnginNum = userInput.split(',');
const lotto = new Lotto(this.#winnginNum);
this.#bonusNum = await this.input.inputBonus();
}

winningStatement() {
this.#matchHistory = this.lottoService.getWinningList(
this.#lottoList,
this.#winnginNum,
this.#bonusNum,
);
this.#rateOfReturn = this.lottoService.getRateReturn(this.#amount);
this.output.winningDetails(this.#matchHistory, this.#rateOfReturn);
}
}

export default Controller;
18 changes: 0 additions & 18 deletions src/Lotto.js

This file was deleted.

36 changes: 36 additions & 0 deletions src/Model/Lotto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Lotto {
#numbers;

constructor(numbers) {
this.#validate(numbers);
this.#winningNumValid(numbers);
this.#isDuplicate(numbers);
this.#numbers = numbers;
}

#validate(numbers) {
if (numbers.length !== 6) {
throw new Error('[ERROR] 로또 번호는 6개여야 합니다.');
}
}

// TODO: 추가 기능 구현
#winningNumValid(numbers) {
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > 45 || numbers[i] < 1) {
throw new Error(
'[ERROR] 로또 번호는 1~45 사이의 숫자만 있어야 합니다.',
);
}
}
}

#isDuplicate(numbers) {
const set = new Set(numbers);
if (set.length !== 6) {
throw new Error('[ERROR] 로또 번호에 중복된 숫자가 있으면 안됩니다.');
}
}
}

export default Lotto;
48 changes: 48 additions & 0 deletions src/Model/LottoService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Console, Random } from '@woowacourse/mission-utils';

class LottoService {
#MIN_NUM = 1;
#MAX_NUM = 45;
#CNT = 6;
#winningList = [0, 0, 0, 0, 0];

createLotto() {
const randomList = Random.pickUniqueNumbersInRange(
this.#MIN_NUM,
this.#MAX_NUM,
this.#CNT,
);
const sortRandomList = randomList.sort((a, b) => {
return a - b;
});
return sortRandomList;
}

getRateReturn(purchase) {
let revenue = 0;
const money = [5000, 50000, 1500000, 30000000, 2000000000];
for (let i = 0; i < this.#winningList.length; i++) {
revenue += money[i] * this.#winningList[i];
}
return parseFloat((revenue / purchase) * 100).toFixed(1);
}

getWinningList(userNumList, winningNumList, bonus) {
for (const lotto of userNumList) {
let match = this.matchNums(lotto, winningNumList);
const hasBonus = lotto.includes(bonus - '0');
if (match === 6 || (match === 5 && hasBonus)) {
match++;
}
this.#winningList[match - 3]++;
}
return this.#winningList;
}

matchNums(numList, winningNumList) {
const result = numList.filter((num) => winningNumList.includes(`${num}`));
return result.length;
}
}

export default LottoService;
47 changes: 47 additions & 0 deletions src/View/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Console } from '@woowacourse/mission-utils';
import { MESSAGES } from './message.js';

class Input {
#purchase;
#isValid;
async inputPurchase() {
while (true) {
try {
this.#purchase = await Console.readLineAsync(MESSAGES.PURCHASE_INPUT);
this.#isValid = this.purchaseValid(this.#purchase);
if (this.#isValid) {
return this.#purchase;
}
} catch (e) {
Console.print(e.message);
}
}
}

purchaseValid(purchase) {
let valid = true;
if (isNaN(purchase)) {
valid = false;
throw new Error('[ERROR] 숫자를 입력해 주세요.');
} else if (parseInt(purchase) < 1000) {
valid = false;
throw new Error('[ERROR] 1000원 이상 입력해 주세요.');
} else if (parseInt(purchase) % 1000 !== 0) {
valid = false;
throw new Error('[ERROR] 1000원단위로 입력해주세요');
}
return valid;
}

async inputWinningNum() {
const winning = await Console.readLineAsync(MESSAGES.WINNING_INPUT);
return winning;
}

async inputBonus() {
const bonus = await Console.readLineAsync(MESSAGES.BONUS_INPUT);
return bonus;
}
}

export default Input;
22 changes: 22 additions & 0 deletions src/View/Output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Console } from '@woowacourse/mission-utils';
import { PRIZE_MESSAGES } from './message.js';

class Output {
purchaseHistory(purchaseList) {
Console.print(`\n${purchaseList.length}개를 구매했습니다.`);
for (const lotto in purchaseList) {
const msg = purchaseList[lotto].join(', ');
Console.print(`[${msg}]`);
}
}

winningDetails(matchNum, rateReturn) {
Console.print('\n당첨통계\n---');
for (let i = 0; i < matchNum.length; i += 1) {
Console.print(`${PRIZE_MESSAGES[i]} - ${matchNum[i]}개`);
}
Console.print(`총 수익률은 ${rateReturn}%입니다.`);
}
}

export default Output;
13 changes: 13 additions & 0 deletions src/View/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const MESSAGES = {
PURCHASE_INPUT: '구입금액을 입력해 주세요.\n',
WINNING_INPUT: '\n당첨 번호를 입력해 주세요.\n',
BONUS_INPUT: '\n보너스 번호를 입력해 주세요.\n',
};

export const PRIZE_MESSAGES = [
'3개 일치 (5,000원)',
'4개 일치 (50,000원)',
'5개 일치 (1,500,000원)',
'5개 일치, 보너스 볼 일치 (30,000,000원)',
'6개 일치 (2,000,000,000원)',
];