Skip to content
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

[자동차 경주 게임] 이영수 미션 제출합니다. #253

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b5baffe
docs : 기능 목록 정리
youngsu5582 Oct 29, 2023
1927d05
feat : 사용자 요구사항 테스트 코드 추가
youngsu5582 Oct 29, 2023
60e0a30
feat : 사용자 요구사항 기능 구현 완료
youngsu5582 Oct 29, 2023
262b439
refactor : 사용자 요구사항 테스트 코드 리팩토링
youngsu5582 Oct 29, 2023
6dd0c3e
feat : 검증자 요구사항 1번 테스트 코드 추가
youngsu5582 Oct 29, 2023
f0f77a2
feat : 검증자 요구사항 1번 기능 구현 완료
youngsu5582 Oct 29, 2023
6bd0ca8
feat : 검증자 요구사항 2번 테스트 코드 추가
youngsu5582 Oct 29, 2023
9c395f5
feat : 검증자 요구사항 2번 기능 구현 완료
youngsu5582 Oct 29, 2023
36c1e26
feat : 검증자 요구사항 3번 테스트 코드 추가
youngsu5582 Oct 29, 2023
001cb09
feat : 검증자 요구사항 3번 기능 구현 완료
youngsu5582 Oct 29, 2023
3d9fe6f
docs : 검증자 요구사항 4번 수정
youngsu5582 Oct 29, 2023
6ae3011
feat : 검증자 요구사항 4번 테스트 코드 추가
youngsu5582 Oct 29, 2023
ab29277
feat : 검증자 요구사항 4번 기능 구현 완료
youngsu5582 Oct 29, 2023
e347d11
feat : 자동차 요구사항 2번 테스트 코드 추가
youngsu5582 Oct 29, 2023
7dfd83e
feat : 자동차 요구사항 2번 기능 구현 완료
youngsu5582 Oct 29, 2023
4406de7
feat : 자동차 요구사항 1번 테스트 코드 & 기능 구현
youngsu5582 Oct 29, 2023
0259097
refactor : 자동차 2번 요구사항 코드 리팩토링
youngsu5582 Oct 29, 2023
f4b658c
docs : 자동차 공장 요구사항 추가
youngsu5582 Oct 29, 2023
04ce788
feat : 자동차 공장 테스트 코드 & 기능 구현
youngsu5582 Oct 29, 2023
1eb1f16
feat : 레이서 요구사항 테스트 코드 추가
youngsu5582 Oct 30, 2023
e586140
feat : 레이서 요구사항 기능 구현 완료
youngsu5582 Oct 30, 2023
48e834f
refactor : 레이서 요구사항 코드 리팩토링
youngsu5582 Oct 30, 2023
0751220
feat : 출력자 요구사항 1번 테스트 코드 추가
youngsu5582 Oct 30, 2023
45a4a16
feat : 출력자 요구사항 1번 기능 구현
youngsu5582 Oct 30, 2023
439d5d7
feat : 출력자 2번 테스트 코드 추가
youngsu5582 Oct 30, 2023
44857fc
feat : 출력자 요구사항 2번 기능 구현 완료
youngsu5582 Oct 30, 2023
4cc0880
feat : 서버 요구사항 1번 테스트 코드 추가
youngsu5582 Oct 30, 2023
934e67c
feat : 서버 요구사항 1번 기능 구현 완료
youngsu5582 Oct 30, 2023
81d936f
docs : 서버 요구사항 추가
youngsu5582 Oct 30, 2023
c55d7aa
feat : 서버 요구사항 2번 테스트 코드 추가
youngsu5582 Oct 30, 2023
fb48e6f
feat : 서버 요구사항 2번 기능 구현 완료
youngsu5582 Oct 30, 2023
601a88a
feat : 서버 요구사항 3번 테스트 코드 추가
youngsu5582 Oct 30, 2023
1398d2e
feat : 서버 요구사항 3번 기능 구현 완료
youngsu5582 Oct 30, 2023
f08d31a
refactor : 서버 요구사항 3번 기능 코드 리팩토링
youngsu5582 Oct 30, 2023
9c3c89a
feat : 서버 요구사항 4번 테스트 코드 추가
youngsu5582 Oct 30, 2023
06a714a
feat : 서버 요구사항 4번 기능 구현 완료
youngsu5582 Oct 30, 2023
0941d91
feat : Application 에 모든 기능 통합
youngsu5582 Oct 30, 2023
6ca2523
refactor : 자동차 요구사항 2번 테스트 코드 리팩토링
youngsu5582 Oct 31, 2023
dbcdb37
feat : RandomsMocking Class 추가
youngsu5582 Oct 31, 2023
f388fe3
feat : 서버 요구사항 4번 테스트 코드 추가
youngsu5582 Oct 31, 2023
30541e5
refactor : class 들 package 로 분리
youngsu5582 Oct 31, 2023
3234cbd
feat : 검증자 메소드 정적 메소드로 변경
youngsu5582 Oct 31, 2023
4be4535
refactor : 시도 횟수 받는 로직 이름 수정
youngsu5582 Oct 31, 2023
12c2e43
refactor : 함수명 , 함수 분리 리팩토링
youngsu5582 Oct 31, 2023
8dbec4b
refactor : Util 클래스 명 변경
youngsu5582 Oct 31, 2023
29d1e77
feat : 레이서 2번 요구사항 테스트 코드 추가
youngsu5582 Oct 31, 2023
ea442b2
feat : 레이서 1번 요구사항 부분 로직 수정
youngsu5582 Oct 31, 2023
38ccd1d
refactor : 위치 표시 문자열 상수 사용
youngsu5582 Oct 31, 2023
a19b97f
feat : 통합 테스트 케이스 추가
youngsu5582 Oct 31, 2023
118cbb7
docs : 구현 후 체크 리스트 수정
youngsu5582 Oct 31, 2023
1970349
refactor : Class 내 import 순서 통일
youngsu5582 Nov 1, 2023
cd80a18
refactor : 출력자 요구사항 함수명 변경
youngsu5582 Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# 🏎️ java-racingcar

youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved

## ⚠️ 구현 전 체크리스트
### 🖥️ 프로그래밍 요구 사항
##### 프로젝트가 JDK 17 버전인가?

##### Java 코드 컨벤션 가이드를 준수하기 위해 이를 알고 있는가?

--- ### 📚 과제 진행 요구 사항

##### 미션은 java-racingcar-6 저장소를 Fork & Clone 하는가?

##### 기능 구현하기 전 docs/README.md 에 구현할 기능 목록을 정리해 추가하였는가?

--- ### 🔘 기능 요구 사항

#### 👦🏻 사용자 요구사항

##### ✅ 사용자는 경주할 레이서들의 이름을 입력할 수 있다.
`camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.
##### ✅ 사용자는 시도할 횟수를 입력할 수 있다.
`camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.

#### 🔎 검증자 요구사항

##### ✅ 사용자가 정해진 형식 ( 이름,이름,이름,... ) 에 맞게 입력 했는지 검증할 수 있다.
` 형식이 맞지 않을시 , "입력된 값이 형식에 맞지 않습니다!" 메시지를 포함해 IllegalArgumentException 을 발생시킨다.

##### ✅ 사용자가 입력한 이름들이 일정 길이 이하 ( Default : <=5 ) 인지 검증할 수 있다.
` 일정 길이를 초과한 이름이 있을시 , "이름이 너무 깁니다!" 메시지를 포함해 IllegalArgumentException 을 발생시킨다.

##### ✅ 사용자 입력한 이름에 중복이 있는지 검증할 수 있다.
` 중복된 이름이 있을시 , "중복된 이름이 있습니다!" 메세지를 포함해 IllegalArgumentException 을 발생시킨다.

##### ✅ 사용자 입력한 횟수가 양의 정수인지 검증할 수 있다.
` 입력한 횟수가 양의 정수가 아닐 시 , "양의 정수를 입력해주세요!" 메시지를 포함해 IllegalArgumentException 을 발생시킨다.

#### 🖥️서버 요구사항

##### ✅ 해당 경주에 참여 하는 레이서 명단을 접수할 수 있다.

##### ✅ 경주를 진행 하는 횟수를 접수할 수 있다.

##### ✅ 경주를 시작할 수 있다.

##### ✅ 경주 완료한 후 , 우승자 를 시상 한다.

#### 🖨️ 출력자 요구사항

##### ✅ 현재 경기 상황을 출력한다.

##### ✅ 우승자를 출력한다.

#### 🧑‍🔧 레이서 요구사항

##### ✅ 자동차 공장에서 , 경주할 차를 받을수 있다.

##### ✅ 자동차의 전진여부에 따라 , 현재 위치에서 일정 칸 전진할 수 있다.
` 기본으로 정해진 일정 칸은 1칸이다.

#### 🏎️ 자동차 요구사항

##### ✅ 최소값 에서 최대값 사이의 무작위 숫자를 생성한다.
` camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용한다.
` 기본으로 정해진 최소값은 0 , 최대값은 9 이다.

##### ✅ 무작위로 생성된 숫자가 일정 값 이상일 경우 전진할 수 있다.
` 기본으로 정해진 일정 값은 4 이다.

#### 🏭 자동차 공장 요구사항

##### ✅ 새로운 차를 생성해서 줄 수 있다.


## 🕶️ 구현 후 체크리스트

### 🎯 프로그래밍 요구 사항

#### 추가된 요구 사항

