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

자동차 경주 게임! #15

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/racing-game.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions src/main/java/racing/RacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racing;

import racing.domain.Cars;
import racing.view.InputView;

import java.util.Scanner;

public class RacingGame {
private final InputView inputView = new InputView(new Scanner(System.in));

public void run() {
int carCount = inputView.inputCarCount();
int tryCount = inputView.inputTryCount();

Cars cars = new Cars(carCount);
cars.operate(tryCount);
}
}
8 changes: 8 additions & 0 deletions src/main/java/racing/RacingGameApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package racing;

public class RacingGameApplication {
public static void main(String[] args) {
RacingGame racingGame = new RacingGame();
racingGame.run();
}
}
19 changes: 19 additions & 0 deletions src/main/java/racing/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package racing.domain;

import racing.util.RandomUtil;

public class Car {
private int distance;
Copy link
Contributor

Choose a reason for hiding this comment

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

엇근데 random으로 받은 distance 값을 바탕으로 outputview를 작성하는데,
이렇게 하면 주어진 요구사항에 맞지 않을 것 같습니다.
레이싱 게임 요구사항을 확인해주세요.


public Car(int distance) {
this.distance = distance;
}

public int getDistance() {
return distance;
}

public void move() {
Copy link
Contributor

Choose a reason for hiding this comment

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

이부분 테스트를 어떻게 하고 있나요?
랜덤이라서 테스트가 어려울 것 같은데 조언을 받아보세요!

public void move(int distance){
this.distance += distance
}

이런식으로 함수를 만들고 인자로 넣어줄 때 randomtuil 을 사용한다면 테스트도 가능한 함수가 됩니다 :)
지금도 좋은데!! 다른분들은 어떻게 테스트를 했는지 얘기해보면 좋을것 같아요

this.distance += RandomUtil.getRandomDistance();
}
Copy link
Member

Choose a reason for hiding this comment

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

이 부분에 대한 테스트가 가능하게 의존성 분리를 해보는 것은 어떨까요?

}
54 changes: 54 additions & 0 deletions src/main/java/racing/domain/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package racing.domain;

import racing.view.ResultView;
Copy link
Member

Choose a reason for hiding this comment

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

도메인에 View 의존성이 존재하네요!
구조를 바꿔봅시다!


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

