-
Notifications
You must be signed in to change notification settings - Fork 4
[자동차 경주] 이원희 미션 제출합니다. #3
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
base: main
Are you sure you want to change the base?
Changes from 9 commits
2af4445
337987a
6dc5694
2138e02
ca2e608
1d16135
3caef05
d55a56b
a90bd7e
736e045
fd27de6
2b0a3bf
568dd52
64f8dc5
7b8b87c
8ff5c39
1db4406
73f6348
43e48bc
624eb25
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,27 @@ | ||
| ## 기능명세 | ||
| ### 1. 자동차 이름을 입력받기 위한 화면을 구성한다. | ||
| - 자동차 이름 입력받기 | ||
| - 자동차 이름이 5자 이하인 경우에만 입력받기 | ||
| - 자동차 이름에 쉼표(,)로 구분된 이름이 1개 이상인 경우에만 입력받기 | ||
| - 자동차 이름에 특수문자 또는 숫자가 포함되어 있지 않은 경우에만 입력받기 | ||
| - 같은 이름의 자동차가 존재하지 않는 경우에만 입력받기 | ||
| - 자동차 이름 저장하기 | ||
| - 자동차 이름을 쉼표(,)로 구분하여 저장하기 | ||
| - 예외 발생 시 처음부터 실행 | ||
|
|
||
| ### 2. 시도할 회수를 입력받기 위한 화면을 구성한다. | ||
| - 시도할 회수 입력받기 | ||
| - 시도할 회수가 1 이상인 경우에만 입력받기 | ||
| - 시도할 회수가 숫자인 경우에만 입력받기 | ||
| - 시도할 회수 저장하기 | ||
| - 시도할 회수를 저장하기 | ||
| - 정수로 저장하기 | ||
| - 예외 발생 시 처음부터 실행 | ||
|
|
||
| ### 3. 자동차 경주를 진행한다. | ||
| - 시도할 회수를 입력 받은 대로 자동차를 전진시킨다. | ||
| - 차수별 자동차 이름과 전진한 거리를 출력한다. | ||
|
|
||
| ### 4. 경주 결과를 출력한다. | ||
| - 경주 결과를 출력한다. | ||
| - 우승자를 출력한다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,28 @@ | ||
| package racingcar; | ||
|
|
||
| import racingcar.model.NumberVaild; | ||
| import racingcar.model.RacingCar; | ||
|
|
||
| import static racingcar.controller.InputController.createRacingCar; | ||
| import static racingcar.controller.InputController.setRoundNum; | ||
| import static racingcar.view.ResultView.printResult; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| startGame(); | ||
| } | ||
|
|
||
| // 게임 시작 | ||
| public static void startGame() { | ||
| createRacingCar(); | ||
| int round = setRoundNum(); | ||
| System.out.println(); | ||
| printResult(); | ||
| for (int i = 0; i < round; i++) { | ||
| RacingCar.moveCars(); | ||
| System.out.println(); | ||
| } | ||
| RacingCar.getWinners(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package racingcar.controller; | ||
| import racingcar.model.NameValid; | ||
| import racingcar.model.NumberVaild; | ||
| import racingcar.model.RacingCar; | ||
| import racingcar.view.InputView; | ||
| import static racingcar.view.InputView.carNameInput; | ||
|
|
||
| public class InputController { | ||
| // 레이싱 자동차를 생성한다. | ||
| public static RacingCar createRacingCar() { | ||
| try{ | ||
| NameValid nameValid = new NameValid(carNameInput()); | ||
| return new RacingCar(nameValid.getNames()); | ||
| }catch (IllegalArgumentException e){ | ||
| return createRacingCar(); | ||
| } | ||
| } | ||
|
|
||
| public static int setRoundNum() { | ||
| try { | ||
| NumberVaild validation = new NumberVaild(Integer.parseInt(InputView.tryCountInput())); | ||
| return validation.getNumber(); | ||
| } catch (IllegalArgumentException e) { | ||
| return setRoundNum(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package racingcar.model; | ||
|
|
||
| public class Car{ | ||
| private String name; | ||
| private int position; | ||
|
|
||
| public Car(String name){ | ||
| this.name = name; | ||
| this.position = 0; | ||
| } | ||
|
|
||
| // 라운드 결과 출력 | ||
| public void printRoundResult(){ | ||
| System.out.print(name.trim() + " : "); | ||
| for(int i = 0; i < position; i++){ | ||
| System.out.print("-"); | ||
| } | ||
| System.out.println(); | ||
| } | ||
|
|
||
| public void move(){ | ||
| // 랜덤 값이 4 이상이면 전진한다. | ||
| if(RandomNumber.getRandomNumber() >= 4){ | ||
| position++; | ||
| } | ||
| } | ||
|
|
||
| // 최대 위치 반환 | ||
| public int getPosition(){ | ||
| return position; | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name.replace(" ", ""); | ||
| } | ||
| } | ||
|
Contributor
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. 이 부분은 취향차이일 수도 있는데, Name의 검증과 관련된 부분은 Car 객체를 생성하는 과정에 넣는 게 더 좋지 않나 싶습니다! 그럴 일은 잘 없겠지만 Controller에서 NameValid를 사용하는 것을 까먹고 바로 Car를 생성할 수도 있는 거고, Car에 해당 검증 로직을 넣으면 원터치로 검증이 가능하기 때문에 좋아보입니다.
Member
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. Validation은 Controller에서 제외하는 것이 좋다는 것에 동의합니다. Controller는 Request를 넘겨주는 entry point의 역할만 수행하도록 만드는게 좋다고 생각합니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package racingcar.model; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
|
|
||
| public class NameValid { | ||
| final ArrayList<String> names; | ||
|
Contributor
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. 리스트의 불변성 관련 검색 키워드
|
||
|
|
||
| public static ArrayList<String> toArrayList(String carsString) { | ||
| String[] carNames = carsString.trim().split(","); | ||
| ArrayList<String> names = new ArrayList<>(Arrays.asList(carNames)); | ||
| return names; | ||
| } | ||
|
|
||
| public NameValid(String carName) { | ||
| this.names = toArrayList(carName); | ||
| isValid(); | ||
| } | ||
|
|
||
| // 자동차 이름이 5자 이하인지 확인 | ||
| public void isNameValid() { | ||
| for (String name : names) { | ||
| if (name.length() > 5) { | ||
| throw new IllegalArgumentException("자동차 이름은 5자 이하만 가능합니다."); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // 자동차 이름이 중복되는지 확인 | ||
| public void isNameDuplicate() { | ||
| for (int i = 0; i < names.size(); i++) { | ||
| for (int j = i + 1; j < names.size(); j++) { | ||
| if (names.get(i).equals(names.get(j))) { | ||
| // 에러 반환 | ||
| throw new IllegalArgumentException("중복된 이름이 존재합니다."); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
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. 감사합니당~ |
||
|
|
||
| // 자동차 이름이 유효한지 확인 | ||
| public void isValid() { | ||
| isNameValid(); | ||
| isNameDuplicate(); | ||
| } | ||
|
|
||
| public ArrayList<String> getNames() { | ||
| return names; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package racingcar.model; | ||
|
|
||
| public class NumberVaild { | ||
| private static int number = 0; | ||
|
|
||
| public NumberVaild(int number) { | ||
| this.number = number; | ||
| isValid(); | ||
| } | ||
|
|
||
| // 숫자가 맞는지 확인한다. | ||
| public void isValid() { | ||
| isNumber(); | ||
| isPositiveNumber(); | ||
| } | ||
|
|
||
| // 숫자만 입력했는지 확인한다. | ||
| public void isNumber() { | ||
| if (!String.valueOf(number).matches("^[0-9]*$")) { | ||
| throw new IllegalArgumentException("숫자만 입력해주세요."); | ||
| } | ||
| } | ||
|
|
||
| // 0보다 큰 숫자인지 확인한다. | ||
| public void isPositiveNumber() { | ||
| if (number < 0) { | ||
| throw new IllegalArgumentException("0보다 큰 숫자를 입력해주세요."); | ||
| } | ||
| } | ||
|
|
||
| public int getNumber() { | ||
| return number; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package racingcar.model; | ||
|
|
||
| import java.util.ArrayList; | ||
|
|
||
| import static racingcar.view.ResultView.printWinner; | ||
|
|
||
| public class RacingCar { | ||
| private static final ArrayList<Car> cars = new ArrayList<>(); | ||
|
Contributor
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. static 키워드를 붙이면 멀티쓰레드 환경에서 필드의 일관성이 보장되지 않기 때문에 당장 생각할 문제는 아니지만 여러 명이 게임을 플레이한다고 가정했을 때 문제가 될 수 있을 것 같습니다! 제거를 고려해보시면 좋을 것 같아유 |
||
|
|
||
| public RacingCar(ArrayList<String> cars) { | ||
| for (String car : cars) { | ||
| RacingCar.cars.add(new Car(car)); | ||
| } | ||
| } | ||
|
|
||
| // 자동차들을 이동시킨다. | ||
| public static void moveCars() { | ||
| for (Car car : cars) { | ||
| car.move(); | ||
| car.printRoundResult(); | ||
|
||
| } | ||
| } | ||
|
|
||
| // 우승자를 반환한다. | ||
| public static void getWinners() { | ||
| ArrayList<String> winners = new ArrayList<>(); | ||
| int maxPosition = 0; | ||
| for (Car car : cars) { | ||
| maxPosition = Math.max(maxPosition, car.getPosition()); | ||
| } | ||
|
||
| for (Car car : cars) { | ||
| if (car.getPosition() == maxPosition) { | ||
| winners.add(car.getName()); | ||
| } | ||
| } | ||
| printWinner(winners); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package racingcar.model; | ||
| import camp.nextstep.edu.missionutils.Randoms; | ||
|
|
||
| public class RandomNumber { | ||
| public static int getRandomNumber() { | ||
| return Randoms.pickNumberInRange(0,9); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package racingcar.view; | ||
| import camp.nextstep.edu.missionutils.Console; | ||
|
|
||
| public class InputView { | ||
|
|
||
| // 자동차의 이름을 입력받는다. | ||
| public static String carNameInput() { | ||
| System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); | ||
| return Console.readLine(); | ||
| } | ||
|
|
||
| // 시도할 회수를 입력받는다. | ||
| public static String tryCountInput() { | ||
| System.out.println("시도할 회수는 몇회인가요?"); | ||
| return Console.readLine(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package racingcar.view; | ||
|
|
||
| import java.util.ArrayList; | ||
|
|
||
| public class ResultView { | ||
|
|
||
| // 경주 결과를 출력한다. | ||
| public static void printResult() { | ||
| System.out.println("실행 결과"); | ||
| } | ||
|
|
||
| // 최종 우승자를 출력한다. | ||
| public static void printWinner(ArrayList<String> winners) { | ||
| System.out.print("최종 우승자 : "); | ||
| for (int i = 0; i < winners.size(); i++) { | ||
| System.out.print(winners.get(i)); | ||
| if (i != winners.size() - 1) { | ||
| System.out.print(", "); | ||
| } | ||
| } | ||
| } | ||
| } |
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.
아무래도 출력과 관련된 부분은 View의 영역이다 보니까, 이 부분에서는 필드인 name과 position의 값을 중점으로 반환하는 게 더 좋을 듯 합니다!
Map<String, Integer> 타입이나 따로 DTO를 만들어서 반환한 후, View 쪽에서 각 값들을 조립하여 출력 메시지를 만드는 게 더 좋은 구조일 것 같습니다...!