diff --git a/.gitignore b/.gitignore index c2065bc..51c2880 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +STUDY.md HELP.md .gradle build/ diff --git a/docs/STUDY.md b/docs/STUDY.md new file mode 100644 index 0000000..a4b4055 --- /dev/null +++ b/docs/STUDY.md @@ -0,0 +1,55 @@ +# Leets 2주차 미션 +## Up - Down Game + +### 기능 +- 버전 분리(영어, 숫자) +- 입력값과 비교해 결과를 반환 + - 사용자 입력 횟수를 기억하고, 범위를 최신화하여 다시 입력받을 수 있어야함 +- 숫자 버전과 영어 버전을 나눌 때 입력과 출력을 하나로 하려면 어떻게 해야할까 + - 영어 -> 숫자로 변환하여 전달? + +### 구현 +[Domain] +- 도메인이 필요할까 고민 +- -> dto 느낌? + +[Service] +- 숫자, 영어 버전을 구현체로 나누기 +- or 내부 클래스 안에서 버전 선택하기 + +[View] +- InputView: 사용자에게 입력을 받고 컨트롤러로 전달 + - 버전, 정답을 입력받음 + - 잘못된 입력시 예외처리 +- OutputView: 결과를 사용자에게 출력 + - 영어, 숫자 버전 별로 받은 중간 결과를 어떻게 출력할까? + +[Controller] +- 입력을 받아 서비스에 전달 +- 서비스 결과를 받아 출력에 전달 +- 입력을 반복적으로 받아야하는 프로그램의 입장에서 view -> controller -> service -> controller -> output의 구조가 효율적일까? +- 게임이 계속 추가된다면 서비스만 추가하면 되니까 괜찮을 거 같기도 함 + +[예외처리] +- [ERROR] 범위 내의 숫자를 입력하세요. +- [ERROR] 범위 내의 알파벳을 입력하세요. + - 이 두 예외는 어디서 처리? InputView? + +[개인내용] +- commit 메시지 + - feat: 새로운 기능 + - fix: 버그 수정 + - docs: 문서 변경 + - 스타일: 코드의 의미에 영향을 주지 않는 변경 사항(예: 서식 지정) + - refactor: 코드 리팩토링 + - test: 테스트 추가 또는 수정 + - chore: 빌드 프로세스, CI 구성 등이 변경됩니다. + +[실제구현] +- InputView와 OutputView로 View를 구성 +- InputView에서 프로그램 구동에 필요한 입력을 받아 GameController로 전달 +- GameController에서는 게임 버전을 구분해 숫자 버전, 영어 버전을 따로 호출해서 게임 진행, OutputView에 Count를 전달해 출력 +- Domain에 뭐가 들어가야할 지 모르겠음. +- 게임을 버전별로 구분해 따로 패키지를 구성하고 싶은데 더 고민해보겠음 -> 입력이 반복되는 데 계속 객체로 넘겨주는 게 오히려 일하는 단계를 늘리느 느낌 +- 로직 테스트. +- view - controller - game의 3층 구조는 비효율 적인 거 같아 game 로직을 controller에 구현하고, match 해주는 컨트롤러를 따로 구성하였음 diff --git a/src/main/java/leets/land/UpdownApplication.java b/src/main/java/leets/land/UpdownApplication.java index 09d7ae5..2983ae0 100644 --- a/src/main/java/leets/land/UpdownApplication.java +++ b/src/main/java/leets/land/UpdownApplication.java @@ -1,8 +1,20 @@ package leets.land; + +import leets.land.controller.MatchController; +import leets.land.view.InputView; + public class UpdownApplication { - public static void main(String[] args) { - System.out.print("hihi :D"); + + public static void main(String[] args) { + InputView inputView = new InputView(); + int versionNum = inputView.inputVersionNum(); + MatchController matchController = appConfig.gameController(versionNum); + matchController.runApp(); } } + + + + diff --git a/src/main/java/leets/land/appConfig.java b/src/main/java/leets/land/appConfig.java new file mode 100644 index 0000000..07e3679 --- /dev/null +++ b/src/main/java/leets/land/appConfig.java @@ -0,0 +1,18 @@ +package leets.land; + +import leets.land.controller.MatchController; +import leets.land.controller.AlphabetGameController; +import leets.land.controller.NumgameController; + +//자바 코드로 의존성 주입을 하기 위한 클래스 +public class appConfig { + + // 버전에 맞는 Game 객체를 컨트롤러로 주입 + public static MatchController gameController(int versionNum){ + if(versionNum==1) { + return new MatchController(new NumgameController()); + } else { + return new MatchController(new AlphabetGameController()); + } + } +} diff --git a/src/main/java/leets/land/controller/AlphabetGameController.java b/src/main/java/leets/land/controller/AlphabetGameController.java new file mode 100644 index 0000000..f217ea1 --- /dev/null +++ b/src/main/java/leets/land/controller/AlphabetGameController.java @@ -0,0 +1,47 @@ +package leets.land.controller; + +import leets.land.view.InputView; + +public class AlphabetGameController implements GameController { + + private final InputView inputView = new InputView(); + + @Override + public int generateRandomVal() { + int randomNum = (int) (Math.random() * 52); + + if (randomNum < 26) { + return (char) ('a' + randomNum); + } + else { + return (char) ('A' + randomNum - 26); + } + } + + @Override + public int updownGameStart(int targetAlphabet) { + char first = 'A'; + char last = 'z'; + int[] count = {0}; + boolean isCorrect = false; + char inputAlphabet; + + while(!isCorrect){ + System.out.print("정답을 입력하세요(" + first + "~" + last + ") : "); + inputAlphabet = inputView.inputChar(first, last, count); + + if(inputAlphabet == targetAlphabet){ + System.out.println("정답입니다!"); + isCorrect = true; + } else if (inputAlphabethigh)){ + throw new IllegalArgumentException("[ERROR] 범위 내의 숫자를 입력하세요 :"); + } + } + + + /* + 영어버전 입력부 + */ + public char inputChar(char first, char last, int[] count){ + try{ + char inputAlphabet = (charScan.nextLine()).charAt(0);//한글을 입력했을 때 필터링 + count[0]++; + checkValidCharRange(first, last, inputAlphabet); + return inputAlphabet; + } catch (IllegalArgumentException e){ + System.out.print(first + "~" + last + " 내의 알파벳을 입력하세요: "); + return inputChar(first, last, count); + } catch (InputMismatchException e){ + System.out.print("[ERROR] 영어 알파벳을 입력하세요 : "); + charScan.nextLine();// 개행문제 비워주기. 안 하면 StackOverFlow + return inputChar(first, last, count); + } + } + + /* + 입력 범위를 벗어난 입력이 들어오면 예외 날리기 + */ + public void checkValidCharRange(char first, char last, char inputAlphabet) { + if ((inputAlphabet < first) || (inputAlphabet > last)) { + throw new IllegalArgumentException("[ERROR] 범위 내의 알파벳을 입력하세요 : "); + } + } +} diff --git a/src/main/java/leets/land/view/OutputView.java b/src/main/java/leets/land/view/OutputView.java new file mode 100644 index 0000000..1f60b2d --- /dev/null +++ b/src/main/java/leets/land/view/OutputView.java @@ -0,0 +1,13 @@ +package leets.land.view; + +public class OutputView { + + public void printStartMessage(){ + System.out.println("Up-Down 게임을 시작합니다"); + } + + public void printCount(int count) { + System.out.println("시도한 횟수: "+ count + "회"); + } + +} diff --git a/src/test/java/leets/land/game/GameControllerTest.java b/src/test/java/leets/land/game/GameControllerTest.java new file mode 100644 index 0000000..78a3eaa --- /dev/null +++ b/src/test/java/leets/land/game/GameControllerTest.java @@ -0,0 +1,30 @@ +package leets.land.game; + +import leets.land.controller.AlphabetGameController; +import leets.land.controller.GameController; +import leets.land.controller.NumgameController; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +class GameControllerTest { + + + + @Test + void 난수_범위_확인(){ + GameController gameController = new NumgameController(); + assertThat(gameController.generateRandomVal()).isBetween(1, 100); + } + + @Test + void 랜덤_알파벳_범위_확인() { + GameController gameController = new AlphabetGameController(); + int randomValue = gameController.generateRandomVal(); + assertThat(randomValue) + .satisfiesAnyOf( + value -> assertThat(value).isBetween(65, 90), + value -> assertThat(value).isBetween(97, 122) + ); + } +} \ No newline at end of file diff --git a/src/test/java/leets/land/view/InputViewTest.java b/src/test/java/leets/land/view/InputViewTest.java new file mode 100644 index 0000000..40a7ccd --- /dev/null +++ b/src/test/java/leets/land/view/InputViewTest.java @@ -0,0 +1,36 @@ +package leets.land.view; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class InputViewTest { + + InputView inputView; + + @BeforeEach + void setUp(){ + inputView = new InputView(); + } + + @Test + void 버전_입력_범위_확인(){ + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, ()-> + inputView.validVersionNum(0) ); + } + + @Test + void 숫자_입력_범위_확인(){ + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, ()-> + inputView.checkValidNumRange(50,100, 20) ); + } + + @Test + void 영어_입력_범위_확인(){ + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, ()-> + inputView.checkValidCharRange('a', 'c', 's')); + } + + +} \ No newline at end of file