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

[로또] 이서현 미션 제출합니다. #394

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
# javascript-lotto-precourse

### 기능 구현 목록

1. 입력

1-1. 로또 구입 금액 입력

- 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리

1-2. 당첨 번호 입력

- 6개의 당첨 번호, 쉼표(,)를 기준으로 구분

1-3. 보너스 번호 입력

2. 기능

2-1. 발행해야 할 로또 개수 구하기

2-2. 로또 숫자 뽑기

- 중복되지 않는 6개의 숫자

- 6개의 숫자와 중복되지 않는 보너스 번호 1개 뽑기

2-3. 로또 당첨 여부 확인

- 4개 일치하는 경우, 보너스 볼과 일치하는지 확인

3. 출력

3-1. 발행한 로또 수량 및 번호 출력

- 오름차순으로 정렬하여 출력

3-2. 당첨 내역 출력

3-3. 수익률 출력

- 소수점 둘째 자리에서 반올림

3-4. 로또 게임 종료
57 changes: 56 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,60 @@
import { Console, MissionUtils } from '@woowacourse/mission-utils';
import { numOfLotto, chkSelectedNum } from '../src/InputComponent.js';
import { verifyLotto, showLottoStatistics, CalculateRate } from '../src/VerifyLotto.js';
import Lotto from './Lotto.js';

class App {
async run() {}
async run() {
try {
// 로또 구입금액 입력
Console.print('구입금액을 입력해 주세요.');
const price = await Console.readLineAsync('');
const lotto = numOfLotto(price); // 로또 개수
if (lotto == 0) this.throwError('로또 구입 금액 입력 오류');

// 로또 구매
const lottoArr = [];
Console.print(`\n${lotto}개를 구매했습니다.`);
for (let i = 0; i < lotto; i++) {
const sortedNumbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b);
const lottoInstance = new Lotto(sortedNumbers);
lottoArr.push(lottoInstance.getNumbers());
}
for (let i = 0; i < lotto; i++) {
Console.print(lottoArr[i]);
}

// 당첨 번호 입력
Console.print('\n당첨 번호를 입력해 주세요.');
const numbers = (await Console.readLineAsync('')).split(',');
let selectedNum = chkSelectedNum(numbers);
if (!selectedNum) this.throwError('당첨 번호 입력 오류');
const selectedNumInstance = new Lotto(selectedNum);
selectedNumInstance.validateRange();
selectedNum = selectedNumInstance.getNumbers();

// 보너스 번호 입력
Console.print('\n보너스 번호를 입력해 주세요.');
const bonusNum = parseInt(await Console.readLineAsync(''));

// 당첨 통계 출력
Console.print('\n당첨 통계');
Console.print('---');
const result = verifyLotto(lottoArr, selectedNum, bonusNum);
showLottoStatistics(result);

// 수익률 계산 및 출력
const gainRate = CalculateRate(parseInt(price), result);
Console.print(`총 수익률은 ${gainRate}%입니다.`);
} catch (error) {
Console.print(error.message);
throw error;
}
}

throwError(message) {
throw new Error(`[ERROR] ${message}`);
}
}

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

export function numOfLotto(price) {
if (price % 1000 != 0) return 0;
return price / 1000;
}

export function chkSelectedNum(num) {
const result = [];
for (let i = 0; i < num.length; i++) {
let trimmed = num[i].trim();
if (trimmed !== '') result.push(trimmed);
}
if (result.length == 6) return result;
}
46 changes: 36 additions & 10 deletions src/Lotto.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
class Lotto {
#numbers;
#numbers;

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

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

// TODO: 추가 기능 구현
// 로또 번호가 1부터 45 사이의 숫자가 아닌 경우
validateRange() {
for (let i = 0; i < 6; i++) {
if (this.#numbers[i] < 1 || this.#numbers[i] > 45) {
}
}
}

// 중복되는 숫자가 있는 경우
validateDuplicate(numbers) {
const uniqueNumbers = new Set(numbers);
if (uniqueNumbers.size !== numbers.length) {
throw new Error('[ERROR] 로또 번호는 중복되지 않는 숫자여야 합니다.');
}
}

#validate(numbers) {
if (numbers.length !== 6) {
throw new Error("[ERROR] 로또 번호는 6개여야 합니다.");
// 정수형으로 변환
#changeToInt() {
this.#numbers = this.#numbers.map((num) => parseInt(num, 10));
}
}

// TODO: 추가 기능 구현
getNumbers() {
this.#changeToInt(this.#numbers);
return this.#numbers;
}
}

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

export function verifyLotto(lottoArr, correctNum, bonus) {
const result = Array(7).fill(0);

for (let i = 0; i < lottoArr.length; i++) {
let outcome = numOfCorrected(lottoArr[i], correctNum);
// 보너스 번호를 포함하는 경우
if (outcome == 5 && chkBonusLotto(lottoArr[i], bonus)) {
result[2] += 1;
continue;
}
if (outcome > 2) result[outcome] += 1;
}
return result;
}

function numOfCorrected(nums, correctNum) {
let cnt = 0;
for (let i = 0; i < 6; i++) {
if (nums.includes(correctNum[i])) cnt++;
}
return cnt;
}

function chkBonusLotto(nums, bonus) {
for (let i = 0; i < 6; i++) {
if (nums[i] == bonus) return true;
}
return false;
}

export function showLottoStatistics(arr) {
Console.print(`3개 일치 (5,000원) - ${arr[3]}`);
Console.print(`4개 일치 (50,000원) - ${arr[4]}`);
Console.print(`5개 일치 (1,500,000원) - ${arr[5]}`);
Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${arr[2]}`);
Console.print(`6개 일치 (2,000,000,000원) - ${arr[6]}`);
}

export function CalculateRate(pay, arr) {
let total = 0;
if (arr[2] != 0) total += 30000000 * arr[2];
if (arr[3] != 0) total += 5000 * arr[3];
if (arr[4] != 0) total += 50000 * arr[4];
if (arr[5] != 0) total += 1500000 * arr[5];
if (arr[6] != 0) total += 2000000000 * arr[6];
return total / pay;
}