Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
# java-baseball-precourse
# java-baseball-precourse

### 문제
- 기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.
- 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를
얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
- [예] 상대방(컴퓨터)의 수가 425일 때, 123을 제시한 경우 : 1스트라이크, 456을 제시한 경우 : 1스트라이크 1볼,
789를 제시한 경우 : 낫싱
- 위 숫자 야구게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
- 사용자가 잘못된 값을 입력할 경우 [ERROR]로 시작하는 에러 메시지를 출력하고 게임을 계속 진행할 수 있어야

### 구조
- 입력기 (controller)
- 출력기 (view)
- baseball 판독기 (model)
- baseball 정답 생성기 (model)
- baseball 게임 진행 (model)
- 에러 핸들러

### 기능 요구사항
- [X] baseball 정답 생성
- [X] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다.
- 제약 사항: 1부터 9까지만, 정답 길이 3
- [X] baseball 정답 판독
- [X] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 반환합니다.
- [X] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다.
- [X] baseball 게임 진행
- [X] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다.
- [X] 게임이 진행중이 아니라면 1의 입력의 경우 정답 생성을 요청하고, 숫자 입력을 요구합니다.
- [X] 게임이 진행중이 아니라면 2의 입력의 경우 게임을 종료합니다.
- [X] 입력기
- [X] 출력기
10 changes: 10 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import config.GameConfig;
import controller.GameController;

public class Main {

public static void main(String[] args) {
GameController gameController = new GameConfig().gameController();
gameController.run();
}
}
27 changes: 27 additions & 0 deletions src/main/java/config/GameConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package config;

import controller.GameController;
import model.BaseballAnswerGenerator;
import model.BaseballAnswerJudge;
import model.BaseballGameManager;
import model.BaseballInputValidator;
import view.OutputView;

public class GameConfig {

public GameController gameController() {
return new GameController(
gameManager(),
new BaseballInputValidator(),
new OutputView()
);
}

private BaseballGameManager gameManager() {
return new BaseballGameManager(
new BaseballAnswerGenerator(),
new BaseballAnswerJudge()
);
}

}
9 changes: 9 additions & 0 deletions src/main/java/constant/GameConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package constant;

public class GameConstants {
public static final int ANSWER_LENGTH = 3;
public static final int MIN_DIGIT = 1;
public static final int MAX_DIGIT = 9;
public static final char EXCLUDED_DIGIT = '0';
public static final String RESTART_COMMAND = "1";
}
16 changes: 16 additions & 0 deletions src/main/java/constant/GameMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package constant;

public class GameMessages {
public static final String GAME_START = "숫자 야구 게임을 시작합니다.";
public static final String INPUT_PROMPT = "숫자를 입력해주세요 : ";
public static final String NOTHING = "낫싱";
public static final String BALL = "볼";
public static final String STRIKE = "스트라이크";
public static final String GAME_WON = "3개의 숫자를 모두 맞히셨습니다! 게임 종료";
public static final String RESTART_PROMPT = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";

public static final String ERROR_INVALID_LENGTH = "[ERROR] 3자리 숫자를 입력해주세요.";
public static final String ERROR_NOT_DIGIT = "[ERROR] 숫자만 입력해주세요.";
public static final String ERROR_INVALID_RANGE = "[ERROR] 1부터 9까지의 숫자만 입력해주세요.";
public static final String ERROR_DUPLICATE = "[ERROR] 중복되지 않는 숫자를 입력해주세요.";
}
57 changes: 57 additions & 0 deletions src/main/java/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package controller;

import constant.GameConstants;
import model.GameManager;
import model.InputValidator;
import view.OutputView;

import java.util.Scanner;

public class GameController {

private final GameManager gameManager;
private final InputValidator inputValidator;
private final OutputView outputView;
private final Scanner scanner;

public GameController(GameManager gameManager, InputValidator inputValidator, OutputView outputView) {
this.gameManager = gameManager;
this.inputValidator = inputValidator;
this.outputView = outputView;
this.scanner = new Scanner(System.in);
}

public void run() {
outputView.printGameStart();
while (true) {
playGame();
if (!askRestart()) break;
}
}

private void playGame() {
gameManager.startGame();
while (gameManager.isPlaying()) {
outputView.printInputPrompt();
String input = scanner.nextLine();
processGuess(input);
}
outputView.printGameWon();
}

private void processGuess(String input) {
try {
inputValidator.validate(input);
int[] result = gameManager.guess(input);
outputView.printResult(result[0], result[1]);
} catch (IllegalArgumentException e) {
outputView.printError(e.getMessage());
}
}

private boolean askRestart() {
outputView.printRestartPrompt();
String input = scanner.nextLine();
return input.equals(GameConstants.RESTART_COMMAND);
}
}
7 changes: 7 additions & 0 deletions src/main/java/model/AnswerGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package model;

