Skip to content

Conversation

@nunomi0
Copy link

@nunomi0 nunomi0 commented Nov 3, 2025

javascript-lotto-precourse

로또 구매부터 당첨 결과 확인까지 전 과정을 시뮬레이션하는 JavaScript 애플리케이션입니다.

기능 소개

  1. 로또 구매: 1,000원 단위로 로또를 구매합니다.
  2. 자동 번호 생성: 1~45 사이의 중복되지 않는 6개의 번호를 자동으로 생성합니다.
  3. 당첨 확인: 구매한 로또와 당첨 번호를 비교하여 당첨 결과를 확인합니다.
  4. 수익률 계산: 총 수익률을 계산하여 표시합니다.

프로젝트 구조

src/
├── App.js                      # 애플리케이션 진입점
├── index.js                    # 프로그램 실행
├── controller/
│   └── LottoController.js      # 로또 게임 로직 제어
├── model/
│   ├── Lotto.js                # 로또 클래스
│   ├── lottoGenerator.js       # 로또 생성 로직
│   ├── calculateResult.js      # 당첨 결과 계산
│   ├── calculateProfit.js      # 수익률 계산
│   ├── validator.js            # 입력 검증
│   └── constants.js            # 상수 정의
└── view/
    ├── inputView.js            # 사용자 입력 처리
    └── outputView.js           # 결과 출력 처리

__tests__/
├── ApplicationTest.js          # 통합 테스트
├── LottoTest.js                # 로또 클래스 테스트
├── validator.test.js           # 유효성 검증 테스트
├── LottoGenerator.test.js      # 로또 생성 테스트
├── calculateResult.test.js     # 결과 계산 테스트
└── calculateProfit.test.js     # 수익률 계산 테스트

구현 기능 목록

입력

  • 로또 구입 금액 입력
    • 숫자가 아닌 경우 예외
    • 정수가 아닌 경우 예외
    • 양수가 아닌 경우 예외
    • 1000으로 나누어 떨어지지 않는 경우 예외
  • 당첨 번호 입력
    • 쉼표로 구분된 6개의 숫자 입력
    • 1~45 범위를 벗어나는 경우 예외
    • 중복된 번호가 있는 경우 예외
  • 보너스 번호 입력
    • 1~45 범위를 벗어나는 경우 예외
    • 당첨 번호와 중복인 경우 예외

로또 발행

  • 구입 금액 / 1000개의 로또 발행
  • 각 로또는 1~45 범위의 중복되지 않은 6개의 랜덤 숫자로 구성
  • 번호 오름차순 정렬

당첨 결과 계산

  • 로또 번호에 따른 당첨 결과 계산
    • 1등: 6개 번호 일치 / 2,000,000,000원
    • 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원
    • 3등: 5개 번호 일치 / 1,500,000원
    • 4등: 4개 번호 일치 / 50,000원
    • 5등: 3개 번호 일치 / 5,000원
  • 수익률 계산
    • 소수점 둘째 자리 반올림

출력

  • 구매한 로또 번호 출력
  • 당첨 통계 출력
  • 수익률 출력
  • 예외 발생 시 [ERROR]로 시작하는 에러 메시지 출력

예외 처리

모든 예외 상황에서 [ERROR]로 시작하는 에러 메시지를 출력하고, 올바른 값을 재입력받습니다.

구입 금액 예외

  • 숫자가 아닌 값 입력 시: [ERROR] 구입 금액은 숫자여야 합니다.
  • 정수가 아닌 값 입력 시: [ERROR] 구입 금액은 정수여야 합니다.
  • 0 이하의 값 입력 시: [ERROR] 구입 금액은 0보다 커야 합니다.
  • 1,000원 단위가 아닌 경우: [ERROR] 구입 금액은 1000원 단위여야 합니다.

