본문 바로가기
공부/TDD

볼링게임 TDD [3]

by Moonsc 2020. 10. 3.
728x90

볼링게임 TDD[3] 을 끝으로 볼링게임 TDD를 마무리하려고 한다. 

우선 남은 할 일 목록을 정리해보자.

[] 볼링 점수 계산기를 만든다. (스트라이크, 스페어를 고려한다.)
[] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.
[] 볼링을 상속받는 객체로는 볼링 플레이어와 볼링 점수 계산기가 존재한다.
    (플레이어와 점수 계산기는 1 : 1 관계를 갖는다.)
[] 점수 계산기를 통해 계산된 점수는 점수 표출기를 통해 점수를 볼 수 있어야 한다.

 

잘 못된 할 일 목록과 불 필요한 목록은 정리하고 볼링게임을 완성하기 위한 할 일 만 남겨두도록 하겠다.

[] 스트라이크, 스페어등 볼링 룰을 적용한다. 
[] 점수 계산기를 통해 최종 점수를 계산해야 한다.
[] 최종 점수는 점수 표출기를 통해 보여야 한다.
[] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.

 

[v] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.

[v] 스트라이크, 스페어등 볼링 룰을 적용한다. 

[v] 점수 계산기를 통해 최종 점수를 계산해야 한다.

    @Test
    void 넘어진_핀_테스트(){
        BowlingPlayer player1 = new BowlingPlayer("player1");
        while(player1.getPitchCount() > 0){
            player1.pitch();
        }
        System.out.println(player1.getDownPins());
    }


    @Test
    void 점수계산기_테스트(){
        BowlingPlayer player1 = new BowlingPlayer("player1");
        while(player1.getPitchCount() > 0){
            player1.pitch();
        }
        System.out.println(player1.toString());
    }

 

public class BowlingPlayer extends Bowling{

    private String name;
    private List<Integer> scores;

    public BowlingPlayer(String name) {
        this.name = name;
        scores = new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public List<Integer> getScores() {
        scoreCalculator(getDownPins());
        return scores;
    }

    public void pitch() {
        setPitchCount();
    }

    public void scoreCalculator(List<Integer> downPins){
        int countByFrame = 0;
        int scoreByFrame = 0;
        int leftScore = 0;
        int rightScore = 0;
        for(int i = 0, n = downPins.size(); i < n; i++){
            countByFrame++;

            if(downPins.get(i) != -1){ // 이전 투구가 스트라이크인지 확인
                scoreByFrame += downPins.get(i);
            }

            if(countByFrame == 1 && scoreByFrame == 10){ // 스트라이크 체크
                if((i+3) < downPins.size() -1){ // 마지막 투구 체크
                    leftScore =  downPins.get(i+2);
                    rightScore = downPins.get(i+3) == -1 ? 10 : downPins.get(i+3);
                    scoreByFrame += leftScore + rightScore;
                }
                scores.add(scoreByFrame);
                countByFrame = 0;
                scoreByFrame = 0;
                i++;
            }
            else if(countByFrame == 2){
                if(scoreByFrame == 10 && (i+1) != downPins.size() -1){ // 마지막 투구가 아니고 스페어면
                    leftScore = downPins.get(i+1);
                    scoreByFrame += leftScore;
                }
                scores.add(scoreByFrame);
                countByFrame = 0;
                scoreByFrame = 0;
            }
        }
        scores.add(downPins.get(20));
    }

    @Override
    public String toString() {
        return "선수 이름 : " + "'" + name + '\''
                + " 투구 당 쓰러트린 핀{" + getDownPins() + '}'
                + " 점수 = " +
                getScores().stream().mapToInt(Integer::intValue).sum() + '}';
    }
}

 

 

드디어 성공!

 

점수 계산기 테스트를 하며 여러 번 빨간 막대를 보았다. 연속된 빨간 막대 덕분에 과연 이걸 끝낼 수 있을까 의심되었지만

빨간 막대 덕분에 코드의 잘못된 부분을 알게 되었고, 스트라이크와 스페어 룰을 적용하여 점수를 계산할 수 있었다.

또한 단위 테스트를 통해 API를 검증하였다. (jUnit을  java API 사용법 테스트로 중간중간 활용하였다.)

단위 테스트는 Java의 기본 API가 될 수도 있고, 내가 만든 기능이 될수도 있다.

 

