Skip to content
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
# java-baseball-precourse
# 숫자 야구 게임 (Baseball)

## 📌 구현할 기능 목록

### 1) 게임 실행/흐름
- 프로그램 시작 시 숫자 야구 게임을 실행한다.
- 한 게임은 “정답 3자리 생성 → 입력 반복 → 정답 시 종료 문구 출력” 흐름으로 진행한다.
- 정답을 맞히면 “3개의 숫자를 모두 맞히셨습니다! 게임 끝”을 출력하고 재시작/종료 입력 단계로 이동한다.
- 재시작(1) 선택 시 새로운 정답을 생성하고 게임을 다시 진행한다.
- 종료(2) 선택 시 프로그램을 종료한다.

### 2) 컴퓨터 숫자 생성
- 0~9 사이의 숫자 중 서로 다른 3개를 무작위로 뽑아 정답으로 사용한다.
- 생성된 정답은 3자리 List(Integer) 형태로 유지한다.

### 3) 사용자 입력(숫자 3자리)
- “숫자를 입력해주세요 : ” 안내 문구를 출력한다.
- 사용자 입력은 정확히 3자리여야 한다.
- 사용자 입력은 모두 숫자여야 한다.
- 사용자 입력은 중복 숫자가 없어야 한다.
- 위 조건을 만족하지 않으면 [ERROR] Invalid input을 출력하고 다시 입력을 받는다.
- 검증이 끝나면 문자열 입력을 정수 리스트로 변환한다.

### 4) 결과 판정(스트라이크/볼)
- 같은 위치에 같은 숫자가 있으면 스트라이크로 센다.
- 숫자는 존재하지만 위치가 다르면 볼로 센다.
- 판정 결과를 Result(strikeCount, ballCount)로 반환한다.
- 스트라이크가 3이면 정답으로 처리한다.

### 5) 결과 출력
- 스트라이크가 1 이상이면 “{n}스트라이크 ”를 출력한다.
- 볼이 1 이상이면 “{n}볼 ”을 출력한다.
- 스트라이크/볼이 모두 0이면 “낫싱”을 출력한다.
- 각 결과 출력은 줄바꿈으로 마무리한다.

### 6) 재시작/종료 입력
- “게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.”를 출력한다.
- 입력은 한 자리 숫자여야 한다.
- 입력값은 1 또는 2만 허용한다.
- 유효하지 않으면 [ERROR] Invalid input을 출력하고 다시 입력을 받는다.
- 1이면 true(계속), 2이면 false(종료)를 반환한다.

## ▶️ 실행 방법 (예시)
1. 프로그램을 실행한다.
2. 안내 문구에 따라 3자리 숫자를 입력한다.
3. 판정 결과(볼/스트라이크/낫싱)를 확인하며 반복한다.
4. 정답을 맞히면 종료 문구가 출력된다.
5. 1을 입력하면 재시작, 2를 입력하면 종료된다.
38 changes: 38 additions & 0 deletions src/main/java/Baseball.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import java.util.ArrayList;
import java.util.Scanner;

public class Baseball {
private final Input input;

public Baseball() {
Scanner scanner = new Scanner(System.in);
this.input = new Input(scanner);;
}

public void run() {
boolean isContinue = true;
while(isContinue){
isContinue = playGame();
}
}

private boolean playGame() {
NumberGenerator generator = new RandomNumberGenerator();
Computer computer = new Computer(generator);

boolean isContinue;
while (true) {
ArrayList<Integer> numbers = input.inputNumbers();
Result result = computer.checkNumbers(numbers);

if (result.isAllStrike()) {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝");
break;
}
Output.printResult(result);
}

isContinue = input.inputContinue();
return isContinue;
}
}
38 changes: 38 additions & 0 deletions src/main/java/Computer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import java.util.List;
import java.util.Objects;

public class Computer {
private final List<Integer> numbers;

public Computer(NumberGenerator generator) {
this.numbers = generator.generate();
}

public Result checkNumbers(List<Integer> inputNumbers) {
int strikeCount = countStrike(inputNumbers);
int ballCount = countBall(inputNumbers);

return new Result(strikeCount, ballCount);
}

private int countStrike(List<Integer> inputNumbers) {
int count = 0;
for (int i = 0; i < numbers.size(); i++) {
if (Objects.equals(numbers.get(i), inputNumbers.get(i))) {
count++;
}
}
return count;
}

private int countBall(List<Integer> inputNumbers) {
int count = 0;
for (int i = 0; i < inputNumbers.size(); i++) {
int num = inputNumbers.get(i);
if (numbers.contains(num) && numbers.get(i) != num) {
count++;
}
}
return count;
}
}
92 changes: 92 additions & 0 deletions src/main/java/Input.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import java.util.ArrayList;
import java.util.Scanner;

