-
Notifications
You must be signed in to change notification settings - Fork 449
[1단계 - 자동차 경주 구현] 기론(김규철) 미션 제출합니다. #317
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
Changes from all commits
49f85d1
5e3881e
1f3c00c
59d00b5
eca16e6
a04c03e
4a90646
eac49e6
f0f9b04
39fa96d
ded1a80
b6b220f
8c161f9
61bca7a
3c3b558
0b98acc
d3765bc
4a5888c
7665e60
be0fded
6471eea
3e48210
1f1e6a5
303258a
e9a6f32
24109dd
295d7f8
e8d1430
5196ae5
06c58c1
45df2a7
fd509e8
052f298
04c79fb
40f917e
f7612cf
1ee5a4b
76ae8ff
2ccbd7f
d64ecbf
62b3f75
086a61a
0462723
114ade9
bbd7f4d
9f1d8da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # 문자열 덧셈 계산기😎 | ||
|
|
||
| ## 기능 구현 목록 👋 | ||
|
|
||
| - [x] 문자열 또는 null 값을 입력할 경우 `0`을 반환해야 한다.(예 : “” => 0, null => 0) | ||
| - [x] 숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.(예 : “1”) | ||
| - [x] 쉼표 또는 콜론으로 나눈 숫자를 더한다. | ||
| - [x] `//`와 `\n` 문자 사이에 커스텀 구분자를 지정할 수 있고 해당 구분자로 숫자를 나누고 더한다. (“//;\n1;2;3” => 6) | ||
|
|
||
| ## 예외 처리 사항 | ||
|
|
||
| - [x] 음수나 문자가 추출된 경우 RuntimeException 예외가 발생해야 한다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # 자동차 경주 🏎 | ||
|
|
||
| ## 🎮 기능 구현 목록 | ||
|
|
||
| ### 입력 기능 | ||
|
|
||
| - [x] 자동차의 이름을 입력 받는 기능 구현 | ||
| - [x] 시도할 횟수를 입력 받는 기능 구현 | ||
| - 예외처리 | ||
| - [x] 정수가 아니면 예외 처리 | ||
| - [x] 0 이하 입력은 예외 처리 | ||
|
|
||
| ### 레이싱 | ||
|
|
||
| - [x] 0~9까지 랜덤 값중 4이상이면 전진하는 기능 구현 | ||
| - [x] 이름을 반환하는 기능 구현 | ||
| - [x] 현재 위치를 반환하는 기능 구현 | ||
|
|
||
| - 예외 처리 | ||
| - [x] 자동차가 1개 이하 일때, 예외 처리(경쟁자가 없으면 경주가 아니기 때문에) | ||
| - [x] 자동차 이름에 빈칸이 입력되었을때 예외 처리 | ||
| - [x] 6자 이상인 자동차 이름 예외 처리 | ||
| - [x] 중복되는 이름 예외 처리 | ||
| - [x] 유저 인풋이 ',' 로 끝나면 예외 처리 | ||
|
|
||
| ### 우승자 결정 기능 | ||
|
|
||
| - [x] 우승자를 결정하는 기능 구현 | ||
| - [x] 우승자가 여러명일 경우 ','를 이용하여 구분하는 기능 구현 | ||
|
|
||
| ### 출력 기능 | ||
|
|
||
| - [x] 매 횟수마다 자동차들의 이름과 위치를 출력하는 기능 구현 | ||
| - [x] 우승자가 2명 이상일 경우에는 쉼표로 구분해서 출력하는 기능 구현 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package calculator; | ||
|
|
||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class StringCalculator { | ||
|
|
||
| private static final String PATTERN = "\\d+"; | ||
|
|
||
| public static int splitAndSum(String input) { | ||
| if (input == null || input.isEmpty()) { | ||
| return 0; | ||
| } | ||
| String[] separatedValues = split(input); | ||
| return getSum(separatedValues); | ||
| } | ||
|
|
||
| private static String[] split(String input) { | ||
| Matcher matcher = Pattern.compile("//(.)\n(.*)").matcher(input); | ||
| if (matcher.find()) { | ||
| String customDelimiter = matcher.group(1); | ||
| return matcher.group(2).split(customDelimiter); | ||
| } | ||
| return input.split(",|:"); | ||
| } | ||
|
|
||
| private static int getSum(String[] separatedValues) { | ||
| int sum = 0; | ||
| for (String separatedValue : separatedValues) { | ||
| checkNaturalNumber(separatedValue); | ||
| sum += Integer.parseInt(separatedValue); | ||
| } | ||
| return sum; | ||
| } | ||
|
|
||
| private static void checkNaturalNumber(String target) { | ||
| if (!Pattern.matches(PATTERN, target)){ | ||
| throw new RuntimeException(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package calculator; | ||
|
|
||
| public class StringCalculatorMain { | ||
| public static void main(String[] args) { | ||
| String input = StringCalculatorUi.getInput(); | ||
| int result = StringCalculator.splitAndSum(input); | ||
| StringCalculatorUi.printOutput(result); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package calculator; | ||
|
|
||
| import java.util.Scanner; | ||
|
|
||
| public class StringCalculatorUi { | ||
|
|
||
| private static final String INPUT_MESSAGE = "더할 값을 입력하세요:"; | ||
| private static final String OUTPUT_MESSAGE = "결과 값은 %d 입니다.\n"; | ||
| private static final String CUSTOM_SEPARATOR_FIRST_CONDITION = "//"; | ||
| private static final String CUSTOM_SEPARATOR_SECOND_CONDITION = "\n"; | ||
|
|
||
| public static void printOutput(int output) { | ||
| System.out.printf(OUTPUT_MESSAGE, output); | ||
| } | ||
|
|
||
| public static String getInput() { | ||
| Scanner scanner = new Scanner(System.in); | ||
| System.out.print(INPUT_MESSAGE); | ||
| String input = scanner.nextLine(); | ||
| if (input.contains(CUSTOM_SEPARATOR_FIRST_CONDITION)) { | ||
| String additionalInput = scanner.nextLine(); | ||
| return input + CUSTOM_SEPARATOR_SECOND_CONDITION + additionalInput; | ||
| } | ||
| return input; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package racingcar; | ||
|
|
||
| import racingcar.domain.RacingCars; | ||
| import racingcar.view.InputView; | ||
| import racingcar.view.OutputView; | ||
|
|
||
| public class Application { | ||
|
|
||
| public static void main(String[] args) { | ||
| RacingCars racingCars = new RacingCars(); | ||
|
|
||
| racingCars.join(InputView.askCarName()); | ||
| RacingGame racingGame = new RacingGame(racingCars); | ||
|
|
||
| racingGame.playGame(racingCars); | ||
|
|
||
| String winnersName = racingGame.getWinnersName(); | ||
| OutputView.printWinners(winnersName); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package racingcar; | ||
|
|
||
| import racingcar.domain.RacingCar; | ||
| import racingcar.domain.RacingCars; | ||
| import racingcar.validator.Validator; | ||
| import racingcar.view.InputView; | ||
| import racingcar.view.OutputView; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class RacingGame { | ||
|
|
||
| private static final String WINNER_NAME_DELIMITER = ", "; | ||
| private final RacingCars racingCars; | ||
|
|
||
| public RacingGame() { | ||
| this.racingCars = new RacingCars(); | ||
| } | ||
|
|
||
| public RacingGame(RacingCars racingCars) { | ||
| this.racingCars = racingCars; | ||
| } | ||
|
|
||
| public void playGame(RacingCars racingCars) { | ||
|
|
||
| String tryCount = InputView.askTryCount(); | ||
| Validator.checkTryCountIsNaturalNumber(tryCount); | ||
| int trialCount = Validator.convertToInt(tryCount); | ||
|
|
||
| OutputView.printGameStartMessage(); | ||
| for (int i = 0; i < trialCount; i++) { | ||
| moveCar(racingCars); | ||
| OutputView.printCurrentRacingSituation(racingCars); | ||
| } | ||
| } | ||
|
|
||
| private void moveCar(RacingCars racingCars) { | ||
| for (RacingCar racingCar : racingCars.getRacingCars()) { | ||
| racingCar.goOrStay(RandomGenerator.generateRandomNumber()); | ||
| } | ||
| } | ||
|
|
||
| public String getWinnersName() { | ||
| ArrayList<RacingCar> winners = getWinners(racingCars); | ||
| ArrayList<String> winnersName = new ArrayList<>(); | ||
| for (RacingCar winner : winners) { | ||
| winnersName.add(winner.getName()); | ||
| } | ||
| return String.join(WINNER_NAME_DELIMITER, winnersName); | ||
| } | ||
|
|
||
| private ArrayList<RacingCar> getWinners(RacingCars racingCars) { | ||
|
|
||
| RacingCar racingCarOfMaxPosition = racingCars.getRacingCarWithMaxPosition(); | ||
| List<RacingCar> racingCarList = racingCars.getRacingCars(); | ||
| ArrayList<RacingCar> winners = new ArrayList<>(); | ||
|
|
||
| for (RacingCar racingCar : racingCarList) { | ||
| if (racingCar.isSamePosition(racingCarOfMaxPosition)) { | ||
| winners.add(racingCar); | ||
| } | ||
| } | ||
| return winners; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package racingcar; | ||
|
|
||
| import java.util.Random; | ||
|
|
||
| public class RandomGenerator { | ||
|
|
||
| private static final int MAX_RANDOM_NUMBER = 10; | ||
|
|
||
| public static int generateRandomNumber() { | ||
| Random random = new Random(); | ||
| return random.nextInt(MAX_RANDOM_NUMBER); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package racingcar.domain; | ||
|
|
||
| public class RacingCar { | ||
|
|
||
| private static final int MOVE_STANDARD = 4; | ||
| private final String name; | ||
| private int position; | ||
|
|
||
| private RacingCar(String name) { | ||
| this.position = 0; | ||
| this.name = name; | ||
| } | ||
|
|
||
| public static RacingCar generateRacingCar(String name) { | ||
| return new RacingCar(name); | ||
| } | ||
|
|
||
| public int getPosition() { | ||
| return position; | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| public void goOrStay(int number) { | ||
| if (number >= MOVE_STANDARD) { | ||
| position++; | ||
| } | ||
| } | ||
|
|
||
| public boolean isSamePosition(RacingCar racingCar) { | ||
| return this.position == racingCar.getPosition(); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package racingcar.domain; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Comparator; | ||
| import java.util.List; | ||
|
|
||
| public class RacingCars { | ||
|
|
||
| private final List<RacingCar> racingCars; | ||
|
|
||
| public RacingCars() { | ||
| racingCars = new ArrayList<>(); | ||
| } | ||
|
|
||
| public RacingCars(List<RacingCar> racingCars) { | ||
| this.racingCars = racingCars; | ||
| } | ||
|
|
||
| public void join(String[] validCarNames) { | ||
| for (String validCarName : validCarNames) { | ||
| racingCars.add(RacingCar.generateRacingCar(validCarName)); | ||
| } | ||
| } | ||
|
|
||
| public List<RacingCar> getRacingCars() { | ||
| return racingCars; | ||
| } | ||
|
|
||
| public RacingCar getRacingCarWithMaxPosition() { | ||
| return racingCars.stream().max(Comparator.comparingInt(RacingCar::getPosition)).get(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| package racingcar.validator; | ||
|
|
||
| import java.util.*; | ||
|
|
||
| public class Validator { | ||
|
|
||
| public static final char MIN_NUMBER_CRITERIA = '0'; | ||
| public static final char MAX_NUMBER_CRITERIA = '9'; | ||
| private static final int MIN_COUNT_OF_CAR = 2; | ||
| private static final int CAR_NAME_STANDARD_SIZE = 5; | ||
| private static final String MIN_CAR_OF_COUNT_MESSAGE = "[ERROR] 자동차 개수는 2개 이상이어야 합니다."; | ||
| private static final String CAR_NAME_EMPTY_MESSAGE = "[ERROR] 자동차 이름은 빈칸일 수 없습니다."; | ||
| private static final String CAR_NAME_SIZE_MASSAGE = "[ERROR] 자동차 이름은 5자 이하여야 합니다."; | ||
| private static final String CAR_NAME_DUPLICATED_MESSAGE = "[ERROR] 자동차 이름이 중복되어선 안됩니다."; | ||
| private static final String LAST_INPUT_IS_COMMA = "[ERROR] 마지막 자동차 이름을 입력하지 않았습니다."; | ||
| private static final String TRY_COUNT_FORMAT_ERROR_MESSAGE = "[ERROR] 시도회수는 자연수여야 합니다."; | ||
|
|
||
| public static void checkCountOfCar(String[] racingCarNames) { | ||
| if (racingCarNames.length < MIN_COUNT_OF_CAR) { | ||
| throw new IllegalArgumentException(MIN_CAR_OF_COUNT_MESSAGE); | ||
| } | ||
| } | ||
|
|
||
| public static void checkCarsNameIsEmpty(String[] racingCarNames) { | ||
| for (String racingCarName : racingCarNames) { | ||
| validatorEmptyName(racingCarName); | ||
| } | ||
| } | ||
|
|
||
| private static void validatorEmptyName(String name) { | ||
| if ("".equals(name)) { | ||
| throw new IllegalArgumentException(CAR_NAME_EMPTY_MESSAGE); | ||
| } | ||
| } | ||
|
|
||
| public static void checkCarsNameSize(String[] racingCarNames) { | ||
| for (String racingCarName : racingCarNames) { | ||
| validatorCarNameSize(racingCarName); | ||
| } | ||
| } | ||
|
|
||
| private static void validatorCarNameSize(String racingCarName) { | ||
| if (racingCarName.length() > CAR_NAME_STANDARD_SIZE) { | ||
| throw new IllegalArgumentException(CAR_NAME_SIZE_MASSAGE); | ||
| } | ||
| } | ||
|
|
||
| public static void checkDuplicatedName(String[] racingCarNames) { | ||
| List<String> nameList = new ArrayList<>(); | ||
| for (String racingCarName : racingCarNames) { | ||
| validatorDuplicatedName(nameList, racingCarName); | ||
| nameList.add(racingCarName); | ||
| } | ||
| } | ||
|
Comment on lines
+48
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정답은 없지만 고민해볼만한 포인트라 남겨요~
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Car들을 관리하는 RacingCars 도메인을 만들었기 때문에 여기서 관리하는건 어떤지 의문 던져주신 거 맞나요? |
||
|
|
||
| private static void validatorDuplicatedName(List<String> nameList, String name) { | ||
| if (nameList.contains(name)) { | ||
| throw new IllegalArgumentException(CAR_NAME_DUPLICATED_MESSAGE); | ||
| } | ||
| } | ||
|
|
||
| public static void checkHaveLastInputComma(String userInput) { | ||
| if (',' == userInput.charAt(userInput.length() - 1)) { | ||
| throw new IllegalArgumentException(LAST_INPUT_IS_COMMA); | ||
| } | ||
| } | ||
|
|
||
| public static void checkTryCountIsNaturalNumber(String tryCountInput) { | ||
| for (int i = 0; i < tryCountInput.length(); ++i) { | ||
| isNumber(tryCountInput.charAt(i)); | ||
| } | ||
| } | ||
|
|
||
| private static void isNumber(char target) { | ||
| if (target < MIN_NUMBER_CRITERIA || target > MAX_NUMBER_CRITERIA) { | ||
| throw new IllegalArgumentException(TRY_COUNT_FORMAT_ERROR_MESSAGE); | ||
| } | ||
| } | ||
|
|
||
| public static int convertToInt(String tryCountInput) { | ||
| if (Integer.parseInt(tryCountInput) == 0) { | ||
| throw new IllegalArgumentException(TRY_COUNT_FORMAT_ERROR_MESSAGE); | ||
| } | ||
| return Integer.parseInt(tryCountInput); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도메인을 잘 만들어주셨어요~
정의된 도메인에 대한 테스트는 꼭 필요한데요. 이 도메인은 테스트를 어떻게 하면 좋을까요? 🤔