-
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
숫자 야구게임 구현 #2774
base: main
Are you sure you want to change the base?
숫자 야구게임 구현 #2774
Changes from all commits
4fe02a2
f86ddca
5db856c
5cfbeda
2793756
52b8e37
6eb2d7b
1a1e3cd
aac9f69
01cbfdb
e420c89
4bec3d6
cb3a5f1
81c2f92
2cfe1de
7201201
ec16338
91a03fc
0a41f1c
0fe393b
e70e394
e237bcc
b3642f0
81e5708
1e13076
94b9fd1
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,48 @@ | ||
# 요구사항 분석 | ||
- 컴퓨터가 수를 선택한다. | ||
- 수는 3자리 숫자이고, 랜덤으로 정해진다. | ||
- 정답을 맞출 때 까지 반복한다. | ||
- 컴퓨터는 입력한 숫자에 대한 결과를 출력한다. | ||
- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력 | ||
- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력 | ||
- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력 | ||
- 사용자가 수를 입력할 수 있다. | ||
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료 | ||
- 컴퓨터의 수를 맞추면 게임 종료. 종료 후 한번 더 할지, 끝낼지 입력받는다. | ||
|
||
# 역할을 나눈다. | ||
|
||
## 답을 생성하는 역할 | ||
- 컴퓨터가 수를 선택한다. | ||
- 수는 서로 다른 3자리 숫자이고, 랜덤으로 정해진다. | ||
|
||
## 정답을 입력을 할 수 있는 역할 | ||
- 사용자가 수를 입력할 수 있다. | ||
- 수는 서로 다른 3자리 숫자이다. (검증필요) | ||
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료 | ||
|
||
## 정답이 맞는지 판단하고 힌트를 주는 역할 | ||
- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력 | ||
- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력 | ||
- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력 | ||
|
||
## 게임을 제어하는 역할 | ||
- 정답을 맞출 때 까지 반복한다. | ||
- 정답을 맞추면 게임 종료. | ||
- 게임을 종료 후 한번 더 할지, 끝낼지 입력받는다. | ||
|
||
# 도메인 설계 및 기능 목록 | ||
|
||
## BaseBallGame | ||
- 게임을 제어하는 역할 | ||
|
||
## Hitter | ||
- 답을 생성하는 역할 | ||
(왜 컴퓨터가 Hitter냐? 플레이어가 포수에게 주는 볼을 잡아서 스트라이크를 면해야되기 때문에 타자입니다.) | ||
## Pitcher | ||
- 정답을 입력을 할 수 있는 역할 | ||
(왜 플레이어가 Pitcher냐? 3스트라이크 즉, 3번 타자가 못치게끔 포수에게 잘 던져줘야 하기 때문에 투수입니다.) | ||
|
||
## Umpire | ||
- 정답이 맞는지 판단하고 힌트를 주는 역할 | ||
|
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> |
This file was deleted.
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) { | ||
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. ??? 메인이 왜 두개인거죠 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. 전에는 절차지향적인 코드를 작성했던걸 깨닫고 OOP측면에서 설계하고 모델링하는 방식을 배워 다시 적용하려고 합니다. |
||
Game game = new BaseBallGame( | ||
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. 코드 스타일이 많이 달라졌는데 이 부분은 따로 설명 부탁드려요. 개인적으로 느끼기엔 참고자료로 가져온 코드 같은데,,, 참고 코드는 리뷰할때 제외해주세요 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. 참고자료로 가져온 코드는 아니고... 다시 새롭게 짜는 코드입니다! 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. 그렇다면 굿... 처음 코드보다 훨씬 접근 방식이 좋네요 |
||
new Hitter(), | ||
new Pitcher(), | ||
new Umpire() | ||
); | ||
game.start(); | ||
} | ||
} |
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); | ||
} | ||
} | ||
} |
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 { | ||
} |
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); | ||
} |
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); | ||
} | ||
|
||
} |
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 { | ||
|
||
} |
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; | ||
} | ||
} |
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; | ||
} | ||
} |
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.
학습하실 때는 롬복 및 외부 라이브러리 사용 지양해주세요!
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.
앗 네!