Skip to content
Closed
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
81 changes: 80 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,80 @@
# javascript-lotto-precourse
# 3주차 프리코스 과제 : 로또
- 간단한 로또 발매기 구현

## 기본 기능
- 구입 금액을 입력하단 해당 금액만큼 로또 발행
- 6개의 당첨 번호와 보너스 번호 입력받아 당첨 통계 계산
- 수익률 계산 후 출력

## 기능 요구사항
1. 로또 구입
- 사용자에게 구입 금액 입력
- 구입 금액은 1,000원 단위의 정수
- 구입 금액에 맞는 개수만큼 로또 발행
- 한 장당 로또 번호는 1~45 사이의 중복되지 않은 6개의 숫자
- 발행된 로또 번호를 오름차순으로 출력
2. 당첨 번호 및 보너스 번호 입력
- 당첨 번호 6개 입력(쉼표(,)로 구분)
- 당첨 번호는 1~45 사이의 중복되지 않은 숫자
- 보너스 번호 1개를 추가로 입력
- 보너스 번호는 당첨 번호와 중복되지 않아야 함
3. 당첨 결과
- 구매한 각 로또의 당첨 개수 계산
- 당첨 기준에 따라 등수 판별
- 각 등수별 당첨 횟수 출력

## 예외 처리
- 구입 금액이 숫자가 아닐 경우 -> [ERROR] 구입 금액은 숫자여야 합니다.
- 구입 금액은 1,000원 단위가 아닐 경우 -> [ERROR] 구입 금액은 1,000원 단위여야 합니다
- 당첨 번호와 보너스 번호가 숫자가 아닐 경우 -> [ERROR] 로또 번호는 숫자여야 합니다.
- 당첨 번호의 구분자가 쉼표가 아닐 경우 -> [ERROR] 당첨 번호의 구분자는 쉼표(,)여야 합니다.
- 당첨 번호와 보너스 번호는 1 ~ 45의 값 사이가 아닐 경우 -> [ERROR] 로또 번호는 1~45 사이의 값이어야 합니다.
- 당첨 번호가 중복될 경우 -> [ERROR] 중복된 번호가 있습니다.
- 보너스 번호가 당첨 번호와 중복된 경우 -> [ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.

## 실행 예시
-----------------------------------------
구입금액을 입력해 주세요.
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%입니다.
-----------------------------------------

## 구현 목록
- [ ] 구입금액 입력
- [ ] 구입 금액에 맞는 로또 수량 및 번호 출력
- [ ] 당첨 번호와 보너스 번호 입력
- [ ] 당첨 통계 출력
- [ ] 예외처리

## 소감문
이번 3주차 프리코스를 수행하면서 피드백을 최대한 반영하려고 노력했지만, 아직 부족한 부분이 많다는 것을 느꼈다.
먼저 README 파일을 작성할 때는 이전보다 조금 더 상세히 작성하려 노력했지만, 기능 구현 목록 작성과 기능 설명 능력이 아직 부족하다고 생각했다.
그래서 앞으로는 다른 사람들의 README 예시를 참고하면서 표현력과 구조를 발전시켜 나갈 계획이다.
또한 기능 목록을 주기적으로 업데이트하면서 진행했어야 했는데, 마지막 소감문을 작성하며 그 부분을 놓쳤다는 것을 깨달아 아쉬움이 남았다.
반면, 하드 코딩을 피하기 위해 의미 있는 상수 선언을 사용한 점은 스스로 칭찬하고 싶다.
이러한 과정을 통해 코드의 가독성과 유지보수성이 얼마나 달라지는지를 체감할 수 있었다.
앞으로는 README 파일을 다시 리뷰하며 더 구조적이고 이해하기 쉬운 문서로 다듬고, 값을 직접 입력하는 하드 코딩 대신 상수나 변수를 활용해 더 좋은 코드로 발전해 나가고자 한다.
132 changes: 131 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,135 @@
import{Console,MissionUtils} from "@woowacourse/mission-utils";
import Lotto from "./Lotto.js";

class App {
async run() {}
async run() {
//5.예외처리
try{
const inputPrice = await this.getInputPrice();
//1.1 구입금액에 맞는 개수만큼 로또 수
const count = inputPrice/1000;
Console.print(`${count}개를 구매했습니다.`);

//2.구입 금액에 맞는 로또 수량 및 번호 출력
const lottos = this.lottoNum(count);
lottos.forEach((lotto) => Console.print(`[${lotto.join(", ")}]`));

//3.당첨 번호와 보너스 번호 입력
const prizeNum = await this.getPrizeNum();
const bonusNum = await this.getBonusNum(prizeNum);

//4.당첨 통계 출력
const prizeStats = this.printPrizeStats(lottos,prizeNum,bonusNum,inputPrice);
}catch(error){
Console.print(error.message);
}

}

async getInputPrice(){
//1.구입금액 입력받기
Console.print("구입금액을 입력해 주세요.");
const input = await Console.readLineAsync("");
if(isNaN(input)){
throw new Error("[ERROR] 구입 금액은 숫자여야 합니다.");
}
const inputNumber = Number(input);
if(inputNumber <= 0){
throw new Error("[ERROR] 구입 금액은 0원보다 커야 합니다.");
}
if(!(inputNumber % 1000 === 0)){
throw new Error("[ERROR] 구입 금액은 1,000원 단위여야 합니다.");
}
return inputNumber;
}

lottoNum(count){
//2.1 금액에 맞는 로또 갯수만큼 로또 생성 후 랜덤값 삽입
let lottoList = [];

Array.from({length:count}, () => {
const lotto = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6);
lotto.sort((a,b) => a - b);
lottoList.push(lotto);
})
return lottoList;
}

async getPrizeNum(){
//3.1 당첨 번호 입력받기
Console.print("당첨 번호를 입력해 주세요.");
const input = await Console.readLineAsync("");

if(!input.includes(",")){
throw new Error("[ERROR] 당첨 번호는 쉼표(,)로 구분된 숫자여야 합니다.");
}

const prizeNumbers = input.split(",").map(Number);
return prizeNumbers;
}

async getBonusNum(prizeNum){
//3.2 보너스 번호 입력받기
Console.print("보너스 번호를 입력해 주세요.");
const input = await Console.readLineAsync("");
const bonusNumber = Number(input);
if (isNaN(bonusNumber)) {
throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다.");
}
if (bonusNumber < 1 || bonusNumber > 45) {
throw new Error("[ERROR] 보너스 번호는 1부터 45 사이여야 합니다.");
}
if (prizeNum.includes(bonusNumber)) {
throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
return bonusNumber;
}

printPrizeStats(lottos,prizeNum,bonusNum,inputPrice){
const PRIZE_MONEY = {
1:2000000000,
2:30000000,
3:1500000,
4:50000,
5:5000
};
let result = {
1:0,
2:0,
3:0,
4:0,
5:0
};

lottos.forEach((lotto) => {
const matchCount = lotto.filter((num) => prizeNum.includes(num)).length;
const hasBonus = lotto.includes(bonusNum);

if(matchCount == 6) result[1]++;
else if(matchCount == 5 && hasBonus) result[2]++;
else if(matchCount == 5) result[3]++;
else if(matchCount == 4) result[4]++;
else if(matchCount == 3) result[5]++;
});

Console.print("당첨 통계\n---");
Console.print(`3개 일치 (5,000원) - ${result[5]}개`);
Console.print(`4개 일치 (50,000원) - ${result[4]}개`);
Console.print(`5개 일치 (1,500,000원) - ${result[3]}개`);
Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${result[2]}개`);
Console.print(`6개 일치 (2,000,000,000원) - ${result[1]}개`);

const totalPrize =
PRIZE_MONEY[1] * result[1] +
PRIZE_MONEY[2] * result[2] +
PRIZE_MONEY[3] * result[3] +
PRIZE_MONEY[4] * result[4] +
PRIZE_MONEY[5] * result[5];

const rate = (totalPrize / inputPrice * 100).toFixed(1);
Console.print(`총 수익률은 ${rate}%입니다.`);
return rate;
}
}

export default App;
21 changes: 20 additions & 1 deletion src/Lotto.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@ class Lotto {
}

#validate(numbers) {
if(!Array.isArray(numbers)){
throw new Error("[ERROR] 로또 번호는 배열 형태여야 합니다");
}
if (numbers.length !== 6) {
throw new Error("[ERROR] 로또 번호는 6개여야 합니다.");
}
numbers.forEach((num) => {
if (typeof num !== "number" || isNaN(num)) {
throw new Error("[ERROR] 로또 번호는 숫자여야 합니다.");
}
if (num < 1 || num > 45) {
throw new Error("[ERROR] 로또 번호는 1부터 45 사이여야 합니다.");
}
});

const uniqueNumbers = new Set(numbers);
if (uniqueNumbers.size !== 6) {
throw new Error("[ERROR] 중복된 번호가 있습니다.");
}
}

getNumbers() {
return this.#numbers;
}

// TODO: 추가 기능 구현
}

export default Lotto;