Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2c8a53d
docs README.md
oliviarla May 22, 2022
72369e7
feat: inputView, resultView
oliviarla May 22, 2022
9ee8c96
docs: README.md 수정
oliviarla May 22, 2022
44464e3
test: BaseballTest 구현
oliviarla May 22, 2022
bf277a4
feat: main 클래스 추가
oliviarla May 22, 2022
2cfa9fb
feat: Baseball 구현 완료
oliviarla May 22, 2022
15c6b05
docs(baseball): README.md 기능 목록 다시 작성
oliviarla May 26, 2022
01dd974
feat(baseball): InputView 구현
oliviarla May 26, 2022
8024763
test(baseball): InputView test
oliviarla May 26, 2022
eb92b3d
feat(baseball): 엔티티 클래스 구현
oliviarla May 26, 2022
a9185d4
docs(baseball): update README.md
oliviarla May 26, 2022
5f8046b
feat(baseball): OutputView 구현
oliviarla May 27, 2022
b294dca
test(baseball): OutputViewTest 구현
oliviarla May 27, 2022
19461c4
feat(baseball): OutputView 구현
oliviarla May 27, 2022
be73fe2
feat(baseball): RandomNumGenerator 구현
oliviarla May 27, 2022
8829032
test(baseball): RandomNumGenerator 테스트
oliviarla May 27, 2022
967f871
docs(baseball): RandomNumGenerator 구현
oliviarla May 27, 2022
a1bb02d
refactor(baseball): Ball 객체의 혼동 방지 위해 Baseball로 이름 변경 + Baseball에서 순서…
oliviarla May 27, 2022
f13c04b
feat(baseball): BaseballService 구현
oliviarla May 27, 2022
01e34cb
docs(baseball): BaseballService 구현
oliviarla May 27, 2022
5b260ec
test(baseball): BaseballService 테스트 구현
oliviarla May 27, 2022
6c2a62c
feat(baseball): 전체 애플리케이션 구현 완료
oliviarla May 27, 2022
65d6ef8
refactor(baseball): 전체 애플리케이션 수정 및 구현 완료
oliviarla May 27, 2022
bbf4efa
refactor(baseball): 사용자 입력 숫자 개수 예외처리
oliviarla May 27, 2022
f7a0fa7
refactor(baseball): 코드 리뷰에 따라 불변 객체로 수정, Ball 엔티티 추가, 서비스 로직 변경 완료
oliviarla Jun 4, 2022
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
37 changes: 37 additions & 0 deletions src/main/java/baseball/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 숫자야구게임
### 룰
1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임

같은 수가 같은 자리에 있으면 `스트라이크`

같은 수가 다른 자리에 있으면 `볼`

같은 수가 전혀 없으면 `포볼 또는 낫싱`

<b>여러번 반복해 정보를 얻으며 상대방(컴퓨터)의 수를 맞추면 승리</b>

e.g. 상대방(컴퓨터)의 수가 425일 때 123을 제시한 경우 : `1스트라이크`, 456을 제시한 경우 : `1볼 1스트라이크`, 789를 제시한 경우 : `낫싱`

### 작동 방식

1) 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택
2) 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과 출력
3) 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임 종료
4) 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다

### 기능 목록
<b>엔티티</b>
- [x] Ball: 세자리 숫자 저장하는 엔티티 클래스
- [x] BallStatus: 유저 Ball과 랜덤 Ball 비교한 결과를 저장하는 엔티티 클래스
- [x] Action: 동작들을 담는 enum 클래스

<b>서비스</b>
- [x] BaseballService
- isBall: 볼 여부 판별
- isStrike: 스트라이크 여부 판별
- compare: RandomNum, UserNum 비교해 BallStatus 반환
- [x] RandomNumGenerator: 임의의 서로다른 3자리 수 생성

<b>뷰</b>
- [x] InputView: 사용자로부터 입력 받는 뷰 담당하는 클래스
- [x] OutputView: 출력 하는 뷰 담당하는 클래스
31 changes: 31 additions & 0 deletions src/main/java/baseball/application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package baseball;

