diff --git a/README.md b/README.md index 8d7e8aee..d49a0756 100644 --- a/README.md +++ b/README.md @@ -1 +1,20 @@ -# java-baseball-precourse \ No newline at end of file +# 카테캠 미니과제 1 - 숫자 야구 +## 개요 +- 카카오 테크 캠퍼스 1차 미니과제 +- 1부터 9까지 서로 다른 수로 이루어진 3자리 숫자를 맞히는 게임 +- 사용자는 컴퓨터가 무작위로 선택한 숫자를 맞히기 위해 입력을 반복, 입력 결과에 따른 힌트 부여 + +## 기술 스택 +- 언어: Java 17 +- 테스트 라이브러리: JUnit 5, AssertJ + +## 기능 목록 +- [x] **숫자 생성** - 게임 시작 시 1부터 9까지 서로 다른 수 3개를 무작위로 생성 +- [x] **사용자 입력** - 사용자는 3자리 숫자를 입력 +- [x] **입력 검증** - 입력받은 숫자가 3자리이며, 각 숫자가 1부터 9까지이고, 중복되지 않는지 확인 +- [x] **결과 반환** - 입력받은 숫자와 컴퓨터가 생성한 숫자를 비교하여 힌트/결과 반환 +- [x] **게임 반복** - 숫자를 맞혔을 경우, 사용자는 게임을 새로 시작할지 또는 종료할지 선택 + +## 개발 규칙 및 스타일 가이드 +- **코드 스타일**: Google Java Style Guide을 기반으로 하되, 들여쓰기는 4 spaces를 사용 +- **커밋 메시지**: AngularJS Git Commit Message Conventions을 기반으로 함 \ No newline at end of file diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..ce050f8d --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,68 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Set; + +public class Application { + private NumberGenerator numberGenerator = new NumberGenerator(); + private InputHandler inputHandler = new InputHandler(); + private InputValidator inputValidator = new InputValidator(); + private ResultCalculator resultCalculator = new ResultCalculator(); + private BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + public void startGame() { + boolean mainGameContinues = true; + + while (mainGameContinues) { + Set computerNumbers = numberGenerator.generateRandomNumbers(); + boolean roundContinues = true; + + while (roundContinues) { + roundContinues = playRound(computerNumbers); + } + + mainGameContinues = askToContinue(); + } + } + + private boolean playRound(Set computerNumbers) { + try { + String userInput = inputHandler.getUserInput(); + inputValidator.validateInput(userInput); + String result = resultCalculator.calculateResult(computerNumbers, userInput); + System.out.println(result); + + if ("3스트라이크".equals(result)) { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + return false; + } + return true; + } catch (IllegalArgumentException | IOException e) { + System.out.println("에러: " + e.getMessage()); + return false; // 에러 발생 시 게임 종료 + } + } + + private boolean askToContinue() { + System.out.print("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요: "); + try { + String decision = br.readLine(); + if ("1".equals(decision)) { + return true; + } else if ("2".equals(decision)) { + return false; + } else { + System.out.println("잘못된 입력입니다. 게임을 종료합니다."); + return false; + } + } catch (IOException e) { + System.out.println("입력 도중 오류가 발생했습니다: " + e.getMessage()); + return false; + } + } + + public static void main(String[] args) { + Application game = new Application(); + game.startGame(); + } +} diff --git a/src/main/java/InputHandler.java b/src/main/java/InputHandler.java new file mode 100644 index 00000000..aee3a506 --- /dev/null +++ b/src/main/java/InputHandler.java @@ -0,0 +1,12 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class InputHandler { + private BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + public String getUserInput() throws IOException { + System.out.print("숫자를 입력해 주세요: "); + return br.readLine(); + } +} diff --git a/src/main/java/InputValidator.java b/src/main/java/InputValidator.java new file mode 100644 index 00000000..317f93f4 --- /dev/null +++ b/src/main/java/InputValidator.java @@ -0,0 +1,22 @@ +import java.util.HashSet; +import java.util.Set; + +public class InputValidator { + public void validateInput(String input) { + if (input == null || input.length() != 3) { + throw new IllegalArgumentException("입력은 정확히 3자리 숫자여야 합니다."); + } + + Set seenDigits = new HashSet<>(); + + for (char ch : input.toCharArray()) { + if (!Character.isDigit(ch) || ch == '0') { + throw new IllegalArgumentException("입력은 1부터 9까지의 숫자여야 합니다."); + } + + if (!seenDigits.add(ch)) { + throw new IllegalArgumentException("모든 숫자는 서로 달라야 합니다."); + } + } + } +} diff --git a/src/main/java/NumberGenerator.java b/src/main/java/NumberGenerator.java new file mode 100644 index 00000000..a8faead0 --- /dev/null +++ b/src/main/java/NumberGenerator.java @@ -0,0 +1,16 @@ +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.Set; + +public class NumberGenerator { + public Set generateRandomNumbers() { + Set numbers = new LinkedHashSet<>(); + Random random = new Random(); + while (numbers.size() < 3) { + int number = 1 + random.nextInt(9); // 1 to 9 + numbers.add(number); + } + return numbers; + } +} diff --git a/src/main/java/ResultCalculator.java b/src/main/java/ResultCalculator.java new file mode 100644 index 00000000..3a756be6 --- /dev/null +++ b/src/main/java/ResultCalculator.java @@ -0,0 +1,31 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class ResultCalculator { + public String calculateResult(Set computerNumbers, String userInput) { + int strikes = 0; + int balls = 0; + List computerList = new ArrayList<>(computerNumbers); + int[] userNumbers = userInput.chars().map(c -> c - '0').toArray(); + + for (int i = 0; i < 3; i++) { + if (userNumbers[i] == computerList.get(i)) { + strikes++; + } else if (computerList.contains(userNumbers[i])) { + balls++; + } + } + + if (balls > 0 && strikes > 0) { + return balls + "볼 " + strikes + "스트라이크"; + } + if (balls > 0) { + return balls + "볼"; + } + if (strikes > 0) { + return strikes + "스트라이크"; + } + return "낫싱"; + } +} diff --git a/src/test/java/InputValidatorTest.java b/src/test/java/InputValidatorTest.java new file mode 100644 index 00000000..75a0dfcf --- /dev/null +++ b/src/test/java/InputValidatorTest.java @@ -0,0 +1,19 @@ +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +class InputValidatorTest { + @Test + void validateInput_ValidInput_ShouldNotThrowException() { + InputValidator validator = new InputValidator(); + assertThatCode(() -> validator.validateInput("123")).doesNotThrowAnyException(); + } + + @Test + void validateInput_InvalidInput_ShouldThrowIllegalArgumentException() { + InputValidator validator = new InputValidator(); + assertThatThrownBy(() -> validator.validateInput("112")).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("모든 숫자는 서로 달라야 합니다."); + assertThatThrownBy(() -> validator.validateInput("abc")).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("1부터 9까지의 숫자여야 합니다."); + } +} diff --git a/src/test/java/NumberGeneratorTest.java b/src/test/java/NumberGeneratorTest.java new file mode 100644 index 00000000..3e992825 --- /dev/null +++ b/src/test/java/NumberGeneratorTest.java @@ -0,0 +1,16 @@ +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +import java.util.Set; + +class NumberGeneratorTest { + @Test + void generateRandomNumbers_ShouldGenerateThreeUniqueNumbersBetweenOneAndNine() { + NumberGenerator generator = new NumberGenerator(); + Set numbers = generator.generateRandomNumbers(); + + assertThat(numbers).hasSize(3); + assertThat(numbers).allMatch(num -> num >= 1 && num <= 9); + assertThat(numbers).doesNotHaveDuplicates(); + } +} diff --git a/src/test/java/ResultCalculatorTest.java b/src/test/java/ResultCalculatorTest.java new file mode 100644 index 00000000..5a9d4897 --- /dev/null +++ b/src/test/java/ResultCalculatorTest.java @@ -0,0 +1,31 @@ +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +import java.util.LinkedHashSet; +import java.util.Set; + +class ResultCalculatorTest { + @Test + void calculateResult_WhenAllMatch_ShouldReturnThreeStrikes() { + ResultCalculator calculator = new ResultCalculator(); + Set computerNumbers = new LinkedHashSet<>(); + computerNumbers.add(1); + computerNumbers.add(2); + computerNumbers.add(3); + String result = calculator.calculateResult(computerNumbers, "123"); + + assertThat(result).isEqualTo("3스트라이크"); + } + + @Test + void calculateResult_NoMatches_ShouldReturnNoting() { + ResultCalculator calculator = new ResultCalculator(); + Set computerNumbers = new LinkedHashSet<>(); + computerNumbers.add(4); + computerNumbers.add(5); + computerNumbers.add(6); + String result = calculator.calculateResult(computerNumbers, "123"); + + assertThat(result).isEqualTo("낫싱"); + } +}