Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
28799a8
feat(view): 게임 시작 메시지 출력 메서드 printNumberPrompt 추가
023-dev Nov 18, 2024
8be4def
feat(view): 숫자 입력 프롬프트 메시지 출력 메서드 printNumberPrompt 추가
023-dev Nov 18, 2024
7592c7a
feat(view): 에러 메시지 출력 메서드 printError 추가
023-dev Nov 18, 2024
7aefda6
feat(view): 숫자 입력 메서드 getNumber 추가
023-dev Nov 18, 2024
f1e64ca
feat(view): 게임 종료 메시지 출력 메서드 printEndMessage 추가
023-dev Nov 18, 2024
ae729c6
feat(view): 게임 재시작 입력 메서드 askRestart 추가
023-dev Nov 18, 2024
703b929
feat(view): 게임 재시작 프롬프트 출력 메서드 printRestartPrompt 추가
023-dev Nov 18, 2024
a2a6689
feat(view): getNumber, askRestart 반환값 추가
023-dev Nov 18, 2024
348a827
feat(controller): 게임을 관리할 클래스 GameComputer 추가
023-dev Nov 18, 2024
92cc2c0
feat(controller): 게임 시작 메서드 start 추가
023-dev Nov 18, 2024
754b5b8
feat(controller): 게임 플레이 메서드 play 추가
023-dev Nov 18, 2024
1659cfc
feat(domain): 게임 메뉴 관리를 위한 클래스 GameMenu 추가
023-dev Nov 18, 2024
a04f212
feat(domain): GameMenu에 재시작 여부 판단 로직 추가
023-dev Nov 18, 2024
d52c1d4
feat(controller): 게임 재시작 메서드 restart 추가
023-dev Nov 18, 2024
6a2146b
feat(controller): 숫자 입력 메서드 input 추가
023-dev Nov 18, 2024
b6e80f2
feat(config): 의존성 주입에 대한 책임 분리를 위한 클래스 GameConfig 추가
023-dev Nov 18, 2024
137c58a
feat(config): GameComputer Getter 메서드 getGameComputer 추가
023-dev Nov 18, 2024
128ef27
feat(main): GameConfig 초기화 및 게임 시작 로직 추가
023-dev Nov 18, 2024
5686309
refactor(view): printEndMessage -> printFinishMessaage 메서드 이름 변경
023-dev Nov 18, 2024
3cae7bd
feat(controller): 게임 종료 메서드 추가
023-dev Nov 18, 2024
4fef63b
feat(domain): 게임에서 숫자를 관리하는 클래스 GameNumber 추가
023-dev Nov 18, 2024
88c5e12
feat(domain): GameNumbe들을 관리하는 일급 컬렉션 클래스 GameNumbers 추가
023-dev Nov 18, 2024
04bd94e
feat(domain): GameNumber에 대한 검증 로직 및 메서드 parse 추가
023-dev Nov 18, 2024
af8c084
feat(domain): GameNumber에 대한 Getter 메서드 getNumber 추가
023-dev Nov 18, 2024
1e34c4b
feat(domain): GameNumbers에 대한 검증 로직 및 메서드 parse 추가
023-dev Nov 18, 2024
d122140
feat(domain): ComputerNumbers 생성 로직 추가
023-dev Nov 18, 2024
985b88e
feat(domain): PlayerNumbers 생성자 추가
023-dev Nov 18, 2024
f9fea8d
refactor(domain): createRandomNumbers -> printComputerNumbers 메서드 이름 변경
023-dev Nov 18, 2024
2f64bfe
refactor(controller): GameComputer -> GameController 클래스 이름 변경
023-dev Nov 18, 2024
024f59e
feat(controller): 입력된 숫자와 컴퓨터 숫자 비교하는 로직 추가
023-dev Nov 18, 2024
3eb1df7
refactor(domain): 오버 엔지니어링 방지를 위한 코드 응집 및 클래스 제거
023-dev Nov 18, 2024
1232aad
feat(constant): 상수 값 관리를 위한 클래스 Constants 추가
023-dev Nov 18, 2024
ba53a04
feat(controller): 에러 메시지 처리를 위한 메서드 error 추가
023-dev Nov 18, 2024
1b60c7b
fix(constant): 상수값 수정 '스트라이커' -> '스트라이크'
023-dev Nov 18, 2024
a3cbd69
style: 코드 컨벤션에 맞게 코드 재정렬
023-dev Nov 18, 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
10 changes: 8 additions & 2 deletions src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/baseball/common/constant/Constants.java
Original file line number Diff line number Diff line change
@@ -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 = "낫싱";
Comment on lines +8 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 상수들은 위 상수들과는 조금 다르게 출력에 초점을 맞추고 있는 상수들이에요. 상수도 분리해서 관리하면 어떨까요?

}
20 changes: 20 additions & 0 deletions src/main/java/baseball/config/GameConfig.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
67 changes: 67 additions & 0 deletions src/main/java/baseball/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -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();
Comment on lines +24 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드가 아주 보기 좋게 잘려있으니 이 둘을 서비스나 다른 컨트롤러로 분리하기 아주 좋아보입니다. ㅎㅎ.... (츄릅)
어떻게 생각하세요?

}
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage());
Comment on lines +27 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어차피 IllegalArgumentException으로 받아서 똑같은 메시지로 다시 던질거면 여기서 try-catch를 왜 사용하신지 궁금해요!

}
}