당첨 번호 예외

  • 6개가 아닌 경우: [ERROR] 당첨 번호는 6개여야 합니다.
  • 숫자가 아닌 값 포함 시: [ERROR] 당첨 번호는 숫자여야 합니다.
  • 1~45 범위를 벗어난 경우: [ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.
  • 중복된 번호가 있는 경우: [ERROR] 중복된 당첨 번호가 있습니다.

보너스 번호 예외

  • 1~45 범위를 벗어난 경우: [ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다.
  • 당첨 번호와 중복인 경우: [ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.

로또 클래스 예외

  • 번호가 6개가 아닌 경우: [ERROR] 로또 번호는 6개여야 합니다.
  • 중복된 번호가 있는 경우: [ERROR] 로또 번호에 중복된 숫자가 있습니다.

설계 시 고려한 부분

  1. MVC 패턴: Controller, Model, View를 분리하여 관심사의 분리 원칙을 준수합니다.
  2. 단일 책임 원칙: 각 모듈은 하나의 책임만 가집니다.
  3. 입력 검증: 모든 사용자 입력은 validator를 통해 검증됩니다.
  4. 에러 처리: 예외 발생 시 적절한 에러 메시지를 표시합니다.
  5. 테스트: 단위 테스트와 통합 테스트를 통해 코드의 안정성을 보장합니다.

- 숫자가 아닌 경우 예외
- 정수가 아닌 경우 예외
- 양수가 아닌 경우 예외
- 1000으로 나누어 떨어지지 않는 경우 예외
- 번호가 6개가 아닌 경우 예외
- 중복된 번호가 있는 경우 예외
- 1~45 범위를 벗어나는 경우 예외
- 1~45 범위를 벗어나는 경우 예외
- 당첨 번호와 중복인 경우 예외
- 구입 금액/1000개의 로또 발행
- 각 로또는 1~45 범위의 중복되지 않은 6개의 랜덤 숫자로 구성
- 번호 오름차순 정렬
- LottoController에서 로또 발행 로직 연동
- PRIZE_TABLE 상수 추가로 조건, 등수, 상금 정의
- calculateResult에 당첨 결과 기능 추가
- lottoController에 calculateResult 연결
- calculateResult() -> initResult(), analyzeLotto(), findPrize()로 분리
- printResult() -> printStatistics(), printProfitRate()
@JangYEhoon00
Copy link

수고하셨습니다 우선 봤을때는 매직넘버와 매직스트링을 사용한다면 더 좋을것같습니다 또 매직넘버와 매직스트링을 사용하는 이유에 대해서 공부하면 더 좋아보입니다

Copy link

@inseong01 inseong01 left a comment

Choose a reason for hiding this comment

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

리드미가 잘 작성되어 있어서 코드 파악하는 데 수월했습니다.

3주 차 미션하시느라 수고하셨습니다~

Comment on lines +4 to +7
async readPurchaseAmount() {
const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n");
return input;
},

Choose a reason for hiding this comment

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

동일한 구조가 반복되고 있어서

Suggested change
async readPurchaseAmount() {
const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n");
return input;
},
async readLine(prompt) {
const input = await Console.readLineAsync(`${prompt}\n`);
return input;
},

이렇게 하면 재사용할 수 있을 것 같아요.


const outputView = {
printPurchasedLottos(lottos) {
Console.print(`\n${lottos.length}개를 구매했습니다.`);

Choose a reason for hiding this comment

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

여러 곳에서 Console.print를 호출하고 있는데 하나의 메서드로 만들어서 인자를 출력하는 방식으로 사용하면 좋을 것 같아요.

@@ -0,0 +1,47 @@
const validator = {

Choose a reason for hiding this comment

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

class가 아닌 객체로 선언한 이유가 궁금해요.

Comment on lines +22 to +29
winningNumbers.forEach((num) => {
if (!Number.isInteger(num)) {
throw new Error("[ERROR] 당첨 번호는 숫자여야 합니다.");
}
if (num < 1 || num > 45) {
throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
});

Choose a reason for hiding this comment

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

한 요소에 두 개의 조건을 동시에 검증하고 있는데

Suggested change
winningNumbers.forEach((num) => {
if (!Number.isInteger(num)) {
throw new Error("[ERROR] 당첨 번호는 숫자여야 합니다.");
}
if (num < 1 || num > 45) {
throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
});
const hasInteger = winningNumbers.every(Number.isInteger);
if (!hasInteger) {
throw new Error("[ERROR] 당첨 번호는 숫자여야 합니다.");
}
const isOutOfNumberRange = winningNumbers.some((num) => num < 1 || num > 45);
if (isOutOfNumberRange) {
throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}

이렇게 하면 들여쓰기 깊이도 줄어들고 validator 코드 구조 통일하는 데 도움될 것 같아요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants