그동안 공부를 하면서 간결하고 쉬운 설명으로 많은 도움을 받았던
테코톡을 진행하는 우테코의 프리코스에 참여하게 되었습니다.
과제 안내 사항
1주 차 미션은 야구 숫자 게임입니다.
과제 repository를 fork 하여 진행합니다.
리드미에 과제 안내 사항에 대해서 자세하게 적혀있습니다.
이 부분을 자세히 읽지 않으면 과제 진행이 어렵습니다.
실제로 코수타 라이브에서 크루들이 말하길 과제 문의를 정말 많이 받았는데
모두 리드미를 충분히 숙지하지 않았던 문제였다고 하네요!
대략적인 안내사항은 다음과 같습니다.
기능 요구 사항
- 랜덤 숫자 3개
- 사용자 입력 숫자 3개
- 위 두 가지 숫자를 비교해서 스트라이크, 볼, 낫싱 문구 출력하고 맞출 때까지 반복
- 3 스트라이크 일 때 1 입력 시 게임 다시 시작 2 입력 시 게임 종료
- 사용자가 잘못된 값 입력시 throw 문으로 예외 발생 시키고 게임 종료
프로그래밍 요구 사항
- Node.js 18.17.1 버전에서 실행 가능해야 함
- 프로그램 실행의 시작점은 App.js의 play 매서드
- package.json 변경금지
- 라이브러리 사용금지
- JavaScript 코드 컨벤션 지키기
- 테스트 통과하기
- @wooacourse/mission-utils에서 제공하는 API 사용하기
과제 진행 요구 사항
- 기능 구현 전 docs/README.md 에 구현할 기능 목록을 정리
- 과제 제출 문서에 따라 과제 진행, 제출
작성한 기능 목록
🔍 구현 기능 목록
1. 게임 시작 시 숫자 야구 게임을 시작합니다. 문구 출력
2. 1에서 9까지 서로 다른 임의의 수 3개 자동 선택
3. 1에서 9까지 서로 다른 임의의 수 3개 수동 선택
- 숫자를 입력해 주세요: ${입력값} 문구 출력
- 잘못된 값 입력 시 [ERROR] 숫자가 잘못된 형식입니다. 문구 출력 후 어플리케이션 종료
4. 1과 2의 일치 정도에 따라 결과 문구 출력
- 같은 순서, 같은 숫자 => 스트라이크
- 다른 순서, 같은 숫자 => 볼
- 스트라이크와 볼은 일치 개수가 문자열 앞에 붙는다. ex) 1볼 1스트라이크
- 순서, 숫자 모두 다를 시 => 낫싱
- 1과 2가 같을 시 => 3개의 숫자를 모두 맞히셨습니다! 게임 종료
5. 게임 종료 상태에서 게임 다시 시작과 종료 가능
- 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요. 문구 출력
- 1 입력 시 게임 새로 시작 2 입력 시 게임 종료
폴더 구조
📦src
┣ 📂game
┃ ┣ 📜compareNumbers.js
┃ ┗ 📜playGame.js
┗ 📜App.js
기능을 분리해서 코드를 작성하고 싶어 파일을 따로 작성해 주었는데
기능 구현에 집중하다가 파일 분리를 더 세분화하지 못했습니다 ㅜ^ㅜ
기능 구현
사실 리드미를 읽기 전 파일을 열어보고 많이 당황했습니다.
프론트엔드 과제이니 당연히 화면을 구현하는 줄 알았지만
class 함수를 사용해 node.js에서 실행되는 게임을 만드는 것이었습니다.
class App {
async play() {
}
}
src 폴더의 App.js 에는 이렇게 코드가 작성되어 있었습니다.
1. 게임 시작 시 숫자 야구 게임을 시작합니다. 문구 출력
class App {
async play() {
MissionUtils.Console.print("숫자 야구 게임을 시작합니다.");
}
}
console.log 대신 안내된 Console.print API를 사용하여 시작 문구를 출력합니다.
게임 최초 실행 시 한 번만 출력되고 랜덤숫자를 받게 됩니다.
initialStartGame를 실행하여 컴퓨터의 숫자를 받고 에러발생 시 예외를 던집니다.
2. 1에서 9까지 서로 다른 임의의 수 3개 자동 선택
const getComputerNumber = () => {
let computerNumbers = "";
while (computerNumbers.length < 3) {
const number = MissionUtils.Random.pickNumberInRange(1, 9);
if (!computerNumbers.includes(number)) {
computerNumbers += number;
}
}
return computerNumbers;
};
제공하는 API를 사용하여 서로 겹치지 않는 랜덤 숫자 3개를 만들어주었습니다.
처음엔 배열로 만들었다가 원시값을 사용하면 값의 일치여부를 쉽게 알 수 있기에
바로 return을 해주기 위해 문자열로 변경하였습니다.
3. 1에서 9까지 서로 다른 임의의 수 3개 수동 선택
- 숫자를 입력해 주세요: ${입력값} 문구 출력
- 잘못된 값 입력 시 [ERROR] 숫자가 잘못된 형식입니다. 문구 출력 후 어플리케이션 종료
const getPlayerNumbers = async () => {
try {
const answer = await MissionUtils.Console.readLineAsync(
"숫자를 입력해주세요: "
);
if (answer.length !== 3) {
throw new Error("[ERROR]");
} else {
return answer;
}
} catch (error) {
throw error;
}
};
readLineAsync는 출력할 문자를 인자로 받고 사용자의 입력을 리턴하는 비동기 함수입니다.
readLineAsync API의 결괏값을 answer에 할당해 줍니다.
입력받은 숫자가 3개가 아니라면 에러를 던져 catch로 예외처리를 해주고
3개라면 answer를 리턴합니다.
여기서 유효성 검사 부분을 함수로 분리하고 입력한 값이 숫자가 맞는지 검사를 못한 것이 아쉬운 부분입니다. 🥹
4. 1과 2의 일치 정도에 따라 결과 문구 출력
- 같은 순서, 같은 숫자 => 스트라이크
- 다른 순서, 같은 숫자 => 볼
- 스트라이크와 볼은 일치 개수가 문자열 앞에 붙는다. ex) 1볼 1스트라이크
- 순서, 숫자 모두 다를 시 => 낫싱
- 1과 2가 같을 시 => 3개의 숫자를 모두 맞히셨습니다! 게임 종료
const startGame = async (computerNumbers) => {
const playerNumbers = await getPlayerNumbers();
if (computerNumbers === playerNumbers) {
MissionUtils.Console.print(
"3스트라이크 \n3개의 숫자를 모두 맞히셨습니다! 게임 종료"
);
return await askGameAgain();
}
const result = compareNumbers(computerNumbers, playerNumbers);
MissionUtils.Console.print(result);
await startGame(computerNumbers);
};
컴퓨터 숫자와 사용자가 입력한 숫자가 같으면
결괏값인 '3스트라이크' 와 '3개의 숫자를 모두 맞히였습니다! 게임 종료' 문구를 출력합니다.
\n은 node.js에서 줄 바꿈 역할을 합니다.
게임을 계속 진행할 것인지 묻는 askGameAgain 함수를 호출하고 종료합니다.
같지 않다면 compareNumbers 함수에
컴퓨터 숫자와 사용자 입력을 인자로 전달하여 결괏값을 화면에 출력하고
startGame을 다시 호출하여 게임을 이어갑니다.
const compareNumbers = (computerNumbers, playerNumbers) => {
let strike = 0;
let ball = 0;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (computerNumbers[i] === playerNumbers[j]) {
if (i === j) {
strike++;
} else {
ball++;
}
}
}
}
const compareResult = printResult(strike, ball);
return compareResult;
};
const printResult = (strike, ball) => {
if (ball === 0 && strike === 0) {
return "낫싱";
}
if (ball === 0) {
return `${strike}스트라이크`;
}
if (strike === 0) {
return `${ball}볼`;
}
return `${ball}볼 ${strike}스트라이크`;
};
5. 게임 종료 상태에서 게임 다시 시작과 종료 가능
- 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요. 문구 출력
- 1 입력 시 게임 새로 시작 2 입력 시 게임 종료
const askGameAgain = async () => {
try {
const answer = await MissionUtils.Console.readLineAsync(
"게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"
);
if (answer === "1") {
return await initialStartGame();
}
if (answer === "2") {
MissionUtils.Console.print("게임종료");
}
} catch {
throw new Error();
}
};
const initialStartGame = async () => {
const computerNumbers = getComputerNumber();
await startGame(computerNumbers);
};
사용자의 입력을 받는 API인 readLineAync으로 사용자의 응답을 받습니다.
응답이 1이라면 컴퓨터 숫자를 새로 받아 게임을 실행하는 initialStartGame 함수를 실행합니다.
응답이 2라면 '게임종료' 문구를 Console.print로 출력하고 종료됩니다.
보완하고 싶은 부분
사용자 입력값 예외 처리
const getPlayerNumbers = async () => {
try {
const answer = await MissionUtils.Console.readLineAsync(
"숫자를 입력해주세요: "
);
// if (answer.length !== 3) {
// throw new Error("[ERROR]");
// } else {
// return answer;
// }
if (isValidNumbers(answer)) {
return answer;
}
throw new Error("[ERROR]");
} catch (error) {
throw error;
}
};
const isValidNumbers = (answer) => {
const checkIsNumber = /^[1-9]+$/;
const length = answer.length;
const charSet = newSet(answer);
if (charSet.size !== answer.length) {
return false;
}
if (length !== 3) {
return false;
}
for (let i = 0; i < length; i++) {
if (!checkIsNumber.test(answer[i])) {
return false;
}
}
return true;
};
사용자 입력값의 유효성을 검사하는 함수 isValidNumbers를 만들어서
if else문을 걷어내고 true일시 바로 입력값을 return 하고
아니라면 에러문구를 던져주었습니다.
isValidNumbers에서는
1. 길이가 3이 아닐 시
2. 입력값이 1-9 사이의 숫자인지 확인하는 정규식을 사용하여 false일시
3. Set 생성자 함수를 사용하여 중복된 숫자를 제거하고 길이를 비교하여 원본 입력값이랑 같지 않을지
return false를 해주었습니다.
이 외에도 문구 상수 화하여 오타 등의 실수를 줄이고
class 함수를 사용해서 메서드 생성을 해보고 문법에 익숙해지고
.. 싶었으나 이번 과제에 시간을 많이 쓰지 못해서
다음과제에서 적용해보도록 해보겠습니다.
소감
과제 제출할 때도 소감을 작성해서 제출을 하게 되어있습니다.
이번에 과제를 진행하면서 해결되지 않는 문제에 새벽 4시까지 붙잡아보았는데요..
원인은 async await 키워드에 있었습니다.
게임을 실행할 때 return 값이 Promise 객체인데
async await키워드를 써주지 않아서 테스트 통과가 되질 않았었습니다.......
테스트 함수가 잘못된 게 아닌지까지 의심했지만.....
네 결국 제 잘못이었습니다^^
거의 하루종일 문제 몰입을 하고 해결해내지 못해 절망하다
다음날이 되어서야 깨닫고 와 나 이것도 모르나.. 했지만
해결했다는 뿌듯함이 더 컸습니다!
우테코 6기 디스코드에는 많은 분들이 모여 지식을 공유하고 있습니다.
오늘은 서로의 코드 리뷰가 가능한 날이라 많은 분들이 게시글을 올려주시고 있습니다.
저도 오늘 코드리뷰를 하기도 하고 받기도 했는데 정말 도움이 많이 되고 재밌었습니다.
또한 디스코드에서 객체지향, 테스트 코드, MVC 패턴 등 저에게는 아직 친숙하지 않은 주제에 대해
열심히 토론을 하시고 계신데 정말 많은 동기부여가 되고 있습니다.
코딩테스트로 일부에게만 프리코스 자격이 주었던 과거와 달리
모두에게 경험의 기회를 주어져서 너무 감사할 따름입니다.
2주 차 과제가 주어지며 공통 피드백을 받았습니다.
코드 컨벤션에 관한 피드백이 대부분이었고
추가 학습 자료에는 모두 git 사용법이었습니다.
제공해 주신 피드백을 토대로 2주 차 과제에서는 성장한 코드로 회고를 남기고 싶네요!
'우테코 프리코스' 카테고리의 다른 글
[우테코 프리코스] 6기 종료 회고 (with 코드리뷰 스터디) (1) | 2023.12.12 |
---|---|
[우테코 프리코스] 4주 차 회고 (7) | 2023.11.28 |
[우테코 프리코스] 3주 차 회고 (1) | 2023.11.23 |
[우테코 프리코스] 2주 차 회고 (3) | 2023.11.03 |