import baseball.domain.Baseball;
import baseball.domain.BaseballStatus;
import baseball.service.BaseballService;
import baseball.service.RandomNumGenerator;
import baseball.view.InputView;
import baseball.view.OutputView;

public class application {
public static void main(String[] args) throws Exception {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
RandomNumGenerator randomNumGenerator = new RandomNumGenerator();
BaseballService baseballService = new BaseballService();

while(true){
Baseball randomBaseball = new Baseball(randomNumGenerator.makeNum());
BaseballStatus baseballStatus = new BaseballStatus();

while(!outputView.exitGame(baseballStatus)){
Baseball userBaseball = inputView.inputBall();
baseballStatus = baseballService.compare(userBaseball, randomBaseball);
outputView.printBaseballStatus(baseballStatus);
}
if(!inputView.resumeGame()){
break;
}
}

Choose a reason for hiding this comment

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

이런 방법은 어떨까요? ☺️

Suggested change
while(true){
Baseball randomBaseball = new Baseball(randomNumGenerator.makeNum());
BaseballStatus baseballStatus = new BaseballStatus();
while(!outputView.exitGame(baseballStatus)){
Baseball userBaseball = inputView.inputBall();
baseballStatus = baseballService.compare(userBaseball, randomBaseball);
outputView.printBaseballStatus(baseballStatus);
}
if(!inputView.resumeGame()){
break;
}
}
do{
Baseball randomBaseball = new Baseball(randomNumGenerator.makeNum());
BaseballStatus baseballStatus = new BaseballStatus();
while(!outputView.exitGame(baseballStatus)){
Baseball userBaseball = inputView.inputBall();
baseballStatus = baseballService.compare(userBaseball, randomBaseball);
outputView.printBaseballStatus(baseballStatus);
}
}while(inputView.resumeGame())

}
}
5 changes: 5 additions & 0 deletions src/main/java/baseball/domain/Action.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package baseball.domain;

public enum Action {
볼, 스트라이크, 낫싱
}
15 changes: 15 additions & 0 deletions src/main/java/baseball/domain/Baseball.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package baseball.domain;

import java.util.List;

public class Baseball {

Choose a reason for hiding this comment

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

InputView에서 Balseball의 리스르 크기 검사를 Baseball 구현체에서 진행하는건 어떨까요? ☺️

List<Integer> baseballs;

Choose a reason for hiding this comment

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

Baseball을 불변 객체로 만들어 수정할 수 없게 만드는 건 어떨까요? ☺️
그리고 외부에서 접근할 수 없도록 접근 제어자도 필요해 보여요!

Choose a reason for hiding this comment

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

그리고 Integer 객체를 담는 리스트 보다 새로운 객체를 만들어 숫자 야구 게임에서의 숫자를 더 의미있게 사용해보는건 어떨까요? ☺️


public Baseball(List<Integer> balls) {
this.baseballs = balls;
}

public List<Integer> getBaseballs() {
return baseballs;
}
}

Choose a reason for hiding this comment

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

개행 문자가 필요해보입니다!

46 changes: 46 additions & 0 deletions src/main/java/baseball/domain/BaseballStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package baseball.domain;

public class BaseballStatus {
int ball;
int strike;

Choose a reason for hiding this comment

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

외부에서 접근할 수 없도록 접근 제어자도 필요해 보여요! 그리고 불변 객체로 만드는 걸 시도해봐도 좋을 것 같아요 ☺️


public int getBall() {
return ball;
}

public int getStrike() {
return strike;
}

public void setBall(int ball) {
this.ball = ball;
}

public void setStrike(int strike) {
this.strike = strike;
}

@Override
public String toString() {
return "BaseballStatus{" +
"ball=" + ball +
", strike=" + strike +
'}';
}

public boolean nothing() {
return strike == 0 && ball == 0;
}

public boolean existsBall() {
return ball > 0;
}

public boolean existsStrike() {
return strike > 0;
}

public boolean exitGame() {
return getStrike() == 3;
}
}
34 changes: 34 additions & 0 deletions src/main/java/baseball/service/BaseballService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package baseball.service;

import baseball.domain.Baseball;
import baseball.domain.BaseballStatus;

