Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Training/1 #2791

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
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
25 changes: 25 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 숫자 야구

## 기능 목록

- [x] 컴퓨터는 1 ~ 9 사이에서 서로 다른 임의의 수 3개를 선택한다.
- [x] 플레이어는 서로 다른 수 3개를 입력한다.
- [x] 컴퓨터가 선택한 수와 플레이어가 입력한 수를 비교하여 결과를 출력한다. ex) 1볼 1스트라이크
- [x] 같은 자리에 같은 수: `스트라이크`
- [x] 다른 자리 같은 수: `볼`
- [x] 같은 수가 전혀 없는 경우: `낫싱`
- [x] 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
- [x] 게임이 종료된 후 재시작/종료를 선택한다. 재시작: 1, 종료: 2

## 예외

사용자가 잘못된 값을 입력하는 경우 `IllegalArgumentException`을 발생시킨다.

- [x] 동일한 수를 입력한 경우
- [x] 숫자가 아닌 문자를 입력한 경우
- [x] 숫자를 3개 입력하지 않은 경우
- [x] 0을 입력한 경우

## 제약 조건

`camp.nextstep.edu.missionutils`의 `Randoms`와 `Console`를 사용한다.
12 changes: 11 additions & 1 deletion src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package baseball;

import baseball.controller.BaseballGame;
import baseball.domain.Computer;
import baseball.domain.Player;
import baseball.view.InputView;
import baseball.view.OutputView;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
BaseballGame baseballGame = new BaseballGame(
new OutputView(), new InputView(),
new Computer(), new Player()
);
baseballGame.start();
}
}
52 changes: 52 additions & 0 deletions src/main/java/baseball/controller/BaseballGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package baseball.controller;

import baseball.domain.BaseballJudge;
import baseball.domain.Computer;
import baseball.domain.Player;
import baseball.dto.CompareResult;
import baseball.view.InputView;
import baseball.view.OutputView;

import java.util.List;

public class BaseballGame {

private final OutputView outputView;
private final InputView inputView;
private final Computer computer;
private final Player player;

public BaseballGame(OutputView outputView, InputView inputView, Computer computer, Player player) {
this.outputView = outputView;
this.inputView = inputView;
this.computer = computer;
this.player = player;
}

public void start() {
outputView.printStartMessage();

do {
play();
} while (isRestart());
}

private void play() {
computer.generateNumbers();

CompareResult compareResult;
do {
List<Integer> inputNumbers = inputView.enterUserNumbers();
player.chooseNumbers(inputNumbers);
compareResult = BaseballJudge.judgeCompareResult(player, computer);
outputView.printCompareResult(compareResult);
} while (!compareResult.isThreeStrike());

outputView.printFinishMessage();
}

private boolean isRestart() {
int input = inputView.enterRestartOrEnd();
return input == 1;
}
}
15 changes: 15 additions & 0 deletions src/main/java/baseball/domain/BaseballJudge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package baseball.domain;

import baseball.dto.CompareResult;

public class BaseballJudge {

public static CompareResult judgeCompareResult(Player player, Computer computer) {
Numbers playerNumbers = player.getNumbers();
Numbers computerNumbers = computer.getNumbers();

int strike = computerNumbers.calculateStrikes(playerNumbers);
int ball = computerNumbers.calculateBalls(playerNumbers);
return new CompareResult(strike, ball);
}
}
27 changes: 27 additions & 0 deletions src/main/java/baseball/domain/Computer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package baseball.domain;

import camp.nextstep.edu.missionutils.Randoms;

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

public class Computer {

private Numbers numbers;

public void generateNumbers() {
List<Integer> numbers = new ArrayList<>();
while (numbers.size() < 3) {
int number = Randoms.pickNumberInRange(Numbers.START_NUMBER, Numbers.END_NUMBER);
if (!numbers.contains(number)) {
numbers.add(number);
}
}

this.numbers = new Numbers(numbers);
}

public Numbers getNumbers() {
return numbers;
}
}
49 changes: 49 additions & 0 deletions src/main/java/baseball/domain/Numbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package baseball.domain;

import baseball.validator.NumbersValidator;

import java.util.List;

public class Numbers {

public static final int START_NUMBER = 1;
public static final int END_NUMBER = 9;
public static final int SIZE = 3;

private final List<Integer> numbers;

public Numbers(List<Integer> numbers) {
validateNumbers(numbers);
this.numbers = numbers;
}

private void validateNumbers(List<Integer> numbers) {
NumbersValidator.validateNumbersSize(SIZE, numbers);
NumbersValidator.validateDuplicateNumbers(numbers);
NumbersValidator.validateContainsZero(numbers);
}

public int calculateStrikes(Numbers compareNumbers) {
List<Integer> numbers = compareNumbers.numbers;
int strikesCount = 0;
for (int i = 0; i < SIZE; i++) {
Integer number = numbers.get(i);
if (this.numbers.indexOf(number) == i) {
strikesCount++;
}
}
return strikesCount;
}

public int calculateBalls(Numbers compareNumbers) {
List<Integer> numbers = compareNumbers.numbers;
int ballsCount = 0;
for (int i = 0; i < SIZE; i++) {
Integer number = numbers.get(i);
if (this.numbers.contains(number) && this.numbers.indexOf(number) != i) {
ballsCount++;
}
}
return ballsCount;
}
}
16 changes: 16 additions & 0 deletions src/main/java/baseball/domain/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package baseball.domain;

import java.util.List;

public class Player {

private Numbers numbers;

public void chooseNumbers(List<Integer> numbers) {
this.numbers = new Numbers(numbers);
}

public Numbers getNumbers() {
return numbers;
}
}
8 changes: 8 additions & 0 deletions src/main/java/baseball/dto/CompareResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package baseball.dto;

public record CompareResult(int strike, int ball) {

public boolean isThreeStrike() {
return strike == 3;
}
}
9 changes: 9 additions & 0 deletions src/main/java/baseball/exception/ErrorMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package baseball.exception;

public class ErrorMessages {

public static final String NUMBER_FORMAT_ERROR = "[ERROR] 숫자만 입력해야 합니다.";
public static final String INVALID_SIZE_ERROR = "[ERROR] 숫자는 %d개이어야 합니다.";
public static final String DUPLICATE_NUMBERS_ERROR = "[ERROR] 숫자는 중복될 수 없습니다.";
public static final String INVALID_NUMBER_ERROR = "[ERROR] 유효하지 않은 수입니다.";
}
29 changes: 29 additions & 0 deletions src/main/java/baseball/validator/NumbersValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package baseball.validator;

import baseball.exception.ErrorMessages;

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

public class NumbersValidator {

public static void validateNumbersSize(int validSize, List<Integer> numbers) {
if (numbers.size() != validSize) {
throw new IllegalArgumentException(String.format(ErrorMessages.INVALID_SIZE_ERROR, validSize));
}
}

public static void validateDuplicateNumbers(List<Integer> numbers) {
Set<Integer> set = new HashSet<>(numbers);
if (set.size() != numbers.size()) {
throw new IllegalArgumentException(ErrorMessages.DUPLICATE_NUMBERS_ERROR);
}
}

public static void validateContainsZero(List<Integer> numbers) {
if (numbers.contains(0)) {
throw new IllegalArgumentException(ErrorMessages.INVALID_NUMBER_ERROR);
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/baseball/view/BaseballMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package baseball.view;

public class BaseballMessages {

public static final String START_MESSAGE = "숫자 야구 게임을 시작합니다.";
public static final String INPUT_NUMBERS_MESSAGE = "숫자를 입력해주세요 : ";
public static final String CONTINUE_OR_END_MESSAGE = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";
public static final String FINISH_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임 종료";

public static final String NOTHING = "낫싱";
public static final String BALL = "볼";
public static final String STRIKE = "스트라이크";
}
35 changes: 35 additions & 0 deletions src/main/java/baseball/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package baseball.view;

import baseball.exception.ErrorMessages;
import camp.nextstep.edu.missionutils.Console;

import java.util.Arrays;
import java.util.List;

public class InputView {

public List<Integer> enterUserNumbers() {
System.out.print(BaseballMessages.INPUT_NUMBERS_MESSAGE);
String input = Console.readLine()
.trim();
try {
return Arrays.stream(input.split(""))
.map(Integer::parseInt)
.toList();
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(ErrorMessages.NUMBER_FORMAT_ERROR);
}
}

public int enterRestartOrEnd() {
System.out.println(BaseballMessages.CONTINUE_OR_END_MESSAGE);
String input = Console.readLine()
.trim();

try {
return Integer.parseInt(input);
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(ErrorMessages.NUMBER_FORMAT_ERROR);
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/baseball/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package baseball.view;

import baseball.dto.CompareResult;

public class OutputView {

public void printStartMessage() {
System.out.println(BaseballMessages.START_MESSAGE);
}

public void printCompareResult(CompareResult compareResult) {
int ball = compareResult.ball();
int strike = compareResult.strike();
if (strike == 0 && ball == 0) {
System.out.println(BaseballMessages.NOTHING);
return;
}

StringBuilder message = new StringBuilder();
if (ball != 0) {
message.append(ball).append(BaseballMessages.BALL)
.append(" ");
}
if (strike != 0) {
message.append(strike).append(BaseballMessages.STRIKE);
}

System.out.println(message);
}

public void printFinishMessage() {
System.out.println(BaseballMessages.FINISH_MESSAGE);
}
}
26 changes: 26 additions & 0 deletions src/test/java/baseball/domain/ComputerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package baseball.domain;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("컴퓨터 도메인 테스트")
class ComputerTest {

// 서로 다른 수만 존재하는지 어떻게 테스트할 수 있을까..?
@DisplayName("컴퓨터는 서로 다른 임의의 수 3개를 선택한다.")
@Test
void generateComputerNumbers() {
// given
Computer computer = new Computer();

// when
computer.generateNumbers();

// then
assertThat(computer).extracting("numbers")
.extracting("numbers").asList()
.hasSize(3);
}
}
Loading