-
Notifications
You must be signed in to change notification settings - Fork 97
[자동차 경주] 김민창 4단계 미션 제출합니다. #62
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: idle2534
Are you sure you want to change the base?
Changes from 7 commits
c5928a7
298065d
49ecbf8
1ca6611
f461973
e6a5ece
5e1aff2
74656e5
664ce8d
83fbd71
13a911b
1a3d4b5
68f54a0
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,76 @@ | ||
| ## 움직이는 자동차 [O] | ||
| ### 기능 요구사항 | ||
| - 자동차는 이름을 가지고 있다. | ||
| - 자동차는 움직일 수 있다. | ||
| - 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. | ||
| ### 새로운 프로그래밍 요구사항 | ||
| - 자동차가 움직이는 기능이 의도대로 동작하는지 테스트한다. | ||
| - 자바 코드 컨벤션을 지키면서 프로그래밍한다. | ||
| - 기본적으로 Java Style Guide을 원칙으로 한다. | ||
| - indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. | ||
| - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. | ||
| - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. | ||
| - 3항 연산자를 쓰지 않는다. | ||
| - else 예약어를 쓰지 않는다. | ||
| - else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. | ||
| - 힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다. | ||
| - 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. | ||
| - 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다. | ||
| ### 기존 프로그래밍 요구사항 | ||
| - 메인 메서드는 만들지 않는다. | ||
|
|
||
| ## 우승 자동차 구하기 [O] | ||
| ### 기능 요구사항 | ||
| - n대의 자동차가 참여할 수 있다. | ||
| - 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. | ||
| - 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. | ||
| - 자동차 경주 게임을 완료한 후 누가 우승했는지를 구할 수 있다. 우승자는 한 명 이상일 수 있다. | ||
| ### 새로운 프로그래밍 요구사항 | ||
| - 우승자를 구하는 기능이 의도대로 동작하는지 테스트한다. | ||
|
|
||
| ## 게임 실행 [O] | ||
| ### 기능 요구사항 | ||
| - 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. | ||
| - 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. | ||
| - 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. | ||
| - 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. | ||
| - 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. | ||
| - 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. | ||
| <br>**실행 결과** | ||
| - 위 요구사항에 따라 3대의 자동차가 5번 움직였을 경우 프로그램을 실행한 결과는 다음과 같다. | ||
| ``` | ||
| 경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분). | ||
| neo,brie,brown | ||
| 시도할 회수는 몇회인가요? | ||
| 5 | ||
|
|
||
| 실행 결과 | ||
| neo : - | ||
| brie : - | ||
| brown : - | ||
|
|
||
| neo : -- | ||
| brie : - | ||
| brown : -- | ||
|
|
||
| neo : --- | ||
| brie : -- | ||
| brown : --- | ||
|
|
||
| neo : ---- | ||
| brie : --- | ||
| brown : ---- | ||
|
|
||
| neo : ----- | ||
| brie : ---- | ||
| brown : ----- | ||
|
|
||
| neo : ----- | ||
| brie : ---- | ||
| brown : ----- | ||
|
|
||
| neo, brown가 최종 우승했습니다. | ||
| ``` | ||
|
|
||
| ### 새로운 프로그래밍 요구사항 | ||
| - 메인 메서드를 추가하여 실행 가능한 애플리케이션으로 만든다. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| public class Main { | ||
| public static void main(String[] args) { | ||
| RacingCarGame game = new RacingCarGame(); | ||
| game.setGame(); | ||
| game.startGame(); | ||
| game.resetGame(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Random; | ||
|
|
||
| public class RacingCar { | ||
| private final String name; | ||
| private int score = 0; | ||
| private final List<Boolean> results = new ArrayList<>(); | ||
|
|
||
| public RacingCar(String name) { | ||
| this.name = name; | ||
| } | ||
|
|
||
| private int randPower() { | ||
| Random rand = new Random(); | ||
| return rand.nextInt(10); | ||
| } | ||
|
|
||
| public int move() { | ||
| return move(randPower()); | ||
| } | ||
|
|
||
| public int move(int power) { | ||
|
||
| boolean isMovable = checkPower(power); | ||
|
|
||
| if (isMovable) | ||
| ++score; | ||
|
|
||
| results.add(isMovable); | ||
|
|
||
| return score; | ||
| } | ||
|
|
||
| private boolean checkPower(int power) { | ||
| if (power < 0 || power > 9) | ||
| throw new IllegalArgumentException("0~9 사이의 Power 값을 필요로 합니다."); | ||
|
|
||
| return power >= 4; | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| public int getScore() { | ||
| return score; | ||
| } | ||
|
|
||
| public String getResultString(int phase) { | ||
| StringBuilder resultString = new StringBuilder(); | ||
|
||
| for (int i = 0; i < phase && i < results.size(); i++) { | ||
| resultString.append(resultToString(results.get(i))); | ||
| } | ||
| return resultString.toString(); | ||
| } | ||
|
|
||
| private String resultToString(Boolean result) { | ||
| if (result) | ||
| return "-"; | ||
|
|
||
| return ""; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| import java.util.ArrayList; | ||
| import java.util.InputMismatchException; | ||
| import java.util.List; | ||
| import java.util.Scanner; | ||
|
|
||
| public class RacingCarGame { | ||
|
|
||
| int highScore; | ||
| int phase = 0; | ||
| List<RacingCar> racingCars = new ArrayList<>(); | ||
| boolean isGameInit = false; | ||
|
|
||
| public void setGame() { | ||
|
||
| Scanner scanner = new Scanner(System.in); | ||
|
|
||
| System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); | ||
| String input = scanner.nextLine(); | ||
|
|
||
| for (String name : input.split(",")) | ||
| racingCars.add(new RacingCar(name)); | ||
|
|
||
| if (racingCars.size() < 2) | ||
| throw new InputMismatchException("최소한 두 명 이상의 플레이어가 필요합니다."); | ||
|
|
||
| System.out.println("시도할 회수는 몇회인가요?"); | ||
| try { | ||
| phase = scanner.nextInt(); | ||
| if (phase < 0) { | ||
| throw new NumberFormatException("음수는 유효한 숫자가 아닙니다."); | ||
| } | ||
| } catch (InputMismatchException e) { | ||
| throw new InputMismatchException("유효한 숫자가 아닙니다."); | ||
| } | ||
|
|
||
|
|
||
| isGameInit = true; | ||
| } | ||
|
|
||
| public void startGame() { | ||
| if (!isGameInit) | ||
| throw new IllegalStateException("게임이 초기화되지 않았습니다."); | ||
|
|
||
| for(int i = 0; i < phase; ++i){ | ||
| moveAllRacingCars(); | ||
| } | ||
|
|
||
| printResult(); | ||
| } | ||
|
|
||
| public void resetGame() { | ||
|
||
| racingCars.clear(); | ||
| highScore = 0; | ||
| } | ||
|
|
||
| private void moveAllRacingCars() { | ||
| for(RacingCar racingCar : racingCars) | ||
| racingCar.move(); | ||
| } | ||
|
|
||
| private void printResult() { | ||
| System.out.println("\n실행 결과"); | ||
|
|
||
| for (int i = 1; i <= phase; ++i){ | ||
| printAllRacingCarResults(i); | ||
| System.out.println(); | ||
| } | ||
|
|
||
| System.out.println(String.join(", ", getWinnerNames()) + "가 최종 우승했습니다."); | ||
| } | ||
|
|
||
| private void printAllRacingCarResults(int phase) { | ||
| for (RacingCar racingCar : racingCars) { | ||
| System.out.println(racingCar.getName() + " : " + racingCar.getResultString(phase)); | ||
| } | ||
| } | ||
|
|
||
| private List<String> getWinnerNames() { | ||
| return racingCars.stream().filter(this::checkWinner).map(RacingCar::getName).toList(); | ||
| } | ||
|
|
||
| private boolean checkWinner(RacingCar racingCar) { | ||
| if (racingCar.getScore() > highScore) | ||
| highScore = racingCar.getScore(); | ||
|
|
||
| return racingCar.getScore() == highScore; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
|
||
| import java.io.ByteArrayInputStream; | ||
| import java.util.InputMismatchException; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Nested; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| public class RacingCarTest { | ||
|
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. 클래스 이름은 RacingCarTest인데, RacingCarGame에 대한 부분도 포함된 것 같아요. 어떤 기준으로 테스트 클래스를 나눠볼 수 있을까요? 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. 예외처리를 하고 싶은 부분이 어느 클래스에 있는지를 기준으로 테스트 클래스를 나뉠 것 같습니다. 이번의 경우 Nested로 처리한 SetRacingCarGameTest를 RacingCarGameTest 클래스를 새로 만들어 거기로 옮긴 후 Nested class 이름을 SetGameTest 수정할 듯 합니다. |
||
|
|
||
| @Nested | ||
| @DisplayName("자동차 이동 테스트") | ||
| class RacingCarMove { | ||
| @Test | ||
| @DisplayName("자동차 랜덤 이동 테스트") | ||
| void randomMove() { | ||
| RacingCar racingCar = new RacingCar("Test"); | ||
| int expected = racingCar.getScore(); | ||
| int actual = racingCar.move(); | ||
|
|
||
| assertThat(actual).isIn(expected, expected + 1); | ||
|
||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("자동차 이동 조건 테스트") | ||
| void moveCondition() { | ||
| RacingCar racingCar = new RacingCar("Test"); | ||
| int expected = 0; | ||
| int actual = racingCar.move(3); | ||
|
|
||
| assertThat(actual).isEqualTo(expected); | ||
|
||
|
|
||
| expected = 1; | ||
| actual = racingCar.move(5); | ||
|
|
||
| assertThat(actual).isEqualTo(expected); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("자동차 이동 조건 예외처리 테스트") | ||
| void moveConditionException() { | ||
| RacingCar racingCar = new RacingCar("Test"); | ||
|
|
||
| assertThatThrownBy(() -> racingCar.move(-1)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); | ||
|
|
||
| assertThatThrownBy(() -> racingCar.move(10)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| @Test | ||
| @DisplayName("자동차 결과 텍스트 테스트") | ||
| void racingCarResultString() { | ||
| RacingCar racingCar = new RacingCar("Test"); | ||
|
|
||
| for (int i = 0; i < 5; ++i) | ||
| racingCar.move(); | ||
|
|
||
|
|
||
| String actual = racingCar.getResultString(5); | ||
| String expected = new String(new char[racingCar.getScore()]).replace("\0", "-"); | ||
|
||
|
|
||
| assertThat(actual).isEqualTo(expected); | ||
| } | ||
|
|
||
| @Nested | ||
| @DisplayName("자동차 게임 설정 테스트") | ||
| class SetRacingCarGameTest { | ||
| @Test | ||
| @DisplayName("자동차 이름 입력이 하나일 경우 테스트") | ||
| void setGameWithLessThanTwoNameInput() { | ||
| RacingCarGame racingCarGame = new RacingCarGame(); | ||
| System.setIn(new ByteArrayInputStream("test1\n1".getBytes())); | ||
|
|
||
| assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("최소한 두 명 이상의 플레이어가 필요합니다."); | ||
|
||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("시도할 횟수 입력이 음수일 경우 테스트") | ||
| void setGameWithNegativePhaseInput() { | ||
| RacingCarGame racingCarGame = new RacingCarGame(); | ||
| System.setIn(new ByteArrayInputStream("test1,test2\n-1\n".getBytes())); | ||
|
|
||
| assertThatThrownBy(racingCarGame::setGame).isInstanceOf(NumberFormatException.class).hasMessage("음수는 유효한 숫자가 아닙니다."); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("시도할 횟수 입력이 숫자가 아닌 경우 테스트") | ||
| void setGameWithInvalidPhaseInput() { | ||
| RacingCarGame racingCarGame = new RacingCarGame(); | ||
| System.setIn(new ByteArrayInputStream("test1,test2\nabc\n".getBytes())); | ||
|
|
||
| assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("유효한 숫자가 아닙니다."); | ||
| } | ||
| } | ||
| } | ||
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.
이름은 5자 이하만 가능하다하였는데, 이 부분은 구현이 안 된 것 같아요!