public class Cars {
Copy link
Contributor

Choose a reason for hiding this comment

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

일급 컬렉션 굿b

private final List<Car> cars;

public Cars(int carCount) {
this.cars = collectCars(carCount);
}

public void operate(int tryCount) {
ResultView resultView = new ResultView();
while (remainTryCount(tryCount--)) {
moveCars();
resultView.printResult(this);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

뷰 의존성 제거해볼게요!


public Car getCar(int idx) {
return cars.get(idx);
}

public int getSize() {
return cars.size();
}

private List<Car> collectCars(int carCount) {
List<Car> cars = new ArrayList<>();
while (remainCar(carCount--)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

음 오히려 while 문을 사용해서 가독성이 떨어지는 것 같아요.
다들 많이 사용하는 for문 사용해도 좋을것 같아요 혹시라도 리터럴이 걱정이라면

for(int carIndex =0; carIndex < carCount; carIndex++)

이런식으로 평소 자주 사용하는 int i =0 보다 내용을 나타낼 수 있습니다. 아니면 IntStream을 사용하는 방법도 있구요!

cars.add(new Car(0));
}
Copy link
Member

Choose a reason for hiding this comment

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

제 생각에는 for문을 사용하는게 오히려 가독성에 좋을것 같아요


return cars;
}

private boolean remainCar(int carCount) {
return carCount > 0;
}

private boolean remainTryCount(int tryCount) {
return tryCount > 0;
}

private void moveCars() {
for (int idx = 0; idx < getSize(); idx++) {
Car car = getCar(idx);
car.move();
}
}
}
23 changes: 23 additions & 0 deletions src/main/java/racing/util/RandomUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package racing.util;

import java.util.Random;

public class RandomUtil{
private static final int MAX = 10;
private static final int MIN = 4;
private static final int STOP = 0;
private static final Random random = new Random();

public static int getRandomDistance() {
int randomDistance = random.nextInt(MAX);
if (lessThanMin(randomDistance)) {
return STOP;
}

return randomDistance;
}

private static boolean lessThanMin(int randomDistance) {
return randomDistance < MIN;
}
}
24 changes: 24 additions & 0 deletions src/main/java/racing/view/InputCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package racing.view;

public class InputCount {
private int count;

public InputCount(int count) {
checkPositive(count);
this.count = count;
}

public int getCount() {
return count;
}

private void checkPositive(int count) {
if (isNotPositive(count)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

이거는 개인 코드 차이인데요, 만약 이 조건문이 일회성으로 사용된다면 저는 private 이어도 method로 빼지 않는 편입니다.
조건문을 메서드로 빼서 중복을 해결할 수 있다면 정답이지만
한번만 사용되는 조건문이라면 지역변수로 넣어두기도 하는 분도 있다고 들었습니다..!
여튼 조건문이 어떤걸 확인하는지 리터럴로 지정해주는건 보는 사람이 코드를 읽기 쉽게 만들어주는 거라서 좋다고 봅니다.

boolean isNotPositive = count <= 0;

throw new IllegalArgumentException("입력하신 값이 양수가 아닙니다.");
}
}

private boolean isNotPositive(int count) {
return count <= 0;
}
}
24 changes: 24 additions & 0 deletions src/main/java/racing/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package racing.view;

import java.util.Scanner;

public class InputView {
private final String FIRST_QUESTION = "자동차 대수는 몇 대 인가요?";
private final String SECOND_QUESTION = "시도할 횟수는 몇 회 인가요?";

private final Scanner sc;

public InputView(Scanner sc) {
malibinYun marked this conversation as resolved.
Show resolved Hide resolved
this.sc = sc;
}

public int inputCarCount() {
System.out.println(FIRST_QUESTION);
return new InputCount(sc.nextInt()).getCount();
Copy link
Member

Choose a reason for hiding this comment

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

단순히 검증을 거쳤다 바깥으로 반환하는 용도로 사용하고 있는 객체인데
검증 로직을 한번 안쪽으로 숨긴것 밖에 안되는 것 같아!
객체 자체를 바깥으로 내보내서 사용하게 하는건 어떨까?

}

public int inputTryCount() {
System.out.println(SECOND_QUESTION);
return new InputCount(sc.nextInt()).getCount();
}
}
38 changes: 38 additions & 0 deletions src/main/java/racing/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package racing.view;

import racing.domain.Car;
import racing.domain.Cars;

public class ResultView {
private final String OPERATE_RESULT = "실행 결과";
private final String DISTANCE = "-";
private final String ENTER = "\n";

public ResultView() {
printEmpty();
System.out.println(OPERATE_RESULT);
}

public void printResult(Cars cars) {
for (int idx = 0; idx < cars.getSize(); idx++) {
printDistance(cars.getCar(idx));
}
printEmpty();
}

private void printDistance(Car car) {
int distance = car.getDistance();
while (remainDistance(distance--)) {
System.out.print(DISTANCE);
}
printEmpty();
}

private boolean remainDistance(int distance) {
return distance > 0;
}

private void printEmpty() {
System.out.print(ENTER);
}
}
36 changes: 36 additions & 0 deletions src/test/java/racing/domain/CarsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package racing.domain;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class CarsTest {
private Cars cars;

@DisplayName("자동차의 갯수가 입력한 값과 같은지 확인한다.")
@ParameterizedTest
@ValueSource(ints = {1, 3, 5, 6})
void getSize(int count) {
cars = new Cars(count);
assertEquals(cars.getSize(), count);
}

@DisplayName("자동차가 랜덤으로 들어온 값만큼 움직였는지 확인한다.")
@RepeatedTest(10)
void moveCars(RepetitionInfo repetitionInfo) {
malibinYun marked this conversation as resolved.
Show resolved Hide resolved
cars = new Cars(5);
cars.operate(1);

for (int idx = 0; idx < cars.getSize(); idx++) {
Car car = cars.getCar(idx);
int postDistance = car.getDistance();
System.out.println("Repetition #" + repetitionInfo.getCurrentRepetition() + " carDistance :" + postDistance);
assertTrue(postDistance == 0 || (postDistance >= 4 && postDistance <= 9), "랜덤으로 들어온 값에따라 자동차가 움직지 않았습니다.");
}
}
}
18 changes: 18 additions & 0 deletions src/test/java/racing/util/RandomUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racing.util;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;

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

public class RandomUtilTest {

@DisplayName("랜덤으로 생성된 값이 0 또는 4이상 9이하의 값만 반환하는지 확인한다.")
@RepeatedTest(100)
public void getRandomDistance(RepetitionInfo repetitionInfo) {
int distance = RandomUtil.getRandomDistance();
System.out.println("Repetition #" + repetitionInfo.getCurrentRepetition() + " RandomValue :" + distance);
assertTrue((distance >= 4 && distance <= 9) || distance == 0, "0 또는 4이상 9이하의 값 외의 다른 값이 반환되었습니다.");
}
}
19 changes: 19 additions & 0 deletions src/test/java/racing/view/InputCountTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package racing.view;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

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

class InputCountTest {

@DisplayName("입력 값이 양수가 아니면 예외발생을 시킨다.")
@ParameterizedTest
@ValueSource(ints = {-1, 0})
void checkPositive2(int count) {
assertThatThrownBy(() -> {
new InputCount(count);
}).isInstanceOf(IllegalArgumentException.class).hasMessage("입력하신 값이 양수가 아닙니다.");
}
}