diff --git a/README.md b/README.md index 8d7e8aee..0a2c951c 100644 --- a/README.md +++ b/README.md @@ -1 +1,26 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + +## 기능 목록 +### Model +#### GameResultModel +1. 사용자가 입력한 숫자에 대한 결과의 관리 +2. 결과 출력을 위한 객체의 stringify +3. 승리 여부 판별 +### View +#### InputView +1. Scanner를 통해 사용자로부터 입력을 받아들이기 +2. 적절한 숫자인지 Validation +3. 적절한 명령인지 Validation +#### OutputView +1. 사용자가 입력한 숫자에 대한 결과 출력 +2. 사용자가 정답 입력 시 게임 지속에 대한 질문 출력 +### Controller +1 숫자 입력 / 지속 여부 입력 상태 관리 +2. 입력받은 숫자를 Judgement를 통해 결과 확인 및 출력 +3. 정답 입력 시 게임 지속 질문 출력 +4. 입력받은 답에 대해 프로그램 종료 혹은 2로 돌아감 +### Service +#### AnswerNumberGenerator +1. 게임의 정답으로 사용할 숫자의 생성 +#### Judgement +1. 입력된 숫자와 정답을 통해 GameResultModel 생성 \ No newline at end of file diff --git a/src/main/java/baseball/App.java b/src/main/java/baseball/App.java new file mode 100644 index 00000000..8f03c569 --- /dev/null +++ b/src/main/java/baseball/App.java @@ -0,0 +1,10 @@ +package baseball; + +import baseball.controller.Controller; + +public class App { + public static void main(String[] args) { + Controller controller = new Controller(); + controller.run(); + } +} diff --git a/src/main/java/baseball/controller/Controller.java b/src/main/java/baseball/controller/Controller.java new file mode 100644 index 00000000..f8d52c8d --- /dev/null +++ b/src/main/java/baseball/controller/Controller.java @@ -0,0 +1,68 @@ +package baseball.controller; + +import baseball.model.GameResultModel; +import baseball.service.AnswerNumberGenerator; +import baseball.service.Judgement; +import baseball.view.InputView; +import baseball.view.OutputView; + +public class Controller { + private InputView inputView; + private OutputView outputView; + private AnswerNumberGenerator answerNumberGenerator; + private Judgement judgement; + + public Controller() { + this.inputView = new InputView(); + this.outputView = new OutputView(); + this.answerNumberGenerator = new AnswerNumberGenerator(); + this.judgement = new Judgement(); + } + + public void run() { + while (true) { + int[] answerNumber = generateAnswerNumber(); + if (playGame(answerNumber)) { + break; + } + } + } + + private int[] generateAnswerNumber() { + return answerNumberGenerator.generateAnswerNumber(); + } + + private int[] getValidInputNumber() { + while (true) { + try { + return inputView.readNumberInput(); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + private int getValidCommandInput() { + while (true) { + try { + return inputView.readCommandInput(); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + private boolean playGame(int[] answerNumber) { + boolean isWin = false; + while (!isWin) { + int[] inputNumber = getValidInputNumber(); + GameResultModel gameResult = judgement.judge(answerNumber, inputNumber); + outputView.printResult(gameResult); + isWin = gameResult.isWin(); + } + outputView.printWinMessage(); + outputView.printContinueQuestion(); + int inputCommand = getValidCommandInput(); + return inputCommand == 2; + } +} diff --git a/src/main/java/baseball/model/GameResultModel.java b/src/main/java/baseball/model/GameResultModel.java new file mode 100644 index 00000000..4ddbe144 --- /dev/null +++ b/src/main/java/baseball/model/GameResultModel.java @@ -0,0 +1,39 @@ +package baseball.model; + +import baseball.service.AnswerNumberGenerator; + +public class GameResultModel { + private int strike; + private int ball; + + public GameResultModel(int strike, int ball) { + this.strike = strike; + this.ball = ball; + } + + public int getStrike() { + return strike; + } + + public int getBall() { + return ball; + } + + public boolean isWin() { + return strike == AnswerNumberGenerator.ANSWER_NUMBER_LENGTH; + } + + @Override + public String toString() { + if (strike == 0 && ball == 0) { + return "낫싱"; + } + if (strike == 0) { + return ball + "볼"; + } + if (ball == 0) { + return strike + "스트라이크"; + } + return strike + "스트라이크 " + ball + "볼"; + } +} diff --git a/src/main/java/baseball/service/AnswerNumberGenerator.java b/src/main/java/baseball/service/AnswerNumberGenerator.java new file mode 100644 index 00000000..a5e8ed97 --- /dev/null +++ b/src/main/java/baseball/service/AnswerNumberGenerator.java @@ -0,0 +1,19 @@ +package baseball.service; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class AnswerNumberGenerator { + public static final int ANSWER_NUMBER_LENGTH = 3; + public int[] generateAnswerNumber() { + Integer[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + List numberList = Arrays.asList(numbers); + Collections.shuffle(numberList); + int[] answerNumber = new int[ANSWER_NUMBER_LENGTH]; + for (int i = 0; i < ANSWER_NUMBER_LENGTH; i++) { + answerNumber[i] = numberList.get(i); + } + return answerNumber; + } +} diff --git a/src/main/java/baseball/service/Judgement.java b/src/main/java/baseball/service/Judgement.java new file mode 100644 index 00000000..98e93a13 --- /dev/null +++ b/src/main/java/baseball/service/Judgement.java @@ -0,0 +1,39 @@ +package baseball.service; + +import baseball.model.GameResultModel; + +public class Judgement { + public GameResultModel judge(int[] answerNumber, int[] inputNumber) { + int strike = countStrike(answerNumber, inputNumber); + int ball = countBall(answerNumber, inputNumber); + return new GameResultModel(strike, ball); + } + + private int countStrike(int[] answerNumber, int[] inputNumber) { + int strike = 0; + for (int i = 0; i < answerNumber.length; i++) { + if (answerNumber[i] == inputNumber[i]) { + strike++; + } + } + return strike; + } + + private int countBall(int[] answerNumber, int[] inputNumber) { + int ball = 0; + for (int i = 0; i < answerNumber.length; i++) { + ball += countBallForPosition(answerNumber, inputNumber, i); + } + return ball; + } + + private int countBallForPosition(int[] answerNumber, int[] inputNumber, int position) { + int ball = 0; + for (int j = 0; j < inputNumber.length; j++) { + if (answerNumber[position] == inputNumber[j] && position != j) { + ball++; + } + } + return ball; + } +} diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java new file mode 100644 index 00000000..5c4c39cc --- /dev/null +++ b/src/main/java/baseball/view/InputView.java @@ -0,0 +1,48 @@ +package baseball.view; + +import java.util.Scanner; + +public class InputView { + private Scanner scanner; + + public InputView() { + this.scanner = new Scanner(System.in); + } + + public int[] readNumberInput() { + System.out.print("숫자를 입력해주세요 : "); + String input = scanner.nextLine(); + if (!validateNumberInput(input)) { + throw new IllegalArgumentException("[Error] Invalid number input"); + } + return parseNumberInput(input); + } + + private boolean validateNumberInput(String input) { + return input.matches("^[1-9]{3}$"); + } + + private int[] parseNumberInput(String input) { + int[] numbers = new int[input.length()]; + for (int i = 0; i < input.length(); i++) { + numbers[i] = Character.getNumericValue(input.charAt(i)); + } + return numbers; + } + + public int readCommandInput() { + String input = scanner.nextLine(); + if (!validateCommandInput(input)) { + throw new IllegalArgumentException("[Error] Invalid command input"); + } + return parseCommandInput(input); + } + + public boolean validateCommandInput(String input) { + return input.matches("^[1-2]$"); + } + + public int parseCommandInput(String input) { + return Integer.parseInt(input); + } +} diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java new file mode 100644 index 00000000..2612cb81 --- /dev/null +++ b/src/main/java/baseball/view/OutputView.java @@ -0,0 +1,17 @@ +package baseball.view; + +import baseball.model.GameResultModel; + +public class OutputView { + public void printResult(GameResultModel gameResult) { + System.out.println(gameResult.toString()); + } + + public void printWinMessage() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); + } + + public void printContinueQuestion() { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + } +} diff --git a/src/test/java/baseball/model/GameResultModelTest.java b/src/test/java/baseball/model/GameResultModelTest.java new file mode 100644 index 00000000..82acaa8e --- /dev/null +++ b/src/test/java/baseball/model/GameResultModelTest.java @@ -0,0 +1,50 @@ +package baseball.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class GameResultModelTest { + @Test + @DisplayName("GameResultModel 생성 테스트") + public void testConstructor() { + GameResultModel gameResultModel = new GameResultModel(1, 2); + assertThat(gameResultModel.getStrike()).isEqualTo(1); + assertThat(gameResultModel.getBall()).isEqualTo(2); + } + + @Test + @DisplayName("GameResultModel 승리 여부 검증 테스트") + public void testIsWin() { + GameResultModel gameResultModel = new GameResultModel(3, 0); + assertThat(gameResultModel.isWin()).isTrue(); + } + + @Test + @DisplayName("GameResultModel 낫싱 출력 검증 테스트") + public void testToStringWhenNothing() { + GameResultModel gameResultModel = new GameResultModel(0, 0); + assertThat(gameResultModel.toString()).isEqualTo("낫싱"); + } + + @Test + @DisplayName("GameResultModel 볼 출력 검증 테스트") + public void testToStringWhenBall() { + GameResultModel gameResultModel = new GameResultModel(0, 1); + assertThat(gameResultModel.toString()).isEqualTo("1볼"); + } + + @Test + @DisplayName("GameResultModel 스트라이크 출력 검증 테스트") + public void testToStringWhenStrike() { + GameResultModel gameResultModel = new GameResultModel(1, 0); + assertThat(gameResultModel.toString()).isEqualTo("1스트라이크"); + } + + @Test + @DisplayName("GameResultModel 볼과 스트라이크 출력 검증 테스트") + public void testToStringWhenBallAndStrike() { + GameResultModel gameResultModel = new GameResultModel(1, 1); + assertThat(gameResultModel.toString()).isEqualTo("1스트라이크 1볼"); + } +} diff --git a/src/test/java/baseball/service/AnswerNumberGeneratorTest.java b/src/test/java/baseball/service/AnswerNumberGeneratorTest.java new file mode 100644 index 00000000..54487c39 --- /dev/null +++ b/src/test/java/baseball/service/AnswerNumberGeneratorTest.java @@ -0,0 +1,16 @@ +package baseball.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class AnswerNumberGeneratorTest { + @Test + @DisplayName("AnswerNumberGenerator 생성 테스트") + public void testGenerateAnswerNumber() { + AnswerNumberGenerator answerNumberGenerator = new AnswerNumberGenerator(); + int[] answerNumber = answerNumberGenerator.generateAnswerNumber(); + assertThat(answerNumber).hasSize(3); + assertThat(answerNumber).doesNotHaveDuplicates(); + } +} diff --git a/src/test/java/baseball/service/JudgementTest.java b/src/test/java/baseball/service/JudgementTest.java new file mode 100644 index 00000000..86a50d25 --- /dev/null +++ b/src/test/java/baseball/service/JudgementTest.java @@ -0,0 +1,55 @@ +package baseball.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +import baseball.model.GameResultModel; + +public class JudgementTest { + @Test + @DisplayName("Judgement 생성 테스트") + public void testConstructor() { + Judgement judgement = new Judgement(); + assertThat(judgement).isNotNull(); + } + + @Test + @DisplayName("Judgement 스트라이크, 볼 카운트 검증 테스트") + public void testCountStrikeAndBall() { + Judgement judgement = new Judgement(); + int[] answerNumber; + int[] inputNumber; + GameResultModel gameResult; + + answerNumber = new int[] {1, 2, 3}; + inputNumber = new int[] {1, 2, 4}; + gameResult = judgement.judge(answerNumber, inputNumber); + assertThat(gameResult.getStrike()).isEqualTo(2); + assertThat(gameResult.getBall()).isEqualTo(0); + + answerNumber = new int[] {1, 2, 3}; + inputNumber = new int[] {3, 1, 4}; + gameResult = judgement.judge(answerNumber, inputNumber); + assertThat(gameResult.getStrike()).isEqualTo(0); + assertThat(gameResult.getBall()).isEqualTo(2); + + answerNumber = new int[] {1, 2, 3}; + inputNumber = new int[] {4, 5, 6}; + gameResult = judgement.judge(answerNumber, inputNumber); + assertThat(gameResult.getStrike()).isEqualTo(0); + assertThat(gameResult.getBall()).isEqualTo(0); + + answerNumber = new int[] {1, 2, 3}; + inputNumber = new int[] {1, 2, 3}; + gameResult = judgement.judge(answerNumber, inputNumber); + assertThat(gameResult.getStrike()).isEqualTo(3); + assertThat(gameResult.getBall()).isEqualTo(0); + + answerNumber = new int[] {1, 2, 3}; + inputNumber = new int[] {2, 3, 1}; + gameResult = judgement.judge(answerNumber, inputNumber); + assertThat(gameResult.getStrike()).isEqualTo(0); + assertThat(gameResult.getBall()).isEqualTo(3); + } +}