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
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
# java-baseball-precourse
# java-baseball-precourse

## ⚾ 숫자 야구 게임

### ✏️ 기능 요구 사항

기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.

- 같은 수가 같은 자리에 있으면

→ 스트라이크

- 다른 자리에 있으면

→ 볼

- 같은 수가 전혀 없으면

→ 낫싱이란 힌트를 얻는다.


이 3가지 힌트로 3자리 수를 맞추면 승리한다.

```java
e.g.
상대방(컴퓨터)의 수가 425일 때,
- 123을 제시한 경우: 1스트라이크
- 456을 제시한 경우: 1볼 1스트라이크
- 789를 제시한 경우: 낫싱
```

- 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException 을 발생시킨 후 애플리케이션은 종료되어야 한다.
### 구현 체크 리스트
- [x] random 3자리 수 반환 가능 `Generator`
- [x] 사용자로 부터 `input` 받는 기능
- [x] 사용자로 부터 받은 input 값과 정답 `비교/검증` 기능
- [x] 잘못된 값을 입력한 경우 `IllegalArgumentException` 을 발생시키는 기능
- 사용자가 입력한 값이 정답과 같은지 판단
- [x] 같다면 ASK REPLAY
- [x] 정답이 아니라면 HINT 제공
- 스트라이크
- 볼
- 낫싱
9 changes: 9 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import controller.BaseballGameController;

public class Application {

public static void main(String[] args) {
BaseballGameController controller = new BaseballGameController();
controller.progress();
}
}
44 changes: 44 additions & 0 deletions src/main/java/controller/BaseballGameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package controller;

import model.AnswerChecker;
import model.GenerateRandomNumber;
import model.Hint;
import view.InputView;
import view.OutputView;

import java.util.List;

public class BaseballGameController {

private final static GenerateRandomNumber generateRandomNumber = new GenerateRandomNumber();
private final static InputView input = new InputView();
private final AnswerChecker answerChecker = new AnswerChecker();
private final OutputView outputView = new OutputView();

public void progress() {
boolean isFinish;
do {
List<Integer> answerNum = generateRandomNumber.getRandomNumberList();

oneGame(answerNum);

isFinish = input.isReplay();

} while (isFinish);
}

private void oneGame(List<Integer> answerNum) {
while (true) {
// feat: input & validation
List<Integer> inputNum = input.input();
// feat: checkAnswer
Hint hint = answerChecker.checkAnswer(answerNum, inputNum);
// feat: print Console
outputView.printResult(hint);
if (answerChecker.isFinished(hint)) {
break;
}
}
}

}
32 changes: 32 additions & 0 deletions src/main/java/model/AnswerChecker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package model;

import java.util.List;

import static model.GenerateRandomNumber.DIGIT;

/**
* correct -> Ask replay
* incorrect -> call Hint class
*/
public class AnswerChecker {

public Hint checkAnswer (List<Integer> answer, List<Integer> userInput) {
Hint hint = new Hint();
for (int i = 0; i < userInput.size(); i++) {
int answerI = answer.get(i);
int userI = userInput.get(i);
if (answerI == userI) {
hint.increaseStrike();
}
else if(userInput.contains(answerI)) { // contains
hint.increaseBall();
}
}
return hint;
}

public boolean isFinished (Hint hint) {
return hint.getStrike() == DIGIT;
}

}
22 changes: 22 additions & 0 deletions src/main/java/model/GenerateRandomNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package model;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
* 1~9 사이의 정수 값 - DIGIT 자리수를 랜덤으로 반환
* DIGIT 조절로 자리 수 변경
*/
public class GenerateRandomNumber {

public static final int DIGIT = 3;

public List<Integer> getRandomNumberList() {
List<Integer> randomNumbers = new ArrayList<>();
for (int i = 0; i < DIGIT; i++) {
randomNumbers.add(ThreadLocalRandom.current().nextInt(1, 10));
}
return randomNumbers;
}
}
29 changes: 29 additions & 0 deletions src/main/java/model/Hint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package model;

