From 649d498b17aa4f6a2a2889236de7d7bb7c6568c1 Mon Sep 17 00:00:00 2001 From: laancer4 Date: Fri, 1 Sep 2023 09:09:12 +0900 Subject: [PATCH 1/3] =?UTF-8?q?StringCalculator=20=EC=99=84=EC=84=B1=20(mi?= =?UTF-8?q?nus=20=EC=96=B4=EB=8A=90=EC=A0=95=EB=8F=84=20=EC=97=B4=EC=96=B4?= =?UTF-8?q?=EC=A3=BC=EB=8A=94=20=EB=B2=84=EC=A0=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/StringAddCalculator.java | 38 ++++++++++++++++++ src/test/java/StringCalculatorTest.java | 52 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/main/java/StringAddCalculator.java create mode 100644 src/test/java/StringCalculatorTest.java diff --git a/src/main/java/StringAddCalculator.java b/src/main/java/StringAddCalculator.java new file mode 100644 index 000000000..e2db2ca1f --- /dev/null +++ b/src/main/java/StringAddCalculator.java @@ -0,0 +1,38 @@ +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringAddCalculator { + + public static int splitAndSum(String input) { + if (isNullOrEmpty(input)) return 0; + if (containsNegativeNumbers(input)) throw new RuntimeException(); + String[] tokens = splitInput(input); + return calculateSum(tokens); + } + + private static String[] splitInput(String input) { + Matcher matcher = Pattern.compile("//(.)\n(.*)").matcher(input); + if (matcher.find()) { + String customDelimiter = matcher.group(1); + return matcher.group(2).split(Pattern.quote(customDelimiter)); + } + return commaColonSplit(input); + } + + private static String[] commaColonSplit(String input) { + return input.split(",|:"); + } + + private static int calculateSum(String[] tokens) { + return Arrays.stream(tokens).mapToInt(Integer::parseInt).sum(); + } + + private static boolean isNullOrEmpty(String input) { + return input == null || input.trim().isEmpty(); + } + + private static boolean containsNegativeNumbers(String input) { + return input.contains("-") && Arrays.stream(splitInput(input)).anyMatch(s -> Integer.parseInt(s) < 0); + } +} \ No newline at end of file diff --git a/src/test/java/StringCalculatorTest.java b/src/test/java/StringCalculatorTest.java new file mode 100644 index 000000000..5893462d9 --- /dev/null +++ b/src/test/java/StringCalculatorTest.java @@ -0,0 +1,52 @@ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +class StringCalculatorTest { + @Test + public void splitAndSum_null_또는_빈문자() { + int result = StringAddCalculator.splitAndSum(null); + assertThat(result).isEqualTo(0); + result = StringAddCalculator.splitAndSum(""); + assertThat(result).isEqualTo(0); + } + + @Test + public void splitAndSum_숫자하나() throws Exception { + int result = StringAddCalculator.splitAndSum("1"); + assertThat(result).isEqualTo(1); + } + + @Test + public void splitAndSum_쉼표구분자() throws Exception { + int result = StringAddCalculator.splitAndSum("1,2"); + assertThat(result).isEqualTo(3); + } + + @Test + public void splitAndSum_쉼표_또는_콜론_구분자() throws Exception { + int result = StringAddCalculator.splitAndSum("1,2:3"); + assertThat(result).isEqualTo(6); + } + + @Test + public void splitAndSum_custom_구분자() throws Exception { + int result = StringAddCalculator.splitAndSum("//;\n1;2;3"); + assertThat(result).isEqualTo(6); + } + + @Test + public void splitAndSum_negative() throws Exception { + assertThatThrownBy(() -> StringAddCalculator.splitAndSum("-1,2,3")) + .isInstanceOf(RuntimeException.class); + } + + @Test // 그냥 contains("-") 로 완전히 막을수도 있음. + public void splitAndSum_커스텀마이너스_핸들(){ + int result = StringAddCalculator.splitAndSum("//-\n1-2-3"); + assertThat(result).isEqualTo(6); + } +} \ No newline at end of file From 42fc6f402296d5575defc29517fbfd23d4367b5d Mon Sep 17 00:00:00 2001 From: DK Date: Fri, 1 Sep 2023 10:54:41 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EC=9E=90=EB=8F=99=EC=B0=A8=20=EA=B2=BD?= =?UTF-8?q?=EC=A3=BC=20=EA=B2=8C=EC=9E=84=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Car.java | 23 ++++++++++++++ src/main/java/CarController.java | 25 ++++++++++++++++ src/main/java/Cars.java | 32 ++++++++++++++++++++ src/main/java/InputView.java | 14 +++++++++ src/main/java/Main.java | 10 +++++++ src/main/java/OutputView.java | 43 +++++++++++++++++++++++++++ src/test/java/CarRacingTest.java | 51 ++++++++++++++++++++++++++++++++ 7 files changed, 198 insertions(+) create mode 100644 src/main/java/Car.java create mode 100644 src/main/java/CarController.java create mode 100644 src/main/java/Cars.java create mode 100644 src/main/java/InputView.java create mode 100644 src/main/java/Main.java create mode 100644 src/main/java/OutputView.java create mode 100644 src/test/java/CarRacingTest.java diff --git a/src/main/java/Car.java b/src/main/java/Car.java new file mode 100644 index 000000000..e3b213815 --- /dev/null +++ b/src/main/java/Car.java @@ -0,0 +1,23 @@ +import java.util.Random; + +public class Car { + private final String name; + private int location = 1; + public Car(String name) { + if (name.length() > 5) throw new RuntimeException(); + this.name = name; + } + + public int getLocation(){ + return this.location; + } + + public void move(){ + Random random = new Random(); + if (random.nextInt(10) >= 4) this.location++; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/CarController.java b/src/main/java/CarController.java new file mode 100644 index 000000000..cee7ca7bf --- /dev/null +++ b/src/main/java/CarController.java @@ -0,0 +1,25 @@ +import java.io.IOException; + +public class CarController { + private final InputView inputView; + private final OutputView outputView; + + public CarController(InputView inputView, OutputView outputView) { // 둘은 완전히 책임이 다르므로 의존주입 받기 + this.inputView = inputView; + this.outputView = outputView; + } + + public void game() throws IOException { + outputView.inputName(); + String input = inputView.getInput(); + String[] splitInput = inputView.getCars(input); + Cars cars = new Cars(splitInput); + outputView.getTrial(); + int trial = Integer.parseInt(inputView.getInput()); + for (int i = 0; i < trial; i++) { + cars.move(); + outputView.result(cars); + } + outputView.winner(cars); + } +} diff --git a/src/main/java/Cars.java b/src/main/java/Cars.java new file mode 100644 index 000000000..9fc08ea12 --- /dev/null +++ b/src/main/java/Cars.java @@ -0,0 +1,32 @@ +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class Cars { + private final List cars; + + public Cars(String[] nameArr){ + this.cars = Arrays.stream(nameArr).map(Car::new).collect(Collectors.toList()); + } + + public void move(){ + cars.forEach(Car::move); + } + + public List getCars() { + return cars; + } + + public List winners() { + int maxLocation = cars.stream() + .mapToInt(Car::getLocation) + .max() + .orElse(0); + + return cars.stream() + .filter(car -> car.getLocation() == maxLocation) + .map(Car::getName) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java new file mode 100644 index 000000000..54592df98 --- /dev/null +++ b/src/main/java/InputView.java @@ -0,0 +1,14 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class InputView { + public String[] getCars(String s) { + return s.split(","); + } + + public String getInput() throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + return br.readLine(); + } +} diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 000000000..7ae699c5d --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,10 @@ +import java.io.IOException; + +public class Main { + public static void main(String[] args) throws IOException { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + CarController carController = new CarController(inputView, outputView); + carController.game(); + } +} diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java new file mode 100644 index 000000000..743043389 --- /dev/null +++ b/src/main/java/OutputView.java @@ -0,0 +1,43 @@ +import java.util.List; + +public class OutputView { + public void inputName(){ + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + } + + public void getTrial(){ + System.out.println("시도할 회수는 몇회인가요?"); + } + + public void result(Cars cars){ + List carList = cars.getCars(); + for (Car car : carList) { + System.out.println(carInfo(car)); + } + } + + public void winner(Cars cars){ + List winners = cars.winners(); + if (winners.size() == 1){ + System.out.println(winners.get(0) + "가 최종 우승했습니다."); + } + if (winners.size() > 1){ + StringBuilder sb = new StringBuilder(); + sb.append(String.join(", ", winners)); + sb.append("가 최종 우승했습니다."); + System.out.println(sb.toString()); + } + } + + private String carInfo(Car car) { + return car.getName() + " : " + intToMinus(car.getLocation()); + } + + private String intToMinus(int location){ + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < location; i++) { + sb.append("-"); + } + return sb.toString(); + } +} diff --git a/src/test/java/CarRacingTest.java b/src/test/java/CarRacingTest.java new file mode 100644 index 000000000..7429fa696 --- /dev/null +++ b/src/test/java/CarRacingTest.java @@ -0,0 +1,51 @@ +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Random; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +public class CarRacingTest { + @Test + void inputByComma(){ + InputView inputView = new InputView(); + String s = "one,two,three"; + String[] cars = inputView.getCars(s); + assertThat(cars.length).isEqualTo(3); + } + + @Test + void carName_failureTest(){ + String name = "more than five words"; + assertThatThrownBy(() -> new Car(name)); + } + @Test + void randomTest(){ + Random random = new Random(); + System.out.println(random.nextInt(10)); + } + @Test + void carMoveTest(){ + Car car = new Car("12"); + while (car.getLocation() != 3){ + car.move(); + } + assertThat(car.getLocation()).isEqualTo(3); + } + + @Test + void carsTest(){ + String[] nameArr = new String[]{"1", "2", "3"}; + Cars cars = new Cars(nameArr); + for (int i = 0; i < 5; i++) { + cars.move(); + } + List cars1 = cars.getCars(); + int count = 0; + for (Car car1 : cars1) { + count += car1.getLocation(); + } + assertThat(count).isGreaterThan(3); // 초기값 3보다는 어쨋든 움직일 확률이 매우 큼 + } +} From 093ca0488c9a807e41e3250237e3f43288f3ad39 Mon Sep 17 00:00:00 2001 From: DK Date: Tue, 3 Oct 2023 13:48:31 +0900 Subject: [PATCH 3/3] =?UTF-8?q?TDD=20=EA=B8=B0=EB=B0=98=EC=9D=98=20?= =?UTF-8?q?=EC=B2=AB=20=EC=8B=9C=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/StringAddCalculator.java | 38 --------------- src/main/java/{ => car}/Car.java | 9 +++- src/main/java/{ => car}/CarController.java | 2 + src/main/java/{ => car}/Cars.java | 3 +- src/main/java/{ => car}/InputView.java | 2 + src/main/java/{ => car}/Main.java | 6 +++ src/main/java/{ => car}/OutputView.java | 2 + .../StringAddCalculator.java | 46 +++++++++++++++++++ src/test/java/CarRacingTest.java | 5 +- src/test/java/CarTest.java | 30 ++++++++++++ src/test/java/StringAddCalculatorTest.java | 33 +++++++++++++ src/test/java/StringCalculatorTest.java | 3 +- 12 files changed, 136 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/StringAddCalculator.java rename src/main/java/{ => car}/Car.java (65%) rename src/main/java/{ => car}/CarController.java (98%) rename src/main/java/{ => car}/Cars.java (96%) rename src/main/java/{ => car}/InputView.java (96%) rename src/main/java/{ => car}/Main.java (79%) rename src/main/java/{ => car}/OutputView.java (98%) create mode 100644 src/main/java/string_calculator/StringAddCalculator.java create mode 100644 src/test/java/CarTest.java create mode 100644 src/test/java/StringAddCalculatorTest.java diff --git a/src/main/java/StringAddCalculator.java b/src/main/java/StringAddCalculator.java deleted file mode 100644 index e2db2ca1f..000000000 --- a/src/main/java/StringAddCalculator.java +++ /dev/null @@ -1,38 +0,0 @@ -import java.util.Arrays; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class StringAddCalculator { - - public static int splitAndSum(String input) { - if (isNullOrEmpty(input)) return 0; - if (containsNegativeNumbers(input)) throw new RuntimeException(); - String[] tokens = splitInput(input); - return calculateSum(tokens); - } - - private static String[] splitInput(String input) { - Matcher matcher = Pattern.compile("//(.)\n(.*)").matcher(input); - if (matcher.find()) { - String customDelimiter = matcher.group(1); - return matcher.group(2).split(Pattern.quote(customDelimiter)); - } - return commaColonSplit(input); - } - - private static String[] commaColonSplit(String input) { - return input.split(",|:"); - } - - private static int calculateSum(String[] tokens) { - return Arrays.stream(tokens).mapToInt(Integer::parseInt).sum(); - } - - private static boolean isNullOrEmpty(String input) { - return input == null || input.trim().isEmpty(); - } - - private static boolean containsNegativeNumbers(String input) { - return input.contains("-") && Arrays.stream(splitInput(input)).anyMatch(s -> Integer.parseInt(s) < 0); - } -} \ No newline at end of file diff --git a/src/main/java/Car.java b/src/main/java/car/Car.java similarity index 65% rename from src/main/java/Car.java rename to src/main/java/car/Car.java index e3b213815..e223fc3b5 100644 --- a/src/main/java/Car.java +++ b/src/main/java/car/Car.java @@ -1,6 +1,9 @@ +package car; + import java.util.Random; public class Car { + private static final int MINIMUM_MOVING_STANDARD = 4; private final String name; private int location = 1; public Car(String name) { @@ -13,8 +16,12 @@ public int getLocation(){ } public void move(){ + if (MINIMUM_MOVING_STANDARD <= getRandomNum()) this.location++; + } + + protected int getRandomNum(){ Random random = new Random(); - if (random.nextInt(10) >= 4) this.location++; + return random.nextInt(10); } public String getName() { diff --git a/src/main/java/CarController.java b/src/main/java/car/CarController.java similarity index 98% rename from src/main/java/CarController.java rename to src/main/java/car/CarController.java index cee7ca7bf..987b0086f 100644 --- a/src/main/java/CarController.java +++ b/src/main/java/car/CarController.java @@ -1,3 +1,5 @@ +package car; + import java.io.IOException; public class CarController { diff --git a/src/main/java/Cars.java b/src/main/java/car/Cars.java similarity index 96% rename from src/main/java/Cars.java rename to src/main/java/car/Cars.java index 9fc08ea12..a7c94c6ac 100644 --- a/src/main/java/Cars.java +++ b/src/main/java/car/Cars.java @@ -1,5 +1,6 @@ +package car; + import java.util.Arrays; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; diff --git a/src/main/java/InputView.java b/src/main/java/car/InputView.java similarity index 96% rename from src/main/java/InputView.java rename to src/main/java/car/InputView.java index 54592df98..46ea60462 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/car/InputView.java @@ -1,3 +1,5 @@ +package car; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; diff --git a/src/main/java/Main.java b/src/main/java/car/Main.java similarity index 79% rename from src/main/java/Main.java rename to src/main/java/car/Main.java index 7ae699c5d..5bff6a8d5 100644 --- a/src/main/java/Main.java +++ b/src/main/java/car/Main.java @@ -1,3 +1,9 @@ +package car; + +import car.CarController; +import car.InputView; +import car.OutputView; + import java.io.IOException; public class Main { diff --git a/src/main/java/OutputView.java b/src/main/java/car/OutputView.java similarity index 98% rename from src/main/java/OutputView.java rename to src/main/java/car/OutputView.java index 743043389..8c51d505e 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/car/OutputView.java @@ -1,3 +1,5 @@ +package car; + import java.util.List; public class OutputView { diff --git a/src/main/java/string_calculator/StringAddCalculator.java b/src/main/java/string_calculator/StringAddCalculator.java new file mode 100644 index 000000000..7c5e25069 --- /dev/null +++ b/src/main/java/string_calculator/StringAddCalculator.java @@ -0,0 +1,46 @@ +package string_calculator; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringAddCalculator { + + public static int splitAndSum(String s) { + if (noInput(s)) return 0; + if (isJustOneInt(s)) return convertToInt(s); + s = replaceColon(s); + return calculateByRest(s); + } + + private static boolean noInput(String s) { + return s == null || s.isEmpty(); + } + + private static String replaceColon(String s){ + return s.replaceAll(":", ","); + } + private static String splitByPattern(String s){ + Matcher m = Pattern.compile("//(.)\n(.*)").matcher(s); + if (m.find()) { + String customDelimiter = m.group(1); + return m.group(2).replaceAll(customDelimiter, ","); + } + return null; + } + private static int calculateByRest(String s){ + String[] split = s.split(","); + int sum = 0; + for (String s1 : split) { + sum +=convertToInt(s1); + } + return sum; + } + + private static boolean isJustOneInt(String s) { + return s.length() == 1; + } + + private static int convertToInt(String s){ + return Integer.parseInt(s); + } +} diff --git a/src/test/java/CarRacingTest.java b/src/test/java/CarRacingTest.java index 7429fa696..4526389d6 100644 --- a/src/test/java/CarRacingTest.java +++ b/src/test/java/CarRacingTest.java @@ -1,3 +1,6 @@ +import car.Car; +import car.Cars; +import car.InputView; import org.junit.jupiter.api.Test; import java.util.List; @@ -6,7 +9,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -public class CarRacingTest { +class CarRacingTest { @Test void inputByComma(){ InputView inputView = new InputView(); diff --git a/src/test/java/CarTest.java b/src/test/java/CarTest.java new file mode 100644 index 000000000..efec9dae4 --- /dev/null +++ b/src/test/java/CarTest.java @@ -0,0 +1,30 @@ +import car.Car; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CarTest { + @Test + void move_SUCCESS(){ + Car car = new Car("소나타"){ + @Override + protected int getRandomNum() { + return 4; + } + }; + car.move(); + assertThat(car.getLocation()).isEqualTo(2); + } + + @Test + void move_FAILURE(){ + Car car = new Car("소나타"){ + @Override + protected int getRandomNum() { + return 3; + } + }; + car.move(); + assertThat(car.getLocation()).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/StringAddCalculatorTest.java b/src/test/java/StringAddCalculatorTest.java new file mode 100644 index 000000000..331ae7852 --- /dev/null +++ b/src/test/java/StringAddCalculatorTest.java @@ -0,0 +1,33 @@ +import org.junit.jupiter.api.Test; +import string_calculator.StringAddCalculator; + +import static org.assertj.core.api.Assertions.assertThat; + +class StringAddCalculatorTest { + @Test + public void splitAndSum_null_또는_빈문자() { + int result = StringAddCalculator.splitAndSum(null); + assertThat(result).isEqualTo(0); + + result = StringAddCalculator.splitAndSum(""); + assertThat(result).isEqualTo(0); + } + + @Test + public void splitAndSum_숫자하나() throws Exception { + int result = StringAddCalculator.splitAndSum("1"); + assertThat(result).isEqualTo(1); + } + + @Test + public void splitAndSum_쉼표구분자() throws Exception { + int result = StringAddCalculator.splitAndSum("1,2"); + assertThat(result).isEqualTo(3); + } + + @Test + public void splitAndSum_쉼표_또는_콜론_구분자() throws Exception { + int result = StringAddCalculator.splitAndSum("1,2:3"); + assertThat(result).isEqualTo(6); + } +} diff --git a/src/test/java/StringCalculatorTest.java b/src/test/java/StringCalculatorTest.java index 5893462d9..780fe8e0c 100644 --- a/src/test/java/StringCalculatorTest.java +++ b/src/test/java/StringCalculatorTest.java @@ -1,6 +1,5 @@ -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import string_calculator.StringAddCalculator; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;