-
숫자야구게임 구현(2) - 요구사항 작성, TDD 적용공부/자바 플레이그라운드 with TDD, 클린코드 2022. 2. 16. 22:33
SI업무를 할 때 ProductionCode 를 먼저 작성하는것뿐만 아니라 TestCode는 매번 Controller 호출하기 싫어서 Service 메서드 호출하는 값만 확인하는 용도로 썼었다.
정말 우물안 개구리라는걸 절실히 느꼈다.
또한 Intellij를 사용하니 TDD방법론을 적용하면서 역으로 TestCode -> ProductionCode 만드는 것이 놀랍도록 쉬워서 이젠 Eclipse도 떠나보낼 때가 온 것같다..
github
요구사항 분석
#기능 요구 사항 기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다. Ball BallPosition position BallNumber num [ ✔ ] 1 ~ 9 숫자범위 BallNumber.validateNumber Balls [ ✔ ] 3자릿수 Balls.validateLength [ ✔ ] 3가지 숫자는 서로 다른 수 Balls.hasSameNumber [ ✔ ] List -> List Balls().createBalls 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱 같은 수, 같은 자리 : 스트라이크 같은 수, 다른 자리 : 볼 없으면 낫싱 Balls <-> Balls Balls <-> Ball Ball <-> Ball [ ✔ ] Ball끼리 비교 Ball.compare, 스트라이크, 볼, 낫싱 상태 반환 [ ✔ ] Balls <-> Ball 비교 Balls.compareBallsAndBall [ ✔ ] Balls끼리 비교 Balls.compareBetweenBalls 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게 임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다. 랜덤 3가지 BallUtil.generateBalls 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다. 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
- 핵심 기능만 만들고 넘어갔다.
TestCode
public class BallsTest { @Test void validateLengthTest() { assertThat(Balls.validateLength(Arrays.asList(1, 2, 3))).isTrue(); } @Test void hasSameNumberTest() { assertThat(Balls.hasSameNumber(Arrays.asList(1,2,3))).isFalse(); assertThat(Balls.hasSameNumber(Arrays.asList(1,2,2))).isTrue(); assertThat(Balls.hasSameNumber(Arrays.asList(1,2,1))).isTrue(); } @Test void compareBallsTest() { Balls computer = new Balls(Arrays.asList(1, 2, 3)); assertThat(computer.compareBallsAndBall(new Ball(0, 1))).isEqualTo(BallStatus.STRIKE); assertThat(computer.compareBallsAndBall(new Ball(2, 1))).isEqualTo(BallStatus.BALL); assertThat(computer.compareBallsAndBall(new Ball(0, 4))).isEqualTo(BallStatus.NOTHING); } @Test void compareBetweenBallsTest() { Balls computer = new Balls(Arrays.asList(1, 2, 3)); assertThat(computer.compareBetweenBalls(new Balls(Arrays.asList(4, 5, 6)))).isEqualTo("낫싱"); assertThat(computer.compareBetweenBalls(new Balls(Arrays.asList(1, 5, 6)))).isEqualTo("1 스트라이크"); assertThat(computer.compareBetweenBalls(new Balls(Arrays.asList(2, 5, 6)))).isEqualTo("1 볼"); assertThat(computer.compareBetweenBalls(new Balls(Arrays.asList(2, 1, 3)))).isEqualTo("1 스트라이크 2 볼"); assertThat(computer.compareBetweenBalls(new Balls(Arrays.asList(1, 2, 3)))).isEqualTo("3 스트라이크"); } }
생성한 클래스
Balls
public class Balls { private final List<Ball> balls; public Balls(List<Integer> balls) { if (!validateLength(balls)) throw new RuntimeException("숫자는 3자릿수만 가능합니다."); if (hasSameNumber(balls)) throw new RuntimeException("같은 숫자가 중복될 수 없습니다."); this.balls = createBalls(balls); } public static boolean validateLength(List<Integer> balls) { return balls.size() == 3; } public static boolean hasSameNumber(List<Integer> balls) { return new HashSet<>(balls).size() != balls.size(); } private List<Ball> createBalls(List<Integer> balls) { List<Ball> result = new ArrayList<>(); for (int position=0; position<balls.size(); position++) { result.add(new Ball(position, balls.get(position))); } return result; } public BallStatus compareBallsAndBall(Ball otherBall) { return balls.stream().map((ball) -> ball.compare(otherBall)) .filter((status) -> status.isStrike() || status.isBall()) .findFirst() .orElse(BallStatus.NOTHING); } public String compareBetweenBalls(Balls otherBalls) { BallScore ballScore = new BallScore(); for (Ball otherBall : otherBalls.balls) { ballScore.setScore(this.compareBallsAndBall(otherBall)); } return ballScore.toString(); } }
BallScore
public class BallScore { private final Map<BallStatus, Integer> ballStatusMap = BallStatus.createBallStatusMap(); public void setScore(BallStatus ballStatus) { ballStatusMap.put(ballStatus, ballStatusMap.get(ballStatus) + 1); } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (hasStrike()) { sb.append(ballStatusMap.get(BallStatus.STRIKE)); sb.append(" 스트라이크 "); } if (hasBall()) { sb.append(ballStatusMap.get(BallStatus.BALL)); sb.append(" 볼"); } if (sb.length() <= 0) sb.append("낫싱"); return sb.toString().trim(); } private boolean hasBall() { return ballStatusMap.get(BallStatus.BALL) > 0; } private boolean hasStrike() { return ballStatusMap.get(BallStatus.STRIKE) > 0; } }
BallStatus를 Key로 하고 Integer Value를 갖는 Map으로 Score 계산을 하였다.
'공부 > 자바 플레이그라운드 with TDD, 클린코드' 카테고리의 다른 글
자동차 경주 게임 피드백 영상 시청 후 (0) 2022.03.02 숫자야구게임 구현(1) (0) 2022.02.13 단위 테스트 실습 - 문자열 계산기 (0) 2022.02.13 객체 지향 생활 체조 원칙 (0) 2022.02.03