diff --git a/README.md b/README.md index 8402279..675bd4d 100644 --- a/README.md +++ b/README.md @@ -1 +1,37 @@ -# baseball +# 기능 목록 + +## 목표값 생성 연산 + +- `Random` 클래스를 이용한 임의의 수 3개 생성 (1~9) +- 추후 연산을 위해 int형 배열로 생성 + +## 야구 게임 시작 안내 문구 출력 + +## 숫자 입력 요청 + +## 입력값에 대한 검사 + +- 잘못된 값에 대한 예외 처리 `IllegalArgumentException` 호출 후 종료 + + - 공백 검사 -> 처음 입력값 저장 시 모든 공백 제거 // 4 5 6 가능 // 456 가능 // 4 56 가능 + - 타입 검사 -> 예외 + - 사이즈 검사 -> 예외 + - 0 검사 (범위 검사) -> 예외 + +## 입력값과 목표값 비교 연산 + +- 입력과 목표 간 값 과 위치가 같다면 스트라이크 +- 값만 같다면 볼 +- 둘 다 다르다면 미스 + +## 연산 결과(힌트) 출력 + +## 실패 시 `숫자 입력 요청`부터 반복 + +## 성공 시 입력 요청 + +## 성공 시 입력값에 따른 반복 + +- 1의 경우 프로그램 처음부터 반복 +- 2의 경우 프로그램 종료 + diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java index b4f76f0..28ee7fb 100644 --- a/src/main/java/baseball/Application.java +++ b/src/main/java/baseball/Application.java @@ -1,7 +1,9 @@ package baseball; +import baseball.controller.BaseballGameController; + public class Application { public static void main(String[] args) { - // TODO: 코드 구현 + new BaseballGameController().run(); } } \ No newline at end of file diff --git a/src/main/java/baseball/controller/BaseballGameController.java b/src/main/java/baseball/controller/BaseballGameController.java new file mode 100644 index 0000000..3903605 --- /dev/null +++ b/src/main/java/baseball/controller/BaseballGameController.java @@ -0,0 +1,33 @@ +package baseball.controller; + +import baseball.model.BaseballGame; +import baseball.view.InputView; +import baseball.view.OutputView; + +import java.util.Scanner; + +public class BaseballGameController { + private final BaseballGame game = new BaseballGame(); + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + + private static final int START = 1; + private static final int END = 9; + + public void run() { + game.createTargetNumber(START, END); + outputView.printStartMessage(); + + while (true) { + game.reset(); // targetNumber의 상태 초기화 및 이전 userNumber free + inputView.getUserNumber(game); + game.match(); + outputView.printResult(game); //todo: ball, strike 연산을 view클래스에서? + + if (game.getStatus() == baseball.model.GameStatus.SUCCESS) { // todo: 이것도 따로 함수로 빼야될 듯 + if (outputView.isRestart(game)) continue; // todo: restart 연산을 view클래스에서? + break; + } + } + } +} diff --git a/src/main/java/baseball/model/BaseballGame.java b/src/main/java/baseball/model/BaseballGame.java new file mode 100644 index 0000000..de4a15a --- /dev/null +++ b/src/main/java/baseball/model/BaseballGame.java @@ -0,0 +1,81 @@ +package baseball.model; + +import java.util.Random; + +public class BaseballGame { + private static final int NUM_SIZE = 3; + + BaseballNumber[] targetNumbers; + BaseballNumber[] userNumbers; + + GameStatus status; + + public void createTargetNumber(int start, int end) { + targetNumbers = new BaseballNumber[NUM_SIZE]; + for (int i = 0; i < NUM_SIZE; i++) { + targetNumbers[i] = new BaseballNumber(new Random().nextInt(end) + start); + } + } + + public void createUserNumbers(String input) { + userNumbers = new BaseballNumber[NUM_SIZE]; + for (int i = 0; i < NUM_SIZE; i++) { + int inputNumber = Integer.parseInt(String.valueOf(input.charAt(i))); + userNumbers[i] = new BaseballNumber(inputNumber); + } + } + + + public void match() { + checkStrike(); + checkBall(); + } + + private void checkStrike() { + for (int index = 0; index < NUM_SIZE; index++) { + if (userNumbers[index].getValue() == targetNumbers[index].getValue()) { + userNumbers[index].setStrike(true); + targetNumbers[index].setStrike(true); + } + } + } + + private void checkBall() { + for (int targetIndex = 0; targetIndex < NUM_SIZE; targetIndex++) { + if (targetNumbers[targetIndex].isStrike()) continue; + for (int userIndex = 0; userIndex < NUM_SIZE; userIndex++) { + if (userNumbers[userIndex].isBall()) continue; + if (targetNumbers[targetIndex].getValue() == userNumbers[userIndex].getValue()) { + targetNumbers[userIndex].setBall(true); + userNumbers[userIndex].setBall(true); + break; + } + } + } + } + + public void reset() { + for (BaseballNumber targetNumber: targetNumbers) { + targetNumber.setStrike(false); + targetNumber.setBall(false); + } + + userNumbers = null; + } + + public BaseballNumber[] getTargetNumbers() { + return targetNumbers; + } + + public GameStatus getStatus() { + return status; + } + + public void setStatus(GameStatus status) { + this.status = status; + } + + public static int getNumSize() { + return NUM_SIZE; + } +} diff --git a/src/main/java/baseball/model/BaseballNumber.java b/src/main/java/baseball/model/BaseballNumber.java new file mode 100644 index 0000000..dc6de78 --- /dev/null +++ b/src/main/java/baseball/model/BaseballNumber.java @@ -0,0 +1,33 @@ +package baseball.model; + +// vo class +public class BaseballNumber { + private final int value; + + private boolean strike = false; + private boolean ball = false; + + public BaseballNumber(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public boolean isStrike() { + return strike; + } + + public boolean isBall() { + return ball; + } + + public void setStrike(boolean strike) { + this.strike = strike; + } + + public void setBall(boolean ball) { + this.ball = ball; + } +} diff --git a/src/main/java/baseball/model/GameStatus.java b/src/main/java/baseball/model/GameStatus.java new file mode 100644 index 0000000..205bf27 --- /dev/null +++ b/src/main/java/baseball/model/GameStatus.java @@ -0,0 +1,7 @@ +package baseball.model; + +public enum GameStatus { + FAIL, + SUCCESS, + RESTART +} diff --git a/src/main/java/baseball/util/Message.java b/src/main/java/baseball/util/Message.java new file mode 100644 index 0000000..7703445 --- /dev/null +++ b/src/main/java/baseball/util/Message.java @@ -0,0 +1,14 @@ +package baseball.util; + +public class Message { + public static final String MESSAGE_START = "숫자 야구 게임을 시작합니다."; + public static final String MESSAGE_INPUT_PROMPT = "숫자를 입력해주세요 : "; + public static final String MESSAGE_INPUT_ERROR = "1~9 사이 3개의 숫자를 입력해주세요 !!"; + public static final String MESSAGE_MISS = "미스"; + public static final String MESSAGE_STRIKE_ONLY_FORMATTED = "%d스트라이크"; + public static final String MESSAGE_BALL_ONLY_FORMATTED = "%d볼"; + public static final String MESSAGE_BALL_STRIKE_FORMATTED = "%d볼 %d스트라이크"; + public static final String MESSAGE_SUCCESS_FORMATTED = "%d개의 숫자를 모두 맞히셨습니다!"; + public static final String MESSAGE_RESTART_PROMPT = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; + public static final String MESSAGE_RESTART_ERROR = "1 또는 2를 입력하세요 !!"; +} \ No newline at end of file diff --git a/src/main/java/baseball/util/Validator.java b/src/main/java/baseball/util/Validator.java new file mode 100644 index 0000000..6f8c9d1 --- /dev/null +++ b/src/main/java/baseball/util/Validator.java @@ -0,0 +1,17 @@ +package baseball.util; + +import baseball.model.BaseballGame; + +public class Validator { + public static void inputValidate(String input) { + try { + Integer.parseInt(input); + if (input.contains("0") || input.length() != BaseballGame.getNumSize()) { + throw new IllegalArgumentException(); + } + } catch (Exception e) { + System.out.println(Message.MESSAGE_INPUT_ERROR); + throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java new file mode 100644 index 0000000..ed79887 --- /dev/null +++ b/src/main/java/baseball/view/InputView.java @@ -0,0 +1,19 @@ +package baseball.view; + +import baseball.model.BaseballGame; +import baseball.util.Message; +import baseball.util.Validator; + +import java.util.Scanner; + +public class InputView { + public void getUserNumber(BaseballGame baseballGame) { + System.out.print(Message.MESSAGE_INPUT_PROMPT); + Scanner scanner = new Scanner(System.in); + String input = scanner.nextLine().replaceAll("\\s+", ""); + + Validator.inputValidate(input); + + baseballGame.createUserNumbers(input); + } +} diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java new file mode 100644 index 0000000..5d26267 --- /dev/null +++ b/src/main/java/baseball/view/OutputView.java @@ -0,0 +1,68 @@ +package baseball.view; + +import baseball.model.BaseballGame; +import baseball.model.BaseballNumber; +import baseball.model.GameStatus; +import baseball.util.Message; + +import java.util.Scanner; + +public class OutputView { + public void printStartMessage() { + System.out.println(Message.MESSAGE_START); + } + + public void printResult(BaseballGame game) { + int strike = 0; + int ball = 0; + + for (BaseballNumber targetNumber : game.getTargetNumbers()) { + if (targetNumber.isStrike()) { + strike++; + continue; + } + if (targetNumber.isBall()) { + ball++; + } + } + + if (ball == 0 && strike == 0) { // todo: 연산을 view클래스에서? + game.setStatus(GameStatus.FAIL); + System.out.println(Message.MESSAGE_MISS); + } else if (ball == 0) { + game.setStatus(GameStatus.FAIL); + System.out.println(String.format(Message.MESSAGE_STRIKE_ONLY_FORMATTED, strike)); + if (strike == game.getNumSize()) { + game.setStatus(GameStatus.SUCCESS); + System.out.println(String.format(Message.MESSAGE_SUCCESS_FORMATTED, BaseballGame.getNumSize())); + } + } else if (strike == 0) { + game.setStatus(GameStatus.FAIL); + System.out.println(String.format(Message.MESSAGE_BALL_ONLY_FORMATTED, ball)); + } else { + game.setStatus(GameStatus.FAIL); + System.out.println(String.format(Message.MESSAGE_BALL_STRIKE_FORMATTED, ball, strike)); + } + } + + public boolean isRestart(BaseballGame game) { // todo: 출력뿐 아니라 조건 분기도 하고 있음.. + System.out.println(Message.MESSAGE_RESTART_PROMPT); + Scanner scanner = new Scanner(System.in); + try { + int option = scanner.nextInt(); + if (option == 1) { + game.createTargetNumber(1, 9); + game.setStatus(GameStatus.RESTART); // 의미가 있나? + return true; + } else if (option == 2) return false; + else { + // 1,2 외의 숫자 + System.out.println(Message.MESSAGE_RESTART_ERROR); + throw new IllegalArgumentException(); + } + } catch (Exception e) { // 잘못된 타입 + System.out.println(Message.MESSAGE_RESTART_ERROR); + throw e; + } + } +} diff --git a/src/test/java/baseball/ApplicationTest.java b/src/test/java/baseball/ApplicationTest.java index d7242f5..8a88584 100644 --- a/src/test/java/baseball/ApplicationTest.java +++ b/src/test/java/baseball/ApplicationTest.java @@ -6,31 +6,31 @@ import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.List; +import baseball.model.BaseballGame; +import baseball.model.BaseballNumber; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ApplicationTest { - // TODO: 클래스명과 함수명 변경 가능 (RandomNumberGenerator.generate()) @Test public void 랜덤_숫자_생성_함수는_1부터_9까지의_숫자_3개를_생성한다() { - // TODO: 실제 구현에서는 RandomNumberGenerator.generate() 등 실제 함수를 호출할 것 - List numbers = List.of(); // 임시 코드. 구현 후 아래 코드로 변경해주세요. - // 예: List numbers = RandomNumberGenerator.generate(); + BaseballGame baseballGame = new BaseballGame(); + baseballGame.createTargetNumber(1,9); + BaseballNumber[] numbers = baseballGame.getTargetNumbers(); - assertThat(numbers.size()).isEqualTo(3); + assertThat(numbers.length).isEqualTo(3); - for (Integer number : numbers) { - assertThat(number).isBetween(1, 9); + for (BaseballNumber number : numbers) { + assertThat(number.getValue()).isBetween(1, 9); } - long distinctCount = numbers.stream().distinct().count(); - assertThat(distinctCount).isEqualTo(3); +// long distinctCount = numbers.stream().distinct().count(); +// assertThat(distinctCount).isEqualTo(3); } - - // TODO: 필요에 따라 추가 테스트 코드 작성 가능 }