-
Notifications
You must be signed in to change notification settings - Fork 0
숫자 야구 게임 [SangBeom-Hahn] #2
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
base: main
Are you sure you want to change the base?
Changes from 9 commits
d3a43d2
79f3e7b
bf40464
3861edb
ff86b26
7dd776f
6e1f6e5
b072ddf
cd05f8e
c9f6dab
968677a
8b975fc
d498845
8ba8368
3e23707
63e284e
6faf838
79a73e2
45901c9
7ccf4e9
53e2e2f
4c24258
c4321d5
4aa97f2
c133bc3
787d1e7
4e39001
fbf0807
f4391a2
0fe1f31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # 요구사항 명세서 | ||
| ### 카테고리 | ||
| 1. 컴퓨터 | ||
| 2. 사용자 | ||
| 3. 시스템 | ||
|
|
||
| ### 요구사항 내용 | ||
| 1. 컴퓨터 | ||
| - 1 ~ 9까지 서로 다른 임의의 수 3개를 선택한다. | ||
| - 사용자가 입력한 숫자에 대한 결과를 출력한다. | ||
|
|
||
|
|
||
|
|
||
| 2. 사용자 | ||
| - 서로 다른 3개의 숫자를 입력한다. | ||
| - 게임을 종료할 때 완전 종료와 다시 시작을 선택한다. | ||
|
|
||
|
|
||
| 3. 시스템 | ||
| - 게임 시작 문구를 출력한다. | ||
| - 사용자와 컴퓨터의 동작을 반복한다. | ||
| - 3개의 숫자를 모두 맞히면 게임을 종료한다. | ||
| 게임이 종료할 때 사용자의 선택에 따라서 완전 종료하거나 다시 시작한다. | ||
| - 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 App을 종료한다. | ||
|
|
||
| # 기능 목록 | ||
| 1. 게임 시작 | ||
| - 게임 시작 문구 출력 | ||
|
|
||
|
|
||
| 2. 게임 진행 | ||
| - 컴퓨터는 1 ~ 9까지 서로 다른 임의의 수 선택 | ||
| - 사용자가 서로 다른 3개의 숫자를 입력 | ||
| - 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 전혀 없으면 낫싱 출력 | ||
|
|
||
|
|
||
| 3. 게임 종료 | ||
| - 사용자가 컴퓨터의 수를 맞추면 게임 종료 출력 | ||
| - 재시작(1) / 종료(2) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package baseball.controller; | ||
|
|
||
| import baseball.model.User; | ||
| import camp.nextstep.edu.missionutils.Console; | ||
|
|
||
| public class BaseballController { | ||
| public void terminateGame(User user) { | ||
| if (isTerminate()) { | ||
| user.terminate(); | ||
| System.out.println("완전 정료"); | ||
|
||
| } else { | ||
| user.restart(); | ||
| } | ||
| } | ||
| public boolean isTerminate() { | ||
|
||
| String restartStatus = Console.readLine(); | ||
|
|
||
| validateRangeRestartStatus(restartStatus); | ||
| validateNotStringRestartStatus(restartStatus); | ||
| validateNotStringRestartStatus(restartStatus); | ||
|
|
||
|
|
||
| if(restartStatus.equals("2") ){ | ||
|
||
| return true; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| public void validateRangeRestartStatus(final String restartStatus) { | ||
| if (Integer.parseInt(restartStatus) < 1 || Integer.parseInt(restartStatus) > 2) { | ||
| throw new IllegalArgumentException("재시작은 1, 완전 종료는 2 입니다."); | ||
| } | ||
| } | ||
|
|
||
| public void validateNotStringRestartStatus(final String restartStatus) { | ||
| if ( !(restartStatus != null && restartStatus.matches("[-+]?\\d*\\.?\\d+")) ) { | ||
| throw new IllegalArgumentException("재시작은 1, 완전 종료는 2인 정수입니다."); | ||
| } | ||
| } | ||
|
|
||
| public void validateNotDoubleRestartStatus(final String restartStatus) { | ||
| if (!restartStatus.chars().allMatch(Character::isDigit)) { | ||
| throw new IllegalArgumentException("재시작은 1, 완전 종료는 2인 정수로 소수를 입력할 수 없습니다."); | ||
| } | ||
| } | ||
|
|
||
|
||
| public void restartGame() { | ||
| // 게임을 끝내지 않을 것이라는 신호를 줌 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||||||||||
| package baseball.model; | ||||||||||||||
|
|
||||||||||||||
| import camp.nextstep.edu.missionutils.Randoms; | ||||||||||||||
|
|
||||||||||||||
| import java.util.ArrayList; | ||||||||||||||
| import java.util.List; | ||||||||||||||
|
|
||||||||||||||
| public class Computer { | ||||||||||||||
| public List<Integer> randomNumber; | ||||||||||||||
|
||||||||||||||
|
|
||||||||||||||
| public Computer() { | ||||||||||||||
| saveRandomNumberWithGameStart(); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+14
to
+16
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. save를 통해서 randomNumber에 대한 init을 한다는거는 알겠는데
Suggested change
와 같이 수정하는게 더 가독성이 좋을거 같은데 어떻게 생각하시나요? |
||||||||||||||
|
|
||||||||||||||
| public List<Integer> getRandomNumber() { | ||||||||||||||
| return randomNumber; | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+18
to
+20
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일반적으로 getter/setter/equals와 같은 메소드들은 클래스 가장 하단에 위치하는게 관례입니다
|
||||||||||||||
|
|
||||||||||||||
| public void saveRandomNumberWithGameStart() { | ||||||||||||||
| randomNumber = new ArrayList<>(); | ||||||||||||||
| Integer digit; | ||||||||||||||
|
|
||||||||||||||
| while (checkLengthSmallThanThree()) { | ||||||||||||||
| digit = getRandomDigit(); | ||||||||||||||
| if (!hasDuplicateDigitInRandomNumber(digit)) { | ||||||||||||||
| randomNumber.add(digit); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
||||||||||||||
|
|
||||||||||||||
| public boolean checkLengthSmallThanThree() { | ||||||||||||||
| if (randomNumber.size() < 3) { | ||||||||||||||
| return true; | ||||||||||||||
| } | ||||||||||||||
| return false; | ||||||||||||||
| } | ||||||||||||||
|
||||||||||||||
|
|
||||||||||||||
| public Integer getRandomDigit() { | ||||||||||||||
| return Randoms.pickNumberInRange(1, 9); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| public boolean hasDuplicateDigitInRandomNumber(Integer digit) { | ||||||||||||||
| if (randomNumber.contains(digit)) { | ||||||||||||||
| return true; | ||||||||||||||
| } | ||||||||||||||
| return false; | ||||||||||||||
| } | ||||||||||||||
|
||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package baseball.model; | ||
|
|
||
|
|
||
| import java.util.List; | ||
|
|
||
| public class User { | ||
| public enum RestartStatus { RESTART, TERMINATE } | ||
|
|
||
| private List<Integer> number; | ||
| public RestartStatus restartStatus; | ||
|
|
||
| public void setNumber(List<Integer> number) { | ||
| validateNumber(number); | ||
| this.number = number; | ||
| } | ||
|
|
||
| public void validateNumber(final List<Integer> number) { | ||
| if (number.size() > 3 || number.size() < 3) { | ||
| throw new IllegalArgumentException("입력 숫자는 3자리입니다."); | ||
| } | ||
|
|
||
| if (!number.stream().allMatch(digit -> digit >= 1 && digit <= 9)) { | ||
| throw new IllegalArgumentException("입력 숫자는 3자리입니다."); | ||
| } | ||
| } | ||
|
||
|
|
||
| public void restart() { | ||
| this.restartStatus = RestartStatus.RESTART; | ||
| } | ||
|
|
||
| public void terminate() { | ||
| this.restartStatus = RestartStatus.TERMINATE; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| package baseball.controller; | ||
|
|
||
| import org.assertj.core.api.Assertions; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.io.ByteArrayInputStream; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class BaseballControllerTest { | ||
| @Test | ||
| @DisplayName("재시작 검증 테스트") | ||
| void ValidateRangeRestartStatusTest() { | ||
| // given | ||
| String restartStatus = "5"; | ||
| BaseballController controller = new BaseballController(); | ||
|
|
||
| // when | ||
|
|
||
|
|
||
| // then | ||
| assertThatThrownBy(() -> controller.validateRangeRestartStatus(restartStatus)) | ||
| .isInstanceOf(IllegalArgumentException.class); | ||
|
|
||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("재시작 검증 테스트") | ||
| void ValidateNotStringRestartStatusTest() { | ||
| // given | ||
| String restartStatus = "*"; | ||
| BaseballController controller = new BaseballController(); | ||
|
|
||
| // when | ||
|
|
||
|
|
||
| // then | ||
| assertThatThrownBy(() -> controller.validateNotStringRestartStatus(restartStatus)) | ||
| .isInstanceOf(IllegalArgumentException.class); | ||
|
|
||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("재시작 검증 테스트") | ||
| void validateNotDoubleRestartStatusTest() { | ||
| // given | ||
| String restartStatus = "1.2"; | ||
| BaseballController controller = new BaseballController(); | ||
|
|
||
| // when | ||
|
|
||
|
|
||
| // then | ||
| assertThatThrownBy(() -> controller.validateNotDoubleRestartStatus(restartStatus)) | ||
| .isInstanceOf(IllegalArgumentException.class); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("사용자 입력에 따른 종료 테스트") | ||
| void BaseballControllerTest() { | ||
| // given | ||
| // 콘솔 입력 시뮬레이션 | ||
| String input = "1"; | ||
| ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes()); | ||
| System.setIn(inputStream); | ||
|
|
||
| BaseballController controller = new BaseballController(); | ||
|
|
||
| // when | ||
|
|
||
| // then | ||
| assertThat(controller.isTerminate()).isFalse(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package baseball.model; | ||
|
|
||
| import org.assertj.core.api.Assertions; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class ComputerTest { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 각각의 테스트가 무엇을 위한 테스트인지는 알겠는데 private scope로 두어야 할 메소드들도 테스트를 위해서 public으로 열어둔 것처럼 보이네요 클래스의 모든 메소드를 테스트하기 위해서 public으로 열어두기 보다 private scope로 두어야할 메소드는 private scope로 두고 해당 메소드를 활용하는 의미있는 public method를 테스트하면 되지 않을까요? |
||
| @Test | ||
| @DisplayName("컴퓨터의 랜덤 수를 저장할 때 중복된 숫자를 가지지 않는지 테스트 ") | ||
| void hasDigitTest() { | ||
| // given | ||
| Computer computer = new Computer(); | ||
|
|
||
| // when | ||
| computer.randomNumber = new ArrayList<>(Arrays.asList(1, 2, 3)); | ||
|
|
||
| // then | ||
| assertThat(computer.hasDuplicateDigitInRandomNumber(1)).isTrue(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("한자리 랜덤 수 생성 테스트") | ||
| void getRandomDigitTest() { | ||
| // given | ||
| Computer computer = new Computer(); | ||
|
|
||
| // when | ||
| Integer randomDigit = computer.getRandomDigit(); | ||
|
|
||
| // then | ||
| assertThat(randomDigit >= 1 && randomDigit <= 9).isTrue(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("랜덤수가 3자리 이하인지 체크 테스트") | ||
| void checkLengthTest() { | ||
| // given | ||
| Computer computer = new Computer(); | ||
|
|
||
| // when | ||
| computer.randomNumber = new ArrayList<>(Arrays.asList(1, 2)); | ||
|
|
||
| // then | ||
| assertThat(computer.checkLengthSmallThanThree()).isTrue(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("랜덤 수 생성 테스트") | ||
| void saveRandomNumberTest() { | ||
| // given | ||
| Computer computer = new Computer(); | ||
|
|
||
| // when | ||
| computer.saveRandomNumberWithGameStart(); | ||
| List<Integer> randomNumber = computer.randomNumber; | ||
|
|
||
| // then | ||
| assertThat(randomNumber.stream().allMatch(digit -> digit >= 111 && digit <= 999)); | ||
| System.out.println(randomNumber); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 코드에서 sout으로 출력을 하는 이유가 있나요 |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package baseball.model; | ||
|
|
||
| import org.assertj.core.api.Assertions; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class UserTest { | ||
| @Test | ||
| @DisplayName("3자리가 아닌 입력 숫자 검증 기능 테스트") | ||
| void validateNumberLengthTest() { | ||
| // given | ||
| User user = new User(); | ||
|
|
||
| // when | ||
| ArrayList<Integer> number = new ArrayList<>(Arrays.asList(1, 2)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 타입을 List로 하지않고 ArrayList로 둔 이유가 있나요? 추가적으로
|
||
|
|
||
| // then | ||
| assertThatThrownBy(() -> user.validateNumber(number)) | ||
| .isInstanceOf(IllegalArgumentException.class); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("3자리가 아닌 입력 숫자 검증 기능 테스트") | ||
| void validateDigitLengthTest() { | ||
| // given | ||
| User user = new User(); | ||
|
|
||
| // when | ||
| ArrayList<Integer> number = new ArrayList<>(Arrays.asList(1, 2, 33)); | ||
|
|
||
| // then | ||
| assertThatThrownBy(() -> user.validateNumber(number)) | ||
| .isInstanceOf(IllegalArgumentException.class); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("RestartStatus 테스트") | ||
| void UserTest() { | ||
| // given | ||
| User user = new User(); | ||
|
|
||
| // when | ||
| user.terminate(); | ||
|
|
||
| // then | ||
| assertThat(user.restartStatus).isEqualTo(User.RestartStatus.RESTART); | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 테스트 깨지는데요 |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일상적인 관점에서는 컴퓨터가 결과를 출력하지만 이 게임상에서는 컴퓨터 & 사용자를 Player로 보고 결과를 도출하는 것은 다른 컴포넌트에게 위임하는게 좋지 않을까요?