diff --git a/README.md b/README.md index 93afe8b..b93d9e4 100644 --- a/README.md +++ b/README.md @@ -1 +1,44 @@ ECONOVATION HEROES 2기 2기 Java Racing Game Practice + +#####step1 +- 접근제어자 접근 범위를 생각하고 사용하기 +- CamelCase 따르기 +- 스터디 규칙 : 모든 변수명은 줄여쓰지 않는다 +- 불필요한 공백 포함하지 않기 +- Java 는 메모리를 직접 접근하여 해제하지 않고 Garbage Collector 를 사용하여 + 메모리 해제함. + + #####step2 + - primitive 타입과 wrapper 타입의 차이점 + - 게임의 룰은 어떤 클래스에 적용할 것인가? + - code formatting 습관 들이기 + - magic number 상수로 추출(상수는 네이밍은 대문자로 하는 것이 룰) + - 의존성 측면 고려하고 코드짜기 + + ######refactoring: + - InputView 클래스 상수 타입 변환 + - Race 클래스 상수 네이밍 대문자 처리 + - CamelCase에 따라 네이밍 고치기 + - 게임의 룰을 관리할 Rule 클래스 생성 + - setter 사용 지양 + - 불필요한 코드 주석 및 공백 제거 + - stream api 적용 + - 게임 시작을 위한 input 과 관련된 print 는 inputview로 옮기기 + - View 에 대한 책임을 Main(RacingGame) 으로 위임 + - InputView static 메소드로 구성하여 객체 생성 비용을 절감하기 + (추가) + - 메서드 체이닝을 적용해서 Arrays.stream(trimmedInputCarName).forEach(~~) + 로 이어 붙이기 + - util 목적으로 사용하실 클래스 객체 생성 비용 줄이기 + - 의미없는 메모리 낭비 없애기 + - 가독성에 유리하게 선언과 할당 같은 곳에서 해주기 + - 테스트 코드 + ###### 해결할 문제 + + 테스트 코드를 작성하다보니 public으로만 테스트가 안된다는 점에서 코드가 잘 짜여지지 않다고 느꼈다. + 테스트 코드를 먼저 작성하고 그에 맞추어 코드를 작성해야할까? + + + + + diff --git a/src/Car.java b/src/Car.java new file mode 100644 index 0000000..366cefc --- /dev/null +++ b/src/Car.java @@ -0,0 +1,21 @@ +public class Car { + private String name; + private int position; + + Car(String name) { + this.name = name; + this.position = 0; + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } + + public void goForward() { + this.position++; + } +} diff --git a/src/InputView.java b/src/InputView.java new file mode 100644 index 0000000..f06dca1 --- /dev/null +++ b/src/InputView.java @@ -0,0 +1,68 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Stream; + +public class InputView { + private static final int MAX_LENGTH = 6; + private static final Scanner scanner = new Scanner(System.in); + + public static List inputCarName() { + String name = scanner.nextLine(); + String[] splittedInputCarName = splitInputCarName(name); + String[] trimmedInputCarName = trimInputCarName(splittedInputCarName); + + try { + processStreamAboutCheckName(trimmedInputCarName); + } catch(IllegalArgumentException e) { + System.out.println(e.getMessage()); + inputCarName(); + } + + List cars = new ArrayList<>(); + for(int i = 0; i< splittedInputCarName.length; i++) { + cars.add(new Car(trimmedInputCarName[i])); + } + return cars; + } + + private static String[] splitInputCarName(String name) { + return name.split(","); + } + + private static String[] trimInputCarName(String[] name) { + for(int i = 0; i= MAX_LENGTH) { + throw new IllegalArgumentException("이름은 5자 이하만 가능합니다."); + } + } + + private static void processStreamAboutCheckName(String[] trimmedInputCarName) { + Stream stream = Arrays.stream(trimmedInputCarName); + stream.forEach(e -> checkNameLength(e)); + } + + public static int inputTrial() { + return scanner.nextInt(); + } + + public static void inputCarNamesMessage() { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + } + + public static void inputCountMessage() { + System.out.println("시도할 횟수는 몇회인가요?"); + } +} + + + + + diff --git a/src/OutputView.java b/src/OutputView.java new file mode 100644 index 0000000..f1038e2 --- /dev/null +++ b/src/OutputView.java @@ -0,0 +1,27 @@ +import java.util.List; + +public class OutputView { + private static final String DRIVE = "-"; + + public void resultMessage() { + System.out.println("\n실행 결과"); + } + + public void oneTrialMessage(List cars) { + for(Car car: cars) { + System.out.println(car.getName() + ": " + raceOneTrial(car)); + } + } + + private StringBuilder raceOneTrial(Car car) { + StringBuilder goSignal = new StringBuilder(); + for(int i = 0; i winnernames) { + System.out.println(String.join(",", winnernames + "가 최종 우승했습니다.")); + } +} diff --git a/src/RacingGame.java b/src/RacingGame.java new file mode 100644 index 0000000..8025f11 --- /dev/null +++ b/src/RacingGame.java @@ -0,0 +1,39 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class RacingGame { + private List winnernames = new ArrayList<>(); + + public void race(List cars) { + for(Car car: cars) { + goOrStay(car); + } + } + + private void goOrStay(Car car) { + if(Rule.isGoForward()) { + car.goForward(); + } + } + + public List getWinner(List cars) { + int positionOfWinner = findPositionOfWinner(cars); + cars = cars.stream().filter(car -> (car.getPosition() == positionOfWinner)).collect(Collectors.toList()); + for (Car car : cars) { + this.winnernames.add(car.getName()); + } + return winnernames; + } + + private int findPositionOfWinner(List cars) { + List position = new ArrayList<>(); + int positionOfWinner; + for(Car car: cars) { + position.add(car.getPosition()); + } + positionOfWinner = Collections.max(position); + return positionOfWinner; + } +} \ No newline at end of file diff --git a/src/RacingMain.java b/src/RacingMain.java new file mode 100644 index 0000000..7d4c83f --- /dev/null +++ b/src/RacingMain.java @@ -0,0 +1,26 @@ +import java.util.ArrayList; +import java.util.List; + +public class RacingMain { + public static void main(String[] args) { + OutputView outputView = new OutputView(); + RacingGame racingGame = new RacingGame(); + List cars = new ArrayList<>(); + int trial; + + InputView.inputCarNamesMessage(); + cars = InputView.inputCarName(); + InputView.inputCountMessage(); + trial = InputView.inputTrial(); + + for(int i = 0; i < trial; i++) { + outputView.resultMessage(); + racingGame.race(cars); + outputView.oneTrialMessage(cars); + } + + outputView.getWinnerMessage(racingGame.getWinner(cars)); + } +} + + diff --git a/src/Rule.java b/src/Rule.java new file mode 100644 index 0000000..04deb34 --- /dev/null +++ b/src/Rule.java @@ -0,0 +1,14 @@ +import java.util.Random; + +public class Rule { + private static final int BOUNDARYNUMBER = 10; + private static final int GOFORWARDCONDITION = 4; + + public static boolean isGoForward() { + Random random = new Random(); + if(random.nextInt(BOUNDARYNUMBER) >= GOFORWARDCONDITION) { + return true; + } + return false; + } +} diff --git a/test/InputViewTest.java b/test/InputViewTest.java new file mode 100644 index 0000000..6a939c2 --- /dev/null +++ b/test/InputViewTest.java @@ -0,0 +1,51 @@ +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertThat; + +public class InputViewTest { + List cars; + @Before + public void setUp() throws Exception { + cars = new ArrayList<>(); + cars.add(new Car("애플")); + cars.add(new Car("삼성")); + cars.add(new Car("전남대")); + } + + @Test + public void inputCarName() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + String carName = "애플, 삼성, 전남대"; + InputView inputView = new InputView(); + try { + Method methodsplit = inputView.getClass().getDeclaredMethod("splitInputCarName", String.class); + methodsplit.setAccessible(true); + Method methodtrim = inputView.getClass().getDeclaredMethod("trimInputCarName", String[].class); + methodtrim.setAccessible(true); + String[] name = (String[]) methodsplit.invoke(inputView, carName); + String[] name1 = (String[]) methodtrim.invoke(inputView, (Object) name); + assertThat("애플", is(name1[0])); + assertThat("삼성", is(name1[1])); + assertThat("전남대", is(name1[2])); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + @Test + public void inputTrial() { + + } + + @After + public void tearDown() throws Exception { + cars = null; + } +} \ No newline at end of file diff --git a/test/RaceTest.java b/test/RaceTest.java new file mode 100644 index 0000000..5d39304 --- /dev/null +++ b/test/RaceTest.java @@ -0,0 +1,12 @@ +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RaceTest { + @Test + public void getWinner() { + + } + + +} \ No newline at end of file diff --git a/test/RacingGameTest.java b/test/RacingGameTest.java new file mode 100644 index 0000000..08ebf3c --- /dev/null +++ b/test/RacingGameTest.java @@ -0,0 +1,49 @@ +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class RacingGameTest { + List cars; + RacingGame racingGame; + @Before + public void setUp() throws Exception { + cars = new ArrayList<>(); + cars.add(new Car("애플")); + cars.add(new Car("삼성")); + cars.add(new Car("전남대")); + racingGame = new RacingGame(); + } + + @Test + public void race() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method goOrStay = racingGame.getClass().getDeclaredMethod("goOrStay", Car.class); + goOrStay.setAccessible(true); + for(Car car: cars) { + goOrStay.invoke(racingGame, car); + } + } + + @Test + public void getWinner() { + cars.get(0).goForward(); + cars.get(1).goForward(); + List expectedWinnerNames = new ArrayList<>(); + expectedWinnerNames.add("애플"); + expectedWinnerNames.add("삼성"); + List actualWinnerNames = racingGame.getWinner(cars); + assertThat(actualWinnerNames,is(expectedWinnerNames)); + } + + @After + public void tearDown() throws Exception { + cars = null; + } +} \ No newline at end of file diff --git a/test/RuleTest.java b/test/RuleTest.java new file mode 100644 index 0000000..c807a2a --- /dev/null +++ b/test/RuleTest.java @@ -0,0 +1,12 @@ +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.either; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +public class RuleTest { + @Test + public void isGoForward() { + assertThat(Rule.isGoForward(),either(is(true)).or(is(false)) ); + } +} \ No newline at end of file