##### ✅ indent 의 depth 가 3을 넘기지 않는가?
##### ✅ 3항 연산자를 쓰지 않는가?
##### ✅ 함수 와 메소드가 한 가지 일만 하는가?
##### ✅ 위 기능 목록에 대한 테스트 코드를 전부 작성하였는가?


##### ✅ System.exit() 를 호출하지 않는가?
##### ✅ 프로그램 구현 완료 시 ApplicationTest 의 모든 테스트가 성공하는가?
##### ✅ build.gradle 및 외부 라이브러리를 사용하지 않았는가?

##### ✅ `camp.nextstep.edu.missionutils`에서 제공하는 `Randoms` 및 `Console` API를 사용하여 구현했는가?
##### ✅ Java 코드 컨벤션 가이드 준수해 프로그래밍 했는가?
17 changes: 16 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
package racingcar;

import racingcar.player.Player;
import racingcar.server.Server;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Player player = new Player();
Server server = new Server();

System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
String racerListString = player.getPlayerInput();
server.confirmRacerList(racerListString);

System.out.println("시도할 회수는 몇회인가요?");
String racerRoundString = player.getPlayerInput();
server.confirmRaceRound(racerRoundString);

server.startRace();
server.finishRace();
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
}
}
19 changes: 19 additions & 0 deletions src/main/java/racingcar/car/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package racingcar.car;

import camp.nextstep.edu.missionutils.Randoms;
import racingcar.configs.Config;

public class Car {

public boolean checkCarSpeedIsExceedThreshold(){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
int randomSpeed = generateRandomSpeed();
if (randomSpeed >= Config.FORWARD_THRESHOLD){
return true;
}
return false;
}
public int generateRandomSpeed(){
int randomSpeed = Randoms.pickNumberInRange(Config.MINIMUM_VALUE,Config.MAXIMUM_VALUE);
return randomSpeed;
}
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
}
7 changes: 7 additions & 0 deletions src/main/java/racingcar/car/CarFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package racingcar.car;

public class CarFactory {
public static Car getNewCarInstance(){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
return new Car();
}
}
9 changes: 9 additions & 0 deletions src/main/java/racingcar/configs/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package racingcar.configs;

public class Config {
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
public final static Integer MINIMUM_VALUE = 0;
public final static Integer MAXIMUM_VALUE = 9;
public final static Integer FORWARD_THRESHOLD = 4;
public final static Integer FORWARD_DISTANCE = 1;
public final static String POS_INDICATOR = "-";
}
18 changes: 18 additions & 0 deletions src/main/java/racingcar/player/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racingcar.player;

import camp.nextstep.edu.missionutils.Console;

import java.util.NoSuchElementException;