public class BaseballService {
public boolean isStrike(int userNum, int randomNum) {
return userNum == randomNum;
}

public boolean isBall(int userNum, int userIdx, Baseball randomBall) {
if (!isStrike(userNum, randomBall.getBaseballs().get(userIdx))) {

Choose a reason for hiding this comment

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

isStrike 조건문을 지나 isBall 메서드가 호출이 될 때, isStrike를 재호출할 필요가 있을까 생각이 듭니다.
중복으로 확인하는 방법 말고 한 번에 전부 확인하는 방법이 있으면 좋을 것 같아요!

return randomBall.getBaseballs().contains(userNum);
}
return false;
}

public BaseballStatus compare(Baseball userBall, Baseball randomBall) {
int strike = 0, ball = 0;

Choose a reason for hiding this comment

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

하나의 선언문에는 하나의 변수만 생성하는 것이 좋습니다. 아래 코딩 컨벤션 을 참고하시면 좋을 것 같아요!
스크린샷 2022-05-28 오후 12 28 29

Suggested change
int strike = 0, ball = 0;
int strike = 0;
int ball = 0;

for (int i = 0; i < userBall.getBaseballs().size(); i++) {
if (isStrike(userBall.getBaseballs().get(i), randomBall.getBaseballs().get(i))) {
strike++;
continue;
}
if (isBall(userBall.getBaseballs().get(i), i, randomBall)) {
ball++;
}
}
BaseballStatus baseballStatus = new BaseballStatus();
baseballStatus.setBall(ball);
baseballStatus.setStrike(strike);
return baseballStatus;
}
}
16 changes: 16 additions & 0 deletions src/main/java/baseball/service/RandomNumGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package baseball.service;

import java.util.*;

public class RandomNumGenerator {
public List<Integer> makeNum(){
Random random = new Random();
Set<Integer> set = new HashSet<>();

while(set.size()<3){

Choose a reason for hiding this comment

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

3이라는 숫자를 상수로 변환하면 코드의 가독성도 좋아지고 유지보수에도 좋아보입니다. ☺️

int num = random.nextInt(9)+1;

Choose a reason for hiding this comment

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

9도 마찬가지로 의미있는 숫자이니 상수로 만들어도 좋을 것 같아요!

Suggested change
int num = random.nextInt(9)+1;
int num = random.nextInt(9)+1;

set.add(num);
}
return new ArrayList<>(set);
}
}
29 changes: 29 additions & 0 deletions src/main/java/baseball/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package baseball.view;

import baseball.domain.Baseball;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

public class InputView {
public Baseball inputBall() throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("숫자를 입력해 주세요 : ");
String input = scanner.next();
List<Integer> list = Arrays.stream(input.split("")).mapToInt(Integer::parseInt).boxed().collect(Collectors.toList());

Choose a reason for hiding this comment

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

입력되는 숫자를 중복확인 하는 방법이 있을까요? ☺️

if(list.size()!=3){
throw new Exception("3자리 숫자여야 합니다.");
}

return new Baseball(list);
}

public boolean resumeGame() {
Scanner scanner = new Scanner(System.in);
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
int input = scanner.nextInt();
return input == 1;
}
}
34 changes: 34 additions & 0 deletions src/main/java/baseball/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package baseball.view;

import baseball.domain.Action;
import baseball.domain.BaseballStatus;

public class OutputView {
public String outputBaseballStatus(BaseballStatus baseballStatus) throws Exception {
String result = "";
if (!baseballStatus.existsBall() && !baseballStatus.existsStrike() && !baseballStatus.nothing())

Choose a reason for hiding this comment

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

외부에서 유효성 검사를 진행해도 좋지만, baseballStatus를 생성할 때, 유효성 검사를 진행할 수 있으리라 생각이 들어요!

throw new Exception("결과를 반환할 수 없습니다");
if (baseballStatus.existsBall()) {
result += baseballStatus.getBall() + Action..toString() + " ";
}
if (baseballStatus.existsStrike()) {
result += baseballStatus.getStrike() + Action.스트라이크.toString();
}
if (baseballStatus.nothing()) {
return Action.낫싱.toString();
}
return result;
}

public void printBaseballStatus(BaseballStatus baseballStatus) throws Exception {
System.out.println(outputBaseballStatus(baseballStatus));
}

public boolean exitGame(BaseballStatus ballStatus) {
if (ballStatus.exitGame()) {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
return true;
}
return false;
}
}
48 changes: 48 additions & 0 deletions src/test/java/baseball/service/BaseballServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package baseball.service;

