-
Notifications
You must be signed in to change notification settings - Fork 99
[그리디] 김하늘 자동차 경주 미션 3, 4단계 제출합니다. #160
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
b296b8a
f5ba9a5
9050ac3
3b46072
3093bd2
dcea9ff
544e29c
04b7121
678b584
0a00e38
652b6e9
7c1319d
81068ce
9a36142
846907e
41dfc93
519416b
8393534
79877da
877fc91
4042972
705dab7
02d127e
6794256
7126155
da974f7
e09c747
52842d5
266f64b
c867636
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,34 @@ | ||
#자동차 경주 미션 | ||
|
||
##기능 | ||
|
||
- 자동차 이름 입력: 쉼표(,)로 구분된, 1자 이상 5자 이하의 자동차 이름을 입력받는다. | ||
- 시도 횟수 입력: 경주를 진행할 총 라운드 수를 입력받는다. | ||
- 전진 또는 정지: 각 자동차는 매 라운드마다 0~9 사이의 무작위 값을 생성하여, 4 이상일 경우 전진한다. | ||
- 라운드별 결과 출력: 매 라운드가 끝날 때마다 모든 자동차의 현재 위치를 출력한다. | ||
- 최종 우승자 발표: 경주가 끝난 후, 가장 멀리 전진한 자동차를 최종 우승자로 발표한다. (공동 우승 가능) | ||
|
||
##조건 | ||
|
||
- MVC 패턴을 적용하여 역할을 분리한다. | ||
- 모든 로직에 단위 테스트를 구현한다. | ||
- indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. | ||
- 3항 연산자를 쓰지 않는다. | ||
- else 예약어를 쓰지 않는다. | ||
- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. | ||
- 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다. | ||
|
||
##프로젝트 구조 | ||
|
||
- model | ||
* Car.java: 자동차 객체 (이름, 위치 상태 및 유효성 검사) | ||
* Cars.java: 자동차 목록을 관리하는 일급 컬렉션 | ||
* MoveCarStrategy.java: NumberGenerator에 따라 자동차 이동 여부를 결정하는 전략. | ||
* Race.java: 경주 상태 및 로직 관리 | ||
* NumberGenerator: 숫자 생성을 위한 인터페이스 | ||
* RandomNumberGenerator:NumberGenerator의 구현체 | ||
- controller | ||
* RacingGameController.java: 게임 전체 흐름 관리 | ||
- view | ||
* InputView.java: 사용자 입력 담당 | ||
* OutputView.java: 결과 출력 담당 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import controller.RacingGameController; | ||
import model.strategy.NumberGenerator; | ||
import model.strategy.RandomNumberGenerator; | ||
|
||
public class RaceMain { | ||
public static void main(String[] args) { | ||
NumberGenerator numberGenerator = new RandomNumberGenerator(); | ||
RacingGameController controller = new RacingGameController(numberGenerator); | ||
Comment on lines
+7
to
+8
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. 이전 코드에서는 컨트롤러가 직접 |
||
controller.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package controller; | ||
|
||
import model.domain.Car; | ||
import model.domain.Cars; | ||
import model.strategy.MoveCarStrategy; | ||
import model.strategy.NumberGenerator; | ||
import model.domain.Race; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
import java.util.List; | ||
|
||
public class RacingGameController { | ||
|
||
private final NumberGenerator numberGenerator; | ||
|
||
public RacingGameController(NumberGenerator numberGenerator) { | ||
this.numberGenerator = numberGenerator; | ||
} | ||
|
||
public void run() { | ||
Cars cars = setupCars(); | ||
Race race = new Race(cars, new MoveCarStrategy(numberGenerator)); | ||
|
||
int rounds = InputView.readRounds(); | ||
runRace(race, rounds); | ||
OutputView.printWinners(race.getWinners()); | ||
|
||
InputView.close(); | ||
} | ||
|
||
private Cars setupCars() { | ||
String[] carNames = InputView.readCarNames(); | ||
return Cars.fromNames(List.of(carNames)); | ||
} | ||
|
||
private void runRace(Race race, int rounds) { | ||
OutputView.printRaceStartMessage(); | ||
for (int i = 0; i < rounds; i++) { | ||
race.runRound(); | ||
printCurrentPositions(race.getCars()); } | ||
} | ||
|
||
private void printCurrentPositions(List<Car> cars) { | ||
for (Car car : cars) { | ||
OutputView.printSingleCarStatus(car.getCarName(), car.getPosition()); | ||
} | ||
OutputView.printNewLine(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package model.domain; | ||
|
||
public class Car { | ||
|
||
private static final int MOVE_DISTANCE = 1; | ||
private static final int MAX_NAME_LENGTH = 5; | ||
|
||
private final String carName; | ||
private int position; | ||
|
||
private Car(String name) { | ||
this.carName = name; | ||
this.position = 0; | ||
} | ||
|
||
public static Car fromName(String name) { | ||
String trimmedName = name.trim(); | ||
validateName(trimmedName); | ||
return new Car(trimmedName); | ||
} | ||
|
||
private static void validateName(String name) { | ||
if (name.length() > MAX_NAME_LENGTH) { | ||
throw new IllegalArgumentException("자동차 이름은 5자 이하만 가능합니다."); | ||
} | ||
} | ||
|
||
public void moveForward() { | ||
position += MOVE_DISTANCE; | ||
} | ||
|
||
public String getCarName() { | ||
return carName; | ||
} | ||
|
||
public int getPosition() { | ||
return position; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package model.domain; | ||
|
||
import model.strategy.MoveCarStrategy; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Cars { | ||
|
||
private final List<Car> cars; | ||
|
||
public Cars(List<Car> cars) { | ||
this.cars = cars; | ||
} | ||
|
||
public static Cars fromNames(List<String> carNames) { | ||
List<Car> carList = carNames.stream() | ||
.map(Car::fromName) | ||
.collect(Collectors.toList()); | ||
return new Cars(carList); | ||
} | ||
|
||
public void moveEachCar(MoveCarStrategy moveCarStrategy) { | ||
for (Car car : cars) { | ||
moveCarStrategy.tryMove(car); | ||
} | ||
} | ||
|
||
public List<String> findWinners() { | ||
int maxPosition = getMaxPosition(); | ||
return cars.stream() | ||
.filter(car -> car.getPosition() == maxPosition) | ||
.map(Car::getCarName) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private int getMaxPosition() { | ||
return cars.stream() | ||
.mapToInt(Car::getPosition) | ||
.max() | ||
.orElse(0); | ||
} | ||
|
||
public List<Car> getCars() { | ||
return Collections.unmodifiableList(cars); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package model.domain; | ||
|
||
import model.strategy.MoveCarStrategy; | ||
|
||
import java.util.List; | ||
|
||
public class Race { | ||
|
||
private Cars cars; | ||
private MoveCarStrategy moveCarStrategy; | ||
|
||
public Race(Cars cars, MoveCarStrategy moveCarStrategy) { | ||
this.cars = cars; | ||
this.moveCarStrategy = moveCarStrategy; | ||
} | ||
|
||
public void runRound() { | ||
cars.moveEachCar(moveCarStrategy); | ||
} | ||
|
||
public List<String> getWinners() { | ||
return cars.findWinners(); | ||
} | ||
|
||
public List<Car> getCars() { | ||
return cars.getCars(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package model.strategy; | ||
|
||
import model.domain.Car; | ||
|
||
public class MoveCarStrategy { | ||
|
||
private static final int MOVE_THRESHOLD = 4; | ||
|
||
private final NumberGenerator numberGenerator; | ||
|
||
public MoveCarStrategy(NumberGenerator numberGenerator) { | ||
this.numberGenerator = numberGenerator; | ||
} | ||
|
||
public void tryMove(Car car) { | ||
int randomNumber = numberGenerator.generate(); | ||
|
||
if (shouldMove(randomNumber)) { | ||
car.moveForward(); | ||
} | ||
} | ||
|
||
private boolean shouldMove(int randomNumber) { | ||
return randomNumber >= MOVE_THRESHOLD; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package model.strategy; | ||
|
||
public interface NumberGenerator { | ||
int generate(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package model.strategy; | ||
|
||
import java.util.Random; | ||
|
||
public class RandomNumberGenerator implements NumberGenerator { | ||
|
||
private static final Random random = new Random(); | ||
private static final int RANDOM_NUMBER_BOUND = 10; | ||
|
||
@Override | ||
public int generate() { | ||
return random.nextInt(RANDOM_NUMBER_BOUND); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package view; | ||
|
||
import java.util.Scanner; | ||
|
||
public class InputView { | ||
|
||
private static Scanner scanner = new Scanner(System.in); | ||
|
||
public static String[] readCarNames() { | ||
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); | ||
return scanner.nextLine().split(","); | ||
} | ||
|
||
public static int readRounds() { | ||
System.out.println("시도할 회수는 몇회인가요?"); | ||
int rounds = scanner.nextInt(); | ||
scanner.nextLine(); | ||
return rounds; | ||
} | ||
|
||
public static void close() { | ||
scanner.close(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package view; | ||
|
||
import model.domain.Car; | ||
|
||
import java.util.List; | ||
|
||
public class OutputView { | ||
|
||
public static void printSingleCarStatus(String name, int position) { | ||
System.out.print(name + " : "); | ||
printPosition(position); | ||
System.out.println(); | ||
} | ||
|
||
public static void printNewLine() { | ||
System.out.println(); | ||
} | ||
|
||
public static void printRaceStartMessage() { | ||
System.out.println("\n실행 결과"); | ||
} | ||
|
||
private static void printPosition(int position) { | ||
System.out.print("-".repeat(position)); | ||
} | ||
|
||
public static void printWinners(List<String> winners) { | ||
System.out.println(String.join(", ", winners) + "가 최종 우승했습니다."); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package model.domain; | ||
|
||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.DisplayNameGeneration; | ||
import org.junit.jupiter.api.DisplayNameGenerator; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
@DisplayName("model.domain.Car 클래스 테스트") | ||
@SuppressWarnings("NonAsciiCharacters") | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
public class CarTest { | ||
|
||
@Test | ||
void 자동차_생성_시_이름과_초기_위치가_올바르게_설정된다() { | ||
String name = "car"; | ||
|
||
Car car = Car.fromName(name); | ||
|
||
assertEquals(name, car.getCarName()); | ||
assertEquals(0, car.getPosition()); | ||
} | ||
|
||
@Test | ||
void moveForward_호출_시_위치가_1_증가한다() { | ||
Car car = Car.fromName("car"); | ||
|
||
car.moveForward(); | ||
|
||
assertEquals(1, car.getPosition()); | ||
} | ||
|
||
@Test | ||
void 자동차_이름이_5자를_초과하면_예외가_발생한다() { | ||
String carName = "testCar"; | ||
|
||
assertThrows(IllegalArgumentException.class, () -> Car.fromName(carName)); | ||
} | ||
} |
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.
자바 미션에 대한 내용은 아니지만, 백엔드 준비하신다면 나중에 시간 나실 때 T메모리에 대해서 찾아보시면 좋아요
(필수 아님, 개발 관련 내용보다는 CS에 가깝습니다)
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.
T메모리라는 개념은 처음 들어보네요. 좋은 키워드 알려주셔서 감사합니다! 이번 기회에 꼭 찾아서 학습해보겠습니다.