Ex) lotto 요구 사항
<hide/>
# 미션 - 로또
## 🔍 진행 방식
- 미션은 **기능 요구 사항, 프로그래밍 요구 사항, 과제 진행 요구 사항** 세 가지로 구성되어 있다.
- 세 개의 요구 사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다.
- 기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다.
## 📮 미션 제출 방법
- 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다.
- GitHub을 활용한 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고해
제출한다.
- GitHub에 미션을 제출한 후 [우아한테크코스 지원](https://apply.techcourse.co.kr) 사이트에 접속하여 프리코스 과제를 제출한다.
- 자세한 방법은 [제출 가이드](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse#제출-가이드) 참고
- **Pull Request만 보내고 지원 플랫폼에서 과제를 제출하지 않으면 최종 제출하지 않은 것으로 처리되니 주의한다.**
## 🚨 과제 제출 전 체크 리스트 - 0점 방지
- 기능 구현을 모두 정상적으로 했더라도 **요구 사항에 명시된 출력값 형식을 지키지 않을 경우 0점으로 처리**한다.
- 기능 구현을 완료한 뒤 아래 가이드에 따라 테스트를 실행했을 때 모든 테스트가 성공하는지 확인한다.
- **테스트가 실패할 경우 0점으로 처리**되므로, 반드시 확인 후 제출한다.
### 테스트 실행 가이드
- 터미널에서 `java -version`을 실행하여 Java 버전이 11인지 확인한다. 또는 Eclipse 또는 IntelliJ IDEA와 같은 IDE에서 Java 11로 실행되는지 확인한다.
- 터미널에서 Mac 또는 Linux 사용자의 경우 `./gradlew clean test` 명령을 실행하고,
Windows 사용자의 경우 `gradlew.bat clean test` 명령을 실행할 때 모든 테스트가 아래와 같이 통과하는지 확인한다.
```
BUILD SUCCESSFUL in 0s
```
---
## 🚀 기능 요구 사항
로또 게임 기능을 구현해야 한다. 로또 게임은 아래와 같은 규칙으로 진행된다.
```
- 로또 번호의 숫자 범위는 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]"로 시작하는 에러 메시지를 출력 후 종료한다.
### 입출력 요구 사항
#### 입력
- 로또 구입 금액을 입력 받는다. 구입 금액은 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%입니다.
```
---
## 🎯 프로그래밍 요구 사항
- JDK 11 버전에서 실행 가능해야 한다. **JDK 11에서 정상적으로 동작하지 않을 경우 0점 처리한다.**
- 프로그램 실행의 시작점은 `Application`의 `main()`이다.
- `build.gradle` 파일을 변경할 수 없고, 외부 라이브러리를 사용하지 않는다.
- [Java 코드 컨벤션](https://github.com/woowacourse/woowacourse-docs/tree/master/styleguide/java) 가이드를 준수하며 프로그래밍한다.
- 프로그램 종료 시 `System.exit()`를 호출하지 않는다.
- 프로그램 구현이 완료되면 `ApplicationTest`의 모든 테스트가 성공해야 한다. **테스트가 실패할 경우 0점 처리한다.**
- 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 이름을 수정하거나 이동하지 않는다.
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다.
- 3항 연산자를 쓰지 않는다.
- 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.
### 추가된 요구 사항
- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
- else 예약어를 쓰지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
- Java Enum을 적용한다.
- 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
- 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다.
- 단위 테스트 작성이 익숙하지 않다면 `test/java/lotto/LottoTest`를 참고하여 학습한 후 테스트를 구현한다.
### 라이브러리
- [`camp.nextstep.edu.missionutils`](https://github.com/woowacourse-projects/mission-utils)에서 제공하는 `Randoms` 및 `Console` API를 사용하여 구현해야 한다.
- Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickUniqueNumbersInRange()`를 활용한다.
- 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.
#### 사용 예시
```java
List<Integer> numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6);
```
### Lotto 클래스
- 제공된 `Lotto` 클래스를 활용해 구현해야 한다.
- `Lotto`에 매개 변수가 없는 생성자를 추가할 수 없다.
- `numbers`의 접근 제어자인 private을 변경할 수 없다.
- `Lotto`에 필드(인스턴스 변수)를 추가할 수 없다.
- `Lotto`의 패키지 변경은 가능하다.
```java
public class Lotto {
private final List<Integer> numbers;
public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers;
}
private void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
throw new IllegalArgumentException();
}
}
// TODO: 추가 기능 구현
}
```
---
## ✏️ 과제 진행 요구 사항
- 미션은 [java-lotto](https://github.com/woowacourse-precourse/java-lotto) 저장소를 Fork & Clone해 시작한다.
- **기능을 구현하기 전 `docs/README.md`에 구현할 기능 목록을 정리**해 추가한다.
- **Git의 커밋 단위는 앞 단계에서 `docs/README.md`에 정리한 기능 목록 단위**로 추가한다.
- [커밋 메시지 컨벤션](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 가이드를 참고해 커밋 메시지를 작성한다.
- 과제 진행 및 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고한다.
- 요구사항
- 위와 같이 요구사항이 너무 많다.
- 메서드 15라인 이하, 들여쓰기 3미만.. 과 같은 간단한 조건도 하나하나 맞추다보니까 시간이 좀 걸렸다.
- 나는 일단 메서드를 모두 만든 다음에 다시 위 조건을 맞추기 위해 메서드를 쪼개고 쪼개고 또 쪼갰다.
- 처음에는 Map, Queue를 이용해서 enum클래스를 사용하지 않았지만 뒤늦게 조건을 맞추기 위해 enum 클래스르 만들었다.
- else에 대한 금지 조건도 있는데 이는 continue 또는 return 같은 예약어를 쓰면 else를 굳이 안 써도 되기 때문에 주어진 것으로 보인다.
- 외부 라이브러리는 금지 되기 때문에 처음에 Lombok 라이브러리를 적용했다가 모두 지우고 getter와 생성자를 구현했다.
- README
<hide/>
# 구현할 기능 목록
1. 로또 구입 금액을 Long으로 입력 받는다.
- 1000의 배수가 아니면 IllegalArgumentException 으로 예외 처리한다.
2. 로또 구입 금액으로 몇 장의 로또를 구입할 수 있는지 개수를 출력한다.
- 구매한 로또 개수에 따라 로또 번호를 랜덤으로 생성한다.
- 각 로또에 대해 유효성을 확인한 다음 로또 구성을 출력한다.
3. 6개의 당첨 번호와 보너스 번호를 입력 받는다.
- split()을 이용해서 콤마를 기준으로 구분해서 int[] 배열에 당첨 번호를 저장한다.
- 1 ~ 45 사이의 숫자가 아닌 경우, IllegalArgumentException 으로 예외 처리한다.
4. 발행한 로또 수량과 로또 번호를 random으로 뽑고 오름차순으로 정렬해서 보여준다.
5. 각 로또마다 사용자의 로또 번호와 당첨 번호를 비교해서 당첨 내역과 수익률을 구한다.
- Enum 클래스
<hide/>
package lotto;
public enum LottoRank {
ZERO("0", 0, 0),
THREE("3개 일치 (5,000원)", 5000, 0),
FOUR("4개 일치 (50,000원)", 50000, 0),
FIVE("5개 일치 (1,500,000원)", 1500000, 0),
FIVE_WITH_BONUS("5개 일치, 보너스 볼 일치 (30,000,000원)", 30000000, 0),
SIX("6개 일치 (2,000,000,000원)", 2000000000, 0);
private final String message;
private final double reward;
private int cnt;
LottoRank(String message, double reward, int cnt) {
this.message = message;
this.reward = reward;
this.cnt = cnt;
}
public String getMessage() {
return message;
}
public int getCnt() {
return cnt;
}
public double getReward() {
return reward;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
}
- 맞춘 개수를 cnt로 파악할 수 있도록 enum클래스를 만든다.
- 로또당첨 번호와 내 번호를 대조해서 각 THREE, FOUR, FIVE, FIVE_WITH_BONUS, SIX에 대해 카운트가 가능하다.
- 요구 사항 대로 enum클래스에 멤버 변수로 메시지, cnt 같은 여러 개의 속성을 넣으니까 메시지를 읽어오거나 cnt값을 세팅해주기에 편리했다.
- Lotto
<hide/>
package lotto;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Lotto {
private final List<Integer> numbers;
public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers;
}
/* 예외처리
사이즈 6인지 확인
1 ~ 45 확인
중복 확인
*/
private static void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 6개로 구성되어야 합니다.");
}
Map<Integer, Integer> map = new HashMap<>();
for (int n : numbers) {
map.put(n, map.getOrDefault(n, 0) + 1);
if (map.get(n) > 1) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다.");
}
if (n < 1 || n > 45) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.");
}
}
}
public static boolean contains(Lotto lotto, int n) {
for (int l : lotto.numbers) {
if (l == n) {
return true;
}
}
return false;
}
public static void printLotto(Lotto lotto) {
System.out.println(lotto.numbers.toString());
}
public static void sortLotto(Lotto lotto) {
for (int i = 0; i < lotto.numbers.size(); ++i) {
for (int j = i + 1; j < lotto.numbers.size(); ++j) {
if (lotto.numbers.get(i) > lotto.numbers.get(j)) {
int tmpI = lotto.numbers.get(i);
int tmpJ = lotto.numbers.get(j);
lotto.numbers.remove(i);
lotto.numbers.add(i, tmpJ);
lotto.numbers.remove(j);
lotto.numbers.add(j, tmpI);
}
}
}
}
}
- 정렬 메서드를 새로 만들었다.
- Lotto의 numbers는 List를 통해 만들지만 List와는 조금 다르기 때문에 Collections.sort()를 이용하면 에러가 났기 때문이다.
- 선택 정렬을 이용해서 구현했다.
- List에서 자주 쓰이는 contains()도 구현했다.
- Lotto를 toString()으로 출력하면 제대로 안 나오길래 출력 메서드도 만들었다.
- validate() 는 기존에 우테코에서 제시된 메서드에 내용만 추가한 형태이다.
- Application
<hide/>
package lotto;
import static lotto.Lotto.printLotto;
import camp.nextstep.edu.missionutils.Console;
import camp.nextstep.edu.missionutils.Randoms;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
public class Application {
static double income = 0;
static String ERROR_MESSAGE = "[ERROR] 구입금액은 숫자만 입력 가능합니다.";
public static int enterPurchaseAmount() {
System.out.println("구입금액을 입력해 주세요.");
String strAmount = Console.readLine();
for (int i = 0; i < strAmount.length(); ++i) {
if (!Character.isDigit(strAmount.charAt(i))) {
System.out.println(ERROR_MESSAGE);
// throw new IllegalArgumentException(ERROR_MESSAGE);
throw new NoSuchElementException(ERROR_MESSAGE);
}
}
int amount = Integer.parseInt(strAmount);
if (amount % 1000 != 0) {
throw new IllegalArgumentException("[ERROR] 1000의 배수만 입력 가능합니다.");
}
return amount;
}
public static int printNumberOfTickets(int amount) {
int cnt = amount / 1000;
System.out.println(cnt + "개를 구매했습니다.");
return cnt;
}
public static boolean isValidateNum(String s) {
for (char c : s.toCharArray()) {
if (!Character.isDigit(c)) {
throw new IllegalArgumentException();
}
}
return true;
}
public static int[] enterWinningNumber() {
System.out.println("당첨 번호를 입력해 주세요.");
String strWinningNums = Console.readLine();
String[] tmpArr = strWinningNums.split(",");
int[] winningNums = new int[tmpArr.length];
for (int i = 0; i < tmpArr.length; ++i) {
isValidateNum(tmpArr[i]);
winningNums[i] = Integer.parseInt(tmpArr[i]);
}
validateLotto(winningNums);
return winningNums;
}
public static boolean validateLotto(int[] winningNums) {
List<Integer> list = new ArrayList<>();
for (int winningNum : winningNums) {
list.add(winningNum);
}
Lotto lotto = new Lotto(list);
return true;
}
public static int enterBonusNum() {
System.out.println("보너스 번호를 입력해 주세요.");
String tmp = Console.readLine();
for (char c : tmp.toCharArray()) {
if (!Character.isDigit(c)) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 숫자만 입력 가능합니다.");
}
}
int bonusNum = Integer.parseInt(tmp);
List<Integer> winningNumsList = new ArrayList<>();
if (winningNumsList.contains(bonusNum) || bonusNum < 1 || 45 < bonusNum) {
throw new IllegalArgumentException(
"[ERROR] 보너스 번호는 1 부터 45 사이의 숫자이며 당첨 번호와 중복될 수 없습니다.");
}
return bonusNum;
}
public static int validateBonusNum(int[] winningNums) {
List<Integer> winningNumsList = new ArrayList<>();
for (int winningNum : winningNums) {
winningNumsList.add(winningNum);
}
int bonusNum = enterBonusNum();
return bonusNum;
}
public static Lotto generateLotto() {
List<Integer> lottoList = new ArrayList<>();
lottoList = Randoms.pickUniqueNumbersInRange(1, 45, 6); // 1, 45 포함
Lotto lotto = new Lotto(lottoList); // 생성한 로또에 대해 유효성 검사
Lotto.sortLotto(lotto);
return lotto;
}
public static List<Lotto> generateAllLotto(int numberOfTickets) {
List<Lotto> allLottoList = new ArrayList<>();
for (int i = 0; i < numberOfTickets; ++i) {
Lotto lotto = generateLotto(); // 로또 랜덤으로 생성
allLottoList.add(lotto);
printLotto(lotto);
}
return allLottoList;
}
public static void getIncomeOfLotto(Lotto lotto, int bonusNum, int cnt) {
if (cnt == 6) {
income += 2000000000;
LottoRank.SIX.setCnt(LottoRank.SIX.getCnt() + 1);
} else if (cnt == 5 && Lotto.contains(lotto, bonusNum)) {
income += 30000000;
LottoRank.FIVE_WITH_BONUS.setCnt(LottoRank.FIVE_WITH_BONUS.getCnt() + 1);
} else if (cnt == 5) {
income += 1500000;
} else if (cnt == 4) {
income += 50000;
LottoRank.FOUR.setCnt(LottoRank.FOUR.getCnt() + 1);
} else if (cnt == 3) {
income += 5000;
LottoRank.THREE.setCnt(LottoRank.THREE.getCnt() + 1);
}
}
public static int contLottoNum(Lotto lotto, int[] winningNums) {
int cnt = 0;
for (int winningNum : winningNums) {
if (Lotto.contains(lotto, winningNum)) {
++cnt;
}
}
return cnt;
}
public static double getTotalIncome(List<Lotto> allLotto, int[] winningNums, int bonusNum) {
for (Lotto lotto : allLotto) {
int cnt = contLottoNum(lotto, winningNums);
getIncomeOfLotto(lotto, bonusNum, cnt);
}
return income;
}
public static void printResult(double rateOfReturn) {
System.out.println("당첨 통계");
System.out.println("---");
System.out.println(LottoRank.THREE.getMessage() + " - " + LottoRank.THREE.getCnt() + "개");
System.out.println(LottoRank.FOUR.getMessage() + " - " + LottoRank.FOUR.getCnt() + "개");
System.out.println(LottoRank.FIVE.getMessage() + " - " + LottoRank.FIVE.getCnt() + "개");
System.out.println(
LottoRank.FIVE_WITH_BONUS.getMessage() + " - " + LottoRank.FIVE_WITH_BONUS.getCnt()
+ "개");
System.out.println(LottoRank.SIX.getMessage() + " - " + LottoRank.SIX.getCnt() + "개");
System.out.print("총 수익률은 ");
System.out.printf("%.1f", rateOfReturn);
System.out.println("%입니다.");
}
public static void main(String[] args) {
// TODO: 프로그램 구현
int amount = enterPurchaseAmount();
int numberOfTickets = printNumberOfTickets(amount);
List<Lotto> allLotto = generateAllLotto(numberOfTickets);
int[] winningNums = enterWinningNumber();
int bonusNum = validateBonusNum(winningNums);
double income = getTotalIncome(allLotto, winningNums, bonusNum);
printResult((double) (income / amount * 100));
}
}
- 제시된 요구 사항을 충족시키기 위해 공을 많이 들였다.
- 가장 곤혼스러웠던 점은 문제의 요구 사항에서는 IllegalArgumentException 을 터뜨리라고 했으나 그렇게 실행하면 test 코드를 통과하지 않았다.
- 그래서 디버깅을 해보니까 NoSuchElementException을 throw 해주니까 해결됐다.
- 꼼수로 테스트 코드를 통과했지만 어떻게 하는 게 올바른 방법인지 아직도 모르겠다.
- 문제를 잘못 출제하셨나? 하는 생각까지 들었다.
- 수익률 구하는 메서드 getIncome()에다가 cnt구하는 로직까지 한번에 몰아서 로직을 구현했는데 라인이 50줄이 넘었다.
- 이 부분 메서드를 쪼개고 또 쪼개는데 고생을 좀 했다.
- 그리고 원래는 모든 Lotto에 대해서 수익과 cnt를 구할 수 있도록 이중 for문 안에 if 문까지 넣으니까 들여쓰기 조건을 충족하지 못했다.
- 이 방법이 효율적이라고 생각해서 구현한건데 들여쓰기 조건을 맞추기 위해서 메서드를 또 분리시켰다.
- 아마 완전탐색에 가깝고 효율성이 떨어지니까 못 쓰도록 하지 않았나 싶다.
- 앞으로는 메서드를 어떻게 분리할지 생각을 한 다음에 구현하는 습관을 들여야겠다.
- 메서드 명을 급하게 지은거라서 잘 지은 것 같지는 않다.
- 사용자한테 값을 입력 받거나 Random으로 값을 추출하는 것을 배민에서 제공하는 라이브러리의 안에 있는 메서드를 이용해야한다.
- 이 부분에 대한 조건은 왜 있는 건지 아직 파악하지 못했다.
느낀 점
- 이제 프리코스가 한 주 남았다. 통과해서 꼭 코테를 경험이라고 하고 싶다..!
- 여행 일정이 있어서 12/17 코테를 본다면 일정이 변경될 수 있지만 그래도 시험은 보고 싶다.
- 이전까지의 과제 중에 주어진 테스트를 통과하기가 너무 어려웠다.
- 이번 주 팀프로젝트가 마무리되고 나면 제로베이스 동기 수강들 10 명과 알고리즘 스터디를 빡시게 해야겠다.
'Boot Camp > [우테코] 프리코스' 카테고리의 다른 글
[4주차] bridge 미션 (0) | 2022.11.20 |
---|---|
[2주차] baseball game 미션 (0) | 2022.11.09 |
[1주차] on-boarding 미션 (0) | 2022.11.01 |