diff --git a/README.md b/README.md index 8fe711203..7b1ce4d13 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,30 @@ git checkout main // 기본 브랜치가 main인 경우 git checkout -b 브랜치이름 ex) git checkout -b apply-feedback ``` +--- +4. 기능 목록 - TDD 구현 +- 1~9의 숫자 중 랜덤으로 3개의 숫자를 구한다 +- 사용자로부터 입력 받는 3개 숫자 예외처리 + - 1~9의 숫자인가? + - 중복 값이 있는가? + - 3자리인가? +- 위치와 숫자 값이 같은 경우 -> 스트라이크 +- 위치는 다른데 숫자 값이 같은 경우 -> 볼 +- 숫자 값이 다른 경우 -> 낫싱 +- 사용자가 입력한 값에 대한 실행 결과를 구한다 + +```jsx +com / user +123 / 123 -> 3 strike +123 / 142 -> 1 strike, 1 ball + +# step 1 +1 2 / 1 2 -> strike +3 2 / 1 2 -> ball +1 3 / 1 2 -> nothing + +# step 2 +123 / 1 1 -> strike +123 / 1 2 -> ball +123 / 1 5 -> nothing +``` \ No newline at end of file diff --git a/src/main/java/baseball/Ball.java b/src/main/java/baseball/Ball.java new file mode 100644 index 000000000..bcf5eabdb --- /dev/null +++ b/src/main/java/baseball/Ball.java @@ -0,0 +1,35 @@ +package baseball; + +public class Ball { + // Step 1 + + private final int position; + private final int ballNum; + + public Ball(int position, int ballNum) { + this.position = position; + this.ballNum = ballNum; + } + + + public BallStatus playBall(Ball ball) { + if(this.equals(ball)) return BallStatus.STRIKE; + if(matchBallNum(ball.ballNum)) return BallStatus.BALL; + return BallStatus.NOTHING; + } + + private boolean matchBallNum(int ballNum) { + return this.ballNum == ballNum; + } + + @Override + public boolean equals(Object o) { + if(this == o)return true; + if(o == null || this.getClass() != o.getClass()) return false; // 실행 중인 클래스 객체의 정보를 확인 + Ball ball = (Ball) o; + return position == ball.position && + ballNum == ball.ballNum; + } + + +} diff --git a/src/main/java/baseball/BallStatus.java b/src/main/java/baseball/BallStatus.java new file mode 100644 index 000000000..4e99126a6 --- /dev/null +++ b/src/main/java/baseball/BallStatus.java @@ -0,0 +1,15 @@ +package baseball; + +public enum BallStatus { + NOTHING, STRIKE, BALL; + + public boolean isNotNothing() { + return this != NOTHING; + } + public boolean isStrike() { + return this == STRIKE; + } + public boolean isBall() { + return this == BALL; + } +} diff --git a/src/main/java/baseball/Balls.java b/src/main/java/baseball/Balls.java new file mode 100644 index 000000000..b3cb0c5b1 --- /dev/null +++ b/src/main/java/baseball/Balls.java @@ -0,0 +1,39 @@ +package baseball; + +import java.util.ArrayList; +import java.util.List; + +public class Balls { + private final List balls; // computer balls + + public Balls(List computer) { + this.balls = getBalls(computer); + } + + + private static List getBalls(List computer) { + List balls = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + balls.add(new Ball(i+1, computer.get(i))); + } + return balls; + } + public Score play(List userInput) { + Balls userBalls = new Balls(userInput); + Score result = new Score(); + // 비교 분석 + for(Ball answer : balls){ // computerBall + BallStatus status = userBalls.playBalls(answer); // 앞 뒤에 들어갈 객체가 바뀌어도 strike,ball 판별에는 문제가 되지 않음 + result.report(status); + } + return result; + } + + public BallStatus playBalls(Ball userBall) { + return balls.stream() + .map(answer -> answer.playBall(userBall)) + .filter(BallStatus::isNotNothing) + .findFirst() + .orElse(BallStatus.NOTHING); + } +} diff --git a/src/main/java/baseball/BallsNumber.java b/src/main/java/baseball/BallsNumber.java new file mode 100644 index 000000000..5a5e4b4ee --- /dev/null +++ b/src/main/java/baseball/BallsNumber.java @@ -0,0 +1,48 @@ +package baseball; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BallsNumber { + + public List splitNumber(int userNumber) { + List userNumList = new ArrayList<>(); + + while(userNumber > 0) { + userNumList.add(0, userNumber % 10); + userNumber /= 10; + } + + return userNumList; + } + public static boolean validateNumber(List ballNumbers) { + return areAllNumbersValid(ballNumbers) && areAllNumbersUnique(ballNumbers); + } + + // 1~9사이 숫자인지 확인 + + private static boolean areAllNumbersValid(List ballNumbers) { + return ballNumbers.stream().allMatch(BallsNumber::isValidNumber); + } + private static boolean isValidNumber(int x) { + if (!(0 < x && x < 10)) { + System.out.println("1~9 사이 숫자로 이루어진 수를 입력해주세요."); + return false; + } + return true; + } + // 숫자 중복 확인 + private static boolean areAllNumbersUnique(List ballNumbers) { + return ballNumbers.stream().allMatch(x -> isUniqueNumber(ballNumbers, x)); + } + private static boolean isUniqueNumber(List ballNumbers, int x) { + if (!(Collections.frequency(ballNumbers, x) == 1)) { + System.out.println("중복 숫자가 없는 수를 입력해주세요."); + return false; + } + return true; + + } +} + diff --git a/src/main/java/baseball/BaseBall.java b/src/main/java/baseball/BaseBall.java new file mode 100644 index 000000000..457262aed --- /dev/null +++ b/src/main/java/baseball/BaseBall.java @@ -0,0 +1,46 @@ +package baseball; + +import ui.InputView; +import ui.ResultView; +import utils.MakeRandomNum; + +import java.util.List; +import java.util.Scanner; + +import static baseball.BallsNumber.validateNumber; + +public class BaseBall { + public void game(){ + // computer num + MakeRandomNum randomNum = new MakeRandomNum(); + Balls answer = new Balls(randomNum.makeRandomNum()); + + // user num + Scanner sc = new Scanner(System.in); + int strike = 0; + + while(strike != 3) { + System.out.print("숫자를 입력해 주세요 : "); + int userInput = sc.nextInt(); + + // 유효성 검사 + BallsNumber ball = new BallsNumber(); + + List ballList = ball.splitNumber(userInput); + if(!validateNumber(ballList)) continue; + + strike = ResultView.result(answer.play(ballList)); + } + + } + public BaseBall() { + while(true){ + game(); + if(InputView.inputNumber()!=1) return; + } + } + + public static void main(String[] args) { + new BaseBall(); + } +} diff --git a/src/main/java/baseball/Score.java b/src/main/java/baseball/Score.java new file mode 100644 index 000000000..aac8c2ebe --- /dev/null +++ b/src/main/java/baseball/Score.java @@ -0,0 +1,26 @@ +package baseball; + +public class Score { + private int strike = 0; + private int ball = 0; + + + public int getStrike() { + return this.strike; + } + public int getBall() { + return this.ball; + } + + public void report(BallStatus status) { + if(status.isBall()) this.ball += 1; + if(status.isStrike()) this.strike += 1; + + } + public boolean isGameEnd() { + return strike == 3; + } + public boolean isNothing() { + return this.strike == 0 && this.ball == 0; + } +} diff --git a/src/main/java/ui/InputView.java b/src/main/java/ui/InputView.java new file mode 100644 index 000000000..599eab35e --- /dev/null +++ b/src/main/java/ui/InputView.java @@ -0,0 +1,12 @@ +package ui; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class InputView { + public static int inputNumber() { + Scanner sc = new Scanner(System.in); + return sc.nextInt(); + } +} diff --git a/src/main/java/ui/ResultView.java b/src/main/java/ui/ResultView.java new file mode 100644 index 000000000..54e1b3d96 --- /dev/null +++ b/src/main/java/ui/ResultView.java @@ -0,0 +1,29 @@ +package ui; + +import baseball.Score; + +public class ResultView { + public static int result(Score score) { + StringBuilder sb = new StringBuilder(); + int result = 0; + + if(score.isNothing()) { + sb.append("낫싱"); + } + if(score.getBall() > 0) { + sb.append(score.getBall()).append("볼 "); + } + if(score.getStrike() > 0){ + sb.append(score.getStrike()).append("스트라이크"); + result = score.getStrike(); + } + if(score.isGameEnd()) { + sb.append("\n") + .append("3개의 숫자를 모두 맞히셨습니다! 게임 종료").append("\n") + .append("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + } + System.out.println(sb); + + return result; + } +} diff --git a/src/main/java/utils/MakeRandomNum.java b/src/main/java/utils/MakeRandomNum.java new file mode 100644 index 000000000..c9721c0af --- /dev/null +++ b/src/main/java/utils/MakeRandomNum.java @@ -0,0 +1,31 @@ +package utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class MakeRandomNum { + private List numList; + private static boolean[] check; // true이면 값이 들어가있다 + public MakeRandomNum() { + check = new boolean[10]; // 1~9 사이의 수 파악 + } + public List makeRandomNum(){ + numList = new ArrayList<>(); + Random random = new Random(); + int idx = 0; + while(idx != 3) { + int num = random.nextInt(9)+1; // 1 ~ 4 까지의 무작위 int 값 리턴 + idx = checkDuplicate(idx, num); + } + return numList; + } + public int checkDuplicate(int idx, int num) { + if(!check[num]) { + idx++; + check[num] = true; + numList.add(num); + } + return idx; + } +} diff --git a/src/test/java/baseball/BallTest.java b/src/test/java/baseball/BallTest.java new file mode 100644 index 000000000..fc4d5fef2 --- /dev/null +++ b/src/test/java/baseball/BallTest.java @@ -0,0 +1,29 @@ +package baseball; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BallTest { + // Step 1. + @Test + @DisplayName("userball과 computerball 각각 1개씩 비교 - strike") + void strike() { + Ball computerBall = new Ball(1, 5); + + assertThat(computerBall.playBall(new Ball(1, 5))).isEqualTo(BallStatus.STRIKE); + } + @Test + @DisplayName("userball과 computerball 각각 1개씩 비교 - ball") + void ball() { + Ball computerBall = new Ball(1, 5); + assertThat(computerBall.playBall(new Ball(2, 5))).isEqualTo(BallStatus.BALL); + } + @Test + @DisplayName("userball과 computerball 각각 1개씩 비교 - nothing") + void nothing() { + Ball computerBall = new Ball(1, 5); + assertThat(computerBall.playBall(new Ball(2, 6))).isEqualTo(BallStatus.NOTHING); + } +} diff --git a/src/test/java/baseball/BallsTest.java b/src/test/java/baseball/BallsTest.java new file mode 100644 index 000000000..0f51b5d69 --- /dev/null +++ b/src/test/java/baseball/BallsTest.java @@ -0,0 +1,82 @@ +package baseball; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static baseball.BallsNumber.validateNumber; +import static org.assertj.core.api.Assertions.assertThat; + +public class BallsTest { + + @Test + @DisplayName("user Ball의 유효성 검사- success") + void validate_success() { + assertThat(validateNumber(Arrays.asList(1,2,3))).isTrue(); + } + @Test + @DisplayName("user Ball의 유효성 검사 - 중복 검사") + void validate_fail1() { + assertThat(validateNumber(Arrays.asList(1,2,2))).isFalse(); + + }@Test + @DisplayName("user Ball의 유효성 검사 - 1~9사이 숫자") + void validate_fail2() { + assertThat(validateNumber(Arrays.asList(1,2,0))).isFalse(); + + } + + // step 3. + @Test + @DisplayName("userball 3개와 computerball 3개를 가지고 비교 - strike") + void play_3strike() { + Balls computer = new Balls(Arrays.asList(1,2,3)); + Score result = computer.play(Arrays.asList(1,2,3)); + assertThat(result.getStrike()).isEqualTo(3); + assertThat(result.getBall()).isEqualTo(0); + assertThat(result.isGameEnd()).isTrue(); + } + @Test + @DisplayName("userball 3개와 computerball 3개를 가지고 비교 - ball") + void play_1strike_2ball() { + Balls computer = new Balls(Arrays.asList(1,2,3)); + Score result = computer.play(Arrays.asList(1,3,2)); + assertThat(result.getStrike()).isEqualTo(1); + assertThat(result.getBall()).isEqualTo(2); + } + + @Test + @DisplayName("userball 3개와 computerball 3개를 가지고 비교 - ball") + void play_nothing() { + Balls computer = new Balls(Arrays.asList(1,2,3)); + Score result = computer.play(Arrays.asList(4,5,6)); + assertThat(result.getStrike()).isNotEqualTo(1); + assertThat(result.getBall()).isNotEqualTo(2); + assertThat(result.isNothing()).isTrue(); + } + // Step 2. + @Test + @DisplayName("userball 1개와 computerball 리스트를 가지고 비교 - strike") + void strike() { + Balls computerBall = new Balls(Arrays.asList(1, 2, 3)); + assertThat(computerBall.playBalls(new Ball(1, 1))).isEqualTo(BallStatus.STRIKE); + + } + @Test + @DisplayName("userball 1개와 computerball 리스트를 가지고 비교 - ball") + void ball() { + Balls computerBall = new Balls(Arrays.asList(1, 2, 3)); + assertThat(computerBall.playBalls(new Ball(1, 3))).isEqualTo(BallStatus.BALL); + + } + @Test + @DisplayName("userball 1개와 computerball 리스트를 가지고 비교 - nothing") + void nothing() { + Balls computerBall = new Balls(Arrays.asList(1, 2, 3)); + assertThat(computerBall.playBalls(new Ball(1, 4))).isEqualTo(BallStatus.NOTHING); + + } +}