diff --git a/README.md b/README.md index fcf3f057..72fa4561 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,15 @@ ## 과제 제출 과정 * [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) + +## 기능 요구사항 +- [x] 3자리 수를 0~9 숫자 3개로 변환 +- [x] 1~9의 서로 다른 임의의 숫자 3개 생성 +- [x] 스트라이크 / 볼 / 낫싱 판별 +- [x] 메인 로직 - 게임 종료 조건 만족할 때까지 게임 반복 + +## 테스트 코드 작성 +해결할 점: private 변수에 접근할 수 없어 테스트 불가 +- [x] 3자리 수를 자릿수로 split +- [x] 랜덤 숫자 3개 생성 +- [x] 스트라이크 / 볼 / 낫싱 판별 \ No newline at end of file diff --git a/src/main/java/Game.java b/src/main/java/Game.java new file mode 100644 index 00000000..616fc09f --- /dev/null +++ b/src/main/java/Game.java @@ -0,0 +1,36 @@ +import java.util.Scanner; + +public class Game { + private NumSet answer; + + public void reset() { + answer = new NumSet(); + } + + public void start() { + Scanner sc = new Scanner(System.in); + boolean isCorrect = false; + while (!isCorrect) { + System.out.print("숫자를 입력해주세요 : "); + int[] submitted = NumSet.convertToList(sc.nextInt()); + + MatchResult matchResult = answer.match(submitted); + matchResult.printResult(); + + isCorrect = matchResult.isCorrect(); + } + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + } + + public boolean willContinue() { + Scanner sc = new Scanner(System.in); + + int next = 0; + while (next != 1 && next != 2) { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + next = sc.nextInt(); + } + + return next == 1; + } +} diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..01c3d2d9 --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,11 @@ +public class Main { + public static void main(String[] args) { + Game game = new Game(); + boolean willContinue = true; + while (willContinue) { + game.reset(); + game.start(); + willContinue = game.willContinue(); + } + } +} diff --git a/src/main/java/MatchResult.java b/src/main/java/MatchResult.java new file mode 100644 index 00000000..5d0a9b92 --- /dev/null +++ b/src/main/java/MatchResult.java @@ -0,0 +1,22 @@ +public class MatchResult { + private int strike, ball; + + public MatchResult(int strike, int ball) { + this.strike = strike; + this.ball = ball; + } + + public boolean isCorrect() { + return strike == 3; + } + + public void printResult() { + if (strike != 0) + System.out.print(strike + " 스트라이크 "); + if (ball != 0) + System.out.print(ball + "볼"); + if (strike == 0 && ball == 0) + System.out.print("낫싱"); + System.out.println(); + } +} diff --git a/src/main/java/NumSet.java b/src/main/java/NumSet.java new file mode 100644 index 00000000..15b44e90 --- /dev/null +++ b/src/main/java/NumSet.java @@ -0,0 +1,64 @@ +import java.util.Random; + +public class NumSet { + private int[] numArr = new int[3]; + + public NumSet() { + for (int i = 0; i < 3; i++) + setRandomNum(i); + } + + private void setRandomNum(int idx) { + Random random = new Random(); + boolean isDiff = false; + while (!isDiff) { + numArr[idx] = random.nextInt(1, 10); + isDiff = isDiffFromForward(idx); + } + } + + private boolean isDiffFromForward(int idx) { + boolean isPrevDiff = true; + for (int i = 0; i < idx; i++) + isPrevDiff = isPrevDiff && (numArr[idx] != numArr[i]); + return isPrevDiff; + } + + // 사용자가 '112'처럼 중복 숫자를 입력할 때 + // 스트라이크와 볼이 중복 카운트되지 않도록 + // 포함하는 수 카운트에서 스트라이크를 빼서 볼을 계산 + public MatchResult match(int[] userArr) { + int strike = countStrike(userArr); + int ball = countContains(userArr) - strike; + return new MatchResult(strike, ball); + } + + private int countStrike(int[] userArr) { + int strike = 0; + for (int i = 0; i < 3; i++) + strike += (numArr[i] == userArr[i]) ? 1 : 0; // depth 1로 만들기 위해... + return strike; + } + + private int countContains(int[] userArr) { + int cnt = 0; + for (int i = 0; i < 3; i++) + cnt += contains(i, userArr) ? 1 : 0; + return cnt; + } + + private boolean contains(int idx, int[] userArr) { + boolean hasNum = false; + for (int i = 0; i < 3; i++) + hasNum = hasNum || (numArr[idx] == userArr[i]); + return hasNum; + } + + public static int[] convertToList(int num) { + return new int[]{ + num / 100, + num / 10 % 10, + num % 10 + }; + } +} diff --git a/src/test/java/NumSetTest.java b/src/test/java/NumSetTest.java new file mode 100644 index 00000000..2f7407f5 --- /dev/null +++ b/src/test/java/NumSetTest.java @@ -0,0 +1,58 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.lang.reflect.Field; + +import static org.assertj.core.api.Assertions.*; + +class NumSetTest { + @Test + void convertToList() { + assertThat(NumSet.convertToList(123)).isEqualTo(new int[]{1, 2, 3}); + assertThat(NumSet.convertToList(719)).isEqualTo(new int[]{7, 1, 9}); + } + + @Test + void generateRandom3Number() throws NoSuchFieldException, IllegalAccessException { + Field numArrField = NumSet.class.getDeclaredField("numArr"); + numArrField.setAccessible(true); + + for (int i = 0; i < 200; i++) { + NumSet numSet = new NumSet(); + int[] numArr = (int[]) numArrField.get(numSet); + + assertThat(numArr[0]).isBetween(1, 9); + assertThat(numArr[1]).isBetween(1, 9); + assertThat(numArr[2]).isBetween(1, 9); + + assertThat(numArr[0]).isNotEqualTo(numArr[1]); + assertThat(numArr[1]).isNotEqualTo(numArr[2]); + assertThat(numArr[2]).isNotEqualTo(numArr[0]); + } + } + + + @ParameterizedTest + @CsvSource({"1,2,3,3,0", "1,3,2,1,2", "1,2,4,2,0", "4,5,1,0,1", "4,5,6,0,0"}) + void match(int userNum1, int userNum2, int userNum3, int strikeExpected, int ballExpected) throws NoSuchFieldException, IllegalAccessException { + Field numArrField = NumSet.class.getDeclaredField("numArr"); + numArrField.setAccessible(true); + + NumSet numSet = new NumSet(); + numArrField.set(numSet, new int[]{1, 2, 3}); + + Field strikeField = MatchResult.class.getDeclaredField("strike"); + strikeField.setAccessible(true); + + Field ballField = MatchResult.class.getDeclaredField("ball"); + ballField.setAccessible(true); + + MatchResult matchResult = numSet.match(new int[]{userNum1, userNum2, userNum3}); + int strike = strikeField.getInt(matchResult); + int ball = ballField.getInt(matchResult); + + assertThat(strike).isEqualTo(strikeExpected); + assertThat(ball).isEqualTo(ballExpected); + } +} \ No newline at end of file