Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
442ad43
docs : 야구 게임 구현을 위해 README.md에 기능 정리
Youngini May 5, 2024
3a696a8
docs : 기능 요구 사항 재정리
Youngini May 5, 2024
c3e102d
docs : 기능을 설명하기 위한 용어 변경
Youngini May 5, 2024
9318598
feat : 숫자 야구 게임의 핵심 로직을 담은 Game 클래스 정의
Youngini May 5, 2024
2f97ade
feat : 사용자가 선택한 숫자들을 관리하기 위한 클래스
Youngini May 5, 2024
27ad581
feat : 지정된 범위 내에서 서로 다른 랜덤 숫자들로 구성된 배열을 생성하는 클래스 정의
Youngini May 5, 2024
8bf50a7
feat : 서로 다른 랜덤 숫자들로 구성된 배열을 생성하는 클래스를 테스트하는 코드 작성
Youngini May 5, 2024
14ac5d6
feat : 사용자의 입력 문자열을 분석(parse)하여 정수 배열로 변환하는 클래스 작성
Youngini May 5, 2024
087e5b8
feat 사용자의 입력 문자열 parsing하는 클래스 기능 확인 및 예외 처리 기능 확인 코드 작성
Youngini May 5, 2024
17c0f74
feat : 사용자에게 문자열 입력 요청을 하고, 게임 종료 후 게임 리트라이를 묻는 view 코드 작성
Youngini May 6, 2024
73fcabf
feat : 낫싱, 볼, 스트라이크, 게임 종료 메세지를 보여주는 view 코드 작성
Youngini May 6, 2024
23324c4
feat : 낫싱, 볼, 스트라이크, 게임 종료 메세지 test 코드 작성
Youngini May 6, 2024
372082d
feat : 실제 숫자 야구 게임을 구현하는 service 코드 작성
Youngini May 6, 2024
7feb666
feat : 게임의 주요 흐름을 제어하는 controller
Youngini May 6, 2024
d3a0975
feat : 숫자 야구 게임 실행 시작 클래스 생성
Youngini May 6, 2024
6565b25
feat : 숫자 야구 게임 test를 위한 코드
Youngini May 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
# java-baseball-precourse
# java-baseball-precourse
## 기능 구현
### 1. 1~9까지의 서로 다른 임의의 수 3개 생성
### 2. 게임 플레이어에게 수를 입력 받음
1) 사용자 입력 검증
1-1) 사용자가 잘못된 값을 입력할 경우, IllegalArgumentException 을 발생시킨 후 애플리케이션은 종료
- 1 ~ 9가 아닌 다른 문자를 입력한 경우
- 1 ~ 9 사이의 숫자를 입력했지만 중복되는 수가 있는 경우

1-2) 사용자가 제대로 된 값을 입력한 경우, 게임을 진행함
- 1 ~ 9 사이의 서로 다른 임의의 수 3개인 경우

게임이 종료되기 전 까지 사용자에게 계속 값을 입력 받음

### 3. 게임 로직 처리
1) 컴퓨터가 생성한 값과 사용자가 입력한 값 중 일치하는 것이 있나 확인함
- 반복문을 통해 먼저 스트라이크가 존재하는지 확인
- 스트라이크가 있다면, 다음 index의 스트라이크 판단
- 스트라이크가 아닌 경우, 볼인지 판단
- 볼도 아니라면 다음 값으로 넘어가서 위의 과정 반복

2) 사용자가 입력한 값의 스트라이크 개수와 볼 개수 확인
- 스트라이크와 볼 개수를 더한 값이 0 : 낫싱
- 스트라이크와 볼 개수를 더한 값이 0이 아니라면, 스트라이크와 볼 수 출력

### 4. 게임을 종료한 후 게임을 다시 시작하거나 완전 종료할 수 있게 함
- 게임을 새로 시작하려면 1, 종료하려면 2룰 입력하개 함
- 1,2 가 아닌 값을 입력할 경우, 다시 입력하게 함
10 changes: 10 additions & 0 deletions src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package baseball;

import baseball.controller.BaseballGameController;

