2주차의 주제는 숫자 야구 게임을 구현하는 것이다. 1주차와 마찬가지로 기능 요구 사항
, 프로그래밍 요구 사항
, 과제 진행 요구 사항
을 지켜서 문제를 풀면 된다. 하지만 2주차 문제는 1주차와는 다른 점이 여러 개 있었다.
기존에는 들여쓰기에 제한이 없었지만 이번 주차부터는 3을 넘기지 않도록 제한 사항이 생겼다. 들여쓰기를 2까지만 허용하는 것이다. 한마디로 while 문 안에 if문 하나가 있다면 이것의 indent depth
가 2인 것이다.
추가된 요구사항으로 하나의 함수에는 최소한의 일만 할 수 있도록 설계해야 한다고 적혀있다. 클래스화를 하던 함수를 하던 최소한의 역할을 할 수 있도록 함수를 잘 쪼갤 예정이다. 여기서 변수나 함수명 또한 직관적으로 이해가 잘가게끔 코드 컨벤션에 의해 작성할 예정이다.
정말 많이 당황했던 것이 바로 이 Jest
활용이었다. 실제로 2일 정도를 Jest 이해하는데 쓰였을 정도였다. Jest는 짧게 말해서 코드의 테스트케이스를 내가 직접 구현하는 것이다. 기존 프로그래머스나 우테코 1주차 온보딩 미션에서는 모든 테스트케이스가 주어져 있었지만 이를 실제로 내가 직접 구현해야 한다. 예시 코드가 몇개 쓰여져있었지만 어떻게 이것을 실제 코드로 활용할 것인지에 대한 이해도가 전혀 없었기 때문에 시간이 오래 소요되긴 하였다.
MissionUtils
라이브러리에서 제공하는 Random 및 Console API를 사용하여 구현해야 한다. 하지만 사용법이 아래 링크에 자세하게 나오기 때문에 사용하는 데 있어서 큰 무리는 없었다.
MissionUtils 활용하기
코드를 짤 때 클래스를 이용하거나 함수를 이용한 적이 프로젝트를 할 때 말고는 없었다. 코딩테스트나 과제테스트 문제를 풀어볼 때 하나의 함수 안에 모든 기능을 집어넣는, 한마디로 가독성 없는 복잡한 코드를 주로 작성하였다. 그게 문제인 것을 알았더라도 '일단은 작동이 되게끔 하고 수정하는 방향으로 하자'라는 마인드가 머리 속에 지배적이었던 것 같다. 이번 2주차 과제 미션도 그렇고 더 나은 코드를 쓰는 개발자가 되기 위해서는 함수를 최대한 많이 활용하고 싶었다. 그래서 로직
을 짜는데 더 많은 시간할당을 하였다.
크게 프로그램 기능 흐름
, 기능 목록
, 구현 방향성
에 대해 작성하였다.
스트라이크
, 볼
, 낫싱
으로 이루어진 힌트를 제공하고 게임을 계속 진행한다."3개의 숫자를 모두 맞히셨습니다! 게임 종료"
를 출력하고 게임을 종료한다."게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."
를 출력하고 사용자의 입력에 맞게 재시작 여부를 결정한다.컴퓨터가 랜덤한 수를 생성하는 기능
빈 배열을 선언
MissionUtils.Random.pickNumberInRange(1,9)
를 통해 랜덤한 숫자 생성
생성한 숫자가 배열에 존재하면 다시 생성하고, 존재하지 않으면 배열에 넣기
배열의 길이가 3이라면 join
메서드를 사용하여 문자열 형태로 변환
사용자에게 숫자를 입력받는 기능
MissionUtils.Console.readLine
을 통해 숫자를 입력하여 게임 실행handleInputDuringGame
메서드getHint
를 통해 반환된 hint가 3스트라이크
와 일치하는지 판별recommendRestart
메서드 호출getUserInput
메서드 호출handleInputAfterGame
메서드restartGame
메서드 호출MissionUtils.Console.close
호출하여 게임 종료getIsInputValueValid
모듈 추가getHint
모듈 추가convertToHintString
함수의 인자로 전달한다.convertStringToArray
함수 추가countStrike
함수 추가convertStringToArray
함수를 사용하여 배열로 변환한다.countBall
함수 추가convertCountToHintString
함수 추가${ballCount}볼
을 힌트 문자열에 추가한다.${strikeCount}스트라이크
를 힌트 문자열에 추가한다.낫싱
을 힌트 문자열에 추가한다.MissionUtils.Console.readLine
을 통해 사용자의 입력값을 받아온다.handleInputDuringGame
에 전달한다.Computer
의 correctNumber
를 getHint
의 인자로 전달해 반환 값을 hint
에 대입한다.hint
를 출력한다.hint
와 3스트라이크
가 불일치하면 getUserInput()
함수 다시 호출recommendRestart
메서드 추가3개의 숫자를 모두 맞히셨습니다! 게임 종료
문구를 출력한다.MissionUtils.Console.readLine
을 통해 사용자에게 값을 입력받는다.restartGame()
호출MissionUtils.Console.close()
를 호출해 게임 종료Computer
클래스의 setNewCorrectNumber
메서드 호출하여 랜덤 숫자 교체Jest에 관한 내용을 구글에서 찾게 된다면 상당히 다양한 문법이 있다. 하지만 여기서 기억해야 하는 명령어는 describe
, test
, expect
, toEqual
정도이다.
아래의 예시 코드를 통해 Jest가 어떻게 동작하는지 간단하게 확인해보자.
const { getHint } = require("../src/Hint");
describe("힌트 산출 테스트", () => {
test('볼과 스트라이크가 함께 있을 때는 "~볼 ~스트라이크"가 출력된다.', () => {
const correctNumber = ["123", "456", "789", "159", "753"];
const inputNumber = ["321", "461", "981", "519", "715"];
const answer = [
"2볼 1스트라이크",
"1볼 1스트라이크",
"1볼 1스트라이크",
"2볼 1스트라이크",
"1볼 1스트라이크",
];
for (let i = 0; i < 5; i++) {
expect(getHint(correctNumber[i], inputNumber[i])).toEqual(answer[i]);
}
});
test('블, 스트라이크 모두 없을 때는 "낫싱"이 출력된다', () => {
const correctNumber = ["123", "456", "789", "159", "753"];
const inputNumber = ["456", "789", "123", "743", "149"];
const answer = "낫싱";
for (let i = 0; i < 5; i++) {
expect(getHint(correctNumber[i], inputNumber[i])).toEqual(answer);
}
});
});
우선 getHint라는 함수를 받아와서 import 해준다. 그리고 describe
로 여러 개의 test
를 하나로 묶는다. 위 예제 코드에서는 두개의 test 코드를 하나로 묶었다. describe와 test 마찬가지로 첫번째 인자로는 해당 test의 설명과 두번째 인자로는 실제 실행되는 함수가 들어간다.
그리고 expect
에는 입력되는 값이 그리고 뒤에 toEqual
에는 기대값이 들어간다. 배열이나 객체일 때는 toEqual
을 사용하지만 원시값인 경우에는 보통 toBe
를 사용한다.