-
Notifications
You must be signed in to change notification settings - Fork 168
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단계 - 콘솔 기반 로또 게임] 초코(강다빈) 미션 제출합니다. #290
Merged
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
9bb5a9e
docs REQUIREMENTS.md 생성
vi-wolhwa 656df6c
docs: test
00kang 85feae0
docs: test 하기
00kang a1f4355
docs: 기능 구현 목록 작성
00kang e8c8231
chore: eslint, prettier 설정 및 package 정보 변경
00kang 812e848
test: 구입 금액에 따른 로또 발행 테스트 작성
00kang 8010ff6
chore: eslint 플러그인 재설치
vi-wolhwa 725f690
feat: 구입금액에 따른 발행 수량 계산
vi-wolhwa 916057e
feat: 랜덤 유틸 클래스 구현
vi-wolhwa d90568f
feat: 수량 만큼 로또 발행
vi-wolhwa 6e11789
feat: 로또 객체 생성 및 번호 정렬
vi-wolhwa f689337
feat: 당첨 결과 분석, 순위 반환
vi-wolhwa 3885553
style: printWidth 변경 (80 -> 100)
vi-wolhwa 41e3459
feat: 당첨 결과 분석 및 순위 반환
vi-wolhwa be26777
refactor: 로또 등수 계산 로직 분리
vi-wolhwa e7aac4b
refactor: 상수명 변경
vi-wolhwa f9d2c32
feat: 콘솔 입력 구현
vi-wolhwa 03ee900
feat: controller, model, view 연결
vi-wolhwa 993ff65
feat: README.md 수정
00kang 7cf4395
style: 입,출력 메시지의 스타일 수정
00kang 6804840
feat: 로또 발행 메서드 컨트롤러에 연결
00kang ea9485a
fix: 컨트롤러에서 당첨번호 입력 기능의 inputWinningNumbers 메서드 수정
00kang a1eb586
fix: 당첨 통계 결과 반환 안되는 오류 수정
00kang 21e5888
fix: 발행된 로또 오름차순 정렬하여 보여주도록 수정
00kang ff23a3a
feat: 실행결과 사진 포함하여 README.md 수정
00kang e1572cf
feat: 구입 금액에 대한 유효성 검사 진행 및 재입력받도록 추가구현
00kang de926bc
feat: 당첨 번호 입력에 대한 유효성 검사 진행 및 재입력받도록 추가구현
00kang 788cbf0
feat: 보너스 점수 입력에 대한 유효성 검사 추가 구현
00kang cb70b91
feat: 게임 재시작 및 유효성 검사 추가 구현
00kang 184aacf
feat: REQUIREMENTS.md 업데이트
00kang ed22aa4
refactor: 컨트롤러로 이동
00kang 27c944d
refactor: 프로그래밍 요구사항에 맞게 eslint 재설치 및 수정
00kang 1b86786
refactor: eslint max-params 규칙에 따라 수정
00kang b573410
refactor: eslint max-lines-per-function 규칙에 따라 LottoController 내의 메서드 분리
00kang c681e4a
refacotr: airbnb 컨벤션에 따라 isNan 대신 Number.isNan으로 수정
00kang dfe9bb0
refacotr: nullish coalescing operator(??) 사용으로 불필요한 비교 줄임
00kang e7b65d9
refactor: eslint max-params 규칙에 따라 객체로 묶는 수정
00kang 979af80
feat:winningNumbers와 bonusNumber를 배열로 반환하여 당첨 결과 출력 오류 수정
00kang f501d39
refactor: eslint max-depth 규칙에 따라 메서드 분리
00kang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,79 @@ | ||
{ | ||
"rules": {}, | ||
"env": { | ||
"es6": true, | ||
"node": true | ||
"node": true, | ||
"jest": true | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": "latest" | ||
"ecmaVersion": "latest", | ||
"sourceType": "module" | ||
}, | ||
"extends": ["eslint:recommended", "plugin:prettier/recommended"] | ||
"extends": [ | ||
"airbnb", | ||
"airbnb/hooks", | ||
"prettier", | ||
"plugin:jest/recommended", | ||
"plugin:prettier/recommended", | ||
"plugin:import/errors", | ||
"plugin:import/warnings", | ||
"eslint:recommended" | ||
], | ||
"plugins": ["import", "jest", "prettier"], | ||
"rules": { | ||
"prettier/prettier": [ | ||
"error", | ||
{ | ||
"endOfLine": "auto", | ||
"printWidth": 100 | ||
} | ||
], | ||
"prefer-const": [ | ||
"error", | ||
{ | ||
"destructuring": "any", | ||
"ignoreReadBeforeAssign": false | ||
} | ||
], | ||
"max-depth": ["error", { "max": 1 }], | ||
"max-params": ["error", { "max": 2 }], | ||
"class-methods-use-this": "off", | ||
"max-lines-per-function": ["error", { "max": 10 }], | ||
"import/extensions": ["error", { "js": "ignorePackages" }], | ||
"import/order": [ | ||
"error", | ||
{ | ||
"groups": [ | ||
"builtin", | ||
"external", | ||
"internal", | ||
["parent", "sibling"], | ||
"index", | ||
"object", | ||
"type", | ||
"unknown" | ||
], | ||
"pathGroups": [ | ||
{ | ||
"pattern": "next", | ||
"group": "builtin", | ||
"position": "before" | ||
}, | ||
{ | ||
"pattern": "@/core/**", | ||
"group": "unknown" | ||
}, | ||
{ | ||
"pattern": "**/*.css.ts", | ||
"group": "unknown", | ||
"position": "after" | ||
} | ||
], | ||
"newlines-between": "always", | ||
"alphabetize": { | ||
"order": "asc", | ||
"caseInsensitive": true | ||
} | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,12 @@ | ||
{ | ||
"printWidth": 100, | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"semi": true, | ||
"singleQuote": true, | ||
"trailingComma": "none", | ||
"bracketSpacing": true, | ||
"arrowParens": "always", | ||
"proseWrap": "never", | ||
"endOfLine": "auto" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,61 @@ | ||
<h1 align="middle">🎱</h1> | ||
<h2 align="middle">level1 - 행운의 로또</h2> | ||
<p align="middle">자바스크립트로 구현 하는 로또 어플리케이션</p> | ||
|
||
### 실행 | ||
|
||
```bash | ||
npm run start-step1 | ||
``` | ||
|
||
### 테스트 | ||
|
||
```bash | ||
npm run test | ||
``` | ||
|
||
### 실행 화면 | ||
|
||
<img src="./lotto-step1.png" alt="실행화면" width="450"> | ||
|
||
### 테스트 실행 화면 | ||
|
||
<img src="./lotto-step1-test.png" alt="테스트 실행화면" width="300"> | ||
|
||
### 도메인 로직 | ||
|
||
### 파일 구조 | ||
|
||
``` | ||
📦src | ||
┣ 📂constant : 상수 관리 | ||
┃ ┣ 📜Messages.js : 입력, 입력힌트, 출력, 에러 메세지 관리 | ||
┃ ┗ 📜Options.js : 로또 가격, 로또 범위 최소, 최대 숫자, 상금, 게임 결과 등 관리 | ||
┣ 📂controller | ||
┃ ┗ 📜LottoController.js : 로또 게임 진행 | ||
┣ 📂domain | ||
┃ ┣ 📜Lotto.js | ||
┃ ┗ 📜LottoMachine.js | ||
┣ 📂util | ||
┃ ┣ 📂random | ||
┃ ┃ ┗ 📜Random.js | ||
┃ ┣ 📂readLine | ||
┃ ┃ ┗ 📜readLineAsync.js | ||
┃ ┗ 📂validation | ||
┃ ┃ ┣ 📜LottoNumbersValidator.js | ||
┃ ┃ ┣ 📜PurchaseAmountValidator.js | ||
┃ ┃ ┗ 📜Validation.js | ||
┣ 📂view | ||
┃ ┣ 📜InputView.js | ||
┃ ┗ 📜OutputView.js | ||
┣ 📜App.js | ||
┣ 📜step1-index.js | ||
┗ 📜step2-index.js | ||
|
||
📦__tests__ | ||
┣ 📜.gitkeep | ||
┣ 📜Lotto.test.js | ||
┣ 📜LottoMachine.test.js | ||
┗ 📜Random.test.js | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* eslint-disable max-lines-per-function */ | ||
import { VARIABLE_ALIAS, ERROR_MESSAGES } from '../src/constant/Messages.js'; | ||
import OPTIONS from '../src/constant/Options.js'; | ||
import Lotto from '../src/domain/Lotto.js'; | ||
|
||
describe('Lotto 단위테스트', () => { | ||
describe('로또 발행 테스트', () => { | ||
test.each([[[1, 2, 3, 4, 5]], [[1, 2, 3, 4, 5, 6, 7]]])( | ||
'로또 번호(%s)가 6개가 아니면 에러를 발생한다.', | ||
(numbers) => { | ||
expect(() => new Lotto(numbers)).toThrow( | ||
`${ERROR_MESSAGES.prefix}${ERROR_MESSAGES.hasNotLength(VARIABLE_ALIAS.lottoNumbers, OPTIONS.LOTTO.combination)}` | ||
); | ||
} | ||
); | ||
|
||
test.each([[['a', 2, 3, 4, 5, 6]], [[1.1, 2, 3, 4, 5, 6]]])( | ||
'로또 번호(%s) 중 정수 이외의 값이 있다면 에러를 발생한다.', | ||
(numbers) => { | ||
expect(() => new Lotto(numbers)).toThrow(); | ||
} | ||
); | ||
|
||
test.each([[[1, 2, 3, 4, 5, 46]], [[0, 1, 2, 3, 4, 5]]])( | ||
'로또 번호(%s)의 범위가 1부터 45 사이가 아니라면 에러를 발생한다.', | ||
(numbers) => { | ||
expect(() => new Lotto(numbers)).toThrow(); | ||
} | ||
); | ||
|
||
test('로또 번호에 중복되는 수가 있다면 에러를 발생한다.', () => { | ||
const numbers = [1, 1, 2, 3, 4, 5]; | ||
|
||
expect(() => new Lotto(numbers)).toThrow(); | ||
}); | ||
|
||
test.each([[[3, 2, 4, 5, 6, 1]], [[13, 12, 14, 15, 16, 11]]])( | ||
'로또 번호는 오름차순으로 정렬된다.', | ||
(numbers) => { | ||
const lotto = new Lotto(numbers); | ||
|
||
expect(lotto.getNumbers()).toStrictEqual(numbers.sort()); | ||
} | ||
); | ||
}); | ||
|
||
describe('로또 당첨 여부 판단 테스트', () => { | ||
let lottoNumbers; | ||
let lotto; | ||
|
||
beforeAll(() => { | ||
lottoNumbers = [1, 2, 3, 4, 5, 6]; | ||
lotto = new Lotto(lottoNumbers); | ||
}); | ||
|
||
test.each([[[1, 2, 3, 4, 5, 6], 7, 1]])( | ||
'6개의 번호가 일치하면 1등을 반환한다.', | ||
(winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
} | ||
); | ||
|
||
test.each([[[1, 2, 3, 4, 5, 45], 6, 2]])( | ||
'5개의 번호 + 보너스 번호가 일치하면 2등을 반환한다.', | ||
(winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
} | ||
); | ||
|
||
test.each([[[1, 2, 3, 4, 5, 45], 7, 3]])( | ||
'5개의 번호가 일치하고 보너스 번호가 다르면 3등을 반환한다.', | ||
(winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
} | ||
); | ||
|
||
test.each([ | ||
[[1, 2, 3, 4, 44, 45], 6, 4], | ||
[[1, 2, 3, 4, 44, 45], 7, 4] | ||
])('4개의 번호가 일치하면 4등을 반환한다.', (winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
}); | ||
|
||
test.each([ | ||
[[1, 2, 3, 43, 44, 45], 6, 5], | ||
[[1, 2, 3, 43, 44, 45], 7, 5] | ||
])('3개의 번호가 일치하면 5등을 반환한다.', (winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
}); | ||
|
||
test.each([ | ||
[[1, 2, 42, 43, 44, 45], 6, 6], | ||
[[1, 2, 42, 43, 44, 45], 7, 6], | ||
[[1, 41, 42, 43, 44, 45], 6, 6], | ||
[[1, 41, 42, 43, 44, 45], 7, 6], | ||
[[40, 41, 42, 43, 44, 45], 6, 6], | ||
[[40, 41, 42, 43, 44, 45], 7, 6] | ||
])('3개 미만의 번호가 일치하면 다음기회에^^.', (winningNumbers, bonusNumber, rank) => { | ||
expect(lotto.determineRank(winningNumbers, bonusNumber)).toBe(rank); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* eslint-disable max-lines-per-function */ | ||
import { ERROR_MESSAGES, VARIABLE_ALIAS } from '../src/constant/Messages.js'; | ||
import OPTIONS from '../src/constant/Options.js'; | ||
import Lotto from '../src/domain/Lotto.js'; | ||
import LottoMachine from '../src/domain/LottoMachine'; | ||
|
||
// TODO: calculateIssueQuantity 함수를 private 함수로 변경 | ||
describe('LottoMachine 단위테스트', () => { | ||
let lottoMachine; | ||
|
||
beforeEach(() => { | ||
lottoMachine = new LottoMachine(); | ||
}); | ||
|
||
describe('구입 금액에 따른 구입 가능 수량 계산 테스트', () => { | ||
test.each(['a', 1.1])( | ||
'구입 금액(%s)이 정수가 아니라면 에러를 발생시킨다.', | ||
(purchaseAmount) => { | ||
expect(() => lottoMachine.calculateIssueQuantity(purchaseAmount)).toThrow( | ||
`${ERROR_MESSAGES.prefix}${ERROR_MESSAGES.isNotInteger(VARIABLE_ALIAS.purchaseAmount)}` | ||
); | ||
} | ||
); | ||
|
||
test('구입 금액이 1000 미만이라면 에러를 발생시킨다.', () => { | ||
const purchaseAmount = 999; | ||
|
||
expect(() => lottoMachine.calculateIssueQuantity(purchaseAmount)).toThrow( | ||
`${ERROR_MESSAGES.prefix}${ERROR_MESSAGES.isNotAtLeast(VARIABLE_ALIAS.purchaseAmount, OPTIONS.LOTTO.price)}` | ||
); | ||
}); | ||
|
||
test.each([ | ||
[1000, 1], | ||
[1999, 1], | ||
[2000, 2] | ||
])('구입 금액(%s)에 따른 발행 수량(%s)을 계산하여 반환한다.', (purchaseAmount, quantity) => { | ||
expect(lottoMachine.calculateIssueQuantity(purchaseAmount)).toBe(quantity); | ||
}); | ||
}); | ||
|
||
describe('지정 수량 만큼 로또 발행 테스트', () => { | ||
test('지정 수량만큼 로또를 발행한다.', () => { | ||
const issueQuantity = 1; | ||
const lottos = lottoMachine.issueLottos(issueQuantity); | ||
|
||
expect(Array.isArray(lottos) && lottos.length === issueQuantity).toBe(true); | ||
}); | ||
|
||
test('로또 객체의 배열을 반환한다.', () => { | ||
const issueQuantity = 1; | ||
const lottos = lottoMachine.issueLottos(issueQuantity); | ||
|
||
expect(lottos.every((lotto) => lotto instanceof Lotto)).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('로또 결과 분석 테스트', () => { | ||
// TEST: 1. 등수 별 당첨 개수 | ||
test('구입한 로또들의 등수를 분석하여 반환한다.', () => { | ||
const numbersList = [ | ||
[1, 2, 3, 4, 5, 6], | ||
[1, 2, 3, 4, 5, 7], | ||
[1, 2, 3, 4, 5, 45], | ||
[1, 2, 3, 4, 44, 45], | ||
[1, 2, 3, 43, 44, 45], | ||
[1, 2, 42, 43, 44, 45] | ||
]; | ||
const lottos = numbersList.map((numbers) => new Lotto(numbers)); | ||
const winningNumbers = [1, 2, 3, 4, 5, 6]; | ||
const bonusNumber = 7; | ||
|
||
const winningResult = { 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1 }; | ||
|
||
expect(lottoMachine.determineLottoRanks(lottos, winningNumbers, bonusNumber)).toStrictEqual( | ||
winningResult | ||
); | ||
}); | ||
|
||
// TEST: 2. 수익률 계산 | ||
test.each([[{ 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 7 }, 62.5]])( | ||
'로또 결과에 따른 수익률을 반환한다.', | ||
(winningResult, profitRate) => { | ||
expect(lottoMachine.calculateProfitRate(winningResult)).toBe(profitRate); | ||
} | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* eslint-disable max-lines-per-function */ | ||
import Random from '../src/util/random/Random.js'; | ||
|
||
describe('랜덤 테스트', () => { | ||
test('특정 범위 내에서 랜덤 값 1개를 반환한다.', () => { | ||
const min = 1; | ||
const max = 10; | ||
const testCount = 10; | ||
|
||
const testSuites = Array(testCount) | ||
.fill() | ||
.map(() => Random.randomPickNumber(min, max)); | ||
|
||
expect(testSuites.every((testSuite) => min <= testSuite && testSuite <= max)).toBe(true); | ||
}); | ||
|
||
test('특정 범위 내에서 중복되지 않은 조합을 반환한다.', () => { | ||
const min = 1; | ||
const max = 45; | ||
const count = 6; | ||
const testCount = 5; | ||
|
||
const testSuites = Array(testCount) | ||
.fill() | ||
.map(() => Random.pickCombination(min, max, count)); | ||
|
||
expect( | ||
testSuites.every((testSuite) => { | ||
return testSuite.length === new Set(testSuite).size && testSuite.length === count; | ||
}) | ||
).toBe(true); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
오 import order까지 👍
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.
위의 두 가지 이유로 eslint 설정을 다시 해보고자 합니다!