public class Input {

private final Scanner scanner;

public Input(Scanner scanner) {
this.scanner = scanner;
}

public ArrayList<Integer> inputNumbers() {
while (true) {
try {
System.out.print("숫자를 입력해주세요 : ");
String input = scanner.next();
return validateInputNumber(input);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

public boolean inputContinue() {
while (true) {
try {
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
String input = scanner.next();
return validateContinue(input);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

private ArrayList<Integer> validateInputNumber(String input) {
if (input == null || input.length() != 3) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
if (!isAllNumbers(input)) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
if (hasDuplicateNumbers(input)) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
return convertStringToNumbers(input);
}

private boolean isAllNumbers(String input) {
for (int i = 0; i < input.length(); i++) {
if (!Character.isDigit(input.charAt(i))) {
return false;
}
}
return true;
}

private boolean hasDuplicateNumbers(String input) {
boolean[] used = new boolean[10];

for (int i = 0; i < input.length(); i++) {
int num = Character.getNumericValue(input.charAt(i));
if (used[num]) {
return true;
}
used[num] = true;
}
return false;
}

private ArrayList<Integer> convertStringToNumbers(String input) {
ArrayList<Integer> numbers = new ArrayList<>();
for (int i = 0; i < input.length(); i++) {
numbers.add(Character.getNumericValue(input.charAt(i)));
}
return numbers;
}

private boolean validateContinue(String input) {
if (input == null || input.length() != 1) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
if (!Character.isDigit(input.charAt(0))) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
int inputNumber = Character.getNumericValue(input.charAt(0));
if (inputNumber != 1 && inputNumber != 2) {
throw new IllegalArgumentException("[ERROR] Invalid input");
}
return inputNumber == 1;
}
}
6 changes: 6 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
public class Main {
public static void main(String[] args) {
Baseball baseball = new Baseball();
baseball.run();
}
}
5 changes: 5 additions & 0 deletions src/main/java/NumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import java.util.List;

public interface NumberGenerator {
List<Integer> generate();
}
16 changes: 16 additions & 0 deletions src/main/java/Output.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
public class Output {
public static void printResult(Result result){
int strikeCount = result.strikeCount();
int ballCount = result.ballCount();
if(strikeCount > 0){
System.out.printf("%d스트라이크 ", strikeCount);
}
if(ballCount > 0){
System.out.printf("%d볼 ", ballCount);
}
if(strikeCount == 0 && ballCount == 0){
System.out.print("낫싱");
}
System.out.println();
}
}
16 changes: 16 additions & 0 deletions src/main/java/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class RandomNumberGenerator implements NumberGenerator {

@Override
public List<Integer> generate() {
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i <= 9; i++) {
numbers.add(i);
}
Collections.shuffle(numbers);
return numbers.subList(0, 3);
}
}
6 changes: 6 additions & 0 deletions src/main/java/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
public record Result(int strikeCount, int ballCount) {

public Boolean isAllStrike() {
return strikeCount == 3;
}
}
84 changes: 84 additions & 0 deletions src/test/java/ComputerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class ComputerTest {
@Test
void allStrike_returns3Strike0Ball() {
// given
Computer computer = new Computer(
new FixedNumberGenerator(Arrays.asList(1, 2, 3))
);
List<Integer> input = Arrays.asList(1, 2, 3);

// when
Result result = computer.checkNumbers(input);

// then
assertEquals(3, result.strikeCount());
assertEquals(0, result.ballCount());
}

@Test
void oneStrike_oneBall() {
// secret: 4 2 5
// guess : 4 5 6
Computer computer = new Computer(
new FixedNumberGenerator(Arrays.asList(4, 2, 5))
);
List<Integer> input = Arrays.asList(4, 5, 6);

Result result = computer.checkNumbers(input);

assertEquals(1, result.strikeCount());
assertEquals(1, result.ballCount());
}

@Test
void onlyBalls_returns0Strike2Ball() {
// secret: 4 2 5
// guess : 2 4 6
Computer computer = new Computer(
new FixedNumberGenerator(Arrays.asList(4, 2, 5))
);
List<Integer> input = Arrays.asList(2, 4, 6);

Result result = computer.checkNumbers(input);

assertEquals(0, result.strikeCount());
assertEquals(2, result.ballCount());
}

@Test
void nothing_returns0Strike0Ball() {
// secret: 4 2 5
// guess : 7 8 9
Computer computer = new Computer(
new FixedNumberGenerator(Arrays.asList(4, 2, 5))
);
List<Integer> input = Arrays.asList(7, 8, 9);

Result result = computer.checkNumbers(input);

assertEquals(0, result.strikeCount());
assertEquals(0, result.ballCount());
}

@Test
void mixedCase_returnsCorrectCounts() {
// secret: 1 2 3
// guess : 1 3 2
Computer computer = new Computer(
new FixedNumberGenerator(Arrays.asList(1, 2, 3))
);
List<Integer> input = Arrays.asList(1, 3, 2);

Result result = computer.checkNumbers(input);

assertEquals(1, result.strikeCount());
assertEquals(2, result.ballCount());
}
}
15 changes: 15 additions & 0 deletions src/test/java/FixedNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import java.util.List;

public class FixedNumberGenerator implements NumberGenerator {

private final List<Integer> numbers;

public FixedNumberGenerator(List<Integer> numbers) {
this.numbers = numbers;
}

@Override
public List<Integer> generate() {
return numbers;
}
}
Loading