diff --git a/README.md b/README.md index 8d7e8aee..38be8df7 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + +## 구현 기능 목록 +- 상대방 (컴퓨터) 클래스 + - 컴퓨터 클래스를 생성할 때 랜덤 3자리 수 생성 + - 사용자가 다시 게임을 진행할 때 랜덤 3자리 수 다시 생성 +- BaseBallGame (게임 진행 로직) 클래스 + - 스트라이크 개수 체크하는 함수 + - 볼 개수 체크하는 함수 + - 스트라이크, 볼, 낫싱 정보 출력하는 함수 +- main 클래스 + - 게임 진행 로직 +- BaseBallGame 클래스 Test 추가 +- Main Test 추가 \ No newline at end of file diff --git a/build.gradle b/build.gradle index 20a92c9e..5c00edef 100644 --- a/build.gradle +++ b/build.gradle @@ -23,3 +23,10 @@ dependencies { test { useJUnitPlatform() } + +/* +아래 설정을 추가해 주지 않으면 제 pc에서는 실행이 되지 않아서 추가했습니다. + */ +tasks.withType(JavaCompile){ + options.encoding = "UTF-8" +} diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..6a205169 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,98 @@ +import computer.Computer; +import game.BaseBallGameService; +import game.GameCondition; + +import java.util.Scanner; + +public class Application { + + private final Computer computer; + private final BaseBallGameService gameService; + private final GameCondition gameCondition; + + public Application(Computer computer, BaseBallGameService gameService, GameCondition gameCondition) { + this.computer = computer; + this.gameService = gameService; + this.gameCondition = gameCondition; + } + + public Computer getComputer() { + return computer; + } + + private boolean inputValidCheck(String clientNumber) { + try{ + gameService.checkNumberValid(clientNumber); + return true; + } + catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return false; + } + } + + private void printGameInfo(int strike, int ball) { + if(strike == 3){ + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + gameCondition.changeCollectAnswer(true); + }else{ + String info = gameService.printGameInfo(strike, ball); + System.out.println(info); + } + } + + private void checkRestartGame(String continueGame){ + try{ + if("1".equals(continueGame)){ + computer.reGenerateNumber(); + gameCondition.changeCollectAnswer(false); + } + else if("2".equals(continueGame)){ + gameCondition.changePlayGame(false); + } + else{ + throw new IllegalArgumentException("입력이 1과 2가 아닙니다. 애플리케이션을 종료합니다."); + } + } + catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + gameCondition.changePlayGame(false); + } + } + public void start(){ + Scanner scanner = new Scanner(System.in); + + while(gameCondition.canPlayGame()){ + System.out.print("숫자를 입력해 주세요 : "); + String clientNumber = scanner.nextLine(); + + if (!inputValidCheck(clientNumber)) { + scanner.close(); + break; + } + + int strike = gameService.checkStrike(computer.getNumber(), clientNumber); + int ball = gameService.checkBall(computer.getNumber(), clientNumber); + + printGameInfo(strike, ball); + + if(gameCondition.canCollectAnswer()){ + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + String continueGame = scanner.nextLine(); + checkRestartGame(continueGame); + } + } + scanner.close(); + System.out.println("안녕히 가세요."); + } + + public static void main(String[] args) { + Computer computer = new Computer(); + BaseBallGameService gameService = new BaseBallGameService(); + GameCondition gameCondition = new GameCondition(); + + Application app = new Application(computer, gameService, gameCondition); + app.start(); + } + +} diff --git a/src/main/java/computer/Computer.java b/src/main/java/computer/Computer.java new file mode 100644 index 00000000..2a83bef5 --- /dev/null +++ b/src/main/java/computer/Computer.java @@ -0,0 +1,45 @@ +package computer; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +public class Computer { + + private String number; + + public Computer() { + number = createBaseballNumber(); + } + + private String createBaseballNumber(){ + Random random = new Random(); + Set numbers = new HashSet<>(); + + while(numbers.size() < 3){ + int randomNumber = random.nextInt(9) + 1; + numbers.add(randomNumber); + } + + String createNumber = ""; + for (Integer num : numbers) { + createNumber += num; + } + + return createNumber; + } + + public void reGenerateNumber(){ + number = createBaseballNumber(); + } + + + public String getNumber() { + return number; + } + + public void changeNumber(String number){ + this.number = number; + } + +} diff --git a/src/main/java/game/BaseBallGameService.java b/src/main/java/game/BaseBallGameService.java new file mode 100644 index 00000000..2bc7175a --- /dev/null +++ b/src/main/java/game/BaseBallGameService.java @@ -0,0 +1,63 @@ +package game; + +public class BaseBallGameService { + + public int checkStrike(String computerNumber, String userNumber){ + int strike = 0; + + for(int i=0; i<3; i++){ + if(computerNumber.charAt(i) == userNumber.charAt(i)){ + strike++; + } + } + + return strike; + } + + public int checkBall(String computerNumber, String userNumber){ + int ball = 0; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i != j && computerNumber.charAt(i) == userNumber.charAt(j)) { + ball++; + } + } + } + return ball; + } + + public String printGameInfo(int strike, int ball){ + if(strike == 0 && ball == 0){ + return "낫싱"; + } else if(strike > 0 && ball == 0) { + return strike+"스트라이크"; + } else if(strike == 0 && ball > 0){ + return ball+"볼"; + } + else{ + return ball+"볼 "+strike+"스트라이크"; + } + } + + public boolean checkNumberValid(String number){ + if (number.length() != 3) { + throw new IllegalArgumentException("잘못된 입력입니다. 애플리케이션을 종료합니다."); + } + + for (int i = 0; i < number.length(); i++) { + char c = number.charAt(i); + + if (!Character.isDigit(c) || c == '0') { + throw new IllegalArgumentException("잘못된 입력입니다. 애플리케이션을 종료합니다."); + } + + long count = number.chars().filter(n -> n == c).count(); + if (count > 1){ + throw new IllegalArgumentException("잘못된 입력입니다. 애플리케이션을 종료합니다."); + } + } + + return true; + } + +} diff --git a/src/main/java/game/GameCondition.java b/src/main/java/game/GameCondition.java new file mode 100644 index 00000000..2b62665e --- /dev/null +++ b/src/main/java/game/GameCondition.java @@ -0,0 +1,27 @@ +package game; + +public class GameCondition { + boolean playGame; + boolean collectAnswer; + + public GameCondition() { + this.playGame = true; + this.collectAnswer = false; + } + + public boolean canPlayGame() { + return playGame; + } + + public boolean canCollectAnswer() { + return collectAnswer; + } + + public void changeCollectAnswer(boolean collectAnswer){ + this.collectAnswer = collectAnswer; + } + + public void changePlayGame(boolean playGame){ + this.playGame = playGame; + } +} diff --git a/src/test/java/ApplicationTest.java b/src/test/java/ApplicationTest.java new file mode 100644 index 00000000..65e776ab --- /dev/null +++ b/src/test/java/ApplicationTest.java @@ -0,0 +1,84 @@ +import computer.Computer; +import game.BaseBallGameService; +import game.GameCondition; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class ApplicationTest { + + private final Application application = new Application( + new Computer(), + new BaseBallGameService(), + new GameCondition() + ); + + private final InputStream systemIn = System.in; + + private final PrintStream standardOut = System.out; + private final ByteArrayOutputStream testOut = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() { + System.setOut(new PrintStream(testOut)); + } + @AfterEach + public void restoreSystemInput() { + System.setOut(standardOut); + System.setIn(systemIn); + } + + @Test + @DisplayName("서로다른 1~9 까지의 3자리 수 입력이 아닌 경우") + void userInvalidInputTest(){ + String invalidInput = "a23"; + ByteArrayInputStream testIn = new ByteArrayInputStream(invalidInput.getBytes()); + System.setIn(testIn); + + application.start(); + + assertTrue(testOut.toString().contains("잘못된 입력입니다. 애플리케이션을 종료합니다.")); + assertTrue(testOut.toString().contains("안녕히 가세요.")); + + } + + @Test + @DisplayName("게임이 종료되고 1과 2의 입력이 아닌 경우") + void userInvalidInputTest2(){ + application.getComputer().changeNumber("123"); + String invalidInput = "123\na\n"; + ByteArrayInputStream testIn = new ByteArrayInputStream(invalidInput.getBytes()); + System.setIn(testIn); + + application.start(); + assertTrue(testOut.toString().contains("입력이 1과 2가 아닙니다. 애플리케이션을 종료합니다.")); + assertTrue(testOut.toString().contains("안녕히 가세요.")); + } + + @Test + @DisplayName("게임 정상 흐름 테스트") + void normalFlowTest(){ + application.getComputer().changeNumber("123"); + String invalidInput = "123\n2\n"; + ByteArrayInputStream testIn = new ByteArrayInputStream(invalidInput.getBytes()); + System.setIn(testIn); + + application.start(); + + assertTrue(testOut.toString().contains("3개의 숫자를 모두 맞히셨습니다! 게임 종료")); + assertTrue(testOut.toString().contains("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.")); + assertTrue(testOut.toString().contains("안녕히 가세요.")); + } + +} \ No newline at end of file diff --git a/src/test/java/computer/ComputerTest.java b/src/test/java/computer/ComputerTest.java new file mode 100644 index 00000000..5e9d20b4 --- /dev/null +++ b/src/test/java/computer/ComputerTest.java @@ -0,0 +1,31 @@ +package computer; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class ComputerTest { + + private final Computer computer = new Computer(); + + @Test + @DisplayName("컴퓨터 서로다른 3자리 숫자 생성 테스트") + void computerInitTest(){ + String number = computer.getNumber(); + + Set numbers = new HashSet<>(); + + for(int i=0; i<3; i++){ + numbers.add(Integer.valueOf(number.charAt(i))); + } + + assertThat(numbers.size()).isEqualTo(3); + } + +} \ No newline at end of file diff --git a/src/test/java/game/BaseBallGameServiceTest.java b/src/test/java/game/BaseBallGameServiceTest.java new file mode 100644 index 00000000..6190f96a --- /dev/null +++ b/src/test/java/game/BaseBallGameServiceTest.java @@ -0,0 +1,87 @@ +package game; + +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.assertThatThrownBy; + +class BaseBallGameServiceTest { + + private final BaseBallGameService baseBallGameService = new BaseBallGameService(); + + @Test + @DisplayName("스트라이크 개수 체크 Test") + void checkStrikeTest(){ + String computerNumber = "123"; + String userNumber = "123"; + + int strike = baseBallGameService.checkStrike(computerNumber, userNumber); + assertThat(strike).isEqualTo(3); + + userNumber = "523"; + strike = baseBallGameService.checkStrike(computerNumber, userNumber); + assertThat(strike).isEqualTo(2); + + userNumber = "563"; + strike = baseBallGameService.checkStrike(computerNumber, userNumber); + assertThat(strike).isEqualTo(1); + + userNumber = "564"; + strike = baseBallGameService.checkStrike(computerNumber, userNumber); + assertThat(strike).isEqualTo(0); + } + + @Test + @DisplayName("볼 개수 체크 Test") + void checkBallTest(){ + String computerNumber = "123"; + String userNumber = "123"; + + int ball = baseBallGameService.checkBall(computerNumber, userNumber); + assertThat(ball).isEqualTo(0); + + userNumber = "312"; + ball = baseBallGameService.checkBall(computerNumber, userNumber); + assertThat(ball).isEqualTo(3); + + userNumber = "412"; + ball = baseBallGameService.checkBall(computerNumber, userNumber); + assertThat(ball).isEqualTo(2); + + userNumber = "415"; + ball = baseBallGameService.checkBall(computerNumber, userNumber); + assertThat(ball).isEqualTo(1); + } + + @Test + @DisplayName("볼 스트라이크 낫싱 정보 출력") + void printInfoTest(){ + assertThat(baseBallGameService.printGameInfo(0, 0)).isEqualTo("낫싱"); + assertThat(baseBallGameService.printGameInfo(2, 0)).isEqualTo("2스트라이크"); + assertThat(baseBallGameService.printGameInfo(2, 0)).isEqualTo("2스트라이크"); + assertThat(baseBallGameService.printGameInfo(1, 2)).isEqualTo(2+"볼 "+1+"스트라이크"); + assertThat(baseBallGameService.printGameInfo(0, 3)).isEqualTo(3+"볼"); + } + + @Test + @DisplayName("입력 유효성 테스트") + void inputValidTest(){ + assertThatThrownBy(()->baseBallGameService.checkNumberValid("agb")) + .isInstanceOf(IllegalArgumentException.class); + + assertThatThrownBy(()->baseBallGameService.checkNumberValid("122")) + .isInstanceOf(IllegalArgumentException.class); + + assertThatThrownBy(()->baseBallGameService.checkNumberValid("12")) + .isInstanceOf(IllegalArgumentException.class); + + assertThatThrownBy(()->baseBallGameService.checkNumberValid("120")) + .isInstanceOf(IllegalArgumentException.class); + + assertThat(baseBallGameService.checkNumberValid("123")).isTrue(); + } + + + +} \ No newline at end of file