    @Test
    void 존재하지않는_인덱스일땐(){
        List<Integer> testList = new ArrayList<>();
        IndexOutOfBoundsException e
                = assertThrows(IndexOutOfBoundsException.class, () ->{
            testList.remove(20);
        });
        assertThat(e.getMessage()).isEqualTo("Index: 20, Size: 0");
    }

 

나의 경우에는 downPins라는 컬렉션의 사이즈를 지정하지 않아 점수를 계산할 때 OutIndexOutOfBoundsException가 발생했고,

그것을 해결하기 위해 볼링 객체에 생성자에 기본 사이즈를 지정해주었다.

 

    public Bowling(){
        this.pin = 10;
        this.pitchCount = 21;
        this.frame = 1;
        this.downPins = new ArrayList<>(21);
    }

 

점수 계산기를 통해 계산된 최종 점수는 아래 볼링 스코어 계산기 사이트를 통해 여러 번 검증하였다.

검증 도중에도 잘못된 최종 점수가 나와서 계속 수정을 하였다....

 

www.bowlinggenius.com/

 

Bowling Score Calculator

THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE

www.bowlinggenius.com

 

이제 점수 표출기를 통해 정말 볼링 점수 모니터를 통해 보는 것처럼 만들어보자!

처음 할 일 목록을 만들며 생각한 볼링게임 설계 단계에서는 

[] 볼링의 하위 객체로는 볼링 플레이어와 볼링 점수 계산기가 존재한다. (플레이어와 점수 계산기는 1 : 1 관계를 갖는다.)

위와 같이 생각하였지만 지금 와서 다시 생각해보니 볼링 플레이어는 볼링을 상속받고 있고, 볼링 플레이어는 scores라는

멤버 필드를 가져서 이것을 점수 표출기에 넘겨주면 그것을 볼링 점수 모니터처럼 콘솔에 뿌려주도록 할 것이다.

 

    @Test
    void 점수는_어떻게_쌓이고있나(){
        BowlingPlayer player1 = new BowlingPlayer("player1");
        while(player1.getPitchCount() > 0){
            player1.pitch();
        }
        System.out.println(player1.getScores());
    }
    
    
    
    console
    [7, 4, 9, 9, 8, 9, 18, 12, 7, 7, 0]
    [5, 9, 9, 6, 20, 20, 19, 9, 13, 9, 0]
    [19, 19, 20, 19, 9, 13, 3, 13, 4, 10, 2]

 

우선 다시 한번 단위 테스트를 진행하였다. scores에는 최종 점수를 계산하기 위해 프레임 별 계산된 점수를 저장해둔 List <Integer> 

멤버 변수이고 총 11번의 점수가 쌓이는 것을 확인하였다. 마지막 11번째의 인덱스는 마지막 21번째 투구이다.

음.. 앞에 점수를 계속해서 더해주며 점수를 보여주면 점수 표출기를 손쉽게 만들 수 있을 것 같다. 

 

    @Test
    void 점수계산기_테스트(){
        BowlingPlayer player1 = new BowlingPlayer("player1");
        BowlingPlayer player2 = new BowlingPlayer("player2");
        while(player1.getPitchCount() > 0){
            player1.pitch();
        }
        System.out.println(player1.toString());
        player1.printScore();
        System.out.println();
        System.out.println();

        player2.pitch();
        player2.pitch();
        player2.pitch();
        player2.pitch();
        player2.pitch();
        System.out.println(player2.toString());
        player2.printScore();
    }

 

package bowling;

public interface PrintScore {

    void printScore();

}

 

    @Override
    public void printScore() {
        int sum = 0;
        StringBuilder print = new StringBuilder("");
        int size = this.scores.size() == 11 ? 10 : this.scores.size();
        for (int i = 0; i < size; i++) {
            sum += this.scores.get(i);
            if(i == 9){
                sum += scores.get(i+1);
            }
            print.append(" | ").append(i + 1).append("Frame : ").append(sum).append(" | ");
        }
        System.out.println("--------------------------------------------------------------------------------------------------------------------------");
        System.out.println(print.toString());
        System.out.println("--------------------------------------------------------------------------------------------------------------------------");
    }

 

 

 

볼링게임 TDD를 진행하며 느낀 점

  • 아직 객체지향에 대한 이해가 부족하다.
  • 좀 더 작은 설계를 위한 능력이 부족하다.
  • 기획이 어렵다는 걸 알았다.
  • TDD 덕에 나아갈 수 있었다.
  • TDD에 대한 이해가 부족하다.

 

볼링게임 TDD는 여기서 마무리하겠습니다.

코드는 github.com/m3252github.com/m3252/study/tree/master/tdd/src/main/java/bowling 에 오시면 보실 수 있으며

코드는 앞으로 좀 더 수정할 예정이지만 블로그는 연재는 여기까지입니다. 감사합니다

 

댓글