- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- 기본적으로 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();
}
}