diff --git a/src/main/java/RacingMain.java b/src/main/java/RacingMain.java index 4394287..42cd187 100644 --- a/src/main/java/RacingMain.java +++ b/src/main/java/RacingMain.java @@ -1,7 +1,16 @@ +import controller.RacingCarController; +import model.RacingCar; + +import java.io.IOException; +import java.util.Scanner; +import java.util.List; +import java.util.ArrayList; +//import org.kokodak.Randoms; public class RacingMain { - public static void main(String[] args) { + public static void main(String[] args) throws IOException { // TODO: MVC 패턴을 기반으로 자동차 경주 미션 구현해보기 - System.out.println("Hello, World!"); + RacingCarController racingCarController = new RacingCarController(); + racingCarController.run(); } } diff --git a/src/main/java/controller/IntegerParser.java b/src/main/java/controller/IntegerParser.java new file mode 100644 index 0000000..8e4ffec --- /dev/null +++ b/src/main/java/controller/IntegerParser.java @@ -0,0 +1,14 @@ +package controller; + +public class IntegerParser { + private static final String NOT_INTEGER_MESSAGE = "[ERROR] 입력 값은 정수여야 합니다."; + + public static int parse(final String input) { + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(NOT_INTEGER_MESSAGE, e); + } + } +} + diff --git a/src/main/java/controller/NumberGenerator.java b/src/main/java/controller/NumberGenerator.java new file mode 100644 index 0000000..80f87cf --- /dev/null +++ b/src/main/java/controller/NumberGenerator.java @@ -0,0 +1,6 @@ +package controller; + +public interface NumberGenerator { + + int generate(); //인터페이스 +} diff --git a/src/main/java/controller/RacingCarController.java b/src/main/java/controller/RacingCarController.java new file mode 100644 index 0000000..ebdc74b --- /dev/null +++ b/src/main/java/controller/RacingCarController.java @@ -0,0 +1,64 @@ +package controller; + +import model.AttemptNumber; +import model.RacingCar; +import model.RacingCars; + +import java.io.IOException; +import java.util.List; +import view.*; + +public class RacingCarController { + private final NumberGenerator numberGenerator; + + public RacingCarController() { + this.numberGenerator = new RandomNumberGenerator(); + } + + public void run() throws IOException { + RacingCars cars = getCars(); + AttemptNumber attemptNumber = getAttemptNumber(); + race(cars, attemptNumber); + printWinners(cars); + } + + private RacingCars getCars() throws IOException { + List carNames = Input.carNameInput(); + try { + return RacingCars.from(carNames); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return getCars(); + } + } + + private AttemptNumber getAttemptNumber() throws IOException { + try { + int number = Input.playTimeInput(); + return new AttemptNumber(number); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return getAttemptNumber(); + } + } + + private void race(RacingCars cars, final AttemptNumber attemptNumber) throws IOException { + Output.printResult(); + while (attemptNumber.isRemain()) { + attemptNumber.decrease(); + cars.moveAll(numberGenerator); + printStatus(cars); + } + } + + private void printStatus(final RacingCars cars) { + List carDtos = RacingCar.getInstances(cars); + Output.printStatus(carDtos); + } + + private void printWinners(final RacingCars cars) { + RacingCars winnerCars = cars.findWinners(); + List winnerCarDtos = RacingCar.getInstances(winnerCars); + Output.printWinners(winnerCarDtos); + } +} diff --git a/src/main/java/controller/RandomNumberGenerator.java b/src/main/java/controller/RandomNumberGenerator.java new file mode 100644 index 0000000..d22d796 --- /dev/null +++ b/src/main/java/controller/RandomNumberGenerator.java @@ -0,0 +1,8 @@ +package controller; +public class RandomNumberGenerator implements NumberGenerator { + + @Override + public int generate() { + return (int) (Math.random() * 10); + } +} diff --git a/src/main/java/controller/util.java b/src/main/java/controller/util.java new file mode 100644 index 0000000..2ea21b4 --- /dev/null +++ b/src/main/java/controller/util.java @@ -0,0 +1,16 @@ +package controller; + +import java.util.ArrayList; +import java.util.List; +public class util { + public static List splitByDelemeter(String input, String delemeter){ + List result = new ArrayList<>(); + + // 문자열을 구분자를 기준으로 분할하여 리스트에 추가 + String[] parts = input.split(delemeter); + for (String part : parts) { + result.add(part); + } + return result; + } +} diff --git a/src/main/java/model/AttemptNumber.java b/src/main/java/model/AttemptNumber.java new file mode 100644 index 0000000..b17e9d1 --- /dev/null +++ b/src/main/java/model/AttemptNumber.java @@ -0,0 +1,35 @@ +package model; + +public class AttemptNumber { + + private static final String NOT_POSITIVE_INTEGER_MESSAGE = "[ERROR] 시도 횟수는 양의 정수여야 합니다."; + private static final String INVALID_NUMBER_MESSAGE = "[ERROR] 시도 횟수는 100회 이하여야 합니다."; + + private int attemptNumber; + + public AttemptNumber(final int attemptNumber) { + validate(attemptNumber); + this.attemptNumber = attemptNumber; + } + + private void validate(final int attemptNumber) { + if (attemptNumber <= 0) { + throw new IllegalArgumentException(NOT_POSITIVE_INTEGER_MESSAGE); + } + if (attemptNumber > 100) { + throw new IllegalArgumentException(INVALID_NUMBER_MESSAGE); + } + } + + public void decrease() { + attemptNumber--; + } + + public boolean isRemain() { + return attemptNumber != 0; + } + + public int getAttemptNumber() { + return attemptNumber; + } +} \ No newline at end of file diff --git a/src/main/java/model/RacingCar.java b/src/main/java/model/RacingCar.java new file mode 100644 index 0000000..778fc54 --- /dev/null +++ b/src/main/java/model/RacingCar.java @@ -0,0 +1,46 @@ +package model; + +import java.util.List; +import java.util.stream.Collectors; + +public class RacingCar { + + private static final int MOVED_LOWER_BOUND = 4; + + private static String carName; + private int position; + private int cnt; + + private RacingCar(final String name, final int position) { + this.carName = name; + this.position = position; + } + + public static RacingCar getInstance(final RacingCar car) { + return new RacingCar(car.getName(), car.getPosition()); + } + + public static List getInstances(final RacingCars cars) { + return cars.getCars().stream() + .map(RacingCar::getInstance) + .collect(Collectors.toList()); + } + + public String getName() { + return carName; + } + + public int getPosition() { + return position; + } + + public static RacingCar from(String s) { + return new RacingCar(s, 0); + } + + public void move(final int number) { + if (number >= MOVED_LOWER_BOUND) { + this.position += 1; + } + } +} diff --git a/src/main/java/model/RacingCars.java b/src/main/java/model/RacingCars.java new file mode 100644 index 0000000..2ef954d --- /dev/null +++ b/src/main/java/model/RacingCars.java @@ -0,0 +1,50 @@ +package model; + +import controller.NumberGenerator; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class RacingCars { + private static final int DEFAULT_POSITION = 0; + + private final List cars; + + public RacingCars(final List cars) { + this.cars = Collections.unmodifiableList(cars); + } + + public static RacingCars from(final List carNames) { + List cars = carNames.stream() + .map(RacingCar::from) + .collect(Collectors.toList()); + return new RacingCars(cars); + } + + public void moveAll(final NumberGenerator numberGenerator) { + for (RacingCar car : cars) { + int number = numberGenerator.generate(); + car.move(number); + } + } + + public RacingCars findWinners() { + int maxPosition = getMaxPosition(); + List winningCars = cars.stream() + .filter(car -> car.getPosition() == maxPosition) + .collect(Collectors.toList()); + return new RacingCars(winningCars); + } + + private int getMaxPosition() { + return cars.stream() + .mapToInt(RacingCar::getPosition) + .max() + .orElse(DEFAULT_POSITION); + } + + public List getCars() { + return cars; + } +} diff --git a/src/main/java/view/Input.java b/src/main/java/view/Input.java new file mode 100644 index 0000000..8fb4f0d --- /dev/null +++ b/src/main/java/view/Input.java @@ -0,0 +1,30 @@ +package view; + +import controller.IntegerParser; +import controller.util; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Input { + private static final String CAR_INPUT = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; + private static final String TRY_CNT = "시도할 회수는 몇회인가요?"; + private static Scanner scanner = new Scanner(System.in); + static String inputString; + String inputStringSplit[]; + public static List carNameInput(){ + System.out.println(CAR_INPUT); + inputString = scanner.nextLine(); + return (util.splitByDelemeter(inputString, ",")); + } + public static int playTimeInput() { + try { + System.out.println(TRY_CNT); + String input = scanner.nextLine(); + return IntegerParser.parse(input); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return playTimeInput(); //while문 없이 재귀형식으로 반복입력도 가능하다 + } + } +} diff --git a/src/main/java/view/Output.java b/src/main/java/view/Output.java new file mode 100644 index 0000000..94fe635 --- /dev/null +++ b/src/main/java/view/Output.java @@ -0,0 +1,39 @@ +package view; + +import model.RacingCar; + +import java.util.List; +import java.util.stream.Collectors; + +public class Output { + private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String RESULT_MESSAGE = "실행 결과"; + private static final String STATUS_PRINT_FORMAT = "%s : %s" + LINE_SEPARATOR; + private static final String WINNER_PRINT_FORMAT = "%s가 최종 우승했습니다." + LINE_SEPARATOR; + private static final String WORD_DELIMITER = ", "; + private static final String POSITION_SYMBOL = "-"; + + public static void printResult() { + System.out.println(RESULT_MESSAGE); + } + + public static void printStatus(final List racingCars) { + for (RacingCar car : racingCars) { + String currentPosition = getCurrentPosition(car.getPosition()); + System.out.printf(STATUS_PRINT_FORMAT, car.getName(), currentPosition); + } + System.out.println(); + } + + private static String getCurrentPosition(final int position) { + return POSITION_SYMBOL.repeat(Math.max(0, position)); + } + + public static void printWinners(final List racingCars) { + List carNames = racingCars.stream() //리스트를 스트림하는 부분 + .map(RacingCar::getName) + .collect(Collectors.toList()); + String winners = String.join(WORD_DELIMITER, carNames); + System.out.printf(WINNER_PRINT_FORMAT, winners); + } +}