private void play() {
boolean isFinish = false;
ComputerNumbers computerNumbers = init();
while (!isFinish) {
PlayerNumbers playerNumbers = input();
isFinish = result(computerNumbers, playerNumbers);
}
Comment on lines +33 to +38

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do while로 처리하면 더 좋을것 같습니다.

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();
}
}
47 changes: 47 additions & 0 deletions src/main/java/baseball/model/domain/ComputerNumbers.java
Original file line number Diff line number Diff line change
@@ -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<Integer> computerNumbers;

public ComputerNumbers() {
this.computerNumbers = createRandomNumbers();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생성자에서 온전히 생성만을 담당하기 위해
생성로직을 분리하는것은 어떨까요?

}

private List<Integer> createRandomNumbers() {
Set<Integer> 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<Integer> 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++;
}
}
Comment on lines +35 to +44

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 클래스에 스트라이크, 볼 판정 로직이 있어도 될지 궁금합니다

return new Result(strikes, balls);
}
}
28 changes: 28 additions & 0 deletions src/main/java/baseball/model/domain/GameMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package baseball.model.domain;

import java.util.Arrays;

public enum GameMenu {
RESTART("1", true),
QUIT("2", false);
Comment on lines +6 to +7

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

재시작을 이넘으로 처리하셨네요 좋은방법 같아 보입니다


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;
}
}
56 changes: 56 additions & 0 deletions src/main/java/baseball/model/domain/PlayerNumbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package baseball.model.domain;

import java.util.ArrayList;
import java.util.List;

public class PlayerNumbers {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlayerNumber와 ComputerNumeber가 비슷한 기능을 수행하는 부분이 있어서, 추상클래스로 묶으면 검증등의 로직을 빼볼 수 있을 것 같아요!

private final List<Integer> playerNumbers;

public PlayerNumbers(String input) {
this.playerNumbers = parse(input);
}

private List<Integer> parse(String input) {
List<String> items = List.of(input.split(""));
List<Integer> numbers = new ArrayList<>();
for (String item : items) {
int number = parseNumber(item);
numbers.add(number);
}
validateNumbers(numbers);
return numbers;
}

Comment on lines +13 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파싱 부분은 따로 클래스를 만들어서 빼는게 어떨까요?

private int parseNumber(String input) {
try {
int number = Integer.parseInt(input);
validateNumber(number);
return number;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("입력값은 숫자여야 합니다.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외처리도 상수화 하시면 좋을것 같습니다

}
}

private int validateNumber(int number) {
if (number < 1 || number > 9) {
throw new IllegalArgumentException("숫자는 1에서 9까지의 수만 허용됩니다.");
}
return number;
}

private void validateNumbers(List<Integer> numbers) {
if (numbers.size() != 3) {
throw new IllegalArgumentException("숫자 3자리를 입력해야 합니다.");
}
int uniqueCount = (int) numbers.stream()
.distinct()
.count();
if (uniqueCount != 3) {
throw new IllegalArgumentException("중복된 숫자는 허용되지 않습니다.");
}
}

public List<Integer> getPlayerNumbers() {
return playerNumbers;
}
}
35 changes: 35 additions & 0 deletions src/main/java/baseball/model/domain/Result.java
Original file line number Diff line number Diff line change
@@ -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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NUMBER_SIZE 상수를 써도 좋을것 같네요.

}

@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();
}
}
14 changes: 14 additions & 0 deletions src/main/java/baseball/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package baseball.view;

import static camp.nextstep.edu.missionutils.Console.readLine;

public class InputView {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InputView에서 좀 더 적극적으로 List나 boolean을 제공하지 않고, String만 제공하는지 궁금합니다! 너무 역할이 없는 것 같아요.


public String getNumber() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드이름에 get이 들어가는걸 지양해야할것 같습니다

return readLine();
}

public String askRestart() {
return readLine();
}
}
30 changes: 30 additions & 0 deletions src/main/java/baseball/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -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));
}

}