public class Player{
public static String inputErrorMessage = "입력을 해주세요!";
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
public String getPlayerInput(){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved

try {
String playerInput = Console.readLine();
return playerInput;
}catch (NoSuchElementException e){
throw new IllegalArgumentException(inputErrorMessage);
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/racingcar/racer/Racer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package racingcar.racer;

import racingcar.car.Car;
import racingcar.car.CarFactory;

import racingcar.configs.Config;

public class Racer {
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
private final String name;
private final Car raceCar;
private int currentPos;
public Racer(String racerName){
raceCar = CarFactory.getNewCarInstance();
name = racerName;
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
currentPos = 0;
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
}
public void runRaceEachStep(){
if (canMoveForward()){
currentPos+= Config.FORWARD_DISTANCE;
}
}
private boolean canMoveForward(){
return raceCar.checkCarSpeedIsExceedThreshold();
}
public int getCurrentPos(){
return currentPos;
}
public boolean isCarInitialized(){return raceCar!=null;};
public String getName(){return name;}
}
70 changes: 70 additions & 0 deletions src/main/java/racingcar/server/Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package racingcar.server;

import racingcar.racer.Racer;

import racingcar.utils.Printer;
import racingcar.utils.Parser;
import racingcar.utils.Validator;

import java.util.ArrayList;
import java.util.List;

public class Server {
private List<Racer> racerList;
private int raceRound;
public Server(){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에 13번째 줄에서 List<Racer racerList = new ArrayList<>();로하는게 더 보기 편할 것 같아요. 또 이번에 피드백 온것에 List라는 자료형을 쓰지 말라고 왔던데 확인해 보시는게 좋을 것 같아요

Copy link
Author

@youngsu5582 youngsu5582 Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 감사합니다!
혹시 이번 피드백에서 내용을 못봤는데 , 어디에 있었는지 알려줄 수 있을까요??!
@aammddkkzxc

Copy link

@aammddkkzxc aammddkkzxc Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메일 확인해보셔요 문서로 첨부해서 나눠줬어요. 아 List 자체를 쓰지 않는게 아니라 네이밍을 racerList이런식으로 하지마라고 온건데 오해의 소지가 있게 말씀 드린거같네요 죄송합니다 ㅠㅠ

racerList = new ArrayList<>();
}

public void confirmRacerList(String racerListString){
Validator.validateUserInputIsCorrectFormat(racerListString);
List<String> racerNameList = Parser.parseStringToListSplitComma(racerListString);
addRacerToList(racerNameList);
}
private void addRacerToList(List<String> racerNameList){
for ( String racerName : racerNameList){
racerList.add(new Racer(racerName));
}
}
public void confirmRaceRound(String raceRoundString){
Validator.validateUserInputIsCorrectRound(raceRoundString);
int raceRound = Integer.parseInt(raceRoundString);
this.raceRound = raceRound;
}
public void startRace(){
System.out.println("실행 결과");
for (int i = 0; i < raceRound; i++){
continueRace();
Printer.printCurrentRaceResult(racerList);
}

}
private void continueRace(){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
for (Racer racer : racerList){
racer.runRaceEachStep();
}
}
public void finishRace(){
List<String> winnerList = aggregateRaceResults();
Printer.printFinalResult(winnerList);
}
private List<String> aggregateRaceResults(){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
int maxPos = 0;
for ( Racer racer : racerList){
int racerPos = racer.getCurrentPos();
if ( racerPos>= maxPos){
maxPos = racerPos;
}
}
List<String> winnerList = new ArrayList<>();
for ( Racer racer : racerList){
if ( racer.getCurrentPos() == maxPos){
winnerList.add(racer.getName());
}
}
return winnerList;
}
public List<Racer> getRacerList(){ return racerList; }
public int getRaceRound() { return raceRound;}

}
10 changes: 10 additions & 0 deletions src/main/java/racingcar/utils/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package racingcar.utils;

import java.util.Arrays;
import java.util.List;

public class Parser {
public static List<String> parseStringToListSplitComma(String paringString){
return Arrays.asList(paringString.split(","));
}
}
27 changes: 27 additions & 0 deletions src/main/java/racingcar/utils/Printer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package racingcar.utils;

import racingcar.configs.Config;
import racingcar.racer.Racer;

import java.util.List;

public class Printer {
public static void printCurrentRaceResult(List<Racer>racerList){
for (Racer racer : racerList){
String name = racer.getName();
Integer racerPos = racer.getCurrentPos();

StringBuilder sb = new StringBuilder();
sb.append(name).append(" : ").append(Config.POS_INDICATOR.repeat(racerPos));
System.out.println(sb.toString());
}
System.out.println();
}
public static void printFinalResult(List<String>winnerList){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
StringBuilder sb = new StringBuilder();
sb.append("최종 우승자 : ");
sb.append(String.join(", ", winnerList));
System.out.println(sb.toString());
}

}
53 changes: 53 additions & 0 deletions src/main/java/racingcar/utils/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package racingcar.utils;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Validator {
public static void validateUserInputIsCorrectFormat(String userInput){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
List<String> toValidateRacerNameList = Parser.parseStringToListSplitComma(userInput);
for (String validateRacerName : toValidateRacerNameList){
validateRacerNameIsContainSpecificSymbol(validateRacerName);
validateRacerNameWithinMaxLength(validateRacerName);
}
validateRacerNameIsNotDuplicated(toValidateRacerNameList);
}
private static void validateRacerNameIsContainSpecificSymbol(String racerName){
for (char element : racerName.toCharArray()){
if (Character.isLetterOrDigit(element)){
continue;
}
throw new IllegalArgumentException("입력된 값이 형식에 맞지 않습니다!");
}
}
private static void validateRacerNameWithinMaxLength(String racerName){
if (racerName.length()>5){
throw new IllegalArgumentException("이름이 너무 깁니다!");
}
}
private static void validateRacerNameIsNotDuplicated(List<String> racerNameList){
youngsu5582 marked this conversation as resolved.
Show resolved Hide resolved
Set<String> stringSet = new HashSet<>();
stringSet.addAll(racerNameList);
if (racerNameList.size() == stringSet.size())
return;
throw new IllegalArgumentException("중복된 이름이 있습니다!");
}
public static void validateUserInputIsCorrectRound(String userInput){
validateUserInputIsInteger(userInput);
Integer count = Integer.parseInt(userInput);
validateIntegerIsPositiveInteger(count);
}
private static void validateUserInputIsInteger(String userInput){
try{
Integer.parseInt(userInput);
}catch (NumberFormatException e){
throw new IllegalArgumentException("양의 정수를 입력해주세요!");
}
}
private static void validateIntegerIsPositiveInteger(Integer count){
if (count<=0){
throw new IllegalArgumentException("양의 정수를 입력해주세요!");
}
}
}
Loading