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

[1단계 - 콘솔 기반 로또 게임] 센트(김영우) 미션 제출합니다. #174

Merged
merged 63 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
aa2cb08
docs: 기능 목록 작성
inyeong-kang Feb 14, 2023
87e601a
chore: package.json 설치
inyeong-kang Feb 14, 2023
2f05918
chore: eslint 세팅
inyeong-kang Feb 14, 2023
b70385c
docs: 기능(예외 상황 등) 목록 구체화
inyeong-kang Feb 14, 2023
985fade
feat(constants): 구입 금액 단위 및 공백 처리 정규식 관련 상수 분리
inyeong-kang Feb 14, 2023
c3a01fe
chore: prettier 관련 세팅
inyeong-kang Feb 15, 2023
07ef6a9
docs: To-do list 작성
inyeong-kang Feb 15, 2023
310cf75
feat(constants): 로또 게임 관련 상수 분리
inyeong-kang Feb 15, 2023
ed5ad95
feat(controller): 구입 금액에 따른 로또 개수 반환 기능 구현
inyeong-kang Feb 15, 2023
0a204c2
feat(validator): 구입 금액에 대한 유효성 검사 구현
inyeong-kang Feb 15, 2023
50c5ae5
docs: 기능 목록 수정
inyeong-kang Feb 15, 2023
bd636c9
feat(domain/model): 로또 번호 한줄(Lotto)을 당첨번호 및 보너스번호와 비교하여 등수 계산 기능 구현
inyeong-kang Feb 15, 2023
3ca1dc8
feat(constants): 로또 게임 수익 관련 상수 분리
inyeong-kang Feb 15, 2023
943f7ed
feat(constants): 등수에 따라 수익을 보여주는 배열 상수 분리
inyeong-kang Feb 15, 2023
92a0198
feat(domain/model): 등수에 따라 수익 계산하는 기능 구현
inyeong-kang Feb 15, 2023
2af4b53
refactor(domain/model): Lotto 모델의 profit 필드 삭제
inyeong-kang Feb 15, 2023
853d6ad
feat(constants): 로또 번호 범위(1-45) 관련 상수 분리
inyeong-kang Feb 15, 2023
798048e
feat(domain/model, utils): 등수로 게임 수익 계산
inyeong-kang Feb 15, 2023
9b01e6e
feat(utils): 무작위의 로또 번호 생성 기능 구현
inyeong-kang Feb 15, 2023
57db5bd
feat(constants): 로또 번호 개수에 대한 상수 분리
inyeong-kang Feb 15, 2023
b295031
test(domain/model): 로또 번호가 일치하는 것이 없는 경우에 대한 테스트 케이스 추가
inyeong-kang Feb 16, 2023
ab08662
feat(domain/model): 구입된 Lotto 인스턴스들로 등수 계산하는 기능 구현
inyeong-kang Feb 16, 2023
cc3904f
chore(eslint): endOfLine 설정 변경
inyeong-kang Feb 16, 2023
a42c6b5
chore: 테스트 코드 내에서 eslint 10줄 메서드 제한 해제
inyeong-kang Feb 16, 2023
a1b8292
feat(domain/model): 로또들(Lottos)로 수익 및 수익률 계산 기능 구현
inyeong-kang Feb 16, 2023
02a2e32
refactor(validator): eslint에 따라 불필요한 삼항 연산자 제거
inyeong-kang Feb 16, 2023
ed281f4
chore: 불필요한 모듈 import 코드 제거
inyeong-kang Feb 16, 2023
4439fda
feat(domain/model): 당첨 번호 인스턴스 생성
inyeong-kang Feb 16, 2023
d8abddd
feat(validation): 당첨 번호 유효성 검사
inyeong-kang Feb 16, 2023
2f8bbe2
feat(domain/model): 보너스 번호 인스턴스 생성
inyeong-kang Feb 16, 2023
fc2e2ff
feat(validation): 보너스 번호 유효성 검사
inyeong-kang Feb 16, 2023
316d7c9
feat(constants): 다시 시작 명령어 관련 상수 분리
inyeong-kang Feb 16, 2023
316b085
feat(validation): 구입 금액 및 다시 시작 명령어 입력값 유효성 검사
inyeong-kang Feb 16, 2023
e12107e
feat(view): Console 입출력 기능 구현
inyeong-kang Feb 16, 2023
0ec3bd8
feat(constants): Console 입출력 메시지 및 로또 개수 일치 관련 상수 분리
inyeong-kang Feb 16, 2023
cc931f0
feat(constants): 당첨 통계(로또 개수, 상금) 관련 상수 분리
inyeong-kang Feb 16, 2023
cc62a94
feat(view): 구입금액, 당첨번호, 보너스 번호, 다시 시작 명령어 입력 기능 구현
inyeong-kang Feb 16, 2023
f4ecc14
feat(controller,constants): 구입 금액 입력 기능 구현
inyeong-kang Feb 16, 2023
10ea448
chore(constants): 콘솔 입력 메시지 수정
inyeong-kang Feb 16, 2023
42d6916
feat(controller, domain): 당첨 번호 입력 기능 구현
inyeong-kang Feb 16, 2023
4cad90b
feat(controller, domain): 보너스 번호 입력 기능 구현
inyeong-kang Feb 16, 2023
4dece78
fix(constants): 게임 총 수익률 출력 메시지 상수 수정
inyeong-kang Feb 16, 2023
7b07aad
feat(controller, view): 게임 실행 결과(당첨 통계 및 총 수익률) 출력 기능 구현
inyeong-kang Feb 16, 2023
979d32e
fix(constants): 게임 실행 결과 관련 상수 메시지 수정
inyeong-kang Feb 16, 2023
7cacc14
fix(__test__): 테스트 함수명 등 오타 수정
inyeong-kang Feb 16, 2023
61e66da
feat: 게임 실행 기능 추가
inyeong-kang Feb 16, 2023
bda4f74
fix: JSON 파일에 있는 주석 삭제
kyw0716 Feb 20, 2023
2636e6b
style(Lotto.test): 테스트 코드 예상되는 결과 값 네이밍 변경 expected => caculated
kyw0716 Feb 20, 2023
53a430a
fix: 쓰지 않는 console.log 삭제
kyw0716 Feb 20, 2023
c308849
docs: 기능 목록 체크 박스 추가
kyw0716 Feb 20, 2023
109b261
style: inputView 콜백 함수 네이밍 변경
kyw0716 Feb 20, 2023
daf00cb
style: RandomNumberGenerator내 숫자 중복 체크 메서드명 변경
kyw0716 Feb 20, 2023
1fe7289
refactor: RandomNumberGenerator내 번호 정렬 함수 분리하지 않는 방식으로 변경
kyw0716 Feb 20, 2023
7d39c97
refactor: RandomNumberGenerator 랜덤 번호 생성 방식 변경
kyw0716 Feb 20, 2023
701bd06
style: 파일명 변경 RandomNumberGenerator => randomNumberGenerator
kyw0716 Feb 20, 2023
8ac62d7
style: validator 하위 메서드들에 *-valid 키워드 제거
kyw0716 Feb 20, 2023
0157f5e
refactor: Lottos의 caculateProfitRate 메서드 속 무의미한 값 할당 삭제
kyw0716 Feb 20, 2023
01c60f5
refactor: Lottos의 caculateProfit 속 무의미한 값 할당 삭제
kyw0716 Feb 20, 2023
3247eab
style: double quote => single quote
kyw0716 Feb 20, 2023
d24cb62
refactor: Lottos 수익 계산 메서드 연산 순서 명시
kyw0716 Feb 20, 2023
7485474
refactor: Lotto내 순위 지정 메서드 속 순위 값 상수처리
kyw0716 Feb 20, 2023
a885dda
test: WinningLotto 클래스 테스트 코드 추가
kyw0716 Feb 20, 2023
22e668a
refactor: WinningNumbers 클래스, BonusNumber 클래스 => WinningLotto 클래스로 통합
kyw0716 Feb 20, 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
33 changes: 31 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

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

