diff --git a/README.md b/README.md index fcf3f057..8e83df67 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,15 @@ ## 과제 제출 과정 * [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) + +## 구현할 기능 목록 +- 1 ~ 9사이의 임의의 수 생성 기능 +- 상대방 수(서로 다른 임의의 수 3개)를 생성하는 기능 +- 사용자의 수를 입력 받는 기능 +- 상대방의 수와 사용자의 수 비교 결과를 출력하는 기능 +- 비교 결과에 따라 낫싱, 스트라이크, 볼 정보를 생성하는 기능 +- 수가 같은지, 다른지 판별하는 기능 +- 수가 같은 자리에 있는지, 포함하고 있는지 판별하는 기능 +- 상대방의 수와 사용자의 수를 비교하는 기능 +- 게임 재시작/종료 기능 +- 게임 재시작/종료 입력값 유효성 검증 기능 diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..bbef3106 --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,9 @@ +import controller.BaseballGameController; + +public class Main { + + public static void main(String[] args) { + new BaseballGameController().execute(); + } + +} diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java new file mode 100644 index 00000000..26cf6b42 --- /dev/null +++ b/src/main/java/controller/BaseballGameController.java @@ -0,0 +1,57 @@ +package controller; + +import domain.BaseballGame; +import domain.Computer; +import domain.GameResult; +import view.Console; + +public class BaseballGameController { + + private static final String RESTART_FLAG = "1"; + private static final String EXIT_FLAG = "2"; + + private final Computer computer; + private final Console console; + + public BaseballGameController() { + computer = new Computer(); + console = new Console(); + } + + public void execute() { + BaseballGame baseballGame = new BaseballGame(computer.generateThreeDifferentNumber()); + + do { + String userNumbers = console.getUserInputNumber(); + GameResult gameResult = baseballGame.compareNumbers(userNumbers); + console.printMessage(gameResult.getDescription()); + } while (!baseballGame.isEnd()); + + handleEndOfGame(console::printEndMessage); + } + + public void handleEndOfGame(Runnable runnable) { + runnable.run(); + String userInput = console.getUserInput(); + + if (!validateRestartOrExitInput(userInput)) { + handleEndOfGame(console::printErrorMessage); + return; + } + + restartOrExit(userInput); + } + + public void restartOrExit(String userInput) { + if (userInput.equals(EXIT_FLAG)) { + return; + } + + execute(); + } + + public boolean validateRestartOrExitInput(String userInput) { + return userInput.equals(RESTART_FLAG) || userInput.equals(EXIT_FLAG); + } + +} diff --git a/src/main/java/domain/BaseballGame.java b/src/main/java/domain/BaseballGame.java new file mode 100644 index 00000000..963a4652 --- /dev/null +++ b/src/main/java/domain/BaseballGame.java @@ -0,0 +1,40 @@ +package domain; + +public class BaseballGame { + + private static final int NUMBER_LENGTH = 3; + + private final String computerNumbers; + private GameResult currentGameResult; + + public BaseballGame(String computerNumbers) { + this.computerNumbers = computerNumbers; + } + + public GameResult compareNumbers(String userNumbers) { + currentGameResult = new GameResult(); + + for (int i = 0; i < NUMBER_LENGTH; i++) { + compareNumber(userNumbers.charAt(i), computerNumbers.charAt(i)); + } + + return currentGameResult; + } + + private void compareNumber(char userNum, char computerNum) { + if (!computerNumbers.contains(String.valueOf(userNum))) { + return; + } + + if (userNum == computerNum) { + currentGameResult.increaseStrikeCount(); + return; + } + currentGameResult.increaseBallCount(); + } + + public boolean isEnd() { + return currentGameResult.getStrikeCount() == NUMBER_LENGTH; + } + +} diff --git a/src/main/java/domain/Computer.java b/src/main/java/domain/Computer.java new file mode 100644 index 00000000..8ea9b9f1 --- /dev/null +++ b/src/main/java/domain/Computer.java @@ -0,0 +1,31 @@ +package domain; + +import java.util.*; + +public class Computer { + + private static final int MIN = 1; + private static final int MAX = 9; + + private final Random random; + + public Computer() { + random = new Random(); + } + + public String generateThreeDifferentNumber() { + Set set = new HashSet<>(); + + while (set.size() < 3) { + set.add(generateRandomNumber()); + } + + return set.toString() + .replaceAll("[^0-9]", ""); + } + + public int generateRandomNumber() { + return random.nextInt(MAX) + MIN; + } + +} diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/GameResult.java new file mode 100644 index 00000000..e4983f88 --- /dev/null +++ b/src/main/java/domain/GameResult.java @@ -0,0 +1,46 @@ +package domain; + +public class GameResult { + + private int strikeCount; + private int ballCount; + + public int getStrikeCount() { + return strikeCount; + } + + public int getBallCount() { + return ballCount; + } + + public String getDescription() { + StringBuilder sb = new StringBuilder(); + + sb.append(checkIsNothing()); + sb.append(checkStrikeCount()); + sb.append(checkBallCount()); + + return sb.toString(); + } + + public void increaseStrikeCount() { + strikeCount += 1; + } + + public void increaseBallCount() { + ballCount += 1; + } + + public String checkIsNothing() { + return strikeCount + ballCount == 0 ? "낫싱" : ""; + } + + public String checkStrikeCount() { + return strikeCount > 0 ? strikeCount + "스트라이크 " : ""; + } + + public String checkBallCount() { + return ballCount > 0 ? ballCount + "볼" : ""; + } + +} diff --git a/src/main/java/view/Console.java b/src/main/java/view/Console.java new file mode 100644 index 00000000..c4b09292 --- /dev/null +++ b/src/main/java/view/Console.java @@ -0,0 +1,40 @@ +package view; + +import java.util.Scanner; + +public class Console { + + private static final String INPUT_MESSAGE = "숫자를 입력해주세요 : "; + private static final String END_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임 종료"; + private static final String RESTART_OR_EXIT_MESSAGE = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; + private static final String ERROR_MESSAGE = "올바른 숫자를 입력해주세요."; + + private final Scanner scanner; + + public Console() { + scanner = new Scanner(System.in); + } + + public String getUserInputNumber() { + System.out.print(INPUT_MESSAGE); + return scanner.nextLine(); + } + + public String getUserInput() { + return scanner.nextLine(); + } + + public void printEndMessage() { + printMessage(END_MESSAGE); + printMessage(RESTART_OR_EXIT_MESSAGE); + } + + public void printErrorMessage() { + printMessage(ERROR_MESSAGE); + } + + public void printMessage(String str) { + System.out.println(str); + } + +} diff --git a/src/test/java/domain/BaseballGameTest.java b/src/test/java/domain/BaseballGameTest.java new file mode 100644 index 00000000..03d58111 --- /dev/null +++ b/src/test/java/domain/BaseballGameTest.java @@ -0,0 +1,36 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class BaseballGameTest { + + @DisplayName("사용자의 수와 컴퓨터의 수 비교 테스트") + @ParameterizedTest + @MethodSource("provideComputerNumbersAndUserNumbers") + void compareNumbersTest(String computerNumbers, String userNumbers, String description, int strikeCount, int ballCount) { + BaseballGame baseballGame = new BaseballGame(computerNumbers); + GameResult gameResult = baseballGame.compareNumbers(userNumbers); + + assertThat(gameResult.getDescription()).isEqualTo(description); + assertThat(gameResult.getStrikeCount()).isEqualTo(strikeCount); + assertThat(gameResult.getBallCount()).isEqualTo(ballCount); + } + + private static Stream provideComputerNumbersAndUserNumbers() { + return Stream.of( + Arguments.of("713", "123", "1스트라이크 1볼", 1, 1), + Arguments.of("713", "145", "1볼", 0, 1), + Arguments.of("713", "256", "낫싱", 0, 0), + Arguments.of("713", "671", "2볼", 0, 2), + Arguments.of("713", "713", "3스트라이크 ", 3, 0) + ); + } + +} \ No newline at end of file diff --git a/src/test/java/domain/ComputerTest.java b/src/test/java/domain/ComputerTest.java new file mode 100644 index 00000000..7422febe --- /dev/null +++ b/src/test/java/domain/ComputerTest.java @@ -0,0 +1,34 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ComputerTest { + + @DisplayName("1 ~ 9 사이의 임의의 수 생성 테스트") + @Test + void generateRandomNumberTest() { + Computer computer = new Computer(); + int min = 1, max = 9; + + for (int i = 0; i < 100; i++) { + int randomNumber = computer.generateRandomNumber(); + assertThat(randomNumber).isGreaterThanOrEqualTo(min).isLessThanOrEqualTo(max); + } + } + + @DisplayName("서로 다른 임의의 수 3개 생성 테스트") + @Test + void generateThreeDifferentNumberTest() { + Computer computer = new Computer(); + char[] nums = computer.generateThreeDifferentNumber() + .toCharArray(); + + assertThat(nums[0]).isNotEqualTo(nums[1]); + assertThat(nums[0]).isNotEqualTo(nums[2]); + assertThat(nums[1]).isNotEqualTo(nums[2]); + } + +} \ No newline at end of file diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java new file mode 100644 index 00000000..c29b0815 --- /dev/null +++ b/src/test/java/domain/GameResultTest.java @@ -0,0 +1,95 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class GameResultTest { + + @DisplayName("스트라이크/볼 증가 테스트") + @ParameterizedTest + @MethodSource("provideIncreaseCount") + void increaseStrikeAndBallCountTest(int strikeCount, int ballCount) { + GameResult gameResult = new GameResult(); + + for (int i = 0; i < strikeCount; i++) { + gameResult.increaseStrikeCount(); + } + + for (int i = 0; i < ballCount; i++) { + gameResult.increaseBallCount(); + } + + assertThat(gameResult.getStrikeCount()).isEqualTo(strikeCount); + assertThat(gameResult.getBallCount()).isEqualTo(ballCount); + } + + @DisplayName("스트라이크와 볼 카운트가 없는 케이스 테스트") + @Test + void checkIsNothingTest() { + GameResult gameResult = new GameResult(); + + assertThat(gameResult.checkIsNothing()).isEqualTo("낫싱"); + assertThat(gameResult.checkStrikeCount()).isEmpty(); + assertThat(gameResult.checkBallCount()).isEmpty(); + } + + @DisplayName("스트라이크와 볼이 있는 케이스 테스트") + @Test + void checkStringAndBallCount() { + GameResult gameResult = new GameResult(); + int strikeCount = 1, ballCount = 1; + + for (int i = 0; i < strikeCount; i++) { + gameResult.increaseStrikeCount(); + } + + for (int i = 0; i < ballCount; i++) { + gameResult.increaseBallCount(); + } + + assertThat(gameResult.checkStrikeCount()).isEqualTo(strikeCount + "스트라이크 "); + assertThat(gameResult.checkBallCount()).isEqualTo(ballCount + "볼"); + } + + + @DisplayName("게임 결과 판별 테스트") + @ParameterizedTest + @MethodSource("provideCountAndDescription") + void gameResultDescriptionTest(int strikeCount, int ballCount, String description) { + GameResult gameResult = new GameResult(); + + for (int i = 0; i < strikeCount; i++) { + gameResult.increaseStrikeCount(); + } + + for (int i = 0; i < ballCount; i++) { + gameResult.increaseBallCount(); + } + + assertThat(gameResult.getDescription()).isEqualTo(description); + } + + private static Stream provideIncreaseCount() { + return Stream.of( + Arguments.of(3, 0), + Arguments.of(1, 2), + Arguments.of(0, 0) + ); + } + + private static Stream provideCountAndDescription() { + return Stream.of( + Arguments.of(0, 0, "낫싱"), + Arguments.of(2, 1, "2스트라이크 1볼"), + Arguments.of(0, 3, "3볼") + ); + } + +} \ No newline at end of file diff --git a/src/test/java/study/StringTest.java b/src/test/java/study/StringTest.java deleted file mode 100644 index 43e47d90..00000000 --- a/src/test/java/study/StringTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package study; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StringTest { - @Test - void replace() { - String actual = "abc".replace("b", "d"); - assertThat(actual).isEqualTo("adc"); - } -}