diff --git a/build.gradle b/build.gradle index 8172fb7..1cdbe77 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'eclipse' group = 'camp.nextstep' version = '1.0.0' -sourceCompatibility = '1.8' +sourceCompatibility = "11" repositories { mavenCentral() @@ -17,3 +17,4 @@ dependencies { test { useJUnitPlatform() } +targetCompatibility = JavaVersion.VERSION_11 diff --git a/src/main/java/study/racingcar/RacingCarApplication.java b/src/main/java/study/racingcar/RacingCarApplication.java new file mode 100644 index 0000000..30b3c08 --- /dev/null +++ b/src/main/java/study/racingcar/RacingCarApplication.java @@ -0,0 +1,10 @@ +package study.racingcar; + +import study.racingcar.controller.CarController; + +public class RacingCarApplication { + + public static void main(String[] args) { + new CarController(); + } +} diff --git a/src/main/java/study/racingcar/controller/CarController.java b/src/main/java/study/racingcar/controller/CarController.java new file mode 100644 index 0000000..e5d8634 --- /dev/null +++ b/src/main/java/study/racingcar/controller/CarController.java @@ -0,0 +1,36 @@ +package study.racingcar.controller; + +import study.racingcar.model.Car; +import study.racingcar.view.InputView; +import study.racingcar.view.ResultView; + +import java.util.ArrayList; +import java.util.List; + +import static study.racingcar.model.Car.requestCarsToMove; + +public class CarController { + public CarController() { + List carList = addCar(InputView.getCarNumber()); + raceStart(InputView.getCarNumber(), InputView.getAttemptNumber(), carList); + } + + public static void raceStart(int carNum, int attemptNum, List carList) { + for (int i = 0; i < attemptNum; i++) { + List racingCar = requestCarsToMove(carNum, carList); + ResultView.printRaceResult(racingCar); + } + } + + public static List addCar(int carNum) { + List carList = new ArrayList<>(); + + for (int i = 0; i < carNum; i++) { + Car car = new Car(0); + + carList.add(i, car); + } + + return carList; + } +} diff --git a/src/main/java/study/racingcar/model/Car.java b/src/main/java/study/racingcar/model/Car.java new file mode 100644 index 0000000..86075d4 --- /dev/null +++ b/src/main/java/study/racingcar/model/Car.java @@ -0,0 +1,41 @@ +package study.racingcar.model; + +import java.util.List; +import java.util.Random; + +public class Car { + private static final int MAX_BOUNDARY_OF_RANDOM_NUMBER= 10; + private int positions; + + public Car(int positions) { + this.positions = positions; + } + + public static List requestCarsToMove(int carNum, List carList) { + for (int i = 0; i < carNum; i++) { + forwardNumber(i, carList); + } + return carList; + } + + private static void forwardNumber(int current, List carList) { + Random random = new Random(); + int forward = random.nextInt(MAX_BOUNDARY_OF_RANDOM_NUMBER); // 0부터 9 + + if (forward >= 4) { + Car car = carList.get(current); + int currentValue = car.getPositions(); + + car.setPositions(currentValue + 1); + carList.set(current, car); + } + } + + public int getPositions() { + return positions; + } + + public void setPositions(int positions) { + this.positions = positions; + } +} diff --git a/src/main/java/study/racingcar/view/InputView.java b/src/main/java/study/racingcar/view/InputView.java new file mode 100644 index 0000000..9e3373c --- /dev/null +++ b/src/main/java/study/racingcar/view/InputView.java @@ -0,0 +1,24 @@ +package study.racingcar.view; + +import java.util.Scanner; + +public class InputView { + public static int getCarNumber() { + Scanner scanner = new Scanner(System.in); + + System.out.println("자동차 대수는 몇 대 인가요?"); + int carNum = scanner.nextInt(); + + return carNum; + } + + public static int getAttemptNumber() { + Scanner scanner = new Scanner(System.in); + + System.out.println("시도할 횟수는 몇 회인가요?"); + int attemptNum = scanner.nextInt(); + System.out.println(); + + return attemptNum; + } +} \ No newline at end of file diff --git a/src/main/java/study/racingcar/view/ResultView.java b/src/main/java/study/racingcar/view/ResultView.java new file mode 100644 index 0000000..3933b6a --- /dev/null +++ b/src/main/java/study/racingcar/view/ResultView.java @@ -0,0 +1,17 @@ +package study.racingcar.view; + +import study.racingcar.model.Car; + +import java.util.List; + +public class ResultView { + public static void printRaceResult(List carList) { + for (Car car : carList) { + for (int k = 0; k < car.getPositions(); k++) { + System.out.print("ㅡ"); + } + System.out.println(); + } + System.out.println(); + } +} diff --git a/src/main/java/study/stringcalculator/StringCalculator.java b/src/main/java/study/stringcalculator/StringCalculator.java new file mode 100644 index 0000000..e8b8483 --- /dev/null +++ b/src/main/java/study/stringcalculator/StringCalculator.java @@ -0,0 +1,36 @@ +package study.stringcalculator; + +import java.util.List; + +public class StringCalculator { + + private StringCalculator() { } + public static int calculate(String text) { + List values = StringParser.parse(text); + int number = Integer.parseInt(values.get(0)); + + for (int i = 1; i < values.size(); i += 2) { + + int operand = Integer.parseInt(values.get(i + 1)); + String operator = values.get(i); + + number = getNumber(number, operand, operator); + } + + return number; + } + + private static int getNumber(int number, int operand, String operator) { + if ("+".equals(operator)) return number + operand; + if ("-".equals(operator)) return number - operand; + if ("*".equals(operator)) return number * operand; + if ("/".equals(operator)) { + if (operand == 0) { + throw new IllegalArgumentException(); + } + return number / operand; + } + + throw new IllegalArgumentException("잘못된 연산자 입니다."); + } +} diff --git a/src/main/java/study/stringcalculator/StringParser.java b/src/main/java/study/stringcalculator/StringParser.java new file mode 100644 index 0000000..423c6d3 --- /dev/null +++ b/src/main/java/study/stringcalculator/StringParser.java @@ -0,0 +1,14 @@ +package study.stringcalculator; + +import java.util.List; + +public class StringParser { + + private StringParser() { } + + static List parse(String input) { + return List.of(input.split(" ")); + // 알아둘 것. ArrayList로 만들면 가변 + null값 허용 + // List.of 메서드로 만들면 불변 + null값은 허용 X + } +} diff --git a/src/test/java/study/StringTest.java b/src/test/java/study/StringTest.java deleted file mode 100644 index 43e47d9..0000000 --- a/src/test/java/study/StringTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package study; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StringTest { - @Test - void replace() { - String actual = "abc".replace("b", "d"); - assertThat(actual).isEqualTo("adc"); - } -} diff --git a/src/test/java/study/exam/SetTest.java b/src/test/java/study/exam/SetTest.java new file mode 100644 index 0000000..bc2e527 --- /dev/null +++ b/src/test/java/study/exam/SetTest.java @@ -0,0 +1,84 @@ +package study.exam; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SetTest { + private Set numbers; + + @BeforeEach + @DisplayName("HashSet에 값을 추가한다.") + void setUp() { + numbers = new HashSet<>(); + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + } + + @Test + @DisplayName("집합의 크기를 확인할 수 있다.") + void setSize() { + int result = numbers.size(); + assertEquals(result, 3); // Set은 중복을 허용하지 않는다. + } + + @Test + @DisplayName("집합에 값이 포함되어있는지 비교할 수 있다.") + void compareContains() { + numbers = new HashSet<>(); + + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + + assertThat(numbers.contains(1)).isTrue(); + assertThat(numbers.contains(2)).isTrue(); + assertThat(numbers.contains(3)).isTrue(); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3}) + @DisplayName("ValueSource를 사용해 입력 받은 숫자가 각각 numbers에 포함되는지 확인한다.") + void compareContains(int value) { + numbers = new HashSet<>(); + + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + + assertThat(numbers.contains(value)).isTrue(); + } + + @ParameterizedTest + @CsvSource({ + "1, true", + "2, true", + "3, true", + "4, false", + "5, false" + }) + @DisplayName("CsvSource로 true 값만 비교하는 것이 아닌 false 값도 비교할 수 있다.") + void compareContains(int value, boolean expected) { + numbers = new HashSet<>(); + + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + + assertThat(numbers.contains(value)).isEqualTo(expected); + } +} \ No newline at end of file diff --git a/src/test/java/study/exam/StringTest.java b/src/test/java/study/exam/StringTest.java new file mode 100644 index 0000000..37fa189 --- /dev/null +++ b/src/test/java/study/exam/StringTest.java @@ -0,0 +1,47 @@ +package study.exam; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class StringTest { + @Test + @DisplayName("abc에서 b를 d로 대체했을 때 같은지 테스트하는 코드") + void replace() { + String actual = "abc".replace("b", "d"); + assertThat(actual).isEqualTo("adc"); + } + // 요구사항 1 + @Test + @DisplayName("특정 문자열로 분리하는 테스트 코드") + public void split() { + String[] values = "1,2".split(","); + assertThat(values).containsExactly("1", "2"); + values = "1".split(","); + assertThat(values).contains("1"); + } + @Test + @DisplayName("특정 문자열까지 읽어서 비교하는 테스트 코드") + public void subString() { + String input = "(1,2)"; + String result = input.substring(1, input.length() - 1); //문자열 인덱스 1부터 input의 길이 - 1 즉 2까지. + assertThat(result).isEqualTo("1,2"); + } + @Test + @DisplayName("String의 특정 위치의 문자 가져오기") + public void getIndexValue() { + String values = "abc"; + assertEquals('a', values.charAt(0)); + } + + @Test + @DisplayName("위치 값을 벗어났을 때의 예외") + public void stringIndexOutOfBoundsException() { + String values = "abc"; + assertThrows(StringIndexOutOfBoundsException.class, () -> values.charAt(-1)); + assertThrows(StringIndexOutOfBoundsException.class, () -> values.charAt(3)); + } +} diff --git a/src/test/java/study/racingcar/CarTest.java b/src/test/java/study/racingcar/CarTest.java new file mode 100644 index 0000000..619992e --- /dev/null +++ b/src/test/java/study/racingcar/CarTest.java @@ -0,0 +1,31 @@ +package study.racingcar; + +import org.junit.jupiter.api.Test; +import study.racingcar.model.Car; + +import java.util.List; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static study.racingcar.controller.CarController.addCar; +import static study.racingcar.model.Car.requestCarsToMove; + +public class CarTest { + + private static final int MAX_BOUNDARY_OF_RANDOM_CAR_NUMBER = 5; + @Test + public void 자동차_전진_로직을_확인한다() { + // given + Random random = new Random(); + int carNum = random.nextInt(MAX_BOUNDARY_OF_RANDOM_CAR_NUMBER + 1); // 1 ~ 5 + List carList = addCar(carNum); + + // when + List checkForward = requestCarsToMove(carNum, carList); + + // then + for (int i = 0 ; i < carNum; i++) { + assertEquals(checkForward.get(i).getPositions() == 0 || checkForward.get(i).getPositions() == 1, true); + } + } +} diff --git a/src/test/java/study/racingcar/README.md b/src/test/java/study/racingcar/README.md new file mode 100644 index 0000000..fe416b1 --- /dev/null +++ b/src/test/java/study/racingcar/README.md @@ -0,0 +1,34 @@ +### **요구사항** + +초간단 자동차 경주 게임을 구현한다. + +- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. +- 사용자는 몇 대의 자동차로 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. +- 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. +- 자동차의 상태를 화면에 출력한다. 어느 시점에 출력할 것인지에 대한 제약은 없다. + +--- +### **체크리스트** +- [x] 자동차 대수를 입력 받는다. +- [x] 시도할 횟수를 입력 받는다. +- [x] 무작위 값을 구해 4 이상일 때 전진하는 조건을 구현한다. + +--- +# 프로그래밍 요구 사항 + +모든 로직에 단위 테스트를 구현한다. +단, UI(System.out, [System.in](http://system.in/)) 로직은 제외 +핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다. +UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다. + +--- +ex. +> 자동차 대수는 몇 대인가요? +> +> 3 +> +> 시도할 횟수는 몇 회인가요? +> +> 5 +> +> ![img.png](img.png) \ No newline at end of file diff --git a/src/test/java/study/racingcar/img.png b/src/test/java/study/racingcar/img.png new file mode 100644 index 0000000..0490a3a Binary files /dev/null and b/src/test/java/study/racingcar/img.png differ diff --git a/src/test/java/study/stringcalculator/README.md b/src/test/java/study/stringcalculator/README.md new file mode 100644 index 0000000..086690b --- /dev/null +++ b/src/test/java/study/stringcalculator/README.md @@ -0,0 +1,11 @@ +### **요구사항** + +- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다. +- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다. +- 예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다. + +### **체크리스트** +- [x] 문자열을 입력받는다. +- [x] 문자열을 파싱한다. +- [x] 0으로 나눴을 때 IllegalArgumentException을 터뜨린다. +- [x] 파싱한 문자열로 계산한다. \ No newline at end of file diff --git a/src/test/java/study/stringcalculator/StringCalculatorTest.java b/src/test/java/study/stringcalculator/StringCalculatorTest.java new file mode 100644 index 0000000..5bcff27 --- /dev/null +++ b/src/test/java/study/stringcalculator/StringCalculatorTest.java @@ -0,0 +1,40 @@ +package study.stringcalculator; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class StringCalculatorTest { + + @Test + public void 문자열을_입력받는다() { + String input = "2 + 3 * 4 / 2"; + + Assertions.assertThat(StringCalculator.calculate(input)); + } + + @Test + public void 수학적_계산이_아닌_문자열_인덱스_순서_대로_연산자와_피연산자를_나누어_계산한다() { + String input = "2 + 3 * 4 / 2"; + + Assertions.assertThat(StringCalculator.calculate(input)).isEqualTo(10); + + } + + @Test + public void 잘못된_연산자가_입력됐을_때_예외가_발생한다() { + String input = "2 + 3 * 4 & 2"; + + Assertions.assertThatThrownBy(() -> { + StringCalculator.calculate(input); + }).isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void 나누는_숫자가_0이면_예외가_발생한다() { + String input = "2 + 3 * 4 / 0"; + + Assertions.assertThatThrownBy(() -> { + StringCalculator.calculate(input); + }).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/study/stringcalculator/StringParserTest.java b/src/test/java/study/stringcalculator/StringParserTest.java new file mode 100644 index 0000000..e971102 --- /dev/null +++ b/src/test/java/study/stringcalculator/StringParserTest.java @@ -0,0 +1,18 @@ +package study.stringcalculator; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class StringParserTest { + + @Test + public void 하나의_문자열을_파싱해서_String_배열로_만든다() { + String input = "2 + 3 * 4 / 2"; + + List stringList = List.of("2", "+", "3", "*", "4", "/", "2"); + + Assertions.assertThat(StringParser.parse(input)).isEqualTo(stringList); + } +}