자바 플레이그라운드 미션1-2 숫자야구게임 구현(beforeFeedback)

이호석·2022년 5월 25일
0

넥스트 스텝의 자바 플레이그라운드

  • 자바 코드 컨벤션을 지키면서 프로그래밍한다.
    • 기본적으로 Google Java Style Guide을 원칙으로 한다.
    • 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
  • indent(인덴트, 들여쓰기) depth를 2가 넘지 않도록 구현한다. 1까지만 허용한다.
    • 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
    • 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
  • else 예약어를 쓰지 않는다.
    • 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
    • else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
  • 모든 로직에 단위 테스트를 구현한다. 단, UI(System.out, System.in) 로직은 제외
    • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
    • UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.
  • 3항 연산자를 쓰지 않는다.
  • 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.

손풀기인 문자열 계산기보다 더 쉽게 구현했다.
물론 막혔던 곳도 있는데 스트라이크와 볼을 판별하는 함수인 judgeStrike, judgeBall부분이다. 이 부분에서 결국 코드 규칙을 어기고 indent(인덴트, 들여쓰기) depth를 2까지 구현했다. 물론 정해진 규칙대로 구현은 가능하지만, 가독성이 떨어지고 직관적이지 않다고 생각해서 규칙을 어겼다. 이 부분은 피드백을 본 이후에 고칠 예정이다.
그리고 단위테스트는 구현을 했지만 전체(?)테스트 코드를 작성하지 못 했는데, 무작위성을 띄는 코드는 어떤식으로 테스트하는지도 알아볼 예정이다.

NumberBaseball.java

public class NumberBaseball {
    private static final int baseballCount = 3;

    public static void main(String[] args) {
        NumberBaseball nb = new NumberBaseball();
        nb.execute();
    }

    public void execute() {
        System.out.println("숫자야구게임에 오신것을 환영합니다.");
        boolean play = true;
        while (play) {
            play = playGame();
        }
    }

    public boolean playGame() {
        int[] randomNumberArr = makeRandomNumberArray();
        boolean threeStrike = false;
        int[] inputNumberArr;
        while (!threeStrike) {
            printInputMessage();
            inputNumberArr = intToArray(scanNumber());
            threeStrike = isGameOver(judgeResult(randomNumberArr, inputNumberArr));
        }
        System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
        System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");

        Scanner sc = new Scanner(System.in);
        String playAgain = sc.nextLine();
        while (!playAgain.equals("1") && !playAgain.equals("2")){
            System.out.println("다시 입력해주세요");
            playAgain = sc.nextLine();
        }
        return playAgain.equals("1");
    }

    public boolean isGameOver(String message) {
        System.out.println(message);
        return message.equals("3S");
    }

    public String judgeResult(int[] randomArr, int[] inputNumberArr) {
        int strikeCount = judgeStrike(randomArr, inputNumberArr);
        int ballCount = judgeBall(randomArr, inputNumberArr);

        if (ballCount != 0 && strikeCount != 0) {
            return ballCount + "B " + strikeCount + "S";
        }
        if (ballCount != 0) {
            return ballCount + "B";
        }
        if (strikeCount != 0) {
            return strikeCount + "S";
        }
        return "4B";
    }

    public int judgeStrike(int[] randomArr, int[] inputNumberArr) {
        int count = 0;
        for (int i = 0; i < baseballCount; i++) {
            if (isSameNumber(randomArr[i], inputNumberArr[i])) {
                count++;
            }
        }
        return count;
    }

    public int judgeBall(int[] randomArr, int[] inputNumberArr) {
        int count = 0;
        for (int i = 0; i < baseballCount; i++) {
            if (containNumberNotSameIndex(randomArr[i], inputNumberArr, i)) {
                count++;
            }
        }
        return count;
    }

    private boolean isSameNumber(int number1, int number2) {
        return number1 == number2;
    }

    private boolean containNumberNotSameIndex(int number, int[] array, int index) {
        for (int i = 0; i < baseballCount; i++) {
            if (isSameNumber(number, array[i]) && i != index) {
                return true;
            }
        }
        return false;
    }

