Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
269 changes: 268 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,268 @@
# javascript-planetlotto-precourse
<aside>

# javascript-lotto-precourse

## 로또

간단한 로또 발매기를 구현하는 미션입니다. 사용자가 구매 금액을 입력하면 해당 금액만큼 로또를 발행하고, 당첨 번호와 보너스 번호를 입력받아 당첨 내역과 수익률을 계산하여 출력합니다.

## 목차

- [프로젝트 구조](#프로젝트-구조)
- [기능 목록](#기능-목록)
- [예외 처리](#예외-처리)
- [실행 결과 예시](#실행-결과-예시)

## 프로젝트 구조

```
src/
├── App.js # 프로그램 진입점
├── index.js # 실행 파일
├── model/
│ └── Lotto.js # 로또 모델 클래스
├── views/
│ └── view.js # 입,출력 처리 뷰
├── controllers/
│ └── LottoController.js # 비즈니스 로직 컨트롤러
└── utils/
├── InputValidator.js # 입력 검증 유틸리티
├── LottoGenerator.js # 로또 번호 생성 유틸리티
└── PrizeCalculator.js # 당첨 계산 유틸리티

__tests__/
├── LottoTest.js # Lotto 클래스 단위 테스트
├── InputValidatorTest.js # 입력 검증 테스트
├── LottoGeneratorTest.js # 로또 생성 테스트
├── PrizeCalculatorTest.js # 당첨 계산 테스트
└── ApplicationTest.js # 통합 테스트

```


## 기능 목록

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

- 사용자로부터 로또 구입 금액을 입력받는다.
- 입력 형식: 500원 단위의 정수 (예: `8000`, `14000`)
- 프롬프트: "로또 구입금액을 입력해주세요.
>"

### 2. 로또 구입 금액 검증

- 빈 문자열 또는 공백만 입력한 경우 검증
- 정수 형식이어야 한다.
- 500원 단위로 나누어 떨어져야 한다.
- 양수여야 한다.

**예외 상황:**

- 로또의 구입금액을 500원 단위로 입력하지않았을때 : `"[ERROR] 로또의 구입금액은 500원 단위여야 합니다."`
- 로또 구입금액 숫자가 아닐때: `"[ERROR] 로또의 구입금액은 500원 단위 숫자여야 합니다."`
- 로또 구입금액 양수가 아닐때: `"[ERROR] 로또의 구입금액은 500원 단위 양수여야 합니다."`
- 로또 구입금액 정수가 아닐때: `"[ERROR] 로또의 구입금액은 500원 단위 정수여야 합니다."`
- 로또 빈문자열 또는 공백만 입력헀을때: `"[ERROR] 로또의 구입금액은 500원 단위 금액으로 입력해야합니다."`
### 3. 로또 발행

- 구입 금액에 따라 발행할 로또 수량을 계산한다. (구입 금액 / 500원)
- Random API를 사용하여 각 로또마다 중복되지 않는 5개의 숫자를 생성한다. (1~30 범위)
- 생성된 로또 번호는 오름차순으로 정렬하여 저장한다.

### 4. 발행한 로또 출력

- 발행한 로또 수량을 출력한다.
- 각 로또 번호를 오름차순으로 출력한다.
- 출력 형식:

```
2개를 구매했습니다.
[8, 11, 13, 21, 22]
[1, 3, 6, 14, 22]
...

```


### 5. 당첨 번호 입력

- 당첨 번호 5개를 쉼표로 구분하여 입력받는다.
- 입력 형식: 쉼표로 구분된 정수 (예: `1,2,3,4,5`)
- 프롬프트: `로또 당첨 번호를 5번호 를 구분하여 입력해주세요.
(번호 구분은 , 를통해서 입력하시오).
* 로또의 당첨 번호는 중복될 수 없습니다.
* 로또의 당첨 번호는 음수, 소수가 될수 없습니다.
>"`

### 6. 당첨 번호 검증

- 빈 문자열 또는 공백만 입력한 경우 검증
- 정확히 5개의 정수여야 한다.
- 각 숫자가 1 이상 30 이하여야 한다.
- 중복된 숫자가 없어야 한다.

### 7. 보너스 번호 입력

- 보너스 번호 1개를 입력받는다.
- 입력 형식: 정수 (예: `7`)
- 프롬프트: "보너스 번호를 입력해주세요.
* 보너스 번호는 당첨번호와 중복될 수 없습니다.
>`

### 8. 보너스 번호 검증

- 빈 문자열 또는 공백만 입력한 경우 검증
- 정수 형식이어야 한다.
- 1 이상 30 이하여야 한다.
- 당첨 번호와 중복되지 않아야 한다.

**예외 상황:**

- 빈 문자열 또는 공백만 입력한 경우: `"[ERROR] 보너스 번호를 입력해 주세요."`
- 숫자가 아닌 경우: `"[ERROR] 보너스 번호는 1부터 30 사이의 숫자여야 합니다."`
- 소수점이 포함된 경우: `"[ERROR] 보너스 번호는 1부터 30 사이의 숫자여야 합니다."`
- 1~45 범위를 벗어난 경우: `"[ERROR] 보너스 번호는 1부터 30 사이의 숫자여야 합니다."`
- 당첨 번호와 중복되는 경우: `"[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."`

### 9. 당첨 결과 계산

- 각 로또 번호와 당첨 번호를 비교하여 일치하는 개수를 계산한다.
- 보너스 번호 포함 여부를 확인한다.
- 등수를 판정한다.
- **1등**: 5개 번호 일치 / 100,000,000원
- **2등**: 4개 번호 + 보너스 번호 일치 / 10,000,000원
- **3등**: 4개 번호 일치 / 1,500,000원
- **4등**: 3개 번호 일치 + 보너스 번호 일치 / 500,000원
- **5등**: 2개 번호 일치 + 보너스 번호 일치 / 5,000원
- **꽝**: 2개 번호 일치 이하 / 0원

### 10. 당첨 통계 계산

- 발행한 모든 로또에 대한 등수별 당첨 개수를 계산한다.
- 총 당첨 금액을 계산한다.

### 11. 수익률 계산

- 수익률 = (총 당첨 금액 / 구입 금액) × 100
- 소수점 둘째 자리에서 반올림한다.

### 12. 당첨 통계 출력

- 당첨 통계 헤더를 출력한다.
- 등수별 당첨 내역을 출력한다.
- 총 수익률을 출력한다.
- 출력 형식:

```
당첨 통계
---
5개 일치 (100,000,000원) - 0개
4개 일치, 보너스 번호 일치 (10,000,000원) - 0개
4개 일치 (1,500,000원) - 0개
3개 일치, 보너스 번호 일치 (500,000원) - 0개
2개 일치, 보너스 번호 일치 (5,000원) - 1개
2개 일치 이하, (0원) - 1개

```


### 13. 예외 처리 및 재입력

- 모든 검증 실패 시 "[ERROR]"로 시작하는 메시지를 출력한다.
- 예외 발생 시 해당 입력부터 다시 입력을 받는다.

## 실행 결과 예시

```
구입금액을 입력해 주세요.
8000
8개를 구매했습니다.
[8, 21, 23, 41, 42]
[3, 5, 11, 16, 32]
[7, 11, 16, 35, 36]
[1, 8, 11, 31, 41]
[13, 14, 16, 38, 42]
[7, 11, 30, 40, 42]
[2, 13, 22, 32, 38]
[1, 3, 5, 14, 22]

당첨 번호를 입력해 주세요.
1,2,3,4,5

보너스 번호를 입력해 주세요.
6

당첨 통계
---
5개 일치 (100,000,000원) - 0개
4개 일치, 보너스 번호 일치 (10,000,000원) - 0개
4개 일치 (1,500,000원) - 0개
3개 일치, 보너스 번호 일치 (500,000원) - 0개
2개 일치, 보너스 번호 일치 (5,000원) - 1개
0개 일치 (0원) - 1개

```

## 예외 처리

모든 예외 상황은 `[ERROR]`로 시작하는 메시지를 출력하고, 해당 입력부터 다시 입력을 받아야 합니다.

### 예외 상황 목록

### 로또 구입 금액

1. **빈 문자열 또는 공백만 입력한 경우**
- 메시지: `"[ERROR] 로또 구입 금액을 입력해 주세요."`
2. **숫자가 아닌 경우**
- 메시지: `"[ERROR] 로또 구입 금액은 500원 단위 숫자여야 합니다."`
3. **소수점이 포함된 경우**
- 메시지: `"[ERROR] 로또 구입 금액은 500원 단위 정수여야 합니다."`
4. **500원 단위가 아닌 경우**
- 메시지: `"[ERROR] 로또 구입 금액은 500원 단위로 입력해야 합니다."`
5. **양수가 아닌 경우**
- 메시지: `"[ERROR] 로또 구입 금액은 500원 단위 양수여야 합니다."`

### 당첨 번호

1. **빈 문자열 또는 공백만 입력한 경우**
- 메시지: `"[ERROR] 당첨 번호를 입력해 주세요."`
2. **숫자가 아닌 값이 포함된 경우**
- 메시지: `"[ERROR] 로또 번호는 1부터 30 사이의 숫자여야 합니다."`
3. **소수점이 포함된 경우**
- 메시지: `"[ERROR] 로또 번호는 1부터 30 사이의 숫자여야 합니다."`
4. **빈 값이 포함된 경우 (예: "1,2,,4,5")**
- 메시지: `"[ERROR] 로또 번호는 5개여야 합니다."`
5. **6개가 아닌 경우**
- 메시지: `"[ERROR] 로또 번호는 5개여야 합니다."`
6. **1~45 범위를 벗어난 경우**
- 메시지: `"[ERROR] 로또 번호는 1부터 30 사이의 숫자여야 합니다."`
7. **중복이 있는 경우**
- 메시지: `"[ERROR] 로또 번호에 중복된 숫자가 있습니다."`

### 보너스 번호

1. **빈 문자열 또는 공백만 입력한 경우**
- 메시지: `"[ERROR] 보너스 번호를 입력해 주세요."`
2. **숫자가 아닌 경우**
- 메시지: `"[ERROR] 보너스 번호는 1부터 30 사이의 정수여야 합니다."`
3. **소수점이 포함된 경우**
- 메시지: `"[ERROR] 보너스 번호는 1부터 30 사이의 정수여야 합니다."`
4. **1~30 범위를 벗어난 경우**
- 메시지: `"[ERROR] 보너스 번호는 1부터 30 사이의 정수여야 합니다."`
5. **당첨 번호와 중복되는 경우**
- 메시지: `"[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."`

### 예외 처리 흐름

```
사용자 입력
검증 로직 실행
[검증 실패] → [ERROR] 메시지 출력 → 해당 입력 재요청
[검증 성공] → 다음 단계 진행

```

</aside>
7 changes: 6 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import LottoController from "./controller/LottoController.js";

class App {
async run() {}
async run() {
const controller = new LottoController;
await controller.run();
}
}

export default App;
17 changes: 17 additions & 0 deletions src/constants/ErrorMesssage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const ErrorMessage = {
PURCHASE_AMOUNT_EMPTY: '로또 구입 금액을 입력해 주세요.',
PURCHASE_AMOUNT_NOT_NUMBER: '로또의 구입금액은 500원 단위 숫자여야 합니다.',
PURCHASE_AMOUNT_NOT_DIVISIBLE: '로또의 구입금액은 500원 단위여야 합니다.',
PURCHASE_AMOUNT_NOT_POSITIVE: "로또의 구입금액은 500원 단위 양수여야 합니다.",

WINNING_NUMBERS_EMPTY: '로또 당첨번호를 입력해 주세요.',
WINNING_NUMBERS_INVALID_COUNT: '로또 번호는 5개여야 합니다.',
WINNING_NUMBERS_INVALID_RANGE: '로또 번호는 1부터 30 사이의 숫자여야 합니다.',
WINNING_NUMBERS_DUPLICATE: '로또 당첨 번호에 중복된 숫자가 있습니다.',

BONUS_NUMBER_EMPTY: '보너스 번호를 입력해 주세요.',
BONUS_NUMBER_INVALID_RANGE: '보너스 번호는 1부터 30 사이의 정수여야 합니다.',
BONUS_NUMBER_DUPLICATE: '보너스 번호는 당첨 번호와 중복될 수 없습니다.',
};

export default ErrorMessage;
9 changes: 9 additions & 0 deletions src/constants/LottoConstants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class LottoConstants {
static LOTTO_PRICE = 500;
static LOTTO_NUMBER_COUNT = 5;
static MIN_NUMBER = 1;
static MAX_NUMBER = 30;
}

export default LottoConstants;

36 changes: 36 additions & 0 deletions src/constants/PrizeConstants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class PrizeConstants {
static RANK = {
FIRST: 1,
SECOND: 2,
THIRD: 3,
FOURTH: 4,
FIFTH: 5,
NONE: 0,
};

static MATCH_COUNT = {
FIRST: 5,
SECOND: 4,
THIRD: 4,
FOURTH: 3,
FIFTH: 2,
};

static PRIZE_AMOUNTS = {
1: 100000000,
2: 10000000,
3: 1500000,
4: 500000,
5: 5000,
};

static PROFIT_RATE_MULTIPLIER = 100;
static PROFIT_RATE_DECIMAL_PLACES = 1;
}

export default PrizeConstants;





5 changes: 5 additions & 0 deletions src/constants/PromptMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const PromptMessages = {
PURCHASE_AMOUNT: "구입금액을 입력해 주세요.\n",
WINNING_NUMBERS: "\n당첨 번호를 입력해 주세요.\n",
BONUS_NUMBER: "\n보너스 번호를 입력해 주세요.\n"
};
Loading