Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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] 스트라이크 / 볼 / 낫싱 판별
36 changes: 36 additions & 0 deletions src/main/java/Game.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
11 changes: 11 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
22 changes: 22 additions & 0 deletions src/main/java/MatchResult.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
64 changes: 64 additions & 0 deletions src/main/java/NumSet.java
Original file line number Diff line number Diff line change
@@ -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
};
}
}
58 changes: 58 additions & 0 deletions src/test/java/NumSetTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}