-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[1단계 - 웹 자동차 경주] 히이로(문제웅) 미션 제출합니다. (#53)
* chore: 기존 콘솔 자동차 경주 프로젝트 코드 마이그레이션 * refactor: 콘솔 기반에서 Web 기반으로 게임 로직 마이그레이션 * feat: 게임 결과 저장 기능 구현 세부사항 - h2 데이터베이스 연동 * refactor: Layered Architecture 적용 * docs: 새로 추가된 기능들 README 추가 * style: 코드 포맷팅 확인 및 수정 * refactor: controller 반환 타입 변경
- Loading branch information
1 parent
07ad425
commit 1e66520
Showing
35 changed files
with
1,019 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,54 @@ | ||
# jwp-racingcar | ||
|
||
# 자동차 경주 구현 | ||
|
||
## 💡프로젝트 개요 | ||
- 자동차 경주 프로젝트는 경주할 자동차 이름과 시도할 횟수를 입력받은 후 전진 과정을 통해 가장 많이 전진한 자동차가 우승을 하는 프로젝트이다. 이 때 자동차 경주 게임을 진행하고 최종 우승 결과를 출력해야한다. | ||
- 진행한 게임 결과는 DB에 저장된다. | ||
--- | ||
|
||
|
||
## 📋 구현 기능 목록 | ||
|
||
## 프로그램 전체 로직 | ||
- ✅자동차 이름에 대한 사용자 입력을 받는다. | ||
- ✅총 시도 횟수에 대한 사용자 입력을 받는다. | ||
- ✅자동차 경주를 진행한다. | ||
- ✅DB에 결과 값들을 저장한다. | ||
- ✅경주 결과를 출력한다. | ||
|
||
|
||
## domain(model) | ||
- ✅자동차 정보를 저장하고 관리한다. | ||
- ✅각 자동차 이름은 1자 이상 5자 이하여야 한다. | ||
- ✅자동차의 위치를 증가 시킬 수 있다. | ||
- ✅자동차의 전진 여부를 판단한다. | ||
- ✅random 값이 4 이상일 경우 전진한다. | ||
- ✅random 값이 3 이하일 경우 정지한다. | ||
- ✅생성된 자동차들의 정보를 저장하고 관리한다. | ||
- ✅자동차 대수는 1대 이상이어야 한다. | ||
- ✅우승한 자동차를 제공한다. | ||
- ✅모든 자동차들이 전진을 1회 시도한다. | ||
- ✅random 하게 0~9 범위 내에 한 자리 숫자를 반환한다. | ||
- ✅자동차 경주를 진행한다. | ||
- ✅몇 라운드를 진행할 지 저장한다. | ||
- ✅라운드가 1 이상의 값으로 주어지는지 검증한다. | ||
- ✅현재 게임진행 현황을 통해 게임 종료 여부를 판단한다. | ||
|
||
|
||
## view | ||
### 입력 | ||
- ✅자동차 이름 입력받기 | ||
- ✅총 시도 횟수 입력받기 | ||
- ✅시도 횟수 입력값은 숫자여야 한다. | ||
- ✅총 시도 횟수는 1 이상의 양의 정수 값이어야 한다. | ||
|
||
### 출력 | ||
- ✅프로그램 실행 결과 | ||
- ✅최종 결과 문구 출력 | ||
- ✅공동 우승자 발생 경우 고려 | ||
|
||
|
||
## 예외 처리 | ||
- ✅자동차 이름이 0자인 경우 고려하기 | ||
- ✅총 시도 횟수 입력값이 양의 정수가 아닌 경우 고려하기 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package racingcar; | ||
|
||
import racingcar.controller.ConsoleRacingCarController; | ||
import racingcar.domain.RandomNumberGenerator; | ||
import racingcar.view.InputView; | ||
import racingcar.view.OutputView; | ||
|
||
import java.util.Scanner; | ||
|
||
public class ConsoleRacingCarApplication { | ||
|
||
public static void main(String[] args) { | ||
ConsoleRacingCarController controller = new ConsoleRacingCarController(new InputView(new Scanner(System.in)), | ||
new OutputView(), | ||
new RandomNumberGenerator()); | ||
|
||
controller.run(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
src/main/java/racingcar/controller/ConsoleRacingCarController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package racingcar.controller; | ||
|
||
import racingcar.domain.Car; | ||
import racingcar.domain.Cars; | ||
import racingcar.domain.NumberGenerator; | ||
import racingcar.domain.RacingGame; | ||
import racingcar.view.InputView; | ||
import racingcar.view.OutputView; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class ConsoleRacingCarController { | ||
|
||
private final InputView inputView; | ||
private final OutputView outputView; | ||
private final NumberGenerator numberGenerator; | ||
|
||
public ConsoleRacingCarController(InputView inputView, OutputView outputView, NumberGenerator numberGenerator) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
this.numberGenerator = numberGenerator; | ||
} | ||
|
||
public void run() { | ||
Cars cars = generateCars(inputView.readCarNames()); | ||
int round = inputView.readRacingRound(); | ||
playGame(cars, round); | ||
} | ||
|
||
private Cars generateCars(List<String> carNames) { | ||
List<Car> carInstances = new ArrayList<>(); | ||
for (String name : carNames) { | ||
carInstances.add(new Car(name, numberGenerator)); | ||
} | ||
return new Cars(carInstances); | ||
} | ||
|
||
private void playGame(Cars cars, int round) { | ||
RacingGame racingGame = new RacingGame(cars, round); | ||
outputView.printResultMessage(); | ||
while (!racingGame.isGameEnded()) { | ||
outputView.printRoundResult(racingGame.playOneRound()); | ||
} | ||
outputView.printFinalResult(racingGame.findWinnerCars()); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/racingcar/controller/WebRacingCarController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package racingcar.controller; | ||
|
||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import racingcar.dto.request.RacingStartRequest; | ||
import racingcar.dto.response.RacingResultResponse; | ||
import racingcar.service.RacingCarService; | ||
|
||
@RestController | ||
public class WebRacingCarController { | ||
|
||
private final RacingCarService racingCarService; | ||
|
||
public WebRacingCarController(RacingCarService racingCarService) { | ||
this.racingCarService = racingCarService; | ||
} | ||
|
||
@PostMapping("/plays") | ||
public ResponseEntity<RacingResultResponse> play(@RequestBody RacingStartRequest racingStartRequest) { | ||
return ResponseEntity.ok(racingCarService.play(racingStartRequest)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package racingcar.dao; | ||
|
||
import racingcar.dto.CarDto; | ||
|
||
import java.util.List; | ||
|
||
public interface CarDao { | ||
|
||
void save(int gameId, List<CarDto> carDtos); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package racingcar.dao; | ||
|
||
import org.springframework.stereotype.Repository; | ||
import racingcar.dto.CarDto; | ||
import racingcar.utils.ConnectionProvider; | ||
|
||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
@Repository | ||
public class H2CarDao implements CarDao { | ||
|
||
@Override | ||
public void save(int gameId, List<CarDto> carDtos) { | ||
String sql = "INSERT INTO CAR(game_id, name, position, is_win) VALUES (?,?,?,?)"; | ||
|
||
try (Connection connection = ConnectionProvider.getConnection()) { | ||
for (CarDto carDto : carDtos) { | ||
PreparedStatement ps = connection.prepareStatement(sql); | ||
|
||
ps.setInt(1, gameId); | ||
ps.setString(2, carDto.getName()); | ||
ps.setInt(3, carDto.getPosition()); | ||
ps.setBoolean(4, carDto.isWin()); | ||
ps.executeUpdate(); | ||
|
||
ps.close(); | ||
} | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package racingcar.dao; | ||
|
||
import org.springframework.stereotype.Repository; | ||
import racingcar.utils.ConnectionProvider; | ||
|
||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.sql.Statement; | ||
|
||
@Repository | ||
public class H2RacingGameDao implements RacingGameDao { | ||
|
||
@Override | ||
public int save(int count) { | ||
String sql = "INSERT INTO RACING_GAME(count) VALUES (?)"; | ||
|
||
try (Connection connection = ConnectionProvider.getConnection(); | ||
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { | ||
ps.setInt(1, count); | ||
ps.executeUpdate(); | ||
|
||
ResultSet rs = ps.getGeneratedKeys(); | ||
|
||
if (rs.next()) { | ||
return rs.getInt(1); | ||
} | ||
|
||
throw new IllegalStateException(); | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package racingcar.dao; | ||
|
||
public interface RacingGameDao { | ||
|
||
int save(int count); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package racingcar.domain; | ||
|
||
import java.util.Objects; | ||
|
||
public class Car implements Comparable<Car> { | ||
|
||
private static final int NAME_MIN_LENGTH = 1; | ||
private static final int NAME_MAX_LENGTH = 5; | ||
private static final int MOVABLE_MIN_NUMBER = 4; | ||
private static final String NAME_LENGTH_ERROR = "[ERROR] 자동차 이름은 1자 이상 5자 이하여야 합니다."; | ||
|
||
private String name; | ||
private int position; | ||
private NumberGenerator numberGenerator; | ||
|
||
public Car(String name, NumberGenerator numberGenerator) { | ||
name = name.trim(); | ||
validateName(name); | ||
this.name = name; | ||
this.position = 0; | ||
this.numberGenerator = numberGenerator; | ||
} | ||
|
||
public void goForward() { | ||
if (numberGenerator.generate() >= MOVABLE_MIN_NUMBER) { | ||
position++; | ||
} | ||
} | ||
|
||
public boolean isSamePosition(Car otherCar) { | ||
return this.position == otherCar.position; | ||
} | ||
|
||
public int getPosition() { | ||
return this.position; | ||
} | ||
|
||
public String getName() { | ||
return this.name; | ||
} | ||
|
||
@Override | ||
public int compareTo(Car otherCar) { | ||
return otherCar.position - this.position; | ||
} | ||
|
||
private void validateName(String name) { | ||
if (name.length() < NAME_MIN_LENGTH || name.length() > NAME_MAX_LENGTH) { | ||
throw new IllegalArgumentException(NAME_LENGTH_ERROR); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean equals(Object other) { | ||
if (this == other) return true; | ||
if (other == null || getClass() != other.getClass()) return false; | ||
Car car = (Car) other; | ||
return position == car.position && Objects.equals(name, car.name); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(name, position); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package racingcar.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Cars { | ||
|
||
private static final int CARS_MIN_SIZE = 1; | ||
private static final String CARS_SIZE_ERROR = "[ERROR] 자동차 대수는 1이상이어야 합니다."; | ||
|
||
private List<Car> cars; | ||
|
||
public Cars(List<Car> cars) { | ||
validateCarsSize(cars); | ||
this.cars = new ArrayList<>(cars); | ||
} | ||
|
||
public List<Car> findAllWinner() { | ||
Car maxPositionCar = findMaxPositionCar(); | ||
return cars.stream() | ||
.filter(car -> car.isSamePosition(maxPositionCar)) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public List<Car> moveEachCar() { | ||
for (Car car : cars) { | ||
car.goForward(); | ||
} | ||
return new ArrayList<>(cars); | ||
} | ||
|
||
// Todo : 나중에 중복되는 이름은 입력되면 예외처리 되도록 구현해야 한다. | ||
private void validateCarsSize(List<Car> cars) { | ||
if (cars.size() < CARS_MIN_SIZE) { | ||
throw new IllegalArgumentException(CARS_SIZE_ERROR); | ||
} | ||
} | ||
|
||
private Car findMaxPositionCar() { | ||
cars.sort(Car::compareTo); | ||
return cars.get(0); | ||
} | ||
|
||
public List<Car> getCars() { | ||
return cars; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package racingcar.domain; | ||
|
||
@FunctionalInterface | ||
public interface NumberGenerator { | ||
|
||
int generate(); | ||
} |
Oops, something went wrong.