-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[숫자 야구 게임] 이영수 미션을 제출합니다. #1338
base: main
Are you sure you want to change the base?
Changes from all commits
9680a61
bcb2082
a32638c
dd62095
3127899
1a9c6c5
b38f51b
c453ea9
4399b06
02dca33
0ce45b2
d046fd4
6ffa384
0d4e739
5cd24a7
17ffbe5
de11b38
a8ff5c6
205f25b
7539c99
d33ed1d
d461868
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,67 @@ | ||
# ⚾️ java-baseball | ||
|
||
|
||
## ⚠️ 구현 전 체크리스트 | ||
### 🖥️ 프로그래밍 요구 사항 | ||
##### 프로젝트가 JDK 17 버전인가? | ||
|
||
##### Java 코드 컨벤션 가이드를 준수하기 위해 이를 알고 있는가? | ||
|
||
### 📚 과제 진행 요구 사항 | ||
|
||
##### 미션은 java-baseball-6 저장소 를 Fork & Clone 하는가? | ||
|
||
##### 기능 구현 하기 전 docs/README.md 에 구현할 기능 목록을 정리해 추가 하였는가? | ||
|
||
### 🔘 기능 요구 사항 | ||
|
||
#### 👦🏻 사용자 요구사항 | ||
|
||
##### ✅ 사용자는 서로 다른 3자리의 수를 입력시 이에 따른 결과를 받는다. | ||
a 볼 카운트 , 스트라이크 카운트가 있으면 n볼 n스트라이크 처럼 결과를 받는다. | ||
b. 볼 카운트 , 스트라이크 카운트가 없는 즉 같은 수가 없으면 낫싱을 받는다. | ||
|
||
##### ✅ 게임 종료 후 사용자는 숫자에 따라 게임을 다시 시작 하거나 애플리케이션을 종료 하는 명령을 보낼 수 있다. | ||
a. 1을 입력하면 게임을 재 시작하는 명령을 보낸다. | ||
b. 2를 입력하면 애플리케이션을 종료하는 명령을 보낸다. | ||
|
||
#### 👾상대방(컴퓨터) 요구사항 | ||
|
||
##### ✅ 상대방 은 게임이 시작 하면 프로그래밍 요구사항에서 요구 하는 Randoms API 를 사용해 서로 다른 무작위 3자리 수를 생성 한다. | ||
|
||
##### ✅ 상대방 은 사용자 가 입력한 값에 대한 카운트를 계산한다. | ||
a. 같은 수가 같은 자리에 있으면 스트라이크 카운트로 계산한다. | ||
b. 같은 수가 다른 자리에 있으면 볼 카운트로 계산한다. | ||
|
||
##### ✅ 상대방 은 계산된 카운트를 통해 결과를 출력한다. | ||
a. 볼 카운트 , 스트라이크 카운트 가 있는 경우 n볼 n스트라이크 처럼 결과를 출력한다. | ||
b. 볼 카운트 , 스트라이크 카운트 가 없는 경우 낫싱을 출력한다. | ||
|
||
##### ✅ 상대방 은 서로 다른 무작위 3자리 수를 재생성 한다. | ||
|
||
#### 🖥️서버 요구사항 | ||
|
||
##### ✅ 서버는 시작 되면 , 게임을 시작 한다. | ||
|
||
##### ✅ 사용자 가 게임을 승리한 후 , 보낸 명령에 맞게 재시작 과 종료 한다. | ||
a. 1을 받으면 게임을 재 시작한다 | ||
b. 2를 받으면 애플리케이션을 종료한다. | ||
|
||
#### 🔎 검증자 요구사항 | ||
|
||
##### ✅ 검증자 는 잘못된 값을 입력할 경우 IllegalArgumentException 을 발생시킨 후 애플리케이션을 종료한다. | ||
a. 숫자가 아닐 시 "숫자를 입력해주세요!" 라는 메시지를 포함해 발생시킨다. | ||
b. 숫자 자리수가 다를 시 "자리수가 다릅니다!" 라는 메시지를 포함해 발생시킨다. | ||
c. 숫자가 범위 밖에 있을 시 "숫자가 범위밖에 있습니다!" 라는 메시지를 포함해 발생시킨다. | ||
d. 중복된 숫자가 있을 시 "중복된 숫자가 있습니다!" 라는 메시지를 포함해 발생시킨다. | ||
|
||
## 🕶️ 구현 후 체크 리스트 | ||
|
||
### 🎯 프로그래밍 요구 사항 | ||
|
||
|
||
##### ✅ System.exit() 를 호출하지 않는가? | ||
##### ✅ 프로그램 구현 완료 시 ApplicationTest 의 모든 테스트가 성공하는가? | ||
##### ✅ build.gradle 및 외부 라이브러리를 사용하지 않았는가? | ||
##### ✅ `camp.nextstep.edu.missionutils`에서 제공하는 `Randoms` 및 `Console` API를 사용하여 구현했는가? | ||
##### ✅ Java 코드 컨벤션 가이드 준수해 프로그래밍 했는가? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package baseball; | ||
|
||
import camp.nextstep.edu.missionutils.Randoms; | ||
|
||
import java.util.ArrayList; | ||
|
||
public class Computer { | ||
private final int minimumCanCreatedValue; | ||
private final int maximumCanCreatedValue; | ||
private ArrayList<Integer> numberList; | ||
private final int digitCount; | ||
|
||
private static int NOT_EXISTED_NUMBER = -1; | ||
public ArrayList<Integer> getNumberList(){ | ||
return this.numberList; | ||
} | ||
|
||
public Computer() { | ||
this.minimumCanCreatedValue = Config.DEFAULT_CAN_CREATED_MINIMUM_VALUE; | ||
this.maximumCanCreatedValue = Config.DEFAULT_CAN_CREATED_MAXIMUM_VALUE; | ||
this.digitCount = Config.DEFAULT_DIGIT_COUNT; | ||
this.numberList = generateRandomNumberListWithNotRepeating(); | ||
} | ||
Comment on lines
+18
to
+23
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 Computer(int digitCount,int minimumCanCreatedValue,int maximumCanCreatedValue) { | ||
this.minimumCanCreatedValue = minimumCanCreatedValue; | ||
this.maximumCanCreatedValue = maximumCanCreatedValue; | ||
this.digitCount = digitCount; | ||
this.numberList = generateRandomNumberListWithNotRepeating(digitCount); | ||
|
||
} | ||
Comment on lines
+18
to
+30
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 ArrayList<Integer> generateRandomNumberListWithNotRepeating(){ | ||
return generateRandomNumberListWithNotRepeating(digitCount); | ||
} | ||
|
||
/** | ||
* 입력한 자리수 만큼 중복되지 않는 숫자 리스트를 생성한다 | ||
* | ||
* 최소값 ( minimumCanCreatedValue ) 과 최대값 ( maximumCanCreatedValue ) 사이 값을 가진다. | ||
* 기존 값에 포함되지 않은 값들만 추가한다. | ||
* | ||
* @param digitCount 생성하는 숫자의 자리수 | ||
* @return | ||
*/ | ||
private ArrayList<Integer> generateRandomNumberListWithNotRepeating(int digitCount){ | ||
|
||
var randomNumberList = new ArrayList<Integer>(); | ||
|
||
while (randomNumberList.size()<digitCount){ | ||
int randomNumber = Randoms.pickNumberInRange(minimumCanCreatedValue,maximumCanCreatedValue); | ||
if (!randomNumberList.contains(randomNumber)){ | ||
randomNumberList.add(randomNumber); | ||
} | ||
} | ||
|
||
return randomNumberList; | ||
} | ||
|
||
/** | ||
* 사용자의 숫자를 비교한 후 , 결과를 반환한다 | ||
* | ||
* 사용자의 숫자와 컴퓨터의 숫자가 모두 일치하면 true 를 반환한다. | ||
* 그렇지 않으면, false 를 반환한다. | ||
* @param playerNumber 사용자가 입력하는 숫자 | ||
* @return boolean | ||
*/ | ||
public boolean checkUserNumberAndResponse(int playerNumber){ | ||
|
||
var compareNumberList = Util.parsingNumberToNumberList(playerNumber,digitCount); | ||
|
||
int strikeCount = calculateStrikeCount(compareNumberList); | ||
int ballCount = calculateBallCount(compareNumberList); | ||
|
||
printResult(strikeCount,ballCount); | ||
|
||
return strikeCount==digitCount; | ||
} | ||
private int calculateStrikeCount(int[] compareNumberList){ | ||
int strikeCount=0; | ||
for (int i =0 ; i< digitCount;i++){ | ||
if (compareNumberList[i]==numberList.get(i)){ | ||
strikeCount++; | ||
compareNumberList[i]=NOT_EXISTED_NUMBER; | ||
} | ||
} | ||
return strikeCount; | ||
} | ||
private int calculateBallCount(int[] compareNumberList){ | ||
int ballCount = 0; | ||
for (int i =0; i<digitCount;i++){ | ||
if (compareNumberList[i]==NOT_EXISTED_NUMBER){ | ||
continue; | ||
} | ||
if (numberList.contains(compareNumberList[i])){ | ||
ballCount++; | ||
compareNumberList[i] = -1; | ||
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. 이 부분도 일관성을 위해 NOT_EXISTED_NUMBER를 사용했다면 좋을 것 같습니다! |
||
} | ||
} | ||
return ballCount; | ||
} | ||
|
||
protected void printResult(int strikeCount,int ballCount){ | ||
StringBuilder resultBuilder = new StringBuilder(); | ||
if (strikeCount==0 && ballCount == 0){ | ||
resultBuilder.append("낫싱"); | ||
} | ||
if (ballCount!=0) { | ||
resultBuilder.append(ballCount).append("볼 "); | ||
} | ||
if (strikeCount!=0){ | ||
resultBuilder.append(strikeCount).append("스트라이크"); | ||
} | ||
String result = resultBuilder.toString(); | ||
System.out.println(result); | ||
} | ||
public void reGenerateNumberList(){ | ||
this.numberList = generateRandomNumberListWithNotRepeating(digitCount); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package baseball; | ||
|
||
public class Config { | ||
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. Config 클래스로 나눠서 상수 관리하는 아이디어 매우 좋은 것 같습니다 👍🏻 |
||
public static final int DEFAULT_DIGIT_COUNT = 3; | ||
public static final int DEFAULT_CAN_CREATED_MINIMUM_VALUE = 1; | ||
public static final int DEFAULT_CAN_CREATED_MAXIMUM_VALUE = 9; | ||
} | ||
Comment on lines
+3
to
+7
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. 상수 값들을 다른 클래스 파일로 분리하니까 상수에 대한 의미가 확실해져서 좋네요! 한 수 배웠습니다😄 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package baseball; | ||
|
||
import camp.nextstep.edu.missionutils.Console; | ||
|
||
import java.util.NoSuchElementException; | ||
|
||
public class Player { | ||
public String getPlayerInput(){ | ||
try{ | ||
Comment on lines
+8
to
+9
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. 자바 코딩 컨벤션에 따라서 괄호 띄어쓰기도 신경써주시면 좋을 것 같습니다! |
||
String playerInput = Console.readLine(); | ||
return playerInput; | ||
}catch (NoSuchElementException e){ | ||
throw new IllegalArgumentException("명령을 입력해주세요!"); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package baseball; | ||
|
||
|
||
public class Server { | ||
private GameStatus gameStatusCode; | ||
private Computer computer; | ||
private Player player; | ||
private Validator validator; | ||
private static final int digitCount = Config.DEFAULT_DIGIT_COUNT; | ||
private static final int minimumCanCreatedValue = Config.DEFAULT_CAN_CREATED_MINIMUM_VALUE; | ||
private static final int maximumCanCreatedValue= Config.DEFAULT_CAN_CREATED_MAXIMUM_VALUE; | ||
|
||
private enum GameStatus{ | ||
RUNNING(1), | ||
STOPPED(2); | ||
Comment on lines
+14
to
+15
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 final int code; | ||
GameStatus(int code){ | ||
this.code = code; | ||
} | ||
public static GameStatus fromCommand(int command){ | ||
for (GameStatus status : GameStatus.values()){ | ||
if (status.code == command){ | ||
return status; | ||
} | ||
} | ||
throw new IllegalArgumentException("없는 명령입니다!"); | ||
} | ||
} | ||
Server(){ | ||
this.computer = new Computer( | ||
digitCount, | ||
minimumCanCreatedValue, | ||
maximumCanCreatedValue | ||
); | ||
this.validator = new Validator( | ||
digitCount, | ||
minimumCanCreatedValue, | ||
maximumCanCreatedValue | ||
); | ||
|
||
this.player = new Player(); | ||
this.gameStatusCode = GameStatus.RUNNING; | ||
} | ||
public void run(){ | ||
while (gameStatusCode ==GameStatus.RUNNING){ | ||
start(); | ||
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); | ||
var playerInput = player.getPlayerInput(); | ||
validator.validatePlayerInputCommand(playerInput); | ||
|
||
var userCommand = Integer.parseInt(playerInput); | ||
if (GameStatus.fromCommand(userCommand) == GameStatus.RUNNING) { | ||
restart(); | ||
} | ||
if (GameStatus.fromCommand(userCommand) == GameStatus.STOPPED) { | ||
quit(); | ||
} | ||
} | ||
} | ||
private void start(){ | ||
while(true) { | ||
System.out.print("숫자를 입력해주세요 : "); | ||
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. 이런 출력 문자열들도 따로 관리하면 더욱 좋을 것 같습니다! |
||
var playerInput = player.getPlayerInput(); | ||
validator.validatePlayerInput(playerInput); | ||
|
||
var playerNumber = Integer.parseInt(playerInput); | ||
var isPlayerWin = computer.checkUserNumberAndResponse(playerNumber); | ||
if (isPlayerWin == true) { | ||
break; | ||
} | ||
} | ||
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); | ||
} | ||
private void restart(){ | ||
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. SRP 원리를 잘 준수하시는 것 같습니다 👍🏻👍🏻 |
||
computer.reGenerateNumberList(); | ||
} | ||
private void quit(){ | ||
gameStatusCode = GameStatus.STOPPED; | ||
} | ||
|
||
public GameStatus getGameStatusCode(){ | ||
return gameStatusCode; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package baseball; | ||
|
||
public class Util { | ||
public static int[] parsingNumberToNumberList(int parsingNumber,int digitCount) { | ||
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. 배열대신 컬렉션을 사용하는 게 좋아보입니다! |
||
int sliceUnit = (int) Math.pow(10, digitCount - 1); | ||
var numberList = new int[digitCount]; | ||
for (int i = 0; i < digitCount; i++) { | ||
int parsedNumber = parsingNumber / sliceUnit; | ||
numberList[i]=parsedNumber; | ||
parsingNumber %= sliceUnit; | ||
sliceUnit /= 10; | ||
} | ||
return numberList; | ||
} | ||
} |
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.
java에서 var 키워드를 써본 적이 없는데, 어떤 장점이 있는지 궁금합니다!