diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java index dd95a34214..7420e5d60b 100644 --- a/src/main/java/baseball/Application.java +++ b/src/main/java/baseball/Application.java @@ -1,7 +1,130 @@ package baseball; +import java.util.InputMismatchException; +import java.util.Random; +import java.util.Scanner; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + try { + playBaseballGame(); + } catch (IllegalArgumentException e) { + System.err.println(e.getMessage()); + } + } + + public static void playBaseballGame() { + Scanner scanner = new Scanner(System.in); + + System.out.println("숫자 야구 게임을 시작합니다."); + do { + int computerNumber = createRandomNumber(); + boolean gameFinished = false; + while (!gameFinished) { + int userNumber = inputNumber(scanner); + validateNumber(userNumber); + gameFinished = checkNumber(userNumber, computerNumber); + } + } while (askForRestart(scanner)); + System.out.println("종료되었습니다."); + } + + private static final int RESTART = 1; + private static final int END = 2; + public static boolean askForRestart(Scanner scanner) { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + try { + int restart = scanner.nextInt(); + if (restart == RESTART) { + return true; + } else if (restart == END) { + return false; + } else { + throw new IllegalArgumentException("잘못된 입력입니다. 1 또는 2를 입력해주세요."); + } + } catch (InputMismatchException e) { + throw new IllegalArgumentException("숫자만 입력해주세요."); + } + } + + //숫자 비교하는 함수 + public static boolean checkNumber(int userNumber, int computerNumber) { +// System.out.println("robot: " + computerNumber); + + String userNumberToString = String.valueOf(userNumber); + String computerNumberToString = String.valueOf(computerNumber); + + int strikes = 0; + int balls = 0; + for (int i = 0; i < 3; i++) { + if (userNumberToString.charAt(i) == computerNumberToString.charAt(i)) { + strikes++; + } else if (computerNumberToString.contains(String.valueOf(userNumberToString.charAt(i)))) { + balls++; + } + } + if (balls > 0 && strikes > 0) { + System.out.println(balls + "볼 " + strikes + "스트라이크"); + } else if (balls > 0) { + System.out.println(balls + "볼"); + } else if (strikes > 0) { + System.out.println(strikes + "스트라이크"); + } else { + System.out.println("낫싱"); + } + + if (strikes == 3) { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + return true; + } + + return false; + } + + //컴퓨터의 랜덤한 수 생성 함수 + public static int createRandomNumber() { + Random random = new Random(); + int firstDigit = random.nextInt(9) + 1; + int secondDigit, thirdDigit; + + do { + secondDigit = random.nextInt(9) + 1; + } while (secondDigit == firstDigit); + + do { + thirdDigit = random.nextInt(9) + 1; + } while (thirdDigit == firstDigit || thirdDigit == secondDigit); + + return firstDigit * 100 + secondDigit * 10 + thirdDigit; + } + + // 숫자 입력 받는 함수 + public static int inputNumber(Scanner scanner) { + System.out.print("숫자를 입력해주세요 : "); + try { + return scanner.nextInt(); + } catch (InputMismatchException e ) { + throw new IllegalArgumentException("입력한 값이 숫자가 아닙니다."); + } + } + + // 잘못된 입력 예외 처리 함수 + public static void validateNumber(int number) { + if (number < 100 || number > 999) { + throw new IllegalArgumentException("입력한 숫자는 3자리 숫자가 아닙니다."); + } + + String numberToString = String.valueOf(number); + char firstDigit = numberToString.charAt(0); + char secondDigit = numberToString.charAt(1); + char thirdDigit = numberToString.charAt(2); + + if (firstDigit == secondDigit || secondDigit == thirdDigit || thirdDigit == firstDigit) { + throw new IllegalArgumentException("입력한 숫자는 각 자리가 중복됩니다."); + } + + if (firstDigit == '0' || secondDigit == '0' || thirdDigit == '0') { + throw new IllegalArgumentException("1부터 9까지 숫자를 입력해주세요."); + } } } diff --git a/src/test/java/baseball/ApplicationTest.java b/src/test/java/baseball/ApplicationTest.java index 3fa29fa67b..91011b265f 100644 --- a/src/test/java/baseball/ApplicationTest.java +++ b/src/test/java/baseball/ApplicationTest.java @@ -1,35 +1,85 @@ package baseball; -import camp.nextstep.edu.missionutils.test.NsTest; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; -import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest; -import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; -class ApplicationTest extends NsTest { - @Test - void 게임종료_후_재시작() { - assertRandomNumberInRangeTest( - () -> { - run("246", "135", "1", "597", "589", "2"); - assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료"); - }, - 1, 3, 5, 5, 8, 9 - ); +import static org.junit.jupiter.api.Assertions.*; + +class ApplicationTest { + + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + + @BeforeEach + void setUpStreams() { + System.setOut(new PrintStream(outContent)); } @Test - void 예외_테스트() { - assertSimpleTest(() -> - assertThatThrownBy(() -> runException("1234")) - .isInstanceOf(IllegalArgumentException.class) - ); + @DisplayName("createRandomNumber 메서드는 3자리 숫자를 반환해야 한다") + void testCreateRandomNumber() { + for (int i = 0; i < 100; i++) { + int number = Application.createRandomNumber(); + assertTrue(number >= 100 && number <= 999); + String numberStr = String.valueOf(number); + assertEquals(3, numberStr.chars().distinct().count()); + assertFalse(numberStr.contains("0")); + } } - @Override - public void runMain() { - Application.main(new String[]{}); + @ParameterizedTest + @ValueSource(ints = {123, 456, 789}) + @DisplayName("validateNumber 메서드는 유효한 입력을 받아들여야 한다") + void testValidateNumberWithValidInput(int number) { + assertDoesNotThrow(() -> Application.validateNumber(number)); } -} + + @ParameterizedTest + @ValueSource(ints = {100, 999, 12, 1000, 111, 990}) + @DisplayName("validateNumber 메서드는 잘못된 입력에 대해 예외를 발생시켜야 한다") + void testValidateNumberWithInvalidInput(int number) { + assertThrows(IllegalArgumentException.class, () -> Application.validateNumber(number)); + } + + @Test + @DisplayName("checkNumber 메서드는 정확한 결과를 반환해야 한다") + void testCheckNumber() { + assertTrue(Application.checkNumber(123, 123)); + assertFalse(Application.checkNumber(123, 456)); + + Application.checkNumber(123, 145); + assertTrue(outContent.toString().contains("1스트라이크")); + + outContent.reset(); + Application.checkNumber(123, 321); + assertTrue(outContent.toString().contains("2볼 1스트라이크")); + + outContent.reset(); + Application.checkNumber(123, 456); + assertTrue(outContent.toString().contains("낫싱")); + } + + // 입력을 숫자로 받는 법을 모르겠음 +// @Test +// @DisplayName("게임이 정상적으로 종료되어야 한다") +// void testGameFlow() { +// int input = 123; +// System.setIn(new ByteArrayInputStream(input.get())); +// +// int input2 = 2; +// +// Application.playBaseballGame(); +// +// String output = outContent.toString(); +// assertTrue(output.contains("숫자 야구 게임을 시작합니다.")); +// assertTrue(output.contains("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.")); +// assertTrue(output.contains("게임 종료")); +// } +} \ No newline at end of file