public class Application {
public static void main(String[] args) {
BaseballGameController controller = new BaseballGameController();
controller.run();
}
}
57 changes: 57 additions & 0 deletions src/main/java/baseball/controller/BaseballGameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package baseball.controller;

import baseball.service.GameService;
import baseball.view.GameMessage;
import baseball.view.RequestInput;
import java.util.Scanner;

public class BaseballGameController {
final int SIZE = 3;
final int START= 1;
final int END = 9;
final int RETRY = 1;
final int GAME_OVER = 2;

GameService gameService = new GameService();
private Scanner scanner = new Scanner(System.in);

public void run() throws IllegalArgumentException {
setGame();
startGame();
endGame();
askRetry();
}

private void setGame() {
gameService.setGame(SIZE, START, END);
}

private void startGame() throws IllegalArgumentException {
gameService.playGame();
}

private void endGame() {
GameMessage.printGameOverMessage();
}

/*
- 유저입력이 (문자 or 개수가 0 or 3 이상) : Exception
- 유저입력이 (1) : 재시작
- 유저입력이 (2) : 종료
*/
private void askRetry() throws IllegalArgumentException {
RequestInput.printRetryMessage();
if (getInputNum() == RETRY) {
run();
}
}

private int getInputNum() throws IllegalArgumentException {
int inputNum = Integer.parseInt(scanner.nextLine());

if (inputNum == 0 || inputNum > GAME_OVER) {
throw new IllegalArgumentException();
}
return inputNum;
}
}
36 changes: 36 additions & 0 deletions src/main/java/baseball/domain/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package baseball.domain;

public class Game {
int strikeCount;
int ballCount;
int[] gameNumbers;

public Game(int[] numbers) {
gameNumbers = numbers;
}

public void initBaseBall() {
strikeCount = 0;
ballCount = 0;
}

public int getStrikeCount() {
return strikeCount;
}

public int getBallCount() {
return ballCount;
}

public int[] getGameNumbers() {
return gameNumbers;
}

public void increaseStrikeCount() {
strikeCount += 1;
}

public void increaseBallCount() {
ballCount += 1;
}
}
13 changes: 13 additions & 0 deletions src/main/java/baseball/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package baseball.domain;

public class User {
int[] userNumbers;

public int[] getUserNumbers() {
return userNumbers;
}

public void setUserNumbers(int[] userNumbers) {
this.userNumbers = userNumbers;
}
}
70 changes: 70 additions & 0 deletions src/main/java/baseball/service/GameService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package baseball.service;

import baseball.domain.Game;
import baseball.domain.User;
import baseball.utils.Parse;
import baseball.utils.GenerateRandomNum;
import baseball.view.RequestInput;
import baseball.view.GameMessage;
import java.util.Scanner;

public class GameService {

int size;
Game game;
User user = new User();
Parse parser = new Parse();
GameMessage systemMessage = new GameMessage();
private final Scanner scanner = new Scanner(System.in);
public void setGame(int size, int start, int end) {
this.size = size;
game = new Game(GenerateRandomNum.getRandomNumbers(size, start, end));
}

public void playGame() {
int strike = 0;
while (strike != 3) {
play();
systemMessage.printScoreMessage(game.getBallCount(), game.getStrikeCount());
strike = game.getStrikeCount();
}
}

private void play() {
game.initBaseBall();
user.setUserNumbers(getUserNumber());
computeScore();
}

private int[] getUserNumber() throws IllegalArgumentException {
RequestInput.requestInputData();
String input = scanner.nextLine();
return parser.parseUserInput(input, size);
}

private void computeScore() {
for (int i = 0; i < size; i++) {
compute(game.getGameNumbers(), user.getUserNumbers(), i);
}
}

private void compute(int[] gameNumber, int[] userNumber, int index) {
int temp = -1;
for (int i = 0; i < gameNumber.length; i++) {
if (gameNumber[i] == userNumber[index]) {
temp = i;
break;
}
}
increaseCount(index, temp);
}

private void increaseCount(int index, int temp) {
if (temp != index && temp != -1) {
game.increaseBallCount();
}
if (temp == index) {
game.increaseStrikeCount();
}
}
}
33 changes: 33 additions & 0 deletions src/main/java/baseball/utils/GenerateRandomNum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package baseball.utils;

