diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java index dd95a34..63d8aee 100644 --- a/src/main/java/baseball/Application.java +++ b/src/main/java/baseball/Application.java @@ -1,7 +1,13 @@ package baseball; +import baseball.config.GameConfig; +import baseball.controller.GameController; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + GameConfig gameConfig = new GameConfig(); + GameController gameController = gameConfig.getGameComputer(); + + gameController.start(); } -} +} \ No newline at end of file diff --git a/src/main/java/baseball/common/constant/Constants.java b/src/main/java/baseball/common/constant/Constants.java new file mode 100644 index 0000000..12f8a74 --- /dev/null +++ b/src/main/java/baseball/common/constant/Constants.java @@ -0,0 +1,12 @@ +package baseball.common.constant; + +public class Constants { + public final static int MIN_NUMBER = 1; + public final static int MAX_NUMBER = 9; + public final static int NUMBERS_SIZE = 3; + + public final static String WHITE_SPACE = " "; + public final static String STRIKE = "%d스트라이크"; + public final static String BALL = "%d볼"; + public final static String NOTHING = "낫싱"; +} diff --git a/src/main/java/baseball/config/GameConfig.java b/src/main/java/baseball/config/GameConfig.java new file mode 100644 index 0000000..e7e3963 --- /dev/null +++ b/src/main/java/baseball/config/GameConfig.java @@ -0,0 +1,20 @@ +package baseball.config; + +import baseball.controller.GameController; +import baseball.view.InputView; +import baseball.view.OutputView; + +public class GameConfig { + + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + private final GameController gameController; + + public GameConfig() { + this.gameController = new GameController(inputView, outputView); + } + + public GameController getGameComputer() { + return gameController; + } +} diff --git a/src/main/java/baseball/controller/GameController.java b/src/main/java/baseball/controller/GameController.java new file mode 100644 index 0000000..6779cc3 --- /dev/null +++ b/src/main/java/baseball/controller/GameController.java @@ -0,0 +1,67 @@ +package baseball.controller; + +import baseball.model.domain.ComputerNumbers; +import baseball.model.domain.GameMenu; +import baseball.model.domain.PlayerNumbers; +import baseball.model.domain.Result; +import baseball.view.InputView; +import baseball.view.OutputView; + +public class GameController { + private final InputView inputView; + private final OutputView outputView; + + public GameController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void start() { + try { + boolean isContinue = true; + outputView.printStartMessage(); + while (isContinue) { + play(); + isContinue = restart(); + } + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + private void play() { + boolean isFinish = false; + ComputerNumbers computerNumbers = init(); + while (!isFinish) { + PlayerNumbers playerNumbers = input(); + isFinish = result(computerNumbers, playerNumbers); + } + finish(); + } + + private ComputerNumbers init() { + return new ComputerNumbers(); + } + + private PlayerNumbers input() { + outputView.printNumberPrompt(); + String input = inputView.getNumber(); + return new PlayerNumbers(input); + } + + private boolean result(ComputerNumbers computerNumbers, PlayerNumbers playerNumbers) { + Result result = computerNumbers.compare(playerNumbers); + outputView.printResultMessage(result.toString()); + return result.isCorrect(); + } + + private boolean restart() { + outputView.printRestartPrompt(); + String input = inputView.askRestart(); + return GameMenu.from(input); + } + + private void finish() { + outputView.printFinishMessage(); + } +} \ No newline at end of file diff --git a/src/main/java/baseball/model/domain/ComputerNumbers.java b/src/main/java/baseball/model/domain/ComputerNumbers.java new file mode 100644 index 0000000..c467ac6 --- /dev/null +++ b/src/main/java/baseball/model/domain/ComputerNumbers.java @@ -0,0 +1,47 @@ +package baseball.model.domain; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static baseball.common.constant.Constants.MAX_NUMBER; +import static baseball.common.constant.Constants.MIN_NUMBER; +import static baseball.common.constant.Constants.NUMBERS_SIZE; +import static camp.nextstep.edu.missionutils.Randoms.pickNumberInRange; + +public class ComputerNumbers { + private final List computerNumbers; + + public ComputerNumbers() { + this.computerNumbers = createRandomNumbers(); + } + + private List createRandomNumbers() { + Set randomNumbers = new HashSet<>(); + while (randomNumbers.size() < NUMBERS_SIZE) { + int randomNumber = pickNumberInRange(MIN_NUMBER, MAX_NUMBER); + randomNumbers.add(randomNumber); + } + return new ArrayList<>(randomNumbers); + } + + public Result compare(PlayerNumbers player) { + int strikes = 0; + int balls = 0; + + List playerNumbers = player.getPlayerNumbers(); + + for (int i = 0; i < NUMBERS_SIZE; i++) { + boolean isStrike = computerNumbers.get(i).equals(playerNumbers.get(i)); + boolean isBall = !isStrike && computerNumbers.contains(playerNumbers.get(i)); + if (isStrike) { + strikes++; + } + if (isBall) { + balls++; + } + } + return new Result(strikes, balls); + } +} diff --git a/src/main/java/baseball/model/domain/GameMenu.java b/src/main/java/baseball/model/domain/GameMenu.java new file mode 100644 index 0000000..fe1ca1c --- /dev/null +++ b/src/main/java/baseball/model/domain/GameMenu.java @@ -0,0 +1,28 @@ +package baseball.model.domain; + +import java.util.Arrays; + +public enum GameMenu { + RESTART("1", true), + QUIT("2", false); + + private final String code; + private final boolean countinue; + + GameMenu(String code, boolean countinue) { + this.code = code; + this.countinue = countinue; + } + + public static boolean from(String input) { + return Arrays.stream(GameMenu.values()) + .filter(menu -> menu.code.equals(input)) + .findFirst() + .map(GameMenu::isCountinue) + .orElseThrow(() -> new IllegalArgumentException("잘못된 메뉴 선택입니다.")); + } + + private boolean isCountinue() { + return countinue; + } +} \ No newline at end of file diff --git a/src/main/java/baseball/model/domain/PlayerNumbers.java b/src/main/java/baseball/model/domain/PlayerNumbers.java new file mode 100644 index 0000000..9dad2c1 --- /dev/null +++ b/src/main/java/baseball/model/domain/PlayerNumbers.java @@ -0,0 +1,56 @@ +package baseball.model.domain; + +import java.util.ArrayList; +import java.util.List; + +public class PlayerNumbers { + private final List playerNumbers; + + public PlayerNumbers(String input) { + this.playerNumbers = parse(input); + } + + private List parse(String input) { + List items = List.of(input.split("")); + List numbers = new ArrayList<>(); + for (String item : items) { + int number = parseNumber(item); + numbers.add(number); + } + validateNumbers(numbers); + return numbers; + } + + private int parseNumber(String input) { + try { + int number = Integer.parseInt(input); + validateNumber(number); + return number; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("입력값은 숫자여야 합니다."); + } + } + + private int validateNumber(int number) { + if (number < 1 || number > 9) { + throw new IllegalArgumentException("숫자는 1에서 9까지의 수만 허용됩니다."); + } + return number; + } + + private void validateNumbers(List numbers) { + if (numbers.size() != 3) { + throw new IllegalArgumentException("숫자 3자리를 입력해야 합니다."); + } + int uniqueCount = (int) numbers.stream() + .distinct() + .count(); + if (uniqueCount != 3) { + throw new IllegalArgumentException("중복된 숫자는 허용되지 않습니다."); + } + } + + public List getPlayerNumbers() { + return playerNumbers; + } +} diff --git a/src/main/java/baseball/model/domain/Result.java b/src/main/java/baseball/model/domain/Result.java new file mode 100644 index 0000000..4ffe91d --- /dev/null +++ b/src/main/java/baseball/model/domain/Result.java @@ -0,0 +1,35 @@ +package baseball.model.domain; + +import static baseball.common.constant.Constants.BALL; +import static baseball.common.constant.Constants.NOTHING; +import static baseball.common.constant.Constants.STRIKE; +import static baseball.common.constant.Constants.WHITE_SPACE; + +public class Result { + private final int strikes; + private final int balls; + + public Result(int strikes, int balls) { + this.strikes = strikes; + this.balls = balls; + } + + public boolean isCorrect() { + return strikes == 3; + } + + @Override + public String toString() { + if (strikes == 0 && balls == 0) { + return NOTHING; + } + StringBuilder result = new StringBuilder(); + if (balls > 0) { + result.append(BALL.formatted(balls)).append(WHITE_SPACE); + } + if (strikes > 0) { + result.append(STRIKE.formatted(strikes)); + } + return result.toString().trim(); + } +} diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java new file mode 100644 index 0000000..6e0b7e1 --- /dev/null +++ b/src/main/java/baseball/view/InputView.java @@ -0,0 +1,14 @@ +package baseball.view; + +import static camp.nextstep.edu.missionutils.Console.readLine; + +public class InputView { + + public String getNumber() { + return readLine(); + } + + public String askRestart() { + return readLine(); + } +} diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java new file mode 100644 index 0000000..d571941 --- /dev/null +++ b/src/main/java/baseball/view/OutputView.java @@ -0,0 +1,30 @@ +package baseball.view; + +public class OutputView { + private final static String ERROR = "[ERROR]%s"; + + public void printStartMessage() { + System.out.println("숫자 야구 게임을 시작합니다."); + } + + public void printNumberPrompt() { + System.out.print("숫자를 입력해주세요 : "); + } + + public void printResultMessage(String message) { + System.out.println(message); + } + + public void printFinishMessage() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + } + + public void printRestartPrompt() { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + } + + public void printErrorMessage(String message) { + System.out.println(ERROR.formatted(message)); + } + +}