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

숫자 야구게임 구현 #2774

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4fe02a2
git first commit - 어느정도 틀 구현, 노트북 -> PC로 옮기기 위해 브랜치 x
tjdxo1193 Nov 1, 2023
f86ddca
구현은 완료했다. 이제 리펙토링을 해야한다.
tjdxo1193 Nov 3, 2023
5db856c
잘못된 입력에 대한 커스텀 예외 생성 및 message setting
tjdxo1193 Nov 4, 2023
5cfbeda
유효한 값 체크하는 메서드 구현 및 예외 복구로 처리했음
tjdxo1193 Nov 4, 2023
2793756
코드 정리 및 주석
tjdxo1193 Nov 4, 2023
52b8e37
import 정리
tjdxo1193 Nov 4, 2023
6eb2d7b
Merge pull request #1 from tjdxo1193/exception
tjdxo1193 Nov 4, 2023
1a1e3cd
[테스트 수행 중 failed 수정] 메세지 출력 오타 및 메세지 출력 프로세스 살짝 수정
tjdxo1193 Nov 4, 2023
aac9f69
지원해주는 api를 사용하여 사용자 입력값과 랜덤수를 가져옴
tjdxo1193 Nov 4, 2023
01cbfdb
기반 필수 클래스 생성
tjdxo1193 Nov 4, 2023
e420c89
메소드 분리 완료 todo 아쉬운점 ..
tjdxo1193 Nov 4, 2023
4bec3d6
Merge pull request #2 from tjdxo1193/리팩토링_1차
tjdxo1193 Nov 4, 2023
cb3a5f1
제목 없는 다이어그램.drawio이 추가되었습니다.
tjdxo1193 Nov 6, 2023
81c2f92
객체지향적 설계 및 재리팩토링
tjdxo1193 Nov 6, 2023
2cfe1de
Merge remote-tracking branch 'origin/main'
tjdxo1193 Nov 6, 2023
7201201
제목 없는 다이어그램.drawio 업데이트
tjdxo1193 Nov 6, 2023
ec16338
도메인 설계 문서 작성
tjdxo1193 Nov 7, 2023
91a03fc
Answer생성자를 통해 각 도메인 별로 파라미터에 따라 다르게 생성하는 로직 구현
tjdxo1193 Nov 7, 2023
0a41f1c
게임을 종료 할지 다시할지 1,2의 코드를 ReplyOrNot enum으로 정의
tjdxo1193 Nov 7, 2023
0fe393b
값에 대한 휴효성 검증 하는 메서드 작성
tjdxo1193 Nov 7, 2023
e70e394
메서드 책임 분리, 자잘한 오타 수정
tjdxo1193 Nov 9, 2023
e237bcc
결과 result를 판단하여 생성하고 결과를 출력하는 로직 구현
tjdxo1193 Nov 9, 2023
b3642f0
출력 줄바꿈 수정
tjdxo1193 Nov 9, 2023
81e5708
절차지향적으로 설계했던 패키지(이전 완성본) 삭제
tjdxo1193 Nov 9, 2023
1e13076
테스트 코드 패키지 변경
tjdxo1193 Nov 9, 2023
94b9fd1
Merge pull request #3 from tjdxo1193/Refactoring_OOP_#1
tjdxo1193 Nov 9, 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ while (computer.size() < 3) {

## ✏️ 과제 진행 요구 사항

- 미션은 [java-baseball-6](https://github.com/woowacourse-precourse/java-baseball-6) 저장소를 Fork & Clone해 시작한다.
- 미션은 [java-baseball_oop-6](https://github.com/woowacourse-precourse/java-baseball-6) 저장소를 Fork & Clone해 시작한다.
- **기능을 구현하기 전 `docs/README.md`에 구현할 기능 목록을 정리**해 추가한다.
- 과제 진행 및 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고한다.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repositories {

dependencies {
implementation 'com.github.woowacourse-projects:mission-utils:1.1.0'
implementation 'org.projectlombok:lombok:1.18.22'

Choose a reason for hiding this comment

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

학습하실 때는 롬복 및 외부 라이브러리 사용 지양해주세요!

Copy link
Author

Choose a reason for hiding this comment

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

앗 네!

}

java {
Expand Down
48 changes: 48 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 요구사항 분석
- 컴퓨터가 수를 선택한다.
- 수는 3자리 숫자이고, 랜덤으로 정해진다.
- 정답을 맞출 때 까지 반복한다.
- 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력
- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력
- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력
- 사용자가 수를 입력할 수 있다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료
- 컴퓨터의 수를 맞추면 게임 종료. 종료 후 한번 더 할지, 끝낼지 입력받는다.

# 역할을 나눈다.

## 답을 생성하는 역할
- 컴퓨터가 수를 선택한다.
- 수는 서로 다른 3자리 숫자이고, 랜덤으로 정해진다.

## 정답을 입력을 할 수 있는 역할
- 사용자가 수를 입력할 수 있다.
- 수는 서로 다른 3자리 숫자이다. (검증필요)
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료

## 정답이 맞는지 판단하고 힌트를 주는 역할
- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력
- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력
- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력

## 게임을 제어하는 역할
- 정답을 맞출 때 까지 반복한다.
- 정답을 맞추면 게임 종료.
- 게임을 종료 후 한번 더 할지, 끝낼지 입력받는다.

# 도메인 설계 및 기능 목록

## BaseBallGame
- 게임을 제어하는 역할

## Hitter
- 답을 생성하는 역할
(왜 컴퓨터가 Hitter냐? 플레이어가 포수에게 주는 볼을 잡아서 스트라이크를 면해야되기 때문에 타자입니다.)
## Pitcher
- 정답을 입력을 할 수 있는 역할
(왜 플레이어가 Pitcher냐? 3스트라이크 즉, 3번 타자가 못치게끔 포수에게 잘 던져줘야 하기 때문에 투수입니다.)

## Umpire
- 정답이 맞는지 판단하고 힌트를 주는 역할

1 change: 1 addition & 0 deletions docs/도메인설계.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mxfile host="drawio-plugin" modified="2023-11-07T07:10:12.473Z" agent="5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36" etag="5S9qTbl9MSshc-uugrrR" version="20.5.3" type="embed"><diagram name="페이지-1" id="q04Y4RyBtX_a_hriLJLF"><mxGraphModel dx="899" dy="399" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="nZR88hf0O_DFail2BoQR-1" value="Game" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="110" y="350" width="120" height="60" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-2" value="Computer" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="420" y="270" width="120" height="60" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-3" value="Judgment" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="420" y="470" width="120" height="60" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-4" value="Player" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="420" y="370" width="120" height="60" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-6" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="nZR88hf0O_DFail2BoQR-1" target="nZR88hf0O_DFail2BoQR-2" edge="1"><mxGeometry width="50" height="50" relative="1" as="geometry"><mxPoint x="340" y="480" as="sourcePoint"/><mxPoint x="390" y="430" as="targetPoint"/></mxGeometry></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-8" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="nZR88hf0O_DFail2BoQR-1" target="nZR88hf0O_DFail2BoQR-4" edge="1"><mxGeometry width="50" height="50" relative="1" as="geometry"><mxPoint x="240" y="375" as="sourcePoint"/><mxPoint x="430" y="310" as="targetPoint"/></mxGeometry></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-9" value="정답을 생성" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"><mxGeometry x="280" y="300" width="70" height="30" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-10" value="정답을 입력" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"><mxGeometry x="300" y="360" width="70" height="30" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-11" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="nZR88hf0O_DFail2BoQR-1" target="nZR88hf0O_DFail2BoQR-3" edge="1"><mxGeometry width="50" height="50" relative="1" as="geometry"><mxPoint x="110" y="520" as="sourcePoint"/><mxPoint x="300" y="625" as="targetPoint"/></mxGeometry></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-12" value="정답인지 판단" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"><mxGeometry x="320" y="430" width="80" height="30" as="geometry"/></mxCell><mxCell id="nZR88hf0O_DFail2BoQR-14" value="" style="curved=1;endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="nZR88hf0O_DFail2BoQR-1" target="nZR88hf0O_DFail2BoQR-1" edge="1"><mxGeometry width="50" height="50" relative="1" as="geometry"><mxPoint x="110" y="460" as="sourcePoint"/><mxPoint x="100" y="380" as="targetPoint"/><Array as="points"><mxPoint x="100" y="450"/><mxPoint x="50" y="410"/><mxPoint x="50" y="380"/></Array></mxGeometry></mxCell><mxCell id="3" value="게임을 더 진행할것인가?" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"><mxGeometry x="70" y="440" width="140" height="30" as="geometry"/></mxCell></root></mxGraphModel></diagram></mxfile>
7 changes: 0 additions & 7 deletions src/main/java/baseball/Application.java

This file was deleted.

19 changes: 19 additions & 0 deletions src/main/java/baseball_oop/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package baseball_oop;

import baseball_oop.domain.game.BaseBallGame;
import baseball_oop.domain.game.Game;
import baseball_oop.domain.participant.computer.Hitter;
import baseball_oop.domain.participant.player.Pitcher;
import baseball_oop.domain.participant.judgment.Umpire;

public class Application {

public static void main(String[] args) {

Choose a reason for hiding this comment

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

??? 메인이 왜 두개인거죠

Copy link
Author

Choose a reason for hiding this comment

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

전에는 절차지향적인 코드를 작성했던걸 깨닫고 OOP측면에서 설계하고 모델링하는 방식을 배워 다시 적용하려고 합니다.

Game game = new BaseBallGame(
Copy link

@Dev-Yesung Dev-Yesung Nov 7, 2023

Choose a reason for hiding this comment

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

코드 스타일이 많이 달라졌는데 이 부분은 따로 설명 부탁드려요. 개인적으로 느끼기엔 참고자료로 가져온 코드 같은데,,, 참고 코드는 리뷰할때 제외해주세요

Copy link
Author

Choose a reason for hiding this comment

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

참고자료로 가져온 코드는 아니고... 다시 새롭게 짜는 코드입니다!

Choose a reason for hiding this comment

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

그렇다면 굿... 처음 코드보다 훨씬 접근 방식이 좋네요

new Hitter(),
new Pitcher(),
new Umpire()
);
game.start();
}
}
114 changes: 114 additions & 0 deletions src/main/java/baseball_oop/domain/game/BaseBallGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package baseball_oop.domain.game;

import baseball_oop.enums.ReplayOrNot;
import baseball_oop.vo.Answer;
import baseball_oop.domain.participant.computer.Computer;
import baseball_oop.domain.participant.judgment.Judgment;
import baseball_oop.domain.participant.player.Player;
import baseball_oop.vo.Result;

import static camp.nextstep.edu.missionutils.Console.readLine;

public class BaseBallGame implements Game {
private final Computer computer;
private final Judgment judgment;
private final Player player;

public BaseBallGame(Computer computer, Player player, Judgment judgment) {
this.computer = computer;
this.judgment = judgment;
this.player = player;
}
@Override
public void start() {
String command;
PrintMessage.printGameStart();
do {
play();
} while (askReplay());
}

private void play() {
Answer answer = computer.generateAnswer();
Answer input;
Result result = null;
while (!gameEnd(result)) {
input = selectInputToPlayer();
printHint(result = judgment.judge(answer, input));
}
}

private static boolean askReplay() {
PrintMessage.printGameReplayOrNot();
return readLine().equals(ReplayOrNot.REPLAY.getCode());
}

private static boolean gameEnd(Result result) {
if (result == null) {
return false;
}

boolean isEnd = result.isWin();
if (isEnd) {
PrintMessage.printWinAndEnd();
}
return isEnd;
}

private Answer selectInputToPlayer() {
PrintMessage.printRequestInputNumber();
return player.generateAnswer();
}

private void printHint(Result result) { // TODO 코드리팩토링 필요
if (result == null) {
return;
}
int strikeCount = result.getStrikeCount();
int ballCount = result.getBallCount();

if (result.getBallCount() == 0 && result.getStrikeCount() == 0) {
PrintMessage.printResultNothing();
return;
}
if (strikeCount != 0 && ballCount == 0) {
PrintMessage.printMessage(strikeCount + PrintMessage.STRIKE);
}
if (strikeCount == 0 && ballCount != 0) {
PrintMessage.printMessage(ballCount + PrintMessage.BALL);
}
if (strikeCount != 0 && ballCount != 0) {
PrintMessage.printMessage(ballCount + PrintMessage.BALL + " " + strikeCount + PrintMessage.STRIKE);
}
}

private static class PrintMessage {
private final static String START = "숫자 야구 게임을 시작합니다.";
private final static String INPUT_NUMBER = "숫자를 입력해주세요 : ";
private final static String WIN = "3개의 숫자를 모두 맞히셨습니다! 게임 종료";
private final static String PLAY_NEXT_GAME_OR_NOT = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";
private final static String NOTHING = "낫싱";
private final static String BALL = "볼";
private final static String STRIKE = "스트라이크";
public static void printRequestInputNumber() {
System.out.print(INPUT_NUMBER);
}
public static void printGameStart() {
System.out.println(START);
}
public static void printWinAndEnd() {
System.out.println(WIN);
}
public static void printGameReplayOrNot() {
System.out.println(PLAY_NEXT_GAME_OR_NOT);
}

public static void printResultNothing() {
System.out.println(NOTHING);
}

public static void printMessage(String message) {
System.out.println(message);
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/baseball_oop/domain/game/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package baseball_oop.domain.game;

public interface Game {
void start();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package baseball_oop.domain.participant;

import baseball_oop.vo.Answer;

public interface AnswerGeneratable {
Answer generateAnswer();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package baseball_oop.domain.participant.computer;

import baseball_oop.domain.participant.AnswerGeneratable;

public interface Computer extends AnswerGeneratable {
}
11 changes: 11 additions & 0 deletions src/main/java/baseball_oop/domain/participant/computer/Hitter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package baseball_oop.domain.participant.computer;

import baseball_oop.vo.Answer;

public class Hitter implements Computer {

@Override
public Answer generateAnswer() {
return new Answer();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package baseball_oop.domain.participant.judgment;

import baseball_oop.vo.Answer;
import baseball_oop.vo.Result;

public interface Judgment {
Result judge(Answer answer, Answer input);
}
15 changes: 15 additions & 0 deletions src/main/java/baseball_oop/domain/participant/judgment/Umpire.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package baseball_oop.domain.participant.judgment;

import baseball_oop.vo.Answer;
import baseball_oop.vo.Result;

public class Umpire implements Judgment {
@Override
public Result judge(Answer answer, Answer input) {
int strikeCount = Answer.countSameElementAndPosition(answer.getValues(), input.getValues());
int ballCount = Answer.countContainElement(answer.getValues(), input.getValues()) - strikeCount;

return new Result(strikeCount, ballCount);
}

}
10 changes: 10 additions & 0 deletions src/main/java/baseball_oop/domain/participant/player/Pitcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package baseball_oop.domain.participant.player;

import baseball_oop.vo.Answer;
import static camp.nextstep.edu.missionutils.Console.readLine;
public class Pitcher implements Player {
@Override
public Answer generateAnswer() {
return new Answer(readLine());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package baseball_oop.domain.participant.player;

import baseball_oop.domain.participant.AnswerGeneratable;

public interface Player extends AnswerGeneratable {

}
17 changes: 17 additions & 0 deletions src/main/java/baseball_oop/enums/ExceptionMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package baseball_oop.enums;

public enum ExceptionMessage {
WRONG_INPUT_DEFAULT("잘못된 입력입니다."),
WRONG_INPUT_NOT_THREE_DIGITS("3자리만 입력 할 수 있습니다."),
WRONG_INPUT_NOT_NUMBER("숫자가 아닙니다."),
WRONG_INPUT_DUPLICATE_VALUE("숫자가 중복되어 있습니다.");
String message;

ExceptionMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}
16 changes: 16 additions & 0 deletions src/main/java/baseball_oop/enums/ReplayOrNot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package baseball_oop.enums;

public enum ReplayOrNot {
REPLAY("1"),
END("2");

public final String code;

ReplayOrNot(String code) {
this.code = code;
}

public String getCode() {
return code;
}
}
Loading