import java.util.Random;
public class GenerateRandomNum {
private static final Random random = new Random();
public static int[] getRandomNumbers(int size, int start, int end) {
int[] numbers = new int[size];

for (int i = 0; i < size; i++) {
numbers[i] = getUniqueRandomNumber(numbers, start, end, i);
}
return numbers;
}

private static int getUniqueRandomNumber(int[] numbers, int start, int end, int i) {
// start와 end 사이의 랜덤 숫자 생성
int randomNumber = start + random.nextInt(end - start + 1);
while (!isUnique(numbers, i, randomNumber)) {
// 랜덤 숫자가 유니크하지 않으면 새로운 랜덤 숫자 생성
randomNumber = start + random.nextInt(end - start + 1);
}
return randomNumber;
}

private static Boolean isUnique(int[] numbers, int i, int randomNumber) {
for (int j = 0; j < i; j++) {
if (numbers[j] == randomNumber) {
return false;
}
}
return true;
}
}
35 changes: 35 additions & 0 deletions src/main/java/baseball/utils/Parse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package baseball.utils;

public class Parse {

public int[] parseUserInput(String input, int size) throws IllegalArgumentException {
checkSize(input, size);
return getParseInt(input, size);
}

private void checkSize(String input, int size) throws IllegalArgumentException {
if (input.length() != size) {
throw new IllegalArgumentException();
}
}

private int[] getParseInt(String input, int size) throws IllegalArgumentException {
int[] parseInt = new int[size];

for (int i = 0; i < input.length(); i++) {
if (!checkDigit(input, i)) {
throw new IllegalArgumentException();
}
parseInt[i] = convertCharToInt(input, i);
}
return parseInt;
}

private int convertCharToInt(String input, int i) {
return input.charAt(i) - '0';
}

private Boolean checkDigit(String input, int i) {
return '0' <= input.charAt(i) && input.charAt(i) <= '9';
}
}
22 changes: 22 additions & 0 deletions src/main/java/baseball/view/GameMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package baseball.view;

public class GameMessage {
public void printScoreMessage(int ball, int strike) {
if (ball == 0 && strike == 0) {
System.out.println("낫싱");
}
if (ball == 0 && strike != 0) {
System.out.println(strike + "스트라이크");
}
if (ball != 0 && strike == 0) {
System.out.println(ball + "볼");
}
if (ball != 0 && strike != 0) {
System.out.println(ball + "볼 " + strike + "스트라이크");
}
}

public static void printGameOverMessage() {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
}
}
12 changes: 12 additions & 0 deletions src/main/java/baseball/view/RequestInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package baseball.view;

public class RequestInput {

public static void requestInputData() {
System.out.print("숫자를 입력해 주세요 : ");
}

public static void printRetryMessage() {
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
}
}
48 changes: 48 additions & 0 deletions src/test/java/baseball/ApplicationTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package baseball;

import baseball.view.GameMessage;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

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

public class ApplicationTest {

private final PrintStream standardOut = System.out;
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();

@BeforeEach
public void setUp() {
System.setOut(new PrintStream(outputStreamCaptor));
}

@AfterEach
public void tearDown() {
System.setOut(standardOut);
}

@Test
public void testPrintScoreMessage() {
GameMessage gameMessage = new GameMessage();
gameMessage.printScoreMessage(0, 0);
assertTrue(outputStreamCaptor.toString().trim().equals("낫싱"));

outputStreamCaptor.reset(); // 스트림 초기화

gameMessage.printScoreMessage(1, 2);
assertTrue(outputStreamCaptor.toString().trim().equals("1볼 2스트라이크"));
}

@Test
public void testPrintGameOverMessage() {
GameMessage.printGameOverMessage();
assertTrue(outputStreamCaptor.toString().trim().equals("3개의 숫자를 모두 맞히셨습니다! 게임 종료"));
}

// RequestInput에 대한 테스트는 복잡성으로 인해 여기서 다루지 않습니다.
// 일반적으로 표준 입력을 직접 다루는 것은 테스트에서 권장되지 않습니다.
}
Loading