OMG... 😱
프론트엔드 개발자라면 다양한 확장자를 주의해서 다뤄야합니다.
HTML.. CSS... JS 모두 주석 사용 방법도 다른데요. JSON은 설정 파일이기때문에 더 주의해야합니다.

  • JSON은 누가? 왜? 무엇을 대체하기 위해 만들어졌을까요?
  • JSON에서는 주석이 가능할까요?
  • 현재 이 JSON을 파싱해보면 잘 동작할까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

JSON에 주석이 지원되지 않는다는 것을 모르고 그동안 사용했던 것 같네요 😭😭
수정한 커밋: bda4f74

추가로 주신 질문들을 보고 학습 한 내용입니다!

Q: JSON은 누가? 왜? 무엇을 대체하기 위해 만들어졌을까요?
A: XML로 정보를 주고 받을 때 헤더와 태그 등 여러 요소들로 인해 가독성이 떨어지고, 쓸데 없는 용량을 잡아먹는다는 단점을 갖고 있어 이를 대체하기 위해 더글라스 크록포드에 의해 만들어졌습니다!

Q: JSON에서는 주석이 가능할까요?
A: JSON에는 주석을 지원하지 않아 설정파일에 주로 사용됩니다! (이걸 몰랐네요 ㅠㅠㅠ)

