diff --git a/README.md b/README.md index fcf3f057..832afa99 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,22 @@ # 숫자 야구 게임 -## 진행 방법 -* 숫자 야구 게임 요구사항을 파악한다. -* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 과제를 제출한다. +## 구현할 기능 목록 -## 과제 제출 과정 -* [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse) +* 1-9사이의 숫자중 3개를 뽑아 3자리 수를 정한다. +* 3자리 수를 입력받는다. + * 받은 값이 3자리가 아닌 경우 예외 출력 + * 받은 값이 숫자가 아닌 경우 예외 출력 + * 받은 값에 중복된 숫자가 있을 시 예외 출력 +* 입력값에 따라 힌트를 구분한다. + * 자리와 숫자 둘다 맞춘 경우 => 스트라이크 + 1 + * 숫자는 같지만 자리가 다른 경우 => 볼 + 1 + * 자리와 숫자 모두 틀린 경우 => 낫싱 (볼과 스트라이크가 모두 0인 상황) + * [예] 상대방(컴퓨터)의 수가 425일 때 + * 123을 제시한 경우 : 1 스트라이크, + * 456을 제시한 경우 : 1 스트라이크 1볼, + * 789를 제시한 경우 : 낫싱 +* 게임의 승패 유무를 판단한다. + * 3스트라이크인 경우, 게임이 종료된다. + * 3스트라이크가 아니면 3자리 수를 입력받는다. +* 게임 종료가 되면, 다시 게임을 진행할지 완전히 프로그램을 종료할 지를 출력한다. + * 1 입력 시 게임 재시작 + * 2 입력 시 프로그램 종료 \ No newline at end of file diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..c2325394 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,12 @@ +import controller.BaseBallController; + +import java.io.IOException; + +public class Application { + + public static void main(String[] args) throws IOException { + BaseBallController baseBallController = new BaseBallController(); + baseBallController.BaseBallGame(); + + } +} diff --git a/src/main/java/controller/BaseBallController.java b/src/main/java/controller/BaseBallController.java new file mode 100644 index 00000000..a3c233d0 --- /dev/null +++ b/src/main/java/controller/BaseBallController.java @@ -0,0 +1,46 @@ +package controller; + +import domain.Computer; +import domain.Score; +import domain.User; +import service.GameServiceImpl; +import service.GameService; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Objects; + +public class BaseBallController { + + private static Computer computer; + private static User user; + private static Score score; + + private static GameService gameService; + + public void BaseBallGame() throws IOException { + computer = new Computer(); + user = new User(); + score = new Score(); + gameService = new GameServiceImpl(); + String newGame = "1"; + while (Objects.equals(newGame, "1")) { + newGame = BaseBallGameStart(); + } + + } + + public static String BaseBallGameStart() throws IOException { + String nextGame = "0"; + gameService.startGame(computer, user, score); + while (!Objects.equals(nextGame, "1") && !Objects.equals(nextGame, "2")){ + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하시오."); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + nextGame = (reader.readLine()); + + } + return nextGame; + } + +} diff --git a/src/main/java/domain/Computer.java b/src/main/java/domain/Computer.java new file mode 100644 index 00000000..96574866 --- /dev/null +++ b/src/main/java/domain/Computer.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.*; + +public class Computer { + private final ArrayList numbers; + + public Computer(ArrayList numbers) { + this.numbers = numbers; + } + + public Computer() { + this.numbers = new ArrayList<>(); + } + + public void reset(){ + this.numbers.clear(); + Random random = new Random(); + random.setSeed(System.currentTimeMillis()); + + while(this.numbers.size() < 3){ + this.computerNumAdd(random.nextInt(9) + 1); + } + + } + public ArrayList getNumbers() { + return numbers; + } + + public void computerNumAdd(int num){ + if (!this.numbers.contains(num)){ + this.numbers.add(num); + } + } +} diff --git a/src/main/java/domain/Score.java b/src/main/java/domain/Score.java new file mode 100644 index 00000000..134077f4 --- /dev/null +++ b/src/main/java/domain/Score.java @@ -0,0 +1,49 @@ +package domain; + +public class Score { + private Integer strike; + private Integer ball; + + public Score() { + reset(); + } + + public void setStrike(Integer strike) { + this.strike = strike; + } + + public void setBall(Integer ball) { + this.ball = ball; + } + + public Integer getStrike() { + return strike; + } + + public Integer getBall() { + return ball; + } + + public boolean isFinish(){ + return this.strike == 3; + } + + public String getScore(){ + StringBuilder sb = new StringBuilder(); + if (this.ball == 0 && this.strike == 0 ){ + return "낫싱"; + } + if (this.strike > 0){ + sb.append(this.strike).append(" 스트라이크 "); + } + if (this.ball > 0){ + sb.append(this.ball).append(" 볼"); + } + return sb.toString().trim(); + } + + public void reset() { + this.strike = 0; + this.ball = 0; + } +} diff --git a/src/main/java/domain/User.java b/src/main/java/domain/User.java new file mode 100644 index 00000000..1dd223fa --- /dev/null +++ b/src/main/java/domain/User.java @@ -0,0 +1,61 @@ +package domain; + +import java.util.ArrayList; + + +public class User { + + private final ArrayList numbers; + + public ArrayList getNumbers() { + return numbers; + } + + + public User() { + this.numbers = new ArrayList<>(); + } + + public void reset(){ + this.numbers.clear(); + } + + public void userNumAdd(int num){ + if(!this.numbers.contains(num)) + { + this.numbers.add(num); + } + } + + public void userNumConvert(String userInput){ + + for (int i = 0; i < userInput.length() ; i++) { + this.userNumAdd(userInput.charAt(i) - '0'); + } + + if (this.getNumbers().size() != 3) { + this.reset(); + throw new IllegalArgumentException("잘못된 입력입니다."); + } + + } + + public void setNumbers(String num){ + + if (num.length() != 3 || !isNumeric(num)){ + this.reset(); + throw new IllegalArgumentException("잘못된 입력입니다."); + } + + this.userNumConvert(num); + } + + public static boolean isNumeric(String s) { + try { + Integer.parseInt(s); + } catch (NumberFormatException e) { + return false; + } + return !s.contains("0"); + } +} diff --git a/src/main/java/service/GameService.java b/src/main/java/service/GameService.java new file mode 100644 index 00000000..aa584d3a --- /dev/null +++ b/src/main/java/service/GameService.java @@ -0,0 +1,20 @@ +package service; + +import domain.Computer; +import domain.Score; +import domain.User; + +import java.io.IOException; +import java.util.ArrayList; + +public interface GameService { + void startGame(Computer computer, User user, Score score) throws IOException; + + boolean playGame(Computer computer, User user, Score score) throws IOException; + + void userInput(User user) throws IOException; + + void compareNumbers(Computer computer, User user, Score score); + + void compareNumber(ArrayList computerNumbers, Integer userNum, int userIndex, Score score); +} diff --git a/src/main/java/service/GameServiceImpl.java b/src/main/java/service/GameServiceImpl.java new file mode 100644 index 00000000..7be50eea --- /dev/null +++ b/src/main/java/service/GameServiceImpl.java @@ -0,0 +1,74 @@ +package service; + +import domain.Computer; +import domain.Score; +import domain.User; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +public class GameServiceImpl implements GameService { + + + @Override + public void startGame(Computer computer, User user, Score score) throws IOException { + computer.reset(); + user.reset(); + score.reset(); + System.out.println(computer.getNumbers()); + while (playGame(computer, user, score)) { + user.reset(); + score.reset(); + } + } + + @Override + public boolean playGame(Computer computer, User user, Score score) throws IOException { + while (user.getNumbers().isEmpty()) { + userInput(user); + } + compareNumbers(computer, user, score); + System.out.println(score.getScore()); + + if (score.isFinish()){ + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + return false; + } + return true; + } + + @Override + public void userInput(User user) throws IOException { + try { + System.out.print("숫자를 입력해주세요 : "); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + String num = reader.readLine(); + user.setNumbers(num); + } + catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Override + public void compareNumbers(Computer computer, User user, Score score){ + for (int i = 0 ; i < 3 ; i++ ){ + compareNumber(computer.getNumbers(), user.getNumbers().get(i), i, score); + } + + } + + @Override + public void compareNumber(ArrayList computerNumbers, Integer userNum, int userIndex, Score score) { + if (computerNumbers.contains(userNum)) { + score.setBall(score.getBall() + 1); + } + if (Objects.equals(computerNumbers.get(userIndex), userNum)) { + score.setBall(score.getBall() - 1); + score.setStrike(score.getStrike() + 1); + } + } + +} diff --git a/src/test/java/Service/GameServiceTest.java b/src/test/java/Service/GameServiceTest.java new file mode 100644 index 00000000..8179461a --- /dev/null +++ b/src/test/java/Service/GameServiceTest.java @@ -0,0 +1,111 @@ +package Service; + +import domain.Computer; +import domain.Score; +import domain.User; +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 service.GameService; +import service.GameServiceImpl; + +import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GameServiceTest { + + @Test + @DisplayName("볼 확인") + public void isBall(){ + GameService gameService = new GameServiceImpl(); + Score score = new Score(); + gameService.compareNumber(new ArrayList<>(Arrays.asList(7, 1, 3)), 7, 1, score); + String actual = score.getScore(); + assertThat(actual).isEqualTo("1 볼"); + } + + @Test + @DisplayName("스트라이크 확인") + public void isStrike(){ + GameService gameService = new GameServiceImpl(); + Score score = new Score(); + gameService.compareNumber(new ArrayList<>(Arrays.asList(7, 1, 3)), 7, 0, score); + String actual = score.getScore(); + assertThat(actual).isEqualTo("1 스트라이크"); + } + + @ParameterizedTest + @DisplayName("점수 확인") + @CsvSource(value = {"124;1 볼", + "214;1 스트라이크", + "173;1 스트라이크 2 볼", + "245;낫싱", + "713;3 스트라이크",}, delimiter = ';') + public void checkScore(String input,String expected){ + GameService gameService = new GameServiceImpl(); + Computer computer = new Computer(new ArrayList<>(Arrays.asList(7, 1, 3))); + User user = new User(); + user.setNumbers(input); + Score score = new Score(); + gameService.compareNumbers(computer, user, score); + String actual = score.getScore(); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @DisplayName("숫자 입력 테스트") + @CsvSource(value = {"123;[1, 2, 3]", + "112;숫자를 입력해주세요 : 잘못된 입력입니다.", + "1234;숫자를 입력해주세요 : 잘못된 입력입니다.", + "a12;숫자를 입력해주세요 : 잘못된 입력입니다."}, delimiter = ';') + void testInput(String input,String expected) throws IOException { + OutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); + User user = new User(); + GameService gameService = new GameServiceImpl(); + String actual; + + systemIn(input); + gameService.userInput(user); + actual = user.getNumbers().toString(); + + if (user.getNumbers().isEmpty()){ + actual = out.toString().trim(); + } + assertThat(actual).isEqualTo(expected); + + } + + @ParameterizedTest + @DisplayName("플레이 테스트") + @CsvSource(value = {"123;숫자를 입력해주세요 : 1 스트라이크 1 볼", + "145;숫자를 입력해주세요 : 1 볼", + "671;숫자를 입력해주세요 : 2 볼", + "216;숫자를 입력해주세요 : 1 스트라이크", + "713;숫자를 입력해주세요 : 3 스트라이크\n3개의 숫자를 모두 맞히셨습니다! 게임 종료"}, delimiter = ';') + void testPlay(String input, String expected)throws IOException { + OutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); + Computer computer = new Computer(new ArrayList<>(Arrays.asList(7, 1, 3))); + User user = new User(); + Score score = new Score(); + GameService gameService = new GameServiceImpl(); + + systemIn(input); + + gameService.playGame(computer, user, score); + + String actual = out.toString().trim(); + assertThat(actual).contains(expected); + + } + + + protected void systemIn(String input) { + System.setIn(new ByteArrayInputStream(input.getBytes())); + } +} diff --git a/src/test/java/domain/ComputerTest.java b/src/test/java/domain/ComputerTest.java new file mode 100644 index 00000000..e7eee15a --- /dev/null +++ b/src/test/java/domain/ComputerTest.java @@ -0,0 +1,19 @@ +package domain; + + + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ComputerTest { + @Test + void create(){ + Computer computer = new Computer(new ArrayList<>(Arrays.asList(7, 1, 3))); + String actual = computer.getNumbers().toString(); + assertThat(actual).isEqualTo("[7, 1, 3]"); + } +} diff --git a/src/test/java/domain/ScoreTest.java b/src/test/java/domain/ScoreTest.java new file mode 100644 index 00000000..b208234f --- /dev/null +++ b/src/test/java/domain/ScoreTest.java @@ -0,0 +1,27 @@ +package domain; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScoreTest { + @Test + void setScore(){ + Score score = new Score(); + + String actual = score.getScore(); + assertThat(actual).isEqualTo("낫싱"); + + score.setBall(2); + actual = score.getScore(); + assertThat(actual).isEqualTo("2 볼"); + + score.setStrike(1); + actual = score.getScore(); + assertThat(actual).isEqualTo("1 스트라이크 2 볼"); + + score.setBall(0); + actual = score.getScore(); + assertThat(actual).isEqualTo("1 스트라이크"); + } + +} diff --git a/src/test/java/domain/UserTest.java b/src/test/java/domain/UserTest.java new file mode 100644 index 00000000..67c429b1 --- /dev/null +++ b/src/test/java/domain/UserTest.java @@ -0,0 +1,29 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class UserTest { + @ParameterizedTest + @DisplayName("숫자 입력 테스트") + @CsvSource(value = {"123;[1, 2, 3]", + "112;잘못된 입력입니다.", + "1234;잘못된 입력입니다.", + "a12;잘못된 입력입니다."}, delimiter = ';') + void testInput(String input,String expected){ + User user = new User(); + String actual; + try { + user.setNumbers(input); + actual = user.getNumbers().toString(); + }catch (IllegalArgumentException e){ + actual = e.getMessage(); + } + assertThat(actual).isEqualTo(expected); + } + +}