우아한 테크코스]프리코스 3주차 로또 - 기능 요구 사항

손지민·2023년 11월 7일
0

개요

1. 기능 요구 사항

로또 게임 기능을 구현해야 한다. 로또 게임은 아래와 같은 규칙으로 진행된다.

- 로또 번호의 숫자 범위는 1~45까지이다.
- 1개의 로또를 발행할 때 중복되지 않는 6개의 숫자를 뽑는다.
- 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다.
- 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다.
    - 1등: 6개 번호 일치 / 2,000,000,000원
    - 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원
    - 3등: 5개 번호 일치 / 1,500,000원
    - 4등: 4개 번호 일치 / 50,000원
    - 5등: 3개 번호 일치 / 5,000원
  • 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다.
  • 로또 1장의 가격은 1,000원이다.
  • 당첨 번호와 보너스 번호를 입력받는다.
  • 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다.
  • 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
    • Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다.

1.1. 입출력 요구 사항

입력

  • 로또 구입 금액을 입력 받는다. 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다.
14000
  • 당첨 번호를 입력 받는다. 번호는 쉼표(,)를 기준으로 구분한다.
1,2,3,4,5,6
  • 보너스 번호를 입력 받는다.
7

출력

  • 발행한 로또 수량 및 번호를 출력한다. 로또 번호는 오름차순으로 정렬하여 보여준다.
8개를 구매했습니다.
[8, 21, 23, 41, 42, 43] 
[3, 5, 11, 16, 32, 38] 
[7, 11, 16, 35, 36, 44] 
[1, 8, 11, 31, 41, 42] 
[13, 14, 16, 38, 42, 45] 
[7, 11, 30, 40, 42, 43] 
[2, 13, 22, 32, 38, 45] 
[1, 3, 5, 14, 22, 45]
  • 당첨 내역을 출력한다.
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
  • 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%)
총 수익률은 62.5%입니다.
  • 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다.
