diff --git a/README.md b/README.md index fcf3f057..130bee6a 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,22 @@ ## 과제 제출 과정 * [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) + +## 구현할 기능 목록 + +1. 컴퓨터가 1~9 사이의 서로 다른 3개의 수를 랜덤으로 선택 + +2. 플레이어가 수 3개를 입력 + +3. 플레이어의 수와 컴퓨터의 수로 점수를 계산 + + - 컴퓨터의 수가 425 일 때, 플레이어 수가 123 이라면 1스트라이크 456이면 1스트라이크 1볼 789라면 낫싱 + +4. 점수에 따라 결과를 출력 + +5. 모두 맞췄을 경우 처리 + + - 게임을 새로 하려면 1, 게임을 종료 하려면 2 + - 1을 누르면 컴퓨터가 랜덤수 3개를 추출하는 메소드(1번)가 다시 실행 + + diff --git a/src/main/java/BaseballGame.java b/src/main/java/BaseballGame.java new file mode 100644 index 00000000..fdbdfa6c --- /dev/null +++ b/src/main/java/BaseballGame.java @@ -0,0 +1,38 @@ + +public class BaseballGame { + private View view = new View(); + private Computer computer = new Computer(); + private Player player = new Player(); + private boolean isRun = true; + public void run() { + while (isRun) { + try { + player.setNumbers(view.getPlayerInput()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + int[] scores = computer.calculateScores(player.getNumbers()); + view.printScore(scores); + isRun = checkIsRun(scores); + } + } + + public boolean checkIsRun(int[] scores) { + if (scores[0] != 3) return true; + try { + if (scores[0] == 3) return checkIsFinish(view.getPlayerRetryChoice()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return false; + } + + private boolean checkIsFinish(boolean playerRetryChoice) { + if (playerRetryChoice == true) { + computer.resetRandomNumbers(); + return true; + } + return false; + } + +} diff --git a/src/main/java/Computer.java b/src/main/java/Computer.java new file mode 100644 index 00000000..b0ca609e --- /dev/null +++ b/src/main/java/Computer.java @@ -0,0 +1,54 @@ +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class Computer { + private Integer[] numbers = new Integer[3]; + + Computer() { + resetRandomNumbers(); + } + + public Integer[] getNumbers() { + return numbers; + } + + public void setNumbers(Integer[] inputNumbers) { + numbers = inputNumbers; + } + + public void resetRandomNumbers() { + numbers = getThreeUniqueRandomNumbers(); + } + public Integer[] getThreeUniqueRandomNumbers() { + Set numberSet = new HashSet<>(); + while (numberSet.size() < 3) { + Double d = Math.random() * 9 + 1; + numberSet.add(d.intValue()); + } + Integer[] randomNumbers = numberSet.toArray(new Integer[0]); + Collections.shuffle(Arrays.asList(randomNumbers)); + return randomNumbers; + } + + public int[] calculateScores(Integer[] playerNumbers) { + int strikeCount = 0; + int ballCount = 0; + for (int i = 0; i < 3; i++) { + strikeCount += checkStrike(i, playerNumbers[i]); + ballCount += checkBall(i, playerNumbers[i]); + } + return new int[] {strikeCount, ballCount}; + } + + public int checkStrike(int idx, Integer number) { + return number.equals(numbers[idx]) ? 1 : 0; + } + + public int checkBall(int idx, Integer playerNumbers) { + if (numbers[(idx+1)%3].equals(playerNumbers)) return 1; + if (numbers[(idx+2)%3].equals(playerNumbers)) return 1; + return 0; + } +} diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..9e1db01b --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,8 @@ + +public class Main { + + public static void main(String args[]) { + BaseballGame baseballGame = new BaseballGame(); + baseballGame.run(); + } +} diff --git a/src/main/java/Player.java b/src/main/java/Player.java new file mode 100644 index 00000000..d0b8dbaa --- /dev/null +++ b/src/main/java/Player.java @@ -0,0 +1,9 @@ +public class Player { + private Integer[] numbers = new Integer[3]; + public Integer[] getNumbers() { + return numbers; + } + public void setNumbers(Integer[] inputNumbers) { + numbers = inputNumbers; + } +} diff --git a/src/main/java/View.java b/src/main/java/View.java new file mode 100644 index 00000000..0424cf02 --- /dev/null +++ b/src/main/java/View.java @@ -0,0 +1,36 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Scanner; + +public class View { + private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + + public Integer[] getPlayerInput() throws IOException { + System.out.println("숫자를 입력해주세요 : "); + String input = reader.readLine(); + String[] numbersInString = input.split(""); + Integer[] numbers = new Integer[3]; + for (int i = 0; i < 3; i++) { + numbers[i] = Integer.parseInt(numbersInString[i]); + } + return numbers; + } + + public void printScore(int[] scores) { + String strike = ""; + String ball = ""; + if (scores[0] != 0) strike = scores[0] + "스트라이크 "; + if (scores[1] != 0) ball = scores[1] + "볼 "; + if (scores[0]+scores[1] != 0) System.out.println(strike + ball); + if (scores[0]+scores[1] == 0) System.out.println("낫싱"); + } + + public boolean getPlayerRetryChoice() throws IOException{ + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + String playerChoice = reader.readLine(); + if (playerChoice.equals("1")) return true; + if (playerChoice.equals("2")) return false; + return getPlayerRetryChoice(); + } +} diff --git a/src/test/java/ComputerTest.java b/src/test/java/ComputerTest.java new file mode 100644 index 00000000..e47ac61b --- /dev/null +++ b/src/test/java/ComputerTest.java @@ -0,0 +1,61 @@ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ComputerTest { + + private static Computer computer; + + @BeforeAll + static void initAll() { + computer = new Computer(); + } + + @Test + @DisplayName("랜덤넘버가 중복되지 않는지 확인") + void testRandomNumberUnique() { + Integer[] randomNumbers = computer.getThreeUniqueRandomNumbers(); + assertThat(randomNumbers[0]).isNotEqualTo(randomNumbers[1]); + assertThat(randomNumbers[0]).isNotEqualTo(randomNumbers[2]); + assertThat(randomNumbers[1]).isNotEqualTo(randomNumbers[2]); + } + + @Test + @DisplayName("랜덤넘버가 1-9 사이인지 확인") + void testRandomNumberInBoundary() { + Integer[] randomNumbers = computer.getThreeUniqueRandomNumbers(); + for (Integer number : randomNumbers) { + assertThat(number).isBetween(1, 9); + } + } + + @Test + @DisplayName("점수 계산 테스트: 1스트라이크") + void testCalculateScoresOneStrike() { + Integer[] computerNumbers = {4, 2, 5}; + computer.setNumbers(computerNumbers); + + Integer[] playerNumbersCaseOne = {1, 2, 3}; + assertThat(computer.calculateScores(playerNumbersCaseOne)).containsExactly(1, 0); + } + @Test + @DisplayName("점수 계산 테스트: 1스트라이크 1볼") + void testCalculateScoresOneStrikeOneBall() { + Integer[] computerNumbers = {4, 2, 5}; + computer.setNumbers(computerNumbers); + + Integer[] playerNumbersCaseTwo = {4, 5, 6}; + assertThat(computer.calculateScores(playerNumbersCaseTwo)).containsExactly(1, 1); + } + @Test + @DisplayName("점수 계산 테스트: 낫싱") + void testCalculateScores1Strike() { + Integer[] computerNumbers = {4, 2, 5}; + computer.setNumbers(computerNumbers); + + Integer[] playerNumbersCaseThree = {7, 8, 9}; + assertThat(computer.calculateScores(playerNumbersCaseThree)).containsExactly(0, 0); + } +} diff --git a/src/test/java/study/SetTest.java b/src/test/java/study/SetTest.java new file mode 100644 index 00000000..371fa814 --- /dev/null +++ b/src/test/java/study/SetTest.java @@ -0,0 +1,45 @@ +package study; + +import org.junit.jupiter.api.BeforeEach; +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.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.*; +public class SetTest { + private Set numbers; + + @BeforeEach + void setUp() { + numbers = new HashSet<>(); + numbers.add(1); + numbers.add(2); + numbers.add(2); + numbers.add(3); + } + + @Test + @DisplayName("Set의 크기") + void setSize() { + assertThat(numbers.size()).isEqualTo(3); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3}) + @DisplayName("Set에 값이 존재하는지 확인") + void setContain(int input) { + assertThat(numbers).contains(input); + } + + @ParameterizedTest + @CsvSource(value = {"1:true", "2:true", "3:true", "4:false", "5:false"}, delimiter = ':') + @DisplayName("Set에 포함되면 true, 안되면 false") + void setContainTrueOrFalse(int input, boolean expected) { + assertThat(numbers.contains(input)).isEqualTo(expected); + } +} diff --git a/src/test/java/study/StringTest.java b/src/test/java/study/StringTest.java index 43e47d90..8f1f38b9 100644 --- a/src/test/java/study/StringTest.java +++ b/src/test/java/study/StringTest.java @@ -1,13 +1,51 @@ package study; +import org.junit.jupiter.api.DisplayName; 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 + @DisplayName("String 치환") void replace() { String actual = "abc".replace("b", "d"); assertThat(actual).isEqualTo("adc"); } + + @Test + @DisplayName("String \',\'로 split") + void split() { + String[] actual = "1,2".split(","); + assertThat(actual).containsExactly("1", "2"); + } + + @Test + @DisplayName("String 문자 하나일때 split") + void splitOne() { + String[] actual = "1".split(","); + assertThat(actual).containsExactly("1"); + } + + @Test + @DisplayName("String 앞뒤 자르기") + void splitBracket() { + String actual = "(1,2)".substring(1, 4); + assertThat(actual).isEqualTo("1,2"); + } + + @Test + @DisplayName("String 인덱스 접근") + void getChar() { + char actual = "abc".charAt(1); + assertThat(actual).isEqualTo('b'); + } + + @Test + @DisplayName("String 인덱스 벗어날 때 예외 처리") + void getCharException() { + assertThatExceptionOfType(IndexOutOfBoundsException.class) + .isThrownBy(() -> { + char actual = "abc".charAt(3); + }).withMessageMatching("Index \\d+ out of bounds for length \\d+"); + } }