From 34e958697c69f0e0903ef1fb3663e936d2dee7ab Mon Sep 17 00:00:00 2001 From: GS_song <20003204@sju.ac.kr> Date: Sat, 4 May 2024 17:05:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=B2=AB=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 26 +++++++++++ src/main/java/baseball/Application.java | 6 ++- .../controller/BullsAndCowsController.java | 39 ++++++++++++++++ .../baseball/domain/ComparisonResult.java | 23 ++++++++++ src/main/java/baseball/domain/Computer.java | 40 +++++++++++++++++ .../baseball/domain/InputNumberGenerator.java | 14 ++++++ .../domain/RandomNumberGenerator.java | 22 +++++++++ src/main/java/baseball/view/InputView.java | 20 +++++++++ src/main/java/baseball/view/OutputView.java | 22 +++++++++ .../baseball/domain/ComparisonResultTest.java | 37 +++++++++++++++ .../java/baseball/domain/ComputerTest.java | 45 +++++++++++++++++++ .../domain/InputNumberGeneratorTest.java | 27 +++++++++++ .../domain/RandomNumberGeneratorTest.java | 20 +++++++++ 13 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 src/main/java/baseball/controller/BullsAndCowsController.java create mode 100644 src/main/java/baseball/domain/ComparisonResult.java create mode 100644 src/main/java/baseball/domain/Computer.java create mode 100644 src/main/java/baseball/domain/InputNumberGenerator.java create mode 100644 src/main/java/baseball/domain/RandomNumberGenerator.java create mode 100644 src/main/java/baseball/view/InputView.java create mode 100644 src/main/java/baseball/view/OutputView.java create mode 100644 src/test/java/baseball/domain/ComparisonResultTest.java create mode 100644 src/test/java/baseball/domain/ComputerTest.java create mode 100644 src/test/java/baseball/domain/InputNumberGeneratorTest.java create mode 100644 src/test/java/baseball/domain/RandomNumberGeneratorTest.java diff --git a/docs/README.md b/docs/README.md index e69de29bb2..780dba8013 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,26 @@ +# 숫자야구 객체지향 사고 연습 (Bulls and Cows) + +메시지 : 숫자 3개와 정답을 비교해 결과를 반환해라 +게임 매니저? 심판? 컴퓨터? +-> 컴퓨터가 정답을 가지고 있으니 컴퓨터가 판단하는게 맞을듯 + +그럼 컴퓨터가 정답을 비교해 결과를 반환하기 위해서 해야하는 일은? +일단 정답을 생성해서 가지고 있어야 한다. + +그럼 컴퓨터의 정답을 생성하는 객체가 필요할까? 컴퓨터는 랜덤한 값을 생성할 책임을 가지나? +Nope, 랜덤한 3개의 값을 생성하는 객체를 만들자. + +정답을 만들어서 컴퓨터를 생성했다고 가정해보자. +입력으로 들어오는 숫자와 정답을 어떻게 비교하지? +입력으로 들어오는 정보를 정답과 같은 데이터 타입으로 변환해주는 객체를 만들자 + +비교한 결과는 어떻게 생성하지? +결과를 담을 객체가 필요하다. -> 결과에 따라 다시 입력을 받을지 끝낼지 결정하자 + + +### 필요 객체 + +- 컴퓨터 - Computer +- 정답 생성기 - RandomNumberGenerator +- 입력 변환기 - InputNumberGenerator +- 비교 결과 - ComparisonResult \ No newline at end of file diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java index dd95a34214..750dcd96cd 100644 --- a/src/main/java/baseball/Application.java +++ b/src/main/java/baseball/Application.java @@ -1,7 +1,11 @@ package baseball; +import baseball.controller.BullsAndCowsController; +import baseball.view.InputView; +import baseball.view.OutputView; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + new BullsAndCowsController(new InputView(), new OutputView()).run(); } } diff --git a/src/main/java/baseball/controller/BullsAndCowsController.java b/src/main/java/baseball/controller/BullsAndCowsController.java new file mode 100644 index 0000000000..5b8137292e --- /dev/null +++ b/src/main/java/baseball/controller/BullsAndCowsController.java @@ -0,0 +1,39 @@ +package baseball.controller; + +import static baseball.domain.InputNumberGenerator.generate; + +import baseball.domain.ComparisonResult; +import baseball.domain.Computer; +import baseball.domain.RandomNumberGenerator; +import baseball.view.InputView; +import baseball.view.OutputView; +import java.util.List; + +public class BullsAndCowsController { + + private final InputView inputView; + private final OutputView outputView; + + + public BullsAndCowsController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + outputView.printStartMessage(); + Computer computer = createComputer(); + ComparisonResult result = null; + do { + outputView.printNumberRequestMessage(); + List input = generate(inputView.scanThreeDigit()); + result = computer.compare(input); + outputView.printResult(result); + } while (!result.isThreeStrike()); + outputView.printEndGameMessage(); + } + + private Computer createComputer() { + return new Computer(RandomNumberGenerator.generate()); + } +} diff --git a/src/main/java/baseball/domain/ComparisonResult.java b/src/main/java/baseball/domain/ComparisonResult.java new file mode 100644 index 0000000000..bd4d6c7099 --- /dev/null +++ b/src/main/java/baseball/domain/ComparisonResult.java @@ -0,0 +1,23 @@ +package baseball.domain; + +public record ComparisonResult(int strike, int ball) { + + public Boolean isThreeStrike() { + return strike == 3; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + if (ball != 0) { + stringBuilder.append(ball + "볼 "); + } + if (strike != 0) { + stringBuilder.append(strike + "스트라이크"); + } + if (ball == 0 && strike == 0) { + stringBuilder.append("낫싱"); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/baseball/domain/Computer.java b/src/main/java/baseball/domain/Computer.java new file mode 100644 index 0000000000..12953f7090 --- /dev/null +++ b/src/main/java/baseball/domain/Computer.java @@ -0,0 +1,40 @@ +package baseball.domain; + +import java.util.List; + +public class Computer { + + private final List answer; + + public Computer(List answer) { + this.answer = answer; + } + + public ComparisonResult compare(List input) { + + return new ComparisonResult(findStrike(input), findBall(input)); + } + + private int findStrike(List input) { + int strike = 0; + for (int i = 0; i < 3; i++) { + if (answer.get(i) == input.get(i)) { + strike++; + } + } + return strike; + } + + private int findBall(List input) { + int ball = 0; + for (int i = 0; i < 3; i++) { + if (answer.get(i) == input.get(i)) { + continue; + } + if (answer.contains(input.get(i))) { + ball++; + } + } + return ball; + } +} diff --git a/src/main/java/baseball/domain/InputNumberGenerator.java b/src/main/java/baseball/domain/InputNumberGenerator.java new file mode 100644 index 0000000000..acb981004a --- /dev/null +++ b/src/main/java/baseball/domain/InputNumberGenerator.java @@ -0,0 +1,14 @@ +package baseball.domain; + +import java.util.List; +import java.util.stream.Collectors; + +public class InputNumberGenerator { + + public static List generate(String input) { + + return input.chars() + .mapToObj(Character::getNumericValue) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/baseball/domain/RandomNumberGenerator.java b/src/main/java/baseball/domain/RandomNumberGenerator.java new file mode 100644 index 0000000000..de7b27fa1b --- /dev/null +++ b/src/main/java/baseball/domain/RandomNumberGenerator.java @@ -0,0 +1,22 @@ +package baseball.domain; + +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.List; + +public class RandomNumberGenerator { + + private static final int startRange = 1; + private static final int endRange = 9; + + public static List generate(){ + List threeDigitNumber = new ArrayList<>(); + while (threeDigitNumber.size() < 3) { + int randomNumber = Randoms.pickNumberInRange(startRange, endRange); + if (!threeDigitNumber.contains(randomNumber)) { + threeDigitNumber.add(randomNumber); + } + } + return threeDigitNumber; + } +} diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java new file mode 100644 index 0000000000..c1af25e1ce --- /dev/null +++ b/src/main/java/baseball/view/InputView.java @@ -0,0 +1,20 @@ +package baseball.view; + +import java.util.Scanner; + +public class InputView { + + Scanner scanner = new Scanner(System.in); + + public String scanThreeDigit() { + String input = scanner.next(); + if (isNotThreeDigitNumber(input)) { + throw new NumberFormatException("3자리 숫자만 입력되어야 합니다."); + } + return input; + } + + public boolean isNotThreeDigitNumber(String input) { + return input.matches("\\D|\\d{1,2}|\\d{4,}"); + } +} diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java new file mode 100644 index 0000000000..898bbcc680 --- /dev/null +++ b/src/main/java/baseball/view/OutputView.java @@ -0,0 +1,22 @@ +package baseball.view; + +import baseball.domain.ComparisonResult; + +public class OutputView { + + public void printStartMessage() { + System.out.println("숫자 야구 게임을 시작합니다."); + } + + public void printNumberRequestMessage() { + System.out.print("숫자를 입력해주세요 : "); + } + + public void printResult(ComparisonResult result) { + System.out.println(result); + } + + public void printEndGameMessage() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + } +} diff --git a/src/test/java/baseball/domain/ComparisonResultTest.java b/src/test/java/baseball/domain/ComparisonResultTest.java new file mode 100644 index 0000000000..53832af72e --- /dev/null +++ b/src/test/java/baseball/domain/ComparisonResultTest.java @@ -0,0 +1,37 @@ +package baseball.domain; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ComparisonResultTest { + @Test + @DisplayName("입력과 정답을 받아 스트라이크 볼의 개수를 가진다.") + void generate() { + int strike = 1; + int ball = 1; + + Assertions.assertDoesNotThrow(() -> + new ComparisonResult(strike, ball)); + + } + + @Test + @DisplayName("3스트라이크일 때 true를 반환한다.") + void ThreeStrikeTrue() { + int strike = 3; + int ball = 0; + ComparisonResult result = new ComparisonResult(strike, ball); + Assertions.assertEquals(result.isThreeStrike(), true); + } + + @Test + @DisplayName("3스트라이크가 아니면 false를 반환한다.") + void ThreeStrikeFalse() { + int strike = 2; + int ball = 1; + ComparisonResult result = new ComparisonResult(strike, ball); + Assertions.assertEquals(result.isThreeStrike(), false); + } + +} \ No newline at end of file diff --git a/src/test/java/baseball/domain/ComputerTest.java b/src/test/java/baseball/domain/ComputerTest.java new file mode 100644 index 0000000000..036ca72ca2 --- /dev/null +++ b/src/test/java/baseball/domain/ComputerTest.java @@ -0,0 +1,45 @@ +package baseball.domain; + +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ComputerTest { + + private Computer computer; + + @BeforeEach + void before() { + computer = new Computer(List.of(1, 2, 3)); + } + + @Test + @DisplayName("입력 리스트를 받아 2볼 1스트라이크를 반환한다.") + void compare2Ball1Strike() throws Exception { + List input = List.of(1, 3, 2); + + ComparisonResult result = computer.compare(input); + Assertions.assertEquals(result.toString(), "2볼 1스트라이크"); + } + + @Test + @DisplayName("입력을 받아 낫싱을 출력한다.") + void compareNothing() throws Exception { + List input = List.of(4, 5, 6); + + ComparisonResult result = computer.compare(input); + Assertions.assertEquals(result.toString(), "낫싱"); + } + + + @Test + @DisplayName("입력을 받아 3스트라이크를 출력한다.") + void compare3Strike() throws Exception { + List input = List.of(1, 2, 3); + + ComparisonResult result = computer.compare(input); + Assertions.assertEquals(result.toString(), "3스트라이크"); + } +} \ No newline at end of file diff --git a/src/test/java/baseball/domain/InputNumberGeneratorTest.java b/src/test/java/baseball/domain/InputNumberGeneratorTest.java new file mode 100644 index 0000000000..c1464da6e9 --- /dev/null +++ b/src/test/java/baseball/domain/InputNumberGeneratorTest.java @@ -0,0 +1,27 @@ +package baseball.domain; + +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class InputNumberGeneratorTest { + + @ParameterizedTest + @DisplayName("입력으로 들어온 문자열을 리스트 형태로 반환한다.") + @ValueSource(strings = {"123", "456", "789"}) + void inputThreeDigit(String input) throws Exception { + List threeDigitNumber = InputNumberGenerator.generate(input); + + Assertions.assertAll( + () -> Assertions.assertEquals( + Character.getNumericValue(input.charAt(0)), threeDigitNumber.get(0)), + () -> Assertions.assertEquals( + Character.getNumericValue(input.charAt(1)), threeDigitNumber.get(1)), + () -> Assertions.assertEquals( + Character.getNumericValue(input.charAt(2)), threeDigitNumber.get(2)) + ); + } + +} \ No newline at end of file diff --git a/src/test/java/baseball/domain/RandomNumberGeneratorTest.java b/src/test/java/baseball/domain/RandomNumberGeneratorTest.java new file mode 100644 index 0000000000..db1f6055a9 --- /dev/null +++ b/src/test/java/baseball/domain/RandomNumberGeneratorTest.java @@ -0,0 +1,20 @@ +package baseball.domain; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RandomNumberGeneratorTest { + + @Test + @DisplayName("3자리 랜덤한 숫자를 리스트로 반환") + void randomThreeDigit() throws Exception { + List randomThreeDigit = RandomNumberGenerator.generate(); + + Assertions.assertEquals(randomThreeDigit.size(), 3); + } + +} \ No newline at end of file From 523b352a572c41bce8ab6d6fb21526c9519ee74d Mon Sep 17 00:00:00 2001 From: GS_song <20003204@sju.ac.kr> Date: Sun, 5 May 2024 20:37:37 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=9E=AC?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=EB=8F=99=EC=9E=91=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BullsAndCowsController.java | 8 ++++++++ src/main/java/baseball/view/InputView.java | 14 +++++++++++++- src/main/java/baseball/view/OutputView.java | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/baseball/controller/BullsAndCowsController.java b/src/main/java/baseball/controller/BullsAndCowsController.java index 5b8137292e..ba4cb0bea8 100644 --- a/src/main/java/baseball/controller/BullsAndCowsController.java +++ b/src/main/java/baseball/controller/BullsAndCowsController.java @@ -22,6 +22,14 @@ public BullsAndCowsController(InputView inputView, OutputView outputView) { public void run() { outputView.printStartMessage(); + int restart; + do { + playGame(); + restart = inputView.scanRestartOrEnd(); + } while (restart == 1); + } + + private void playGame() { Computer computer = createComputer(); ComparisonResult result = null; do { diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java index c1af25e1ce..68c7617bf5 100644 --- a/src/main/java/baseball/view/InputView.java +++ b/src/main/java/baseball/view/InputView.java @@ -14,7 +14,19 @@ public String scanThreeDigit() { return input; } - public boolean isNotThreeDigitNumber(String input) { + public int scanRestartOrEnd() { + String input = scanner.next(); + if (isNotOneOrTwo(input)) { + throw new NumberFormatException("1이나 2만 입력되어야 합니다."); + } + return Integer.parseInt(input); + } + + private boolean isNotThreeDigitNumber(String input) { return input.matches("\\D|\\d{1,2}|\\d{4,}"); } + + private boolean isNotOneOrTwo(String input) { + return input.matches("[^12]"); + } } diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java index 898bbcc680..ed3c64f5a1 100644 --- a/src/main/java/baseball/view/OutputView.java +++ b/src/main/java/baseball/view/OutputView.java @@ -18,5 +18,6 @@ public void printResult(ComparisonResult result) { public void printEndGameMessage() { System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); } } From 05ccac4ffc3cfefecae3f1c4d9310faa8c2a98b0 Mon Sep 17 00:00:00 2001 From: GS_song <20003204@sju.ac.kr> Date: Mon, 6 May 2024 18:51:36 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor=20:=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=95=BD=EA=B0=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BullsAndCowsController.java | 17 +++++++------ src/main/java/baseball/domain/Computer.java | 25 ++++++------------- src/main/java/baseball/view/InputView.java | 25 +++++++++++-------- src/main/java/baseball/view/OutputView.java | 3 +++ 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/main/java/baseball/controller/BullsAndCowsController.java b/src/main/java/baseball/controller/BullsAndCowsController.java index ba4cb0bea8..f9adb855c9 100644 --- a/src/main/java/baseball/controller/BullsAndCowsController.java +++ b/src/main/java/baseball/controller/BullsAndCowsController.java @@ -1,9 +1,8 @@ package baseball.controller; -import static baseball.domain.InputNumberGenerator.generate; - import baseball.domain.ComparisonResult; import baseball.domain.Computer; +import baseball.domain.InputNumberGenerator; import baseball.domain.RandomNumberGenerator; import baseball.view.InputView; import baseball.view.OutputView; @@ -25,23 +24,27 @@ public void run() { int restart; do { playGame(); + outputView.printRestartMessage(); restart = inputView.scanRestartOrEnd(); } while (restart == 1); } private void playGame() { - Computer computer = createComputer(); - ComparisonResult result = null; + Computer computer = initComputer(); + ComparisonResult result; do { outputView.printNumberRequestMessage(); - List input = generate(inputView.scanThreeDigit()); - result = computer.compare(input); + result = computer.compare(scanInputNumber()); outputView.printResult(result); } while (!result.isThreeStrike()); outputView.printEndGameMessage(); } - private Computer createComputer() { + private Computer initComputer() { return new Computer(RandomNumberGenerator.generate()); } + + private List scanInputNumber() { + return InputNumberGenerator.generate(inputView.scanThreeDigit()); + } } diff --git a/src/main/java/baseball/domain/Computer.java b/src/main/java/baseball/domain/Computer.java index 12953f7090..d7f2d64739 100644 --- a/src/main/java/baseball/domain/Computer.java +++ b/src/main/java/baseball/domain/Computer.java @@ -1,6 +1,7 @@ package baseball.domain; import java.util.List; +import java.util.stream.IntStream; public class Computer { @@ -11,30 +12,18 @@ public Computer(List answer) { } public ComparisonResult compare(List input) { - return new ComparisonResult(findStrike(input), findBall(input)); } private int findStrike(List input) { - int strike = 0; - for (int i = 0; i < 3; i++) { - if (answer.get(i) == input.get(i)) { - strike++; - } - } - return strike; + return (int) IntStream.range(0, 3) + .filter(i -> answer.get(i).equals(input.get(i))) + .count(); } private int findBall(List input) { - int ball = 0; - for (int i = 0; i < 3; i++) { - if (answer.get(i) == input.get(i)) { - continue; - } - if (answer.contains(input.get(i))) { - ball++; - } - } - return ball; + return (int) IntStream.range(0, 3) + .filter(i -> !answer.get(i).equals(input.get(i)) && answer.contains(input.get(i))) + .count(); } } diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java index 68c7617bf5..3b50ef1b2c 100644 --- a/src/main/java/baseball/view/InputView.java +++ b/src/main/java/baseball/view/InputView.java @@ -1,32 +1,35 @@ package baseball.view; import java.util.Scanner; +import java.util.regex.Pattern; public class InputView { - Scanner scanner = new Scanner(System.in); + private Scanner scanner = new Scanner(System.in); + private final String threeDigitPattern = "^\\d{3}$"; + private final String oneOrTwoPattern = "^(1|2)$"; public String scanThreeDigit() { String input = scanner.next(); - if (isNotThreeDigitNumber(input)) { - throw new NumberFormatException("3자리 숫자만 입력되어야 합니다."); - } + isNotThreeDigitNumber(input); return input; } public int scanRestartOrEnd() { String input = scanner.next(); - if (isNotOneOrTwo(input)) { - throw new NumberFormatException("1이나 2만 입력되어야 합니다."); - } + isNotOneOrTwo(input); return Integer.parseInt(input); } - private boolean isNotThreeDigitNumber(String input) { - return input.matches("\\D|\\d{1,2}|\\d{4,}"); + private void isNotThreeDigitNumber(String input) { + if (!Pattern.matches(threeDigitPattern, input)) { + throw new NumberFormatException("3자리 숫자만 입력되어야 합니다."); + } } - private boolean isNotOneOrTwo(String input) { - return input.matches("[^12]"); + private void isNotOneOrTwo(String input) { + if (!Pattern.matches(oneOrTwoPattern, input)) { + throw new NumberFormatException("1이나 2만 입력되어야 합니다."); + } } } diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java index ed3c64f5a1..149eaee9d9 100644 --- a/src/main/java/baseball/view/OutputView.java +++ b/src/main/java/baseball/view/OutputView.java @@ -18,6 +18,9 @@ public void printResult(ComparisonResult result) { public void printEndGameMessage() { System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + } + + public void printRestartMessage() { System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); } }