볼링게임 TDD [3]
볼링게임 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);
}
점수 계산기를 통해 계산된 최종 점수는 아래 볼링 스코어 계산기 사이트를 통해 여러 번 검증하였다.
검증 도중에도 잘못된 최종 점수가 나와서 계속 수정을 하였다....
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 에 오시면 보실 수 있으며
코드는 앞으로 좀 더 수정할 예정이지만 블로그는 연재는 여기까지입니다. 감사합니다