diff --git a/README.md b/README.md index fcf3f057..035f869d 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,8 @@ ## 과제 제출 과정 * [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) + +## 구현 기능 +- 임의의 3자리 수 선정 +- 유저 input & 결과(힌트) return +- (게임 오버 시) 재시작 여부 체크 diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..da7e3469 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,13 @@ +import game.BaseballGame; +import service.RandomGenerator; + +public class Application { + public static void main(String[] args) { + RandomGenerator.generateRandomNumber(); + Boolean keepPlaying = true; + while (keepPlaying) { + BaseballGame baseballGame = new BaseballGame(); + keepPlaying = baseballGame.playGame(); + } + } +} diff --git a/src/main/java/game/BaseballGame.java b/src/main/java/game/BaseballGame.java new file mode 100644 index 00000000..4cf239f2 --- /dev/null +++ b/src/main/java/game/BaseballGame.java @@ -0,0 +1,66 @@ +package game; + +import service.RandomGenerator; +import service.StrikeBallCount; +import service.SubmissionValidator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class BaseballGame { + private final List answer; + private final List userInput = new ArrayList<>(); + private final Scanner scanner = new Scanner(System.in); + + public BaseballGame() { + this.answer = RandomGenerator.generateRandomNumber(); + } + + public Boolean playGame() { + Boolean stop = false; + while (!stop) { + stop = progressGame(); + } + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + return scanner.nextInt() == 1; + } + + private Boolean progressGame() { + setUserInput(); + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(userInput, answer); + System.out.println(strikeBallCount.getResultString()); + return strikeBallCount.isCorrect(); + } + + private void setUserInput() { + System.out.print("숫자를 입력해주세요: "); + String input = scanner.nextLine().replaceAll("\\s", ""); + if (isInputValid(input)) { + updateUserInput(input); + return; + } + System.out.println("올바른 숫자를 입력해 주세요!"); + setUserInput(); + } + + private void updateUserInput(String input) { + userInput.clear(); + for (int i = 0; i < 3; i++) { + userInput.add(Character.getNumericValue(input.charAt(i))); + } + } + + private boolean isInputValid(String input) { + if (input.length() != 3) return false; + int idx = 0; + while (idx < 3 && Character.isDigit(input.charAt(idx)) && Character.getNumericValue(input.charAt(idx)) > 0) { + idx++; + } + if (idx != 3) { + return false; + } + return true; + } +} diff --git a/src/main/java/service/RandomGenerator.java b/src/main/java/service/RandomGenerator.java new file mode 100644 index 00000000..78c900ee --- /dev/null +++ b/src/main/java/service/RandomGenerator.java @@ -0,0 +1,22 @@ +package service; + +import java.util.ArrayList; +import java.util.List; + +public class RandomGenerator { + public static List generateRandomNumber() { + ArrayList candidate = new ArrayList<>(); + while (candidate.size() < 3) { + insertDistinctNumber(candidate); + } + return candidate; + } + + private static void insertDistinctNumber(List candidate) { + int newCandidate = (int) ((Math.random() * 8) + 1); + while (candidate.contains(newCandidate)) { + newCandidate = (int) ((Math.random() * 8) + 1); + } + candidate.add(newCandidate); + } +} diff --git a/src/main/java/service/StrikeBallCount.java b/src/main/java/service/StrikeBallCount.java new file mode 100644 index 00000000..39a6bb2e --- /dev/null +++ b/src/main/java/service/StrikeBallCount.java @@ -0,0 +1,38 @@ +package service; + +public class StrikeBallCount { + private int strikeCount = 0; + private int ballCount = 0; + + public int getStrikeCount() { + return strikeCount; + } + + public int getBallCount() { + return ballCount; + } + + public void updateStrike() { + this.strikeCount += 1; + } + + public void updateBall() { + this.ballCount += 1; + } + + public Boolean isCorrect() { + return this.strikeCount == 3; + } + + public Boolean isNothing() { + return this.ballCount == 0 & this.strikeCount == 0; + } + + public String getResultString() { + StringBuilder res = new StringBuilder(); + if (this.strikeCount > 0) res.append(strikeCount).append("스트라이크 "); + if (this.ballCount > 0) res.append(ballCount).append("볼"); + if (this.isNothing()) res.append("낫싱"); + return res.toString(); + } +} diff --git a/src/main/java/service/SubmissionValidator.java b/src/main/java/service/SubmissionValidator.java new file mode 100644 index 00000000..1a7157e0 --- /dev/null +++ b/src/main/java/service/SubmissionValidator.java @@ -0,0 +1,24 @@ +package service; + +import java.util.List; + +public class SubmissionValidator { + public static StrikeBallCount validateSubmission(List submission, List answer) { + StrikeBallCount strikeBallCount = new StrikeBallCount(); + for (int idx = 0; idx < 3; idx++) { + updateStrikeBallCountPerIdx(idx, submission, answer, strikeBallCount); + } + return strikeBallCount; + } + + private static void updateStrikeBallCountPerIdx(int idx, List submission, List answer, StrikeBallCount strikeBallCount) { + if (submission.get(idx).equals(answer.get(idx))) { + strikeBallCount.updateStrike(); + return; + } + if(answer.contains(submission.get(idx))) { + strikeBallCount.updateBall(); + return; + } + } +} diff --git a/src/test/java/game/BaseballGameTest.java b/src/test/java/game/BaseballGameTest.java new file mode 100644 index 00000000..d2c3861d --- /dev/null +++ b/src/test/java/game/BaseballGameTest.java @@ -0,0 +1,10 @@ +package game; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BaseballGameTest { + BaseballGame game = new BaseballGame(); + +} \ No newline at end of file diff --git a/src/test/java/service/RandomGeneratorTest.java b/src/test/java/service/RandomGeneratorTest.java new file mode 100644 index 00000000..3431104f --- /dev/null +++ b/src/test/java/service/RandomGeneratorTest.java @@ -0,0 +1,30 @@ +package service; + +import org.junit.jupiter.api.Test; +import java.util.HashSet; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class RandomGeneratorTest { + + @Test + void generateRandomNumber_sizeIsThree() { + List randomNumber = RandomGenerator.generateRandomNumber(); + assertThat(randomNumber.size()).isEqualTo(3); + } + + @Test + void generateRandomNumber_noDuplicate() { + List randomNumber = RandomGenerator.generateRandomNumber(); + assertThat(new HashSet<>(randomNumber).size()).isEqualTo(randomNumber.size()); + } + + @Test + void generateRandomNumber_isInRange() { + List randomNumber = RandomGenerator.generateRandomNumber(); + for (Integer num : randomNumber) { + assertThat(num).isBetween(1, 9); + } + } +} \ No newline at end of file diff --git a/src/test/java/service/SubmissionValidatorTest.java b/src/test/java/service/SubmissionValidatorTest.java new file mode 100644 index 00000000..5bd355d0 --- /dev/null +++ b/src/test/java/service/SubmissionValidatorTest.java @@ -0,0 +1,164 @@ +package service; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class SubmissionValidatorTest { + + @Test + void validateSubmission_isStrikeThree() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(1); + answer.add(2); + answer.add(3); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(3); + assertThat(strikeBallCount.getBallCount()).isEqualTo(0); + } + + @Test + void validateSubmission_isStrikeThreeAndCorrect() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(1); + answer.add(2); + answer.add(3); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(3); + assertThat(strikeBallCount.getBallCount()).isEqualTo(0); + assertThat(strikeBallCount.isCorrect()).isTrue(); + } + + @Test + void validateSubmission_isBallThree() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(3); + answer.add(1); + answer.add(2); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(0); + assertThat(strikeBallCount.getBallCount()).isEqualTo(3); + } + + @Test + void validateSubmission_isTwoBallOneStrike() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(1); + answer.add(3); + answer.add(2); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(1); + assertThat(strikeBallCount.getBallCount()).isEqualTo(2); + } + + @Test + void validateSubmission_isOneBall() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(4); + answer.add(5); + answer.add(1); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(0); + assertThat(strikeBallCount.getBallCount()).isEqualTo(1); + } + + @Test + void validateSubmission_noMatch() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(4); + answer.add(5); + answer.add(6); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(0); + assertThat(strikeBallCount.getBallCount()).isEqualTo(0); + } + + @Test + void validateSubmission_noMatchAndNothing() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(4); + answer.add(5); + answer.add(6); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getStrikeCount()).isEqualTo(0); + assertThat(strikeBallCount.getBallCount()).isEqualTo(0); + assertThat(strikeBallCount.isNothing()).isTrue(); + } + + @Test + void validateSubmission_resultStringIsTwoBallOneStrike() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(1); + answer.add(3); + answer.add(2); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getResultString()).isEqualTo("1스트라이크 2볼"); + } + + @Test + void validateSubmission_resultStringIsNothing() { + List submission = new ArrayList<>(); + submission.add(1); + submission.add(2); + submission.add(3); + + List answer = new ArrayList<>(); + answer.add(4); + answer.add(5); + answer.add(6); + + StrikeBallCount strikeBallCount = SubmissionValidator.validateSubmission(submission, answer); + assertThat(strikeBallCount.getResultString()).isEqualTo("낫싱"); + } +} \ No newline at end of file diff --git a/src/test/java/study/SetTest.java b/src/test/java/study/SetTest.java new file mode 100644 index 00000000..5f833d7c --- /dev/null +++ b/src/test/java/study/SetTest.java @@ -0,0 +1,43 @@ +package study; + +import org.junit.jupiter.api.Assertions; +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 org.junit.jupiter.params.provider.ValueSource; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SetTest { + private Set numbers; + + @BeforeEach + void setUp() { + numbers = new HashSet<>(); + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + } + + @Test + void sizeOfSet() { + assertThat(numbers.size()).isEqualTo(3); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3}) + void contains(int input) { + assertThat(numbers.contains(input)).isTrue(); + } + + @ParameterizedTest + @CsvSource(value = {"1:true", "2:true", "3:true", "4:false", "5:false"}, delimiter = ':') + void contains_trueAndFalse(int input, Boolean expected) { + Assertions.assertEquals(expected, numbers.contains(input)); + } +} diff --git a/src/test/java/study/StringTest.java b/src/test/java/study/StringTest.java index 43e47d90..6447fb39 100644 --- a/src/test/java/study/StringTest.java +++ b/src/test/java/study/StringTest.java @@ -2,12 +2,35 @@ import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; public class StringTest { @Test - void replace() { - String actual = "abc".replace("b", "d"); - assertThat(actual).isEqualTo("adc"); + void splitOneAndTwo() { + String str = "1,2"; + String[] resStr = str.split(","); + assertThat(resStr).contains("1", "2"); + } + + @Test + void splitOne() { + String str = "1"; + String[] resStr = str.split(","); + assertThat(resStr).containsExactly("1"); + } + + @Test + void removeParenthesis() { + String str = "(1,2)"; + String resStr = str.substring(1, 4); + assertThat(resStr).isEqualTo("1,2"); + } + + @Test + void strIdxOutOfBound() { + String str = "abc"; + assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> { + str.charAt(3); + }).withMessageMatching("Index \\d+ out of bounds for length \\d+"); } }