Q: 현재 이 JSON을 파싱해보면 잘 동작할까요?
A:

const json = '{"hi": true //주석}';
const obj = JSON.parse(json);

console.log(obj);

주석이 있을 때 파싱이 이루어질 수 있는지 판별해보고자 간단한 예시 코드를 실행시켜 보았더니 오류가 발생하는 것을 확인할 수 있었습니다😭

Copy link
Contributor

Choose a reason for hiding this comment

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

오 완벽합니다!!
JSON에게 어쩌면 주석조차도 데이터가 아닐까요? 후후

"rules": {},
"env": {
"browser": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaVersion": "latest"
},
"extends": ["eslint:recommended", "plugin:prettier/recommended"]
"extends": ["airbnb", "plugin:prettier/recommended"],
"rules": {
Copy link
Contributor

Choose a reason for hiding this comment

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

5기는 ESLint 경쟁이 한참인가보군요 ㅋㅋ

"prettier/prettier": [
"error",
{ "singleQuote": true, "endOfLine": "auto" }
],
"indent": ["error", 2],
"quotes": ["error", "single"],
"max-lines-per-function": ["error", 12],
"max-depth": ["error", 2],
"no-else-return": ["error", { "allowElseIf": false }],
"max-params": ["error", 3],
"no-confusing-arrow": [
"error",
{ "allowParens": true, "onlyOneSimpleParam": false }
],
"prefer-destructuring": [
"error",
{
"array": true,
"object": true
},
{
"enforceForRenamedProperties": false
}
],
"spaced-comment": ["error", "always", { "exceptions": ["-", "+"] }],
"eol-last": ["error", "always"],
"no-var": "error"
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
dist/

TODO.md
3 changes: 0 additions & 3 deletions .prettierrc

This file was deleted.

12 changes: 12 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

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

여기도..ㅠㅠ주석이..

"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.alwaysShowStatus": true,
"prettier.disableLanguages": ["js"],
Copy link
Contributor

Choose a reason for hiding this comment

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

아니 이것은... 👀

"files.autoSave": "onFocusChange"
Copy link
Contributor

Choose a reason for hiding this comment

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

  "[javascript]": {
    "editor.formatOnSave": true
  },

위의 설정이랑 겹치지 않을까요?

}
78 changes: 78 additions & 0 deletions __tests__/Lotto.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*eslint-disable */
const { profitByRank } = require("../src/constants/constants");
const Lotto = require("../src/domain/model/Lotto");
const { calculateProfit } = require("../src/utils");