    public int[] intToArray(int threeNumber) {
        int[] array = new int[baseballCount];
        for (int i = 0; i < baseballCount; i++) {
            array[i] = (int) (threeNumber / Math.pow(10, baseballCount - 1 - i)) % 10;
        }

        return array;
    }

    public int scanNumber() {
        Scanner sc = new Scanner(System.in);
        String inputString = sc.nextLine();
        int inputNumber;
        try {
            inputNumber = Integer.parseInt(inputString);
        } catch (NumberFormatException e) {
            System.out.println("숫자가 아닌 다른 값이 입력 되었습니다. 다시 입력해주세요");
            return scanNumber();
        }

        if (inputString.length() != 3) {
            System.out.println("본 게임은 3자리 숫자의 숫자 야구 게임입니다. 3자리만 입력해주세요");
            return scanNumber();
        }
        return inputNumber;
    }

    private void printInputMessage() {
        System.out.println("숫자를 입력해주세요 : ");
    }

    public int[] makeRandomNumberArray() {
        int[] randomNumber = new int[baseballCount];
        for (int i = 0; i < baseballCount; i++) {
            randomNumber[i] = noDuplicateNumber(randomNumber);
        }
        return randomNumber;
    }

    private int noDuplicateNumber(int[] randomNumber) {
        int n = (int) (Math.random() * 9) + 1;

        while (randomNumber[0] == n || randomNumber[1] == n) {
            n = (int) (Math.random() * 9);
        }
        return n;
    }
}

NumberBaseballTest.java

class NumberBaseballTest {

    NumberBaseball nb = new NumberBaseball();

    public static void inputHandling(String userInput) {
        InputStream in = new ByteArrayInputStream(userInput.getBytes());
        System.setIn(in);
    }

    @Test
    void makeRandomNumber() {
        for (int i = 0; i < 20; i++) {
            int[] randomNumber = nb.makeRandomNumberArray();
            assertThat(randomNumber[0] == randomNumber[1]).isFalse();
            assertThat(randomNumber[0] == randomNumber[2]).isFalse();
            assertThat(randomNumber[1] == randomNumber[2]).isFalse();
        }
    }

    @Test
    void scanNumber() {
        inputHandling("123");
        assertThat(nb.scanNumber()).isEqualTo(123);
    }

    @Test
    void intToArray() {
        int[] arr = nb.intToArray(123);
        assertThat(arr).containsExactly(1, 2, 3);
    }

    @Test
    void judgeStrike() {
        int[] randomArr = {1, 2, 3};
        int[] inputArr = {1, 2, 3};
        assertThat(nb.judgeStrike(randomArr, inputArr)).isEqualTo(3);
        inputArr[0] = 5;
        assertThat(nb.judgeStrike(randomArr, inputArr)).isEqualTo(2);
    }

    @Test
    void judgeBall() {
        int[] randomArr = {1, 2, 3};
        int[] inputArr = {3, 1, 2};
        assertThat(nb.judgeBall(randomArr, inputArr)).isEqualTo(3);
        int[] inputArr2 = {1, 2, 3};
        assertThat(nb.judgeBall(randomArr, inputArr2)).isEqualTo(0);
    }

    @Test
    void judgeResult() {
        int[] randomArr = {1, 2, 3};

        assertThat(nb.judgeResult(randomArr, new int[]{1, 2, 3})).isEqualTo("3S");
        assertThat(nb.judgeResult(randomArr, new int[]{3, 1, 2})).isEqualTo("3B");
        assertThat(nb.judgeResult(randomArr, new int[]{5, 4, 6})).isEqualTo("4B");
        assertThat(nb.judgeResult(randomArr, new int[]{1, 3, 6})).isEqualTo("1B 1S");
    }

    @Test
    void isGameOver(){
        assertThat(nb.isGameOver("3S")).isTrue();
        assertThat(nb.isGameOver("2B")).isFalse();
    }
}

0개의 댓글