import baseball.domain.Baseball;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import java.util.Arrays;

import static org.assertj.core.api.Assertions.assertThat;

public class BaseballServiceTest {
BaseballService baseballService;

@BeforeEach
void setUp(){
baseballService= new BaseballService();
}

@Test
void isStrikeTest(){
Baseball userBall = new Baseball(Arrays.asList(1,2,3));
Baseball randomBall = new Baseball(Arrays.asList(1,2,3));
for(int i=0;i<3;i++){
assertThat(baseballService.isStrike(userBall.getBaseballs().get(i), randomBall.getBaseballs().get(i))).isTrue();
}
}

@Test
void isBallTest(){
Baseball userBall = new Baseball(Arrays.asList(1,3,2));
Baseball randomBall = new Baseball(Arrays.asList(2,1,3));
for(int i=0;i<3;i++){
assertThat(baseballService.isBall(userBall.getBaseballs().get(i), i, randomBall)).isTrue();
}
}

@ParameterizedTest
@CsvSource({"1,2,6,1,9,2,1,1", "3,7,5,7,3,9,2,0", "1,2,3,4,5,6,0,0", "3,4,8,3,4,2,0,2"})
void compareTest(int u1,int u2,int u3,int r1,int r2,int r3, int e1, int e2){
Baseball userBall = new Baseball(Arrays.asList(u1, u2, u3));
Baseball randomBall = new Baseball(Arrays.asList(r1, r2, r3));

assertThat(new int[]{baseballService.compare(userBall, randomBall).getBall(), baseballService.compare(userBall, randomBall).getStrike()}).isEqualTo(new int[]{e1, e2});
//assertThat().isEqualTo(ballStatus.getStrike());
}
}
36 changes: 36 additions & 0 deletions src/test/java/baseball/service/RandomNumTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package baseball.service;

import baseball.domain.Baseball;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class RandomNumTest {
RandomNumGenerator randomNumGenerator;

@BeforeEach
public void setUp() {
randomNumGenerator = new RandomNumGenerator();
}

@Test
@DisplayName("3개의 서로다른 숫자가 생성되는지 확인하는 테스트입니다.")
public void makeNumTest() {
List<Integer> list = randomNumGenerator.makeNum();

Baseball randomNum = new Baseball(list);
assertThat(randomNum.getBaseballs().size()).isEqualTo(3);
}

@Test
@DisplayName("1부터 9 사이의 값인지 확인하는 테스트입니다.")
public void rangeTest() {
List<Integer> list = randomNumGenerator.makeNum();

assertThat(list.stream().filter(integer -> integer >= 1 && integer <= 9).count()).isEqualTo(3);
}
}
44 changes: 44 additions & 0 deletions src/test/java/baseball/view/InputViewTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package baseball.view;

import baseball.domain.Baseball;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.*;

import static org.assertj.core.api.Assertions.assertThat;

public class InputViewTest {
InputView inputView;
Baseball baseball;

@BeforeEach
void setUp() {
inputView = new InputView();
String input = "349";
OutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
InputStream in = new ByteArrayInputStream(input.getBytes());
System.setIn(in);
}

@Test
void countTest() throws Exception {
baseball = inputView.inputBall();
assertThat(baseball.getBaseballs().size()).isEqualTo(3);
}

@Test
void rangeTest() throws Exception {
baseball = inputView.inputBall();
assertThat(baseball.getBaseballs().stream().filter(b -> b < 10 && b > 0).count()).isEqualTo(3);
}

@Test
void resumeTest() {
String data = "1";
InputStream in = new ByteArrayInputStream(data.getBytes());
System.setIn(in);
assertThat(inputView.resumeGame()).isTrue();
}
}
Loading