-
Notifications
You must be signed in to change notification settings - Fork 455
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
[자동차 경주 게임] 베디 미션 제출합니다. #19
Changes from 35 commits
a707a5c
77a2405
749bc6d
115436b
282850f
c7c1b37
6658f6e
70f1e0d
47ee117
18bc46a
d263662
e8411fc
eba48e3
0ece395
3f5fe50
236c0d7
7d906ab
7ed1147
285d20f
7b41ebf
4ba568a
b05c373
598aff7
3a1aaf3
da85f16
5d233f7
37deb54
9dd7cd8
93b20da
54bb4ec
a6fe5b2
2713a21
8bcb758
01b2a21
c5dc889
dfede40
3d93975
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 |
---|---|---|
@@ -1,5 +1,84 @@ | ||
# java-racingcar | ||
자동차 경주 게임 미션 저장소 | ||
|
||
|
||
|
||
## 기능 요구사항 | ||
|
||
- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. | ||
- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. | ||
- 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. | ||
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. | ||
- 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. | ||
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. | ||
|
||
|
||
|
||
## 필요한 기능 | ||
|
||
1. 문자열을 입력받아 car 객체를 생성 | ||
|
||
- 문자열을 입력받는다. | ||
|
||
- 문자열을 나눈다. | ||
|
||
- car 객체들을 생성한다 | ||
- 일급컬렉션에 담아준다. | ||
|
||
2. 반복회수를 입력받아 레이싱을 진행하고, 상태를 출력한다. | ||
- 반복회수 숫자를 입력받는다. | ||
- 반복회수마다 Car를 이동시킨다. | ||
- Car는 랜덤 숫자를 생성하고, 그 숫자가 4 이상일 경우 한칸 전진한다. | ||
- Car객체의 State를 출력한다. | ||
|
||
3. 우승자를 구하고 출력한다. | ||
- Car의 일급 컬렉션은 모든 Car에 대해 최대 이동 거리를 구한다. | ||
- 최대 이동거리에 속하는 Car 객체를 구한다. | ||
- Car객체의 Name을 출력한다. | ||
|
||
## 가능한 예외 | ||
|
||
#### 1번케이스 | ||
|
||
- 쉼표로 구분되지 않는 경우. | ||
- 구분된 문자열의 길이가 5를 초과하는 경우. | ||
- Car 이름이 공백인 경우 | ||
|
||
#### 2번케이스 | ||
|
||
- 반복회수가 숫자가 아닌 경우. | ||
- 반복회수가 0이거나 음수인 경우. | ||
|
||
|
||
|
||
|
||
|
||
# 문자열 계산기 | ||
|
||
|
||
|
||
## 요구사항 | ||
|
||
- 문자열을 계산하는 계산기 (사칙연산 우선순위는 무시한다.) | ||
- if문을 사용하지 않고 구현 | ||
|
||
|
||
|
||
## 기능 | ||
|
||
- 문자열을 입력 받으면 `Space`를 기준으로 분리해준다. ex) `3 + 2 * 4 / 10` | ||
- 적절한 입력이 아닐 경우 예외처리 후 재입력한다. | ||
- 분리한 연산자와 숫자들을 이용해서 계산해준다. | ||
- 연산자를 Map의 key로 연산은 Value로 구현해준다. | ||
- 연산자와 숫자를 넣으면 map에서 해당 연산자(value)의 연산메소드를 이용해서 연산 결과를 반환해준다. | ||
|
||
- | ||
|
||
## 해결과정 | ||
|
||
- https://dublin-java.tistory.com/38 | ||
|
||
|
||
|
||
## 우아한테크코스 코드리뷰 | ||
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) | ||
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package cal; | ||
|
||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.function.BiFunction; | ||
|
||
public class Calculator { | ||
private static Map<String, BiFunction<Double, Double, Double>> operators = new HashMap<>(); | ||
|
||
static { | ||
operators.put("+", (num1, num2) -> num1 + num2); | ||
operators.put("-", (num1, num2) -> num1 - num2); | ||
operators.put("*", (num1, num2) -> num1 * num2); | ||
operators.put("/", (num1, num2) -> num1 / num2); | ||
} | ||
|
||
public static double calculate(String operator, double num1, double num2) { | ||
return operators.get(operator).apply(num1, num2); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package cal; | ||
|
||
public class TextCalculator { | ||
public static double calculate(String inputText) { | ||
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. "TextCalculator 클래스에 인스턴스 변수를 없애고 모든 메서드를 정적 메서드로 변경"하였다는 기록이 있네요. 제가 정적 메서드에 대해 오해를 드린 것 같아요. 아래의 글은 읽고 느낀 점을 전체 코드에 반영해보면 어떨까요? |
||
String tokens[] = inputText.trim().split(" "); | ||
double result = toDouble(tokens[0]); | ||
|
||
for (int i = 1; i < tokens.length; i += 2) { | ||
String operator = tokens[i]; | ||
double number = toDouble(tokens[i + 1]); | ||
result = calculate(operator, result, number); | ||
} | ||
return result; | ||
} | ||
|
||
private static double calculate(String operator, double result, double number) { | ||
return Calculator.calculate(operator, result, number); | ||
} | ||
|
||
private static double toDouble(String value) { | ||
try { | ||
return Double.parseDouble(value); | ||
} catch (Exception e) { | ||
throw new IllegalArgumentException("적절한 입력이 아닙니다."); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package cal; | ||
|
||
import java.util.Scanner; | ||
|
||
public class TextCalculatorMain { | ||
public static void main(String[] args) { | ||
Scanner scanner = new Scanner(System.in); | ||
TextCalculator.calculate(scanner.nextLine()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package racing; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
RacingGame racingGame = new RacingGame(); | ||
racingGame.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package racing; | ||
|
||
import racing.domain.Car; | ||
import racing.domain.RacingCars; | ||
import racing.domain.RepeatNumber; | ||
import racing.view.ConsoleMessages; | ||
import racing.view.InputView; | ||
import racing.view.OutputView; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class RacingGame { | ||
public void run() { | ||
RacingCars racingCars = new RacingCars(generateCars()); | ||
|
||
startRace(racingCars, inputRepeatNumber()); | ||
|
||
OutputView.printWinners(racingCars.getWinners()); | ||
} | ||
|
||
private List<Car> generateCars() { | ||
try { | ||
return getCarNames().stream() | ||
.map(name -> new Car(name)) | ||
.collect(Collectors.toList()); | ||
} catch (Exception e) { | ||
System.err.println(e.getMessage()); | ||
return generateCars(); | ||
} | ||
} | ||
|
||
private List<String> getCarNames() { | ||
List<String> splitNames = Arrays.asList(InputView.inputCarNames().split(",")); | ||
|
||
if (splitNames.isEmpty()){ | ||
throw new IllegalArgumentException(ConsoleMessages.ERR_CAR_BLANK_NAME.getMessage()); | ||
} | ||
return splitNames; | ||
} | ||
|
||
private static RepeatNumber inputRepeatNumber() { | ||
return toRepeatNumber(InputView.inputRepeatNumber()); | ||
} | ||
|
||
|
||
private static RepeatNumber toRepeatNumber(String number) { | ||
try { | ||
return new RepeatNumber(number); | ||
} catch (NumberFormatException e) { | ||
System.err.println(ConsoleMessages.ERR_REPEAT_NUMBER.getMessage()); | ||
} catch (IllegalArgumentException e) { | ||
System.err.println(e.getMessage()); | ||
} | ||
return inputRepeatNumber(); | ||
} | ||
|
||
private void startRace(RacingCars racingCars, RepeatNumber repeatNumber) { | ||
for (int i = 0; i < repeatNumber.getNumber(); i++) { | ||
racingCars.race(); | ||
OutputView.printStatus(racingCars.getRaceStatus()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package racing.domain; | ||
|
||
import racing.view.ConsoleMessages; | ||
|
||
public class Car implements Comparable<Car> { | ||
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. Comparable 인터페이스 👍 |
||
private static final int DEFAULT_DISTANCE = 1; | ||
|
||
private final String name; | ||
private int distance; | ||
|
||
public Car(final String name) { | ||
this(name, DEFAULT_DISTANCE); | ||
} | ||
|
||
public Car(final String name, final int distance) { | ||
this.name = validName(name); | ||
this.distance = distance; | ||
} | ||
|
||
private String validName(String name) { | ||
dpudpu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
String trimmedName = trimName(name); | ||
|
||
checkBlankName(trimmedName); | ||
|
||
checkNameLength(trimmedName); | ||
|
||
return trimmedName; | ||
} | ||
|
||
private String trimName(String name) { | ||
return name.trim(); | ||
} | ||
|
||
private void checkBlankName(String trimmedName) { | ||
if (trimmedName.isEmpty()) { | ||
throw new IllegalArgumentException(ConsoleMessages.ERR_CAR_BLANK_NAME.getMessage()); | ||
} | ||
} | ||
|
||
private void checkNameLength(String trimmedName) { | ||
if (trimmedName.length() > Rules.MAX_CAR_NAME) { | ||
throw new IllegalArgumentException(ConsoleMessages.ERR_CAR_NAME.getMessage()); | ||
} | ||
} | ||
|
||
public int move(int number) { | ||
if (isMove(number)) { | ||
distance++; | ||
} | ||
return distance; | ||
} | ||
|
||
private boolean isMove(int number) { | ||
return number >= Rules.MIN_MOVABLE_NUMBER; | ||
} | ||
|
||
public boolean isMatchDistance(Car car) { | ||
return this.distance == car.distance; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getDistance() { | ||
return distance; | ||
} | ||
|
||
@Override | ||
public int compareTo(Car car) { | ||
return this.distance - car.distance; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package racing.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class RaceStatusDto { | ||
private final List<Car> cars; | ||
|
||
public RaceStatusDto(List<Car> cars) { | ||
this.cars = new ArrayList<>(cars); | ||
} | ||
|
||
public List<Car> getCars() { | ||
return cars; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package racing.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class RacingCars { | ||
private final List<Car> cars; | ||
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. 놀라워요! 이미 일급 컬렉션의 개념을 알고 계신 것 같아요. 👍 아래의 글을 읽고 일급 컬렉션을 내 것으로 확실히 완성시켜보세요. 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 RacingCars(List<Car> cars) { | ||
this.cars = new ArrayList<>(cars); | ||
} | ||
|
||
public void race() { | ||
cars.forEach(car -> car.move(Rules.generateRandomNumber())); | ||
} | ||
|
||
public RaceStatusDto getRaceStatus() { | ||
return new RaceStatusDto(cars); | ||
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.
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.
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 List<String> getWinners() { | ||
Car winnerCar = Collections.max(cars); | ||
return cars.stream() | ||
.filter(car -> car.isMatchDistance(winnerCar)) | ||
.map(Car::getName) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package racing.domain; | ||
|
||
import racing.view.ConsoleMessages; | ||
|
||
public class RepeatNumber { | ||
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.
|
||
private int number; | ||
|
||
public RepeatNumber(int number) { | ||
if (number <= 0) | ||
throw new IllegalArgumentException(ConsoleMessages.ERR_INVALID_REPEAT_NUMBER.getMessage()); | ||
this.number = number; | ||
} | ||
|
||
public RepeatNumber(String number) { | ||
this(Integer.parseInt(number)); | ||
} | ||
|
||
public int getNumber() { | ||
return number; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package racing.domain; | ||
|
||
import java.util.Random; | ||
|
||
public class Rules { | ||
public static final int MAX_CAR_NAME = 5; | ||
public static final int MIN_MOVABLE_NUMBER = 4; | ||
public static final int RANDOM_NUMBER_RANGE = 10; | ||
|
||
public static int generateRandomNumber() { | ||
Random random = new Random(); | ||
return random.nextInt(RANDOM_NUMBER_RANGE); | ||
} | ||
} |
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.
문자열 계산기에 대한 기능도 README.md 파일에 정리해 추가하면 좋을 것 같아요. 👍
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.
미처 생각하지 못했네요. 추가했습니다.