[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.

실행 결과 예시

구입금액을 입력해 주세요.
8000

8개를 구매했습니다.
[8, 21, 23, 41, 42, 43] 
[3, 5, 11, 16, 32, 38] 
[7, 11, 16, 35, 36, 44] 
[1, 8, 11, 31, 41, 42] 
[13, 14, 16, 38, 42, 45] 
[7, 11, 30, 40, 42, 43] 
[2, 13, 22, 32, 38, 45] 
[1, 3, 5, 14, 22, 45]

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

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

당첨 통계
---
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
총 수익률은 62.5%입니다.

2. 3주차 공부한 부분

2.1. README.md 작성을 위한 마크다운 문법

2.2. Java 상수

2.3. Java Enum

2.4. 도메인 로직에 단위 테스트 적용하기


3. 구현

3.1. 기능 목록

1. 게임 시작

2. 로또 번호 생성

  • 1부터 45까지의 숫자 중 6개의 랜덤한 숫자 생성
  • 중복되지 않는 6개의 숫자 생성

3. 로또 구매 기능

  • 로또 구입 금액 입력
  • 입력 금액에 해당하는 만큼 로또 발급
  • 한 장의 로또는 1,000원

4. 당첨 번호 및 보너스 번호 입력

  • 당첨 번호 6개와 보너스 번호 1개를 입력
  • 입력된 번호로 당첨 결과 확인

5. 로또 당첨 결과 확인

  • 당첨번호와 구매한 로또 번호 비교
  • 당첨 결과와 수익률 확인

6. 입력값 유효성 검사 및 예외 처리

  • 입력 값 범위 확인 (로또 번호, 구입 금액 등)
  • 잘못된 입력 시 에러 처리 ("[ERROR]"로 시작하는 에러 메시지 출력)

7. 출력 기능

  • 발급된 로또 수량 및 번호 출력
  • 당첨 결과 및 수익률 출력

8. 콘솔 입력/출력

  • 사용자에게 정보 요청 및 결과 출력

9. 수익률 계산

  • 구매한 로또 대비 총 수익률 계산

3.2. 클래스 설계

Lotto: 로또 번호 생성과 당첨 여부 확인
LottoGame: 로또 게임 진행, 당첨 번호 입력 및 결과 확인
LottoShop: 로또 구매 및 발급
InputValidator: 입력값 유효성 검사 및 예외 처리
ResultPrinter: 결과 출력 담당
ConsoleManager: 콘솔 입력 및 출력 관리
ProfitCalculator: 수익률 계산 담당

3.2.1 LottoGame.java

package lotto;

import java.util.List;

public class LottoGame {

    public void startGame() {
        // 게임 시작
        LottoShop lottoShop = new LottoShop();
        Lotto winningLotto = Lotto.createRandomLotto();

        LottoTicket purchasedTickets = lottoShop.buyLottoTicket();
        List<Lotto> lottos = purchasedTickets.getLottos();

        InputValidator validator = new InputValidator();
        List<Integer> winningNumbers = validator.getValidWinningNumbers();
        int bonusNumber = validator.getValidBonusNumber();

        ResultChecker resultChecker = new ResultChecker();
        int matchCount;
        int totalMatchCount = 0;
        int manualTicketCount = 0;

        for (Lotto lotto : lottos) {
            matchCount = resultChecker.checkResult(lotto, winningLotto, winningNumbers, bonusNumber);
            if (matchCount == Lotto.LOTTO_SIZE) {
                manualTicketCount++;
            }
            totalMatchCount += matchCount;
        }

        ResultPrinter resultPrinter = new ResultPrinter();
        resultPrinter.printResult(winningLotto, winningNumbers, bonusNumber, lottos.size(), manualTicketCount, totalMatchCount);
        
        ProfitCalculator profitCalculator = new ProfitCalculator();
        profitCalculator.calculateProfit(lottos.size(), totalMatchCount);
    }
}

4. 마주한 문제

4.1. Random 값 추출이 중복 검사 해주나?

  • 우테코 요구사항
    Random 값 추출은 camp.nextstep.edu.missionutils.Randoms의 pickUniqueNumbersInRange()를 활용한다.
    위 코드를 분석해보니 pickUniqueNumbersInRange(1,45,6) 이렇게 입력하면 6개의 값을 1~45사이에서 선택해주지만, 중복검사는 해주지 않고 있다.

4.2. 보너스 번호는 어떻게 따로 로또 번호에 구분해서 저장하지?


4.3. 비상 대실수. 실제 로또랑 다른 시스템인걸 너무 늦게 알았다.

4.3.1. 게임 흐름 재정립

로또 게임은 다음과 같은 과정으로 진행됩니다:

1. 로또 금액 및 번호 선택:

  • 사용자로부터 1000원 단위로 구매할 금액을 입력 받습니다.
  • 사용자는 로또 번호를 6자리 입력합니다. 각 번호는 1부터 45까지의 숫자여야 합니다. 숫자들은 쉼표(,)로 구분됩니다.
  • 사용자는 보너스 번호도 입력해야 합니다.

2. 로또 번호 생성:

  • 입력된 금액을 1000원으로 나누어 몇 개의 로또 티켓을 구매할지 결정합니다.
  • 결정된 로또 티켓 수만큼, 랜덤으로 로또 번호를 생성합니다. 1부터 45까지의 숫자 중에서 중복되지 않는 6개의 숫자로 이루어진 번호입니다. (Randoms.pickUniqueNumbersInRange(MIN_NUMBER, MAX_NUMBER, LOTTO_SIZE) 메서드 사용)

3. 당첨 결과 확인:

  • 사용자가 입력한 당첨 번호, 보너스 번호와 생성된 로또 번호를 비교하여 당첨 결과를 확인합니다.
  • 6개의 번호가 일치하면 1등, 5개 번호와 보너스 번호가 일치하면 2등, 5개 번호가 일치하면 3등, 4개 번호가 일치하면 4등, 3개 번호가 일치하면 5등에 당첨됩니다.
  • 각 당첨 등수에 따른 상금은 각각 1등: 2,000,000,000원, 2등: 30,000,000원, 3등: 1,500,000원, 4등: 50,000원, 5등: 5,000원입니다.

4. 게임 종료:

  • 당첨 결과와 수익률을 출력하고, 게임을 종료합니다.

이렇게 구성된 로또 게임은 사용자의 입력과 랜덤한 번호 생성, 그리고 당첨 결과 확인을 통해 게임이 진행되고, 최종적으로 당첨 결과와 수익률이 출력됩니다.


4.3.2. 클래스 구성

1. LottoGame:

  • startGame() 메서드를 포함한 클래스로, 전반적인 로또 게임 흐름을 관리합니다.

2. LottoShop:

  • 로또 티켓 구매를 처리하는 클래스로, 사용자가 입력한 금액에 따라 로또 티켓을 구매하고 관련된 기능을 담당합니다.

3. Lotto:

  • 로또 번호를 생성하고, 번호 간의 비교를 담당합니다.
  • createRandomLotto() 메서드: 랜덤으로 번호를 생성합니다.

4. InputValidator:

  • 사용자로부터 입력 받은 값의 유효성 검사를 수행합니다.
  • 예를 들어, 로또 번호의 유효성을 확인하거나 1000원 단위의 입력인지 확인하는 역할을 합니다.

5. ResultChecker:

  • 로또 번호와 당첨 번호의 일치를 확인하고, 당첨 결과를 반환합니다.

6. ResultPrinter:

  • 게임 결과를 출력하는데 사용됩니다.

7. ProfitCalculator:

  • 로또 게임의 수익률을 계산하고 반환하는 역할을 합니다.

8. Randoms (외부 라이브러리):

  • 무작위로 중복되지 않는 숫자를 생성하는 데 사용되는 클래스입니다.
profile
Developer

0개의 댓글