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
8 changes: 8 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 기능 목록

- [x] 게임 관리 - GameManager class
- [x] 게임 시작 - start()
- [x] 숫자 야구 구현 - BaseballGame class
- [x] 세 자리수 랜덤 숫자 생성 - generateAnswer()
- [x] 사용자 입력 받기 - receiveUserInput()
- [x] 사용자 숫자를 받아 채점 및 정답 여부 반환 - score()
Comment on lines +1 to +8

Choose a reason for hiding this comment

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

각 기능에 대한 예외사항과 핸들링도 기재되면 좋을 것 같습니다!

3 changes: 2 additions & 1 deletion src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

import camp.nextstep.edu.missionutils.Console;
import camp.nextstep.edu.missionutils.Randoms;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class BaseballGame {

private Integer answer;

Choose a reason for hiding this comment

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

int가 아닌 Integer을 사용한 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

의도는 generateAnswer()에서 answer에 값을 넣어주는 부분이 있는데,
int 자료형이면 값 참조를 못해서, 값이 안들어갈까봐 Integer로 설정해주었습니다!

그런데, 찾아보니까 int여도 값이 잘 들어간다고 하네요ㅠ
int로 바꾸는게 더 좋을 것 같습니다.


public BaseballGame() {
this.answer = 0;
}

public Integer getAnswer() {
return answer;
}

public int generateAnswer() {

AtomicInteger index = new AtomicInteger();

LinkedHashSet<Integer> numbers = new LinkedHashSet<>();
while (numbers.size() < 3) {
numbers.add(Randoms.pickNumberInRange(1, 9));
}
Comment on lines +29 to +31

Choose a reason for hiding this comment

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

3, 1, 9와 같은 숫자를 상수로 선언해 사용하시는건 어떨까요?


answer = numbers.stream().reduce(0, (x, y) -> {
int result = (int) (x + y * Math.pow(10, 2 - index.doubleValue()));
index.getAndIncrement();
return result;
});
return answer;
}

public int receiveUserInput() {
System.out.print("숫자를 입력해주세요 : ");

String input = Console.readLine();
validateInput(input);

try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("잘못된 입력 형식입니다.");
}
}
Comment on lines +41 to +52

Choose a reason for hiding this comment

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

해당 부분은 view로 분리할 수 있을 것 같아보입니당


private void validateInput(String input) {
if (input.length() != 3) {
throw new IllegalArgumentException("잘못된 입력 형식입니다.");
}
}

public boolean score(int answer, int userAnswer) {

List<Integer> answerDigits = getDigits(answer);
List<Integer> userAnswerDigits = getDigits(userAnswer);

int strike = 0;
int ball = 0;
for (int index = 0; index < 3; index++) {
int num = userAnswerDigits.get(index);

if (num == answerDigits.get(index)) {
strike++;
continue;
}

if (answerDigits.contains(num)) {
ball++;
}
}

StringBuilder sb = new StringBuilder();
if (strike == 0 && ball == 0) {
sb.append("낫싱");
}

if (ball > 0) {
sb.append(ball).append("볼 ");
}
if (strike > 0) {
sb.append(strike).append("스트라이크 ");
}
System.out.println(sb);

if (strike == 3) {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
return true;
}
Comment on lines +93 to +96

Choose a reason for hiding this comment

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

출력과 boolean값 return을 동시에 해서 두가지 일을 하는 것 처럼 보입니다
외부에서 ture/false에 따라 출력 여부를 결정하도록 변경하면 어떨까요?

return false;
}

private static List<Integer> getDigits(int num) {
List<Integer> answerNums = new ArrayList<>();
int current = num;
for (int i = 0; i < 3; i++) {
answerNums.add(0, current % 10);
current /= 10;
}
return answerNums;
}
}
37 changes: 37 additions & 0 deletions src/main/java/baseball/GameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package baseball;

import camp.nextstep.edu.missionutils.Console;

public class GameManager {

private BaseballGame game;

public GameManager() {
this.game = new BaseballGame();
}

public void start() {

System.out.println("숫자 야구 게임을 시작합니다.");
game.generateAnswer();

boolean result = false;
while (!result) {
int userInput = game.receiveUserInput();
result = game.score(game.getAnswer(), userInput);
}

String endInput = askRestart();
if (endInput.equals("1")) {
start();
}
if (endInput.equals("2")) {
return;
}
}

private String askRestart() {
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
return Console.readLine();
}
}
95 changes: 95 additions & 0 deletions src/test/java/baseball/BaseballGameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package baseball;

import camp.nextstep.edu.missionutils.Console;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

class BaseballGameTest {

private BaseballGame baseballGame;

private final InputStream originalIn = System.in;
private final PrintStream originalOut = System.out;
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();


@BeforeEach
void setUp() {
baseballGame = new BaseballGame();
System.setOut(new PrintStream(outputStream));
}

@AfterEach
void tearDown() {
System.setOut(originalOut);
System.setIn(originalIn);
}

@Test
void generateAnswer_정답을_answer에_채워넣는다() {
baseballGame.generateAnswer();

assertThat(baseballGame.getAnswer()).isNotEqualTo(0);
}

@Test
void generateAnswer_정답은_세자리수_이다() {
baseballGame.generateAnswer();

int length = baseballGame.getAnswer().toString().length();
assertThat(length).isEqualTo(3);
}

@Test
void receiveUserInput_유저의_입력을_반환한다() {
String input = "123";
ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
System.setIn(inputStream);

int result = baseballGame.receiveUserInput();

assertThat(result).isEqualTo(Integer.parseInt(input));
}

@Test
void score_한개만_맞으면_1스트라이크를_출력한다() {
boolean result = baseballGame.score(123, 145);

String output = outputStream.toString().trim();

assertThat(result).isFalse();
assertThat(output).isEqualTo("1스트라이크");
}

@Test
void score_다른_자리에_같은_숫자가_있으면_1볼을_출력한다() {
boolean result = baseballGame.score(123, 245);

String output = outputStream.toString().trim();

assertThat(result).isFalse();
assertThat(output).isEqualTo("1볼");
}

@Test
void score_3숫자_모두_맞추면_정답메세지를_출력하고_true를_반환한다() {
boolean result = baseballGame.score(123, 123);

String output = outputStream.toString().trim();

assertThat(result).isTrue();
assertThat(output).isEqualTo("3스트라이크 \n" +
"3개의 숫자를 모두 맞히셨습니다! 게임 종료");
}
}
12 changes: 12 additions & 0 deletions src/test/java/baseball/GameManagerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package baseball;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class GameManagerTest {

@Test
void start() {
}
}