-
Notifications
You must be signed in to change notification settings - Fork 0
[조윤호] 야구 게임 미션 #2
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
base: main
Are you sure you want to change the base?
Changes from all commits
c0abb19
f449f83
714d713
3ac7ecc
292c25c
e4f003c
6e8eec3
6b2fc50
dcc759f
483d073
6a580a1
9a837a4
d6fb92a
756a633
951f6b7
2169607
3198cf6
fec8802
9336696
d5d7ade
4472181
cc19a60
314e127
1b3f09b
7e9f562
6472f4a
dc3d36f
9d64f96
af4d49d
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,20 @@ | ||
| # 기능 목록 | ||
|
|
||
| 입출력 | ||
| - [ ] 사용자 입력 | ||
| - [ ] 숫자 입력 | ||
| - [ ] 예외처리 | ||
| - [ ] 게임 진행(1 or 2) 입력 | ||
| - [ ] 예외처리 | ||
| - [ ] 메시지 출력 | ||
| - [ ] 시작 메시지 | ||
| - [ ] (b, s) -> 볼/스트라이크 출력 | ||
| - [ ] 종료 메시지 | ||
|
|
||
| 게임 진행 | ||
| - [ ] main | ||
| - [ ] 게임 시작 | ||
| - [ ] 게임 종료, 결과 출력 | ||
| - [ ] singleGame | ||
| - [ ] init : 난수 생성 | ||
| - [ ] singleTurn (xxx) -> 판정 후 결과 리턴 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,22 @@ | ||
| package baseball; | ||
|
|
||
| import baseball.game.model.GameCommand; | ||
| import baseball.game.model.GameStatus; | ||
| import baseball.game.GameService; | ||
| import baseball.inout.UserInput; | ||
| import baseball.inout.UserOutput; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| GameCommand command = GameCommand.CONTINUE; | ||
|
|
||
| while (command.isContinue()){ | ||
| GameService gameService = new GameService(); | ||
| gameService.playSingleGame(); | ||
| command = gameService.getCommand(); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package baseball.game; | ||
|
|
||
| import baseball.game.model.GameBall; | ||
| import baseball.game.model.GameCommand; | ||
| import baseball.game.model.GameStatus; | ||
| import baseball.inout.UserInput; | ||
| import baseball.inout.UserOutput; | ||
| import camp.nextstep.edu.missionutils.Randoms; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class GameService { | ||
|
|
||
| GameBall computer; | ||
|
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. 변수 접근제한자 지정!
Author
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 GameService() { | ||
| computer = GameBall.createRandomBall(); | ||
| } | ||
|
|
||
| public void playSingleGame() { | ||
| boolean isContinue = true; | ||
|
|
||
| while (isContinue) { | ||
| GameBall playNum = GameBall.createBall(UserInput.getNum()); | ||
| GameStatus gameStatus = computer.getStatus(playNum); | ||
| UserOutput.printStatus(gameStatus); | ||
| isContinue = gameStatus.isContinue(); | ||
| } | ||
| UserOutput.printEndMessage(); | ||
| } | ||
|
|
||
| public GameCommand getCommand() { | ||
| return GameCommand.getCommand(UserInput.isContinue()); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,74 @@ | ||||||
| package baseball.game.model; | ||||||
|
|
||||||
| import camp.nextstep.edu.missionutils.Randoms; | ||||||
|
|
||||||
| import java.util.*; | ||||||
|
|
||||||
| public class GameBall { | ||||||
|
|
||||||
| private final static int BALL_MAX = 9; | ||||||
| private final static int BALL_MIN = 1; | ||||||
| private final static int BALL_NUM = 3; | ||||||
|
|
||||||
| private List<Integer> ballNumbers; | ||||||
|
|
||||||
| private GameBall(List<Integer> ballNumbers) { | ||||||
| this.ballNumbers = ballNumbers; | ||||||
| } | ||||||
|
|
||||||
| public static GameBall createBall(String userInput){ | ||||||
| if (isInvalidLength(userInput)) | ||||||
| throw new IllegalArgumentException("3자리의 숫자를 입력해야 합니다."); | ||||||
| if (isInvalidRange(userInput)) | ||||||
| throw new IllegalArgumentException("숫자의 범위가 올바르지 않습니다."); | ||||||
|
Comment on lines
+20
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. 볼을 만드는 메소드에서 검증 책임을 같이 수행하고 있네요. 검증하는 로직을 메소드로 분리하면 좋을 것 같아요! |
||||||
|
|
||||||
| List<Integer> ball = new ArrayList<>(); | ||||||
| for (int i = 0; i < 3; i++) | ||||||
|
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.
Suggested change
|
||||||
| ball.add(userInput.charAt(i) - '0'); | ||||||
|
|
||||||
| if (isDuplicated(ball)) | ||||||
| throw new IllegalArgumentException("중복이 없는 3자리의 숫자를 입력해야 합니다."); | ||||||
|
|
||||||
| return new GameBall(ball); | ||||||
| } | ||||||
|
|
||||||
| public static GameBall createRandomBall (){ | ||||||
| Set<Integer> ball = new LinkedHashSet<>(); | ||||||
|
|
||||||
| while(ball.size() < BALL_NUM) { | ||||||
| int randomNumber = Randoms.pickNumberInRange(1, 9); | ||||||
| ball.add(randomNumber); | ||||||
| } | ||||||
|
|
||||||
| return new GameBall(new ArrayList<>(ball)); | ||||||
| } | ||||||
|
|
||||||
| public GameStatus getStatus(GameBall other) { | ||||||
| int strike = 0; | ||||||
| int ball = 0; | ||||||
|
|
||||||
| for (int i = 0; i < this.ballNumbers.size(); i++) { | ||||||
| if (other.ballNumbers.get(i).equals(this.ballNumbers.get(i))) strike++; | ||||||
| else if (other.ballNumbers.contains(this.ballNumbers.get(i))) ball++; | ||||||
| } | ||||||
|
|
||||||
| return new GameStatus(ball, strike); | ||||||
| } | ||||||
|
|
||||||
| private static boolean isInvalidLength(String input) { | ||||||
| return input.length() != BALL_NUM; | ||||||
| } | ||||||
|
|
||||||
| private static boolean isDuplicated(List<Integer> input) { | ||||||
| return input.size() != (new HashSet<Integer>(input)).size(); | ||||||
| } | ||||||
|
|
||||||
| private static boolean isInvalidRange(String input) { | ||||||
| for (int i = 0; i < input.length(); i++) { | ||||||
| int num = input.charAt(i) - '0'; | ||||||
| if (num > BALL_MAX || num < BALL_MIN) return true; | ||||||
| } | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package baseball.game.model; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| public enum GameCommand { | ||
| QUIT(2), | ||
| CONTINUE(1); | ||
|
|
||
| private final int number; | ||
|
|
||
| GameCommand(int number) { | ||
| this.number = number; | ||
| } | ||
|
|
||
| public static GameCommand getCommand(String userInput) { | ||
| int commandNumber; | ||
| try { | ||
| commandNumber = Integer.parseInt(userInput); | ||
| } catch (NumberFormatException ex) { | ||
| throw new IllegalArgumentException("숫자를 입력해야 합니다."); | ||
| } | ||
|
Comment on lines
+16
to
+21
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. 파싱하는 로직도 분리하면 좋을 것 같아요! |
||
|
|
||
| GameCommand command = Arrays.stream(values()) | ||
| .filter(value -> value.number == commandNumber) | ||
| .findAny() | ||
| .orElseThrow(() -> new IllegalArgumentException("올바른 숫자가 입력되지 않았습니다.")); | ||
|
|
||
| return command; | ||
| } | ||
|
|
||
| public boolean isContinue() { | ||
| return this == CONTINUE; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package baseball.game.model; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class GameStatus { | ||
| public int ball; | ||
| public int strike; | ||
|
|
||
| public GameStatus(int ball, int strike) { | ||
| this.ball = ball; | ||
| this.strike = strike; | ||
| } | ||
|
|
||
| public boolean isContinue() { | ||
| return !(strike == 3 && ball == 0); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| GameStatus that = (GameStatus) o; | ||
| return ball == that.ball && strike == that.strike; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(ball, strike); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package baseball.inout; | ||
|
|
||
|
|
||
| import camp.nextstep.edu.missionutils.Console; | ||
|
|
||
| public class UserInput { | ||
|
|
||
| private UserInput() { | ||
| } | ||
|
|
||
| /** | ||
| * 숫자 입력 | ||
| */ | ||
| public static String getNum() { | ||
| System.out.print("숫자를 입력해주세요 : "); | ||
| String input = Console.readLine().trim(); | ||
| return input; | ||
| } | ||
|
|
||
| /** | ||
| * 게임 진행여부 입력 | ||
| */ | ||
| public static String isContinue() { | ||
|
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. 메소드 네이밍이 어색합니다. |
||
| System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); | ||
| String input = Console.readLine().trim(); | ||
| return input; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package baseball.inout; | ||
|
|
||
| import baseball.game.model.GameStatus; | ||
|
|
||
| public class UserOutput { | ||
|
|
||
| private UserOutput() { | ||
| } | ||
|
|
||
| public static void initMessage() { | ||
| System.out.println("숫자 야구 게임을 시작합니다."); | ||
| } | ||
|
|
||
| public static void printStatus(GameStatus status) { | ||
| if (status.ball == 0 && status.strike == 0) | ||
| System.out.println("낫싱"); | ||
| else if (status.ball == 0) | ||
| System.out.println(status.strike + "스트라이크"); | ||
| else if (status.strike == 0) | ||
| System.out.println(status.ball + "볼"); | ||
| else | ||
| System.out.println(status.ball + "볼 " + status.strike + "스트라이크"); | ||
|
Comment on lines
+15
to
+22
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. view에서 출력 외 로직이 동작하는 것이 어색합니다!
Author
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. 그렇군요..!! GameStatus로 옮기는 것을 고려해봐야겠네요 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 static void printEndMessage() { | ||
| System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package baseball.game.model; | ||
|
|
||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.params.ParameterizedTest; | ||
| import org.junit.jupiter.params.provider.CsvSource; | ||
| import org.junit.jupiter.params.provider.ValueSource; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| import static org.assertj.core.api.Assertions.*; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class GameBallTest { | ||
|
|
||
| @ParameterizedTest | ||
| @DisplayName("GameBall 생성 동작 테스트") | ||
| @ValueSource(strings = {"123", "145", "671"}) | ||
| void createBall(String input) { | ||
| // given | ||
|
|
||
| // when & then | ||
| assertThatCode( () -> { | ||
| GameBall.createBall(input); | ||
| }).doesNotThrowAnyException(); | ||
| } | ||
|
|
||
|
|
||
| @ParameterizedTest | ||
| @DisplayName("GameBall 생성 예외 테스트") | ||
| @ValueSource(strings = {"111", "122", "1325", "a11"}) | ||
| void createBallErrors(String input) { | ||
| // given | ||
|
|
||
| // when & then | ||
| assertThatThrownBy( () -> { | ||
| GameBall.createBall(input); | ||
| }).isInstanceOf(IllegalArgumentException.class); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @DisplayName("getStatus 생성 동작 테스트") | ||
| @CsvSource(value = {"456:0:0", | ||
| "516:1:0", "156:0:1", "231:3:0", "123:0:3"}, delimiter = ':' | ||
| ) | ||
| void getStatus(String input, int ball, int strike) { | ||
| // given | ||
| GameBall computer = GameBall.createBall("123"); | ||
| GameBall player = GameBall.createBall(input); | ||
|
|
||
| // when | ||
| GameStatus gameStatus = computer.getStatus(player); | ||
|
|
||
| // then | ||
| assertThat(gameStatus).isEqualTo(new GameStatus(ball, strike)); | ||
| } | ||
|
|
||
| } |
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.
안쓰는 임포트는 지워주세요!
인텔리제이를 사용하신다면, 맥 기준 ctrl+option+o(영어 오) / 윈도우 기준 ctrl+alt+o 임포트 정리 단축키를 사용해서 간편하게 정리할 수 있습니다ㅎㅎ
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.
오오 꿀팁이네요