public interface AnswerGenerator {

String generateAnswer();

}
8 changes: 8 additions & 0 deletions src/main/java/model/AnswerJudge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package model;

public interface AnswerJudge {

Integer countStrikes(String input, String answer);

Integer countBalls(String input, String answer);
}
29 changes: 29 additions & 0 deletions src/main/java/model/BaseballAnswerGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package model;

import constant.GameConstants;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;

public class BaseballAnswerGenerator implements AnswerGenerator {

@Override
public String generateAnswer() {
Set<Integer> numbers = new HashSet<>();

while (numbers.size() < GameConstants.ANSWER_LENGTH) {
numbers.add(ThreadLocalRandom.current().nextInt(
GameConstants.MIN_DIGIT,
GameConstants.MAX_DIGIT + 1
));
}

StringBuilder answer = new StringBuilder();
for (int n : numbers) {
answer.append(n);
}

return answer.toString();
}
}
29 changes: 29 additions & 0 deletions src/main/java/model/BaseballAnswerJudge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package model;

import constant.GameConstants;

public class BaseballAnswerJudge implements AnswerJudge {

@Override
public Integer countStrikes(String input, String answer) {
int result = 0;
for (int index = 0; index < GameConstants.ANSWER_LENGTH; index++) {
if (input.charAt(index) == answer.charAt(index)) {
result++;
}
}
return result;
}

@Override
public Integer countBalls(String input, String answer) {
int result = 0;
for (int index = 0; index < GameConstants.ANSWER_LENGTH; index++) {
char item = input.charAt(index);
if (item != answer.charAt(index) && answer.indexOf(item) != -1) {
result++;
}
}
return result;
}
}
48 changes: 48 additions & 0 deletions src/main/java/model/BaseballGameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package model;

import constant.GameConstants;

public class BaseballGameManager implements GameManager {
private final AnswerGenerator answerGenerator;
private final AnswerJudge answerJudge;
private String answer;
private boolean playing;
private boolean gameWon;

public BaseballGameManager(AnswerGenerator answerGenerator, AnswerJudge answerJudge) {
this.answerGenerator = answerGenerator;
this.answerJudge = answerJudge;
this.playing = false;
this.gameWon = false;
}

@Override
public void startGame() {
this.answer = answerGenerator.generateAnswer();
this.playing = true;
this.gameWon = false;
}

@Override
public int[] guess(String input) {
int strikes = answerJudge.countStrikes(input, answer);
int balls = answerJudge.countBalls(input, answer);

if (strikes == GameConstants.ANSWER_LENGTH) {
this.playing = false;
this.gameWon = true;
}

return new int[]{strikes, balls};
}

@Override
public boolean isPlaying() {
return playing;
}

@Override
public boolean isGameWon() {
return gameWon;
}
}
49 changes: 49 additions & 0 deletions src/main/java/model/BaseballInputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package model;

import constant.GameConstants;
import constant.GameMessages;

import java.util.HashSet;
import java.util.Set;

public class BaseballInputValidator implements InputValidator {

@Override
public void validate(String input) {
validateLength(input);
validateDigitsOnly(input);
validateRange(input);
validateNoDuplicates(input);
}

private void validateLength(String input) {
if (input.length() != GameConstants.ANSWER_LENGTH) {
throw new IllegalArgumentException(GameMessages.ERROR_INVALID_LENGTH);
}
}

private void validateDigitsOnly(String input) {
for (char c : input.toCharArray()) {
if (!Character.isDigit(c)) {
throw new IllegalArgumentException(GameMessages.ERROR_NOT_DIGIT);
}
}
}

private void validateRange(String input) {
for (char c : input.toCharArray()) {
if (c == GameConstants.EXCLUDED_DIGIT) {
throw new IllegalArgumentException(GameMessages.ERROR_INVALID_RANGE);
}
}
}

private void validateNoDuplicates(String input) {
Set<Character> seen = new HashSet<>();
for (char c : input.toCharArray()) {
if (!seen.add(c)) {
throw new IllegalArgumentException(GameMessages.ERROR_DUPLICATE);
}
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/model/GameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package model;

public interface GameManager {

void startGame();

int[] guess(String input);

boolean isPlaying();

boolean isGameWon();

}
7 changes: 7 additions & 0 deletions src/main/java/model/InputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package model;

public interface InputValidator {

void validate(String input);

}
Loading