describe("로또 클래스 테스트", () => {
test.each([
[8, 21, 23, 41, 42, 43],
[3, 5, 11, 16, 32, 38],
[7, 11, 16, 35, 36, 44],
[1, 8, 11, 31, 41, 42],
])(
"당첨 번호를 넘겨주었을 때, 해당 값을 필드로 갖는 인스턴스를 생성 기능",
(lottoNumbers) => {
const lotto = new Lotto(lottoNumbers);

expect(lottoNumbers).toEqual(lotto.getNumbers());
}
);

test.each([
{ input: [1, 2, 3, 4, 5, 6], caculatedRank: 1 },
{ input: [1, 2, 3, 4, 5, 7], caculatedRank: 2 },
{ input: [1, 2, 3, 4, 5, 8], caculatedRank: 3 },
{ input: [1, 2, 3, 4, 8, 9], caculatedRank: 4 },
{ input: [1, 2, 3, 8, 9, 10], caculatedRank: 5 },
{ input: [8, 9, 10, 11, 12, 13], caculatedRank: undefined },
])(
"당첨 번호와 보너스 번호를 넘겨주었을 때, 로또 번호와 비교하여 등수를 계산 기능",
({ input, caculatedRank }) => {
const lotto = new Lotto(input);
const winningNumbers = [1, 2, 3, 4, 5, 6];
const bonusNumber = 7;

lotto.calculateRank(winningNumbers, bonusNumber);

expect(lotto.getRank()).toEqual(caculatedRank);
}
);

test.each([
{ lottoNumber: [1, 2, 3, 4, 5, 6], caculatedProfit: profitByRank[0] },
{ lottoNumber: [1, 2, 3, 4, 5, 7], caculatedProfit: profitByRank[1] },
{ lottoNumber: [1, 2, 3, 4, 5, 8], caculatedProfit: profitByRank[2] },
{ lottoNumber: [1, 2, 3, 4, 8, 9], caculatedProfit: profitByRank[3] },
{ lottoNumber: [1, 2, 3, 8, 9, 10], caculatedProfit: profitByRank[4] },
{ lottoNumber: [8, 9, 10, 11, 12, 13], caculatedProfit: 0 },
])("등수 입력시 수익을 반환하는 기능", ({ lottoNumber, caculatedProfit }) => {
const lotto = new Lotto(lottoNumber);
const winningNumbers = [1, 2, 3, 4, 5, 6];
const bonusNumber = 7;

lotto.calculateRank(winningNumbers, bonusNumber);

const profit = calculateProfit(lotto.getRank());

expect(profit).toBe(caculatedProfit);
});

test.each([
{ lottoNumber: [1, 2, 3, 4, 5, 6], caculatedProfit: profitByRank[0] },
{ lottoNumber: [1, 2, 3, 4, 5, 7], caculatedProfit: profitByRank[1] },
{ lottoNumber: [1, 2, 3, 4, 5, 8], caculatedProfit: profitByRank[2] },
{ lottoNumber: [1, 2, 3, 4, 8, 9], caculatedProfit: profitByRank[3] },
{ lottoNumber: [1, 2, 3, 8, 9, 10], caculatedProfit: profitByRank[4] },
{ lottoNumber: [8, 9, 10, 11, 12, 13], caculatedProfit: 0 },
])("등수 입력시 수익을 반환하는 기능", ({ lottoNumber, caculatedProfit }) => {
const lotto = new Lotto(lottoNumber);
const winningNumbers = [1, 2, 3, 4, 5, 6];
const bonusNumber = 7;

lotto.calculateRank(winningNumbers, bonusNumber);

const profit = calculateProfit(lotto.getRank());

expect(profit).toBe(caculatedProfit);
});
});
17 changes: 17 additions & 0 deletions __tests__/LottoGameController.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*eslint-disable */
const Validator = require('../src/domain/validation/validator');