public class Hint {

private int strike;
private int ball;

public Hint() {
strike = 0;
ball = 0;
}

public int getStrike() {
return strike;
}

public int getBall() {
return ball;
}

public void increaseStrike() {
strike++;
}

public void increaseBall() {
ball++;
}

}
102 changes: 102 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package view;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class InputView {

Scanner scanner;
public static final int DIGIT = 3; // 자리수
private static final String ASK_INPUT_NUM = "숫자를 입력해 주세요: ";
private static final String INPUT_ERROR_INT = "입력한 값이 숫자가 아닙니다. ";
private static final String INPUT_ERROR_BOUND = "1과 2중 값을 입력해주세요. ";

public InputView() {
scanner = new Scanner(System.in);
}

/**
* 1. input number
* 2. validation
* 3. return number
*/
public List<Integer> input() {
System.out.print(ASK_INPUT_NUM);
String inputValue = scanner.nextLine();
inputValidation(inputValue);
return parseToInputList(inputValue);
}

/**
* 두 가지 validation 진행
* 1. 자리수 확인
* 2. input type 확인
*/
public void inputValidation(String inputValue) {
if (!isValidateDigitCount(inputValue)) {
throw new IllegalArgumentException("입력한 숫자의 자릿수를 " + DIGIT + "자리 수로 입력해주세요.");
}
if (!isValidateInt(inputValue)) {
throw new IllegalArgumentException(INPUT_ERROR_INT);
}
}

/**
* @param inputValue: input() 메소드에서 Scanner로 받은 값
* @return 자리 수 확인 후 true/false
*/
public boolean isValidateDigitCount(String inputValue) {
int digitCount = String.valueOf(inputValue).length();
return digitCount == DIGIT;
}

/**
* @param inputValue: input() 메소드에서 Scanner로 받은 값
* @return int 확인 후 true/false
*/
public boolean isValidateInt(String inputValue) {
try {
Integer.parseInt(String.valueOf(inputValue));
return true;
} catch (NumberFormatException e) {
return false;
}
}

/**
* List로 변환하는 메소드
* @param inputValue int
* @return List<Integer>
*/
public List<Integer> parseToInputList(String inputValue) {
List<Integer> intList = new ArrayList<>();
for (int i = 0; i<DIGIT; i++) {
char digitChar = inputValue.charAt(i);
int digit = Character.getNumericValue(digitChar);
intList.add(digit);
}
return intList;
}

/**
* 게임 다시 할건지 사용자로 부터 답을 받는 메소드
* @return true/false
*/
public boolean isReplay() {
String inputValue = scanner.nextLine();

if (!isValidateInt(inputValue)) {
throw new IllegalArgumentException(INPUT_ERROR_INT);
}
int isReplay = Integer.parseInt(inputValue);
if (isReplay == 1) {
return true;
} else if (isReplay == 2) {
return false;
} else {
throw new IllegalArgumentException(INPUT_ERROR_BOUND);
}
}

}
39 changes: 39 additions & 0 deletions src/main/java/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package view;

import model.Hint;

import static model.GenerateRandomNumber.DIGIT;

public class OutputView {

private static final String HINT_STRIKE = "스트라이크";
private static final String HINT_BALL = "볼 ";
private static final String HINT_NOTHING = "낫싱";
private static final String MESSAGE_FINISH = "3개의 숫자를 모두 맞히셨습니다! 게임종료";
private static final String MESSAGE_REPLAY = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";

public void printResult(Hint hint) {
StringBuilder result = new StringBuilder();

int strike = hint.getStrike();
int ball = hint.getBall();

if (strike == DIGIT) {
result.append(MESSAGE_FINISH).append("\n").append(MESSAGE_REPLAY);
}
else {
if (ball > 0) {
result.append(ball).append(HINT_BALL);
}
if (strike > 0) {
result.append(strike).append(HINT_STRIKE);
}
if (ball == 0 && strike == 0) {
result.append(HINT_NOTHING);
}
}

System.out.println(result);
}

}
53 changes: 53 additions & 0 deletions src/test/java/controller/BaseballGameControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package controller;

import model.AnswerChecker;
import model.GenerateRandomNumber;
import model.Hint;
import org.junit.jupiter.api.Test;
import view.InputView;
import view.OutputView;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

class BaseballGameControllerTest {

private final static GenerateRandomNumber generateRandomNumber = new GenerateRandomNumber();
private final static InputView input = new InputView();
private final static AnswerChecker answerChecker = new AnswerChecker();
private final static OutputView outputView = new OutputView();

private BaseballGameController baseballGameController;

@Test
void progress() {
// Generate a random number
List<Integer> answerNum = List.of(1, 2, 3);

// Simulate user input for replay
boolean isReplay = false;

// Simulate answer checking result
Hint hint = answerChecker.checkAnswer(answerNum, List.of(1, 2, 3));

// Verify that the game ends after one iteration
assertThat(answerChecker.isFinished(hint)).isTrue();
}

@Test
void testOneGame() {
// Generate a random number
List<Integer> answerNum = List.of(5, 8, 4);

// Simulate user input
List<Integer> userInput = List.of(5, 8, 4);

// Simulate answer checking result
Hint hint = answerChecker.checkAnswer(answerNum, userInput);

// Verify that the correct hint is returned
assertThat(hint.getStrike()).isEqualTo(3);
assertThat(hint.getBall()).isZero();
}
}
Loading