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

[숫자 야구 게임] 이영수 미션을 제출합니다. #1338

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9680a61
docs : 기능 목록 정리
youngsu5582 Oct 20, 2023
bcb2082
feat : 상대방 기능 요구사항 1번 완성
youngsu5582 Oct 21, 2023
a32638c
feat : 상대방 기능 요구사항 1번 수정
youngsu5582 Oct 21, 2023
dd62095
feat : 상대방 기능 요구사항 1번 테스트 코드 추가
youngsu5582 Oct 21, 2023
3127899
feat : 상대방 기능 요구사항 2번 완성
youngsu5582 Oct 21, 2023
1a9c6c5
feat : 상대방 기능 요구사항 JavaDoc 완성
youngsu5582 Oct 22, 2023
b38f51b
feat : 서버 기능 요구사항 1번 완성
youngsu5582 Oct 22, 2023
c453ea9
feat : 서버 기능 요구사항 1번 테스트 코드 & JavaDoc 추가
youngsu5582 Oct 22, 2023
4399b06
feat : 서버 기능 요구사항 2번 완성 & 테스트 코드 추가
youngsu5582 Oct 22, 2023
02dca33
feat : 사용자 요구사항 1,2번 완성
youngsu5582 Oct 22, 2023
0ce45b2
feat : Config 파일 추가
youngsu5582 Oct 23, 2023
d046fd4
refactor : Server restart 부분 리팩토링
youngsu5582 Oct 23, 2023
6ffa384
feat : Validator 파일 추가
youngsu5582 Oct 23, 2023
0d4e739
feat : GameStatus 추가
youngsu5582 Oct 23, 2023
5cd24a7
refactor : Computer 리팩토링
youngsu5582 Oct 23, 2023
17ffbe5
feat : reGenerateNumberList 기능 추가
youngsu5582 Oct 23, 2023
de11b38
docs : 추가 기능들에 따른 README 수정
youngsu5582 Oct 23, 2023
a8ff5c6
feat : 사용자 요구사항 테스트 코드 추가
youngsu5582 Oct 24, 2023
205f25b
refactor : 전반적인 리팩토링
youngsu5582 Oct 24, 2023
7539c99
feat : ServerTest 파일 삭제
youngsu5582 Oct 24, 2023
d33ed1d
feat : 테스트에 @Disabled 추가
youngsu5582 Oct 24, 2023
d461868
docs : 구현 후 체크 리스트 수정
youngsu5582 Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 67 additions & 0 deletions docs/README.md
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 코드 컨벤션 가이드 준수해 프로그래밍 했는가?
4 changes: 3 additions & 1 deletion src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

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

Choose a reason for hiding this comment

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

java에서 var 키워드를 써본 적이 없는데, 어떤 장점이 있는지 궁금합니다!

System.out.println("숫자 야구 게임을 시작합니다.");
server.run();
}
}
118 changes: 118 additions & 0 deletions src/main/java/baseball/Computer.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

Choose a reason for hiding this comment

The 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

Choose a reason for hiding this comment

The 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;

Choose a reason for hiding this comment

The 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);
}
}
7 changes: 7 additions & 0 deletions src/main/java/baseball/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package baseball;

public class Config {
Copy link

Choose a reason for hiding this comment

The 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

Choose a reason for hiding this comment

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

상수 값들을 다른 클래스 파일로 분리하니까 상수에 대한 의미가 확실해져서 좋네요! 한 수 배웠습니다😄

17 changes: 17 additions & 0 deletions src/main/java/baseball/Player.java
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

Choose a reason for hiding this comment

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

자바 코딩 컨벤션에 따라서 괄호 띄어쓰기도 신경써주시면 좋을 것 같습니다!

String playerInput = Console.readLine();
return playerInput;
}catch (NoSuchElementException e){
throw new IllegalArgumentException("명령을 입력해주세요!");
}
}

}
85 changes: 85 additions & 0 deletions src/main/java/baseball/Server.java
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

Choose a reason for hiding this comment

The 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("숫자를 입력해주세요 : ");
Copy link

Choose a reason for hiding this comment

The 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(){
Copy link

Choose a reason for hiding this comment

The 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;
}

}
15 changes: 15 additions & 0 deletions src/main/java/baseball/Util.java
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) {

Choose a reason for hiding this comment

The 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;
}
}