describe('기능 테스트', () => {
test('구입 금액에 따라 로또 개수 반환하기', () => {
//given
const LottoGameController = require('../src/controller/LottoGameController');
const lottoGameController = new LottoGameController();
const purchasePrice = '8000';

//when
const lottoCount = lottoGameController.calculateLottoCount(purchasePrice);

//then
expect(lottoCount).toBe(8);
});
});
19 changes: 19 additions & 0 deletions __tests__/Lottos.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*eslint-disable */
const Lottos = require("../src/domain/model/Lottos");

describe("Lottos 테스트", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

아주 깔끔한 테스트군요 ㅎㅎ
GWT 까지 좋아요

test("로또 개수에 맞는 Lotto 인스턴스 생성 기능", () => {
// given
const lottoCount = 1000;

// when
const lottos = new Lottos(lottoCount);
const winningNumbers = [1, 2, 3, 4, 5, 6];
const bonusNumber = 7;

lottos.calculateAllRanks(winningNumbers, bonusNumber);

// then
expect(lottos.getLottos().length).toEqual(lottoCount);
});
});
90 changes: 90 additions & 0 deletions __tests__/Validator.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*eslint-disable */
const Validator = require("../src/domain/validation/validator");

describe("Validator 테스트", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

유효성 검사가 꼼꼼하네요
현재 단계에서는 문제가 없어보여요

test.each([
{ input: "우테코", expected: false },
{ input: "1000", expected: true },
])("입력된 구입 금액이 숫자인지 판별하기.", ({ input, expected }) => {
expect(Validator.isNumber(input)).toBe(expected);
});

test.each([
{ input: " ", expected: true },
{ input: "1000", expected: false },
])(
"입력된 구입 금액이 공백을 포함하는지 판별하기.",
({ input, expected }) => {
expect(Validator.isBlankIncluded(input)).toBe(expected);
}
);

test.each([
{ input: "", expected: true },
{ input: "1000", expected: false },
])("입력된 구입 금액이 빈 문자열인지 판별하기.", ({ input, expected }) => {
expect(Validator.isEmpty(input)).toBe(expected);
});

test.each([
{ input: "-1000", expected: true },
{ input: "0", expected: true },
{ input: "1000", expected: false },
])("입력된 구입 금액이 0또는 음수인지 판별하기.", ({ input, expected }) => {
expect(Validator.isSmallerOrEqualThanZero(input)).toBe(expected);
});

test.each([
{ input: "700", expected: false },
{ input: "1200", expected: false },
{ input: "3000", expected: true },
])("입력된 구입 금액이 1000원 단위인지 판별하기.", ({ input, expected }) => {
expect(Validator.checkUnit(input)).toBe(expected);
});

test.each([
{ input: " ", expected: false },
{ input: "-1000", expected: false },
{ input: "0", expected: false },
{ input: "700", expected: false },
{ input: "1200", expected: false },
{ input: "k", expected: false },
{ input: "3000", expected: true },
])("구입 금액 입력값이 유효한지 판별하기.", ({ input, expected }) => {
expect(Validator.purchasePrice(input)).toBe(expected);
});

test.each([
{ input: "", expected: false },
{ input: "1, 2, 3, 4, 5, 6", expected: false },
{ input: "1,2,3,4,5", expected: false },
{ input: "1,1,2,3,4,5", expected: false },
{ input: "0,1,2,3,4,5", expected: false },
{ input: "1,2,3,4,5,46", expected: false },
{ input: "1,2,3,4,5,6", expected: true },
])("당첨 번호 입력값이 유효한지 판별하기.", ({ input, expected }) => {
expect(Validator.winningNumbers(input)).toBe(expected);
});

test.each([
{ input: "", expected: false },
{ input: "k", expected: false },
{ input: "0", expected: false },
{ input: "46", expected: false },
{ input: "6", expected: false },
{ input: "7", expected: true },
])("보너스 번호 입력값이 유효한지 판별하기.", ({ input, expected }) => {
const winningNumbers = [1, 2, 3, 4, 5, 6];
expect(Validator.bonusNumber(winningNumbers, input)).toBe(expected);
});

test.each([
{ input: "", expected: false },
{ input: "yk", expected: false },
{ input: "y ", expected: false },
{ input: "y", expected: true },
{ input: "n", expected: true },
])("다시 시작 명령어 입력값이 유효한지 판별하기.", ({ input, expected }) => {
expect(Validator.checkRestartCommand(input)).toBe(expected);
});
});
13 changes: 13 additions & 0 deletions __tests__/WinningLotto.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable no-undef */
const WinningLotto = require('../src/domain/model/WinningLotto');

describe('WinningLotto 클래스 테스트', () => {
test('당첨번호와 보너스 번호가 중복되면 에러를 발생시킨다.', () => {
const winningNumbers = [1, 2, 3, 4, 5, 6];
const bonusNumber = 6;

expect(() => {
const winningLotto = new WinningLotto(winningNumbers, bonusNumber);
}).toThrow();
});
});
Empty file removed __tests__/unit.test.js
Empty file.
64 changes: 64 additions & 0 deletions docs/REQUIREMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 기능 목록
Copy link
Contributor

Choose a reason for hiding this comment

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

체크박스가 없는 것을 보면.. 다 했다고 볼 수 있는 것일까요?!

Copy link
Member Author

Choose a reason for hiding this comment

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

체크박스 추가했습니다! 진행상황을 중간중간 체크하기 위해서 체크박스를 쓰는 것이 좋을 것 같네요!! 감사합니다😀😀

수정된 커밋: c308849


- [x] 구입금액 입력하기

- [x] 콘솔로 입력 받기 (view)
- [x] 숫자가 아닌 경우 에러 발생 (domain)
- [x] 띄어쓰기(또는 아무것도 입력하지 않은 경우)인 경우 에러 발생 (domain)
- [x] 0 이하의 값을 입력할 경우 에러 발생
- [x] 1,000원 단위가 아닌 경우 에러 발생 (domain)
- [x] 입력된 금액으로 로또 개수 계산 (domain)
- [x] 계산된 로또 개수로 LottoGame 클래스 인스턴스 생성 (domain)

<hr>

- [x] 로또 번호 랜덤으로 생성하기

- [x] 랜덤 숫자 생성 함수 구현

<hr>

- [x] 구입한 로또 개수 및 번호 보여주기 (view)

- [x] 발행된 로또 번호순으로 정렬하기 (domain)

<hr>

- [x] 당첨번호 입력하기

- [x] 콘솔로 입력 받기 (view)
- [x] 숫자가 아닌 경우 에러 발생 (domain)
- [x] 띄어쓰기(또는 아무것도 입력하지 않은 경우)인 경우 에러 발생 (domain)
- [x] 당첨번호가 6개 아닌 경우 (domain)
- [x] 당첨번호가 중복되는 경우 (domain)
- [x] 숫자 범위가 1 ~ 45가 아닌 경우 에러 발생 (domain)

<hr>

- [x] 보너스 번호 입력하기

- [x] 콘솔로 입력 받기 (view)
- [x] 숫자가 아닌 경우 에러 발생 (domain)
- [x] 띄어쓰기(또는 아무것도 입력하지 않은 경우)인 경우 에러 발생 (domain)
- [x] 당첨번호 6개 중 중복되는 경우 에러 발생 (domain)
- [x] 숫자 범위가 1 ~ 45가 아닌 경우 에러 발생 (domain)

<hr>

- [x] 당첨 통계 계산하기 (Lotto Class)

- [x] 번호 일치하는 개수를 당첨 금액에 따라 계산하기 (domain)
- [x] 총 수익률 계산하기 (domain)
- [x] 콘솔에 출력하기 (view)

<hr>

- [x] 다시 시작/종료 명령어 입력하기

- [x] 콘솔로 입력 받기 (view)
- [x] y 또는 n 이 아닌 경우 에러 발생 (domain)

<hr>

- [x] 예외 상황 처리
- [x] 에러 메시지 출력 후 그 부분부터 다시 입력 (view)
Loading