diff --git a/__tests__/ApplicationTest.js b/__tests__/ApplicationTest.js index 227bd03864..c82e1f5f34 100644 --- a/__tests__/ApplicationTest.js +++ b/__tests__/ApplicationTest.js @@ -28,7 +28,7 @@ const runException = async (input) => { // given const logSpy = getLogSpy(); - const RANDOM_NUMBERS_TO_END = [1,2,3,4,5,6]; + const RANDOM_NUMBERS_TO_END = [1, 2, 3, 4, 5, 6]; const INPUT_NUMBERS_TO_END = ["1000", "1,2,3,4,5,6", "7"]; mockRandoms([RANDOM_NUMBERS_TO_END]); @@ -40,12 +40,12 @@ const runException = async (input) => { // then expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("[ERROR]")); -} +}; describe("로또 테스트", () => { beforeEach(() => { jest.restoreAllMocks(); - }) + }); test("기능 테스트", async () => { // given @@ -95,4 +95,3 @@ describe("로또 테스트", () => { await runException("1000j"); }); }); - diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 97bd457659..ee47293cfe 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -8,11 +8,20 @@ describe("로또 클래스 테스트", () => { }); // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 + + test("로또 번호에 숫자가 아닌 값이 포함되어 있으면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 8, 4, 39, "&"]); + }).toThrow("[ERROR]"); + }); test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 5]); }).toThrow("[ERROR]"); }); - - // 아래에 추가 테스트 작성 가능 + test("로또 번호에 1~45 사이의 값이 아닌 값이 포함되어 있으면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 39, 48]); + }).toThrow("[ERROR]"); + }); }); diff --git a/src/App.js b/src/App.js index c38b30d5b2..2a490a1ff0 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,82 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import { LottoRandom } from "./LottoRandom"; +import Lotto from "./Lotto"; + class App { - async play() {} + async play() { + let lotto_price = await this.getIncomeAndCheck(); + let lotto_num = lotto_price / 1000; + + MissionUtils.Console.print(`${lotto_num}개를 구매했습니다.`); + + const lottoArray = new LottoRandom(lotto_num); + lottoArray.printLottoSet(); + // 보너스 번호를 입력 받는다. + let real_num = await this.getRealLottoNumber(); + let bonus = await MissionUtils.Console.readLineAsync( + "보너스 번호를 입력해 주세요." + ); + lottoArray.getPrize(real_num, bonus); + lottoArray.getResult(); + this.printReturnRate(lottoArray.win, lotto_price); + } + + //[x]구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. + async getIncomeAndCheck() { + let income_num; + while (true) { + try { + let income = await MissionUtils.Console.readLineAsync( + "구입금액을 입력해 주세요." + ); + income_num = Number(income); + if (isNaN(income_num)) + throw new Error("[ERROR] 숫자가 잘못된 형식입니다."); + if (income_num % 1000 != 0) + throw new Error("[ERROR] 구입 금액은 1,000원 단위로 입력해주세요."); + break; + } catch (error) { + MissionUtils.Console.print(error.message); + } + } + return income_num; + } + + async getRealLottoNumber() { + let real_number, real_number_arr; + while (true) { + real_number = await MissionUtils.Console.readLineAsync( + "\n당첨 번호를 입력해 주세요.\n" + ); + if (real_number) { + //[x] 당첨 번호를 입력 받는다. 번호는 쉼표(,)를 기준으로 구분한다. + real_number_arr = real_number.split(","); + real_number_arr = real_number_arr.map((e) => Number(e)); // 숫자로 변환 + + try { + new Lotto(real_number_arr); + break; + } catch (error) { + MissionUtils.Console.print(error.message); + } + } else { + MissionUtils.Console.print("[ERROR] 당첨 번호를 입력해주세요."); + } + } + return real_number_arr; + } + + // [x] 수익률은 소수점 둘째 자리에서 반올림한다 + printReturnRate(prize, num) { + let all_prize = + prize[0] * 5000 + + prize[1] * 50000 + + prize[2] * 1500000 + + prize[3] * 30000000 + + prize[4] * 2000000000; + let rate = ((100 * all_prize) / num).toFixed(1); + MissionUtils.Console.print(`총 수익률은 ${rate}%입니다.`); + } } export default App; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e9..ebbcd374a8 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,18 +1,51 @@ -class Lotto { +import { MissionUtils } from "@woowacourse/mission-utils"; + +export class Lotto { #numbers; constructor(numbers) { this.#validate(numbers); + if (new Set(numbers).size !== numbers.length) { + throw new Error("[ERROR] 당첨 번호엔 중복이 없어야 합니다."); + } + for (let num of numbers) { + if (typeof num != "number") + throw new Error("[ERROR] 당첨 값은 숫자로만 구성되어 있어야 합니다."); + if (num > 45 || num < 1) { + throw new Error("[ERROR] 당첨 번호는 1에서 45의 숫자여야 합니다."); + } + } this.#numbers = numbers; } #validate(numbers) { - if (numbers.length !== 6) { + if (!numbers || !Array.isArray(numbers) || numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } } - // TODO: 추가 기능 구현 + printAllLottoNum() { + let arr = this.#numbers.sort((a, b) => a - b); + let formatted_arr = `[${arr.join(", ")}]`; + MissionUtils.Console.print(formatted_arr); + } + + countWin(arr) { + let win = 0; + for (let i = 0; i < 6; i++) { + if (this.#numbers.includes(arr[i])) { + win++; + } + } + return win; + } + + getUserLotto(bonus) { + if (this.#numbers.includes(bonus)) { + return true; + } + return false; + } } export default Lotto; diff --git a/src/LottoRandom.js b/src/LottoRandom.js new file mode 100644 index 0000000000..bb642cb4a6 --- /dev/null +++ b/src/LottoRandom.js @@ -0,0 +1,66 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import { Lotto } from "./Lotto.js"; + +export class LottoRandom { + constructor(lotto_num) { + this.num = lotto_num; + this.lotto_value_arr = []; + this.makeAllLottoSet(this.num); + this.win = new Array(5).fill(0); + } + makeAllLottoSet() { + for (let i = 0; i < this.num; i++) { + let one = this.makeOneLottoSet(); + this.lotto_value_arr.push(one); + } + } + + makeOneLottoSet() { + let one_lotto = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); + one_lotto = new Lotto(one_lotto); + return one_lotto; + } + + printLottoSet() { + for (let lotto of this.lotto_value_arr) { + lotto.printAllLottoNum(); + } + } + + getPrize(win, bonus) { + for (let i = 0; i < this.num; i++) { + let isWin = this.lotto_value_arr[i].countWin(win); + let isBonus = this.lotto_value_arr[i].getUserLotto(bonus); + this.calculatePrize(isWin, isBonus); + } + } + + calculatePrize(isWin, isBonus) { + if (isWin === 3) { + this.win[0]++; + } + if (isWin === 4) { + this.win[1]++; + } + if (isWin === 5 && isBonus == false) { + this.win[2]++; + } + if (isWin === 5 && isBonus == true) { + this.win[3]++; + } + if (isWin === 6) { + this.win[4]++; + } + } + // / 결과 출력 + getResult() { + MissionUtils.Console.print("\n당첨 통계\n___"); + MissionUtils.Console.print(`3개 일치 (5,000원) - ${this.win[0]}개`); + MissionUtils.Console.print(`4개 일치 (50,000원) - ${this.win[1]}개`); + MissionUtils.Console.print(`5개 일치 (1,500,000원) - ${this.win[2]}개`); + MissionUtils.Console.print( + `5개 일치, 보너스 볼 일치 (30,000,000원) - ${this.win[3]}개` + ); + MissionUtils.Console.print(`6개 일치 (2,000,000,000원) - ${this.win[4]}개`); + } +}