diff --git a/.gitignore b/.gitignore index 249cf086..24b2196e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ HELP.md .gradle build/ +bin/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/** !**/src/test/** diff --git a/README.md b/README.md index fcf3f057..8bc82098 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,74 @@ ## 과제 제출 과정 * [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) + + +## 기능 목록 + + +### 1. GameRule : 숫자야구 게임 규칙상의 조건과 절차 + + - numbers 조건 + - length 3 + - letter range 1 ~ 9 + - letter 중복 없음 + + - 2 numbers A, B 대조 + - a in A is in B => ball += 1 + - ai = bi => strike += 1 + - ball -= strike + + - 게임 결과 생성 + - 스트라이크와 볼의 갯수 + - 3스트라이크시 게임 종료 명시 + + +### 2. UI : 입출력을 담당하는 인터페이스 + + - numbers 입력 + - string 입력 받기 + - GameRule을 참조하여 올바른 입력인지 검증하기 + - 올바른 입력일 시 string을 array로 변환하여 리턴 + + - 인게임 결과 출력 + - 인자로 받은 스트라이크 볼 갯수를 자연어로 번역 + - 0인 경우 생략 + - 둘 모두 0일 경우 낫싱 + - 인게임 반복 여부 리턴 + - 3 스트라이크일 경우 False + - 그 외 True + + - 게임 종료 여부 입력 + - 인게임 종료 알림 출력 + - string 입력 루프 + - 잘못된 입력인 경우 리로드 + - 게임 종료 여부 리턴 + - 1일 경우 False + - 2일 경우 True + + +### 3. Computer : 인게임 상대 역할 + - 자신의 numbers 생성 + - 새 게임 시작을 전달받았을 때 실행 + - GameRule을 참조하여 numbers 필드 갱신 + - 인게임 결과 전달 + - numbers를 전달받았을 때 실행 + - GameRule의 게임 결과 생성 메소드를 이용하여 인게임 결과 받기 + - 인게임 결과 리턴 + + +### 4. Control : 게임 흐름 제어 + + - 객체 생성, 게임 루프 시작 + - 게임 루프 + - Computer에게 새 게임 시작 알리기 + - 인게임 루프 시작 + - 인게임 루프 + - UI 메소드 호출하여 numbers 받기 + - numbers를 Computer에게 전달하여 인게임 결과 받기 + - 인게임 결과를 인자로 UI 메소드 호출하여 인게임 반복 여부 받기 + - 인게임 반복 여부에 따라 루프 반복 혹은 탈출 + - 인게임 루프 탈출 = 게임 종료 + - UI 메소드 호출하여 게임 재시작 여부 받기 + - 게임 재시작 여부에 따라 루프 반복 혹은 탈출 + - 게임 루프 탈출 = 프로세스 종료 diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..8fd97a2b --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,8 @@ +import game.Control; + +public class Main { + public static void main(String[] args){ + Control control = new Control(); + control.start(); + } +} diff --git a/src/main/java/game/Computer.java b/src/main/java/game/Computer.java new file mode 100644 index 00000000..553dc61a --- /dev/null +++ b/src/main/java/game/Computer.java @@ -0,0 +1,37 @@ +package game; + +import java.util.Random; +import java.util.HashSet; + +public class Computer { + private GameRule gameRule; + private Random random; + private int[] numbers; + + public Computer(GameRule gameRule) { + this.gameRule = gameRule; + this.random = new Random(); + this.numbers = new int[gameRule.numbersLengh]; + } + + private int getNewNum(HashSet appearedSet) { + Integer randomNum = gameRule.numbersRange[random.nextInt(gameRule.numbersRange.length)]; + boolean isNew = appearedSet.add(randomNum); + while (!isNew) { + randomNum = gameRule.numbersRange[random.nextInt(gameRule.numbersRange.length)]; + isNew = appearedSet.add(randomNum); + } + return randomNum; + } + + public void updateNumbers() { + HashSet appearedSet = new HashSet(); + for (int i = 0; i < gameRule.numbersLengh; i++) { + numbers[i] = this.getNewNum(appearedSet); + } + } + + public GameRule.Result getResult(int[] inputNumbers) { + return gameRule.judgeResult(inputNumbers, numbers); + } +} diff --git a/src/main/java/game/Control.java b/src/main/java/game/Control.java new file mode 100644 index 00000000..5a7606d7 --- /dev/null +++ b/src/main/java/game/Control.java @@ -0,0 +1,40 @@ +package game; + +public class Control { + private GameRule gameRule; + private UI ui; + private Computer computer; + + public Control() { + this.gameRule = new GameRule(); + this.ui = new UI(gameRule); + this.computer = new Computer(gameRule); + } + + private boolean inGameLoop() { + int[] numbers = ui.getUserNumbers(); + GameRule.Result result = computer.getResult(numbers); + ui.printResult(result); + if (result.isEnd) + return true; + return false; + } + + private boolean gameLoop() { + boolean isEnd = false; + computer.updateNumbers(); + while (!isEnd) { + isEnd = this.inGameLoop(); + } + if (ui.getEndingStatus()) + return true; + return false; + } + + public void start() { + boolean isEnd = false; + while (!isEnd) { + isEnd = this.gameLoop(); + } + } +} \ No newline at end of file diff --git a/src/main/java/game/GameRule.java b/src/main/java/game/GameRule.java new file mode 100644 index 00000000..5f9d80df --- /dev/null +++ b/src/main/java/game/GameRule.java @@ -0,0 +1,47 @@ +package game; + +public class GameRule { + public int numbersLengh = 3; + public int[] numbersRange = {1,2,3,4,5,6,7,8,9}; + + + private int judgeStrike(int num1, int num2) { + if (num1 == num2) + return 1; + return 0; + } + + private int judgeBall(int num, int[] numbers) { + boolean isBall = false; + for (int i = 0; i < numbersLengh; i++) { + isBall = isBall || num == numbers[i]; + } + if (isBall) + return 1; + return 0; + } + + public class Result { + public int strike; + public int ball; + public boolean isEnd; + + public Result(int strike, int ball,boolean isEnd) { + this.strike = strike; + this.ball = ball; + this.isEnd = isEnd; + } + } + + public Result judgeResult(int[] numbers1, int[] numbers2) { + int strike = 0; + int ball = 0; + for (int i = 0; i < numbersLengh; i++) { + strike += this.judgeStrike(numbers1[i], numbers2[i]); + ball += this.judgeBall(numbers1[i], numbers2); + } + ball -= strike; + return new Result(strike, ball, strike == numbersLengh); + } +} + diff --git a/src/main/java/game/UI.java b/src/main/java/game/UI.java new file mode 100644 index 00000000..1361114c --- /dev/null +++ b/src/main/java/game/UI.java @@ -0,0 +1,111 @@ +package game; + +import java.util.Scanner; +import java.util.HashSet; + +public class UI { + private GameRule gameRule; + private Scanner scanner; + + public UI(GameRule gameRule) { + this.gameRule = gameRule; + this.scanner = new Scanner(System.in); + } + + private boolean verifyNumbersLength(String input) { + return input.length() == gameRule.numbersLengh; + } + + private boolean verifyNumbersRangeOfLetter(int letter) { + boolean isInRange = false; + for (int num : gameRule.numbersRange) { + isInRange = isInRange || letter == num; + } + return isInRange; + } + + private boolean verifyNumbersRange(String input) { + boolean isCorrect = true; + for (int i = 0; i < gameRule.numbersLengh; i++) { + isCorrect = isCorrect && this.verifyNumbersRangeOfLetter(input.charAt(i) - '0'); + } + return isCorrect; + } + + private boolean verifyNumbersDuplication(String input) { + boolean isCorrect = true; + HashSet appearedSet = new HashSet(); + for (int i = 0; i < gameRule.numbersLengh; i++) { + Character letter = input.charAt(i); + isCorrect = isCorrect && appearedSet.add(letter); + } + return isCorrect; + } + + private boolean verifyNumbers(String input) { + if (!this.verifyNumbersLength(input)) + return false; + if (!this.verifyNumbersRange(input)) + return false; + if (!this.verifyNumbersDuplication(input)) + return false; + return true; + } + + private int[] parseNumbers(String input) { + int[] numbers = new int[gameRule.numbersLengh]; + for (int i = 0; i < gameRule.numbersLengh; i++) { + numbers[i] = input.charAt(i) -'0'; + } + return numbers; + } + + public int[] getUserNumbers() { + System.out.print("숫자를 입력해주세요 : "); + String input = scanner.nextLine(); + boolean verification = this.verifyNumbers(input); + while (!verification) { + System.out.print("올바른 조건의 숫자를 입력해주세요 : "); + input = scanner.nextLine(); + verification = this.verifyNumbers(input); + } + return this.parseNumbers(input); + } + + public void printResult(GameRule.Result result) { + if (result.strike == 0 && result.ball == 0) { + System.out.println("낫싱"); + return; + } + if (result.strike > 0) + System.out.print(result.strike + " 스트라이크 "); + if (result.ball > 0) + System.out.print(result.ball + " 볼"); + System.out.println(); + } + + private boolean verifyEndingStatus(String input) { + if (input.equals("1") || input.equals("2")) + return true; + return false; + } + + private boolean parseEndingStatus(String input) { + if (input.equals("2")) + return true; + return false; + } + + public boolean getEndingStatus() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + String input = scanner.nextLine(); + boolean verification = this.verifyEndingStatus(input); + if (!verification) { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + input = scanner.nextLine(); + verification = this.verifyEndingStatus(input); + } + return this.parseEndingStatus(input); + } +} diff --git a/src/test/java/game/UnitTest.java b/src/test/java/game/UnitTest.java new file mode 100644 index 00000000..00b1915e --- /dev/null +++ b/src/test/java/game/UnitTest.java @@ -0,0 +1,80 @@ +package game; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class UnitTest { + @Test + void gameRule_can_judgeResult() { + GameRule gameRule = new GameRule(); + int[] numbersTarget = {1,2,3}; + int[] numbersTestCase; + GameRule.Result result; + + // 3 strike + numbersTestCase = new int[]{1,2,3}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(3, result.strike); + assertEquals(0, result.ball); + assertTrue(result.isEnd); + + // 2 strike + numbersTestCase = new int[]{1,2,4}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(2, result.strike); + assertEquals(0, result.ball); + assertFalse(result.isEnd); + + // 1 strike 2 ball + numbersTestCase = new int[]{1,3,2}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(1, result.strike); + assertEquals(2, result.ball); + assertFalse(result.isEnd); + + // 1 strike 1 ball + numbersTestCase = new int[]{1,3,4}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(1, result.strike); + assertEquals(1, result.ball); + assertFalse(result.isEnd); + + // 1 strike + numbersTestCase = new int[]{1,4,5}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(1, result.strike); + assertEquals(0, result.ball); + assertFalse(result.isEnd); + + // 3 ball + numbersTestCase = new int[]{2,3,1}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(0, result.strike); + assertEquals(3, result.ball); + assertFalse(result.isEnd); + + // 2 ball + numbersTestCase = new int[]{2,1,4}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(0, result.strike); + assertEquals(2, result.ball); + assertFalse(result.isEnd); + + // 1 ball + numbersTestCase = new int[]{2,4,5}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(0, result.strike); + assertEquals(1, result.ball); + assertFalse(result.isEnd); + + // nothing + numbersTestCase = new int[]{4,5,6}; + result = gameRule.judgeResult(numbersTarget, numbersTestCase); + assertEquals(0, result.strike); + assertEquals(0, result.ball); + assertFalse(result.isEnd); + } +}