Completed code:
public class Game
{
public int score()
{
return scoreForFrame(itsCurrentFrame);
}
public void add(int pins)
{
itsScorer.addThrow(pins);
adjustCurrentFrame(pins);
}
private void adjustCurrentFrame(int pins)
{
if (lastBallInFrame(pins))
advanceFrame();
else
firstThrowInFrame = false;
}
private boolean lastBallInFrame(int pins)
{
return strike(pins) || !firstThrowInFrame;
}
private boolean strike(int pins)
{
return (firstThrowInFrame && pins == 10);
}
private void advanceFrame()
{
itsCurrentFrame = Math.min(10, itsCurrentFrame + 1);
}
public int scoreForFrame(int theFrame)
{
return itsScorer.scoreForFrame(theFrame);
}
private int itsCurrentFrame = 0;
private boolean firstThrowInFrame = true;
private Scorer itsScorer = new Scorer();
}
public class Scorer
{
public void addThrow(int pins)
{
itsThrows[itsCurrentThrow++] = pins;
}
public int scoreForFrame(int theFrame)
{
ball = 0;
int score=0;
for (int currentFrame = 0;
currentFrame < theFrame;
currentFrame++)
{
if (strike())
{
score += 10 + nextTwoBallsForStrike();
ball++;
}
else if ( spare() )
{
score += 10 + nextBallForSpare();
ball+=2;
}
else
{
score += twoBallsInFrame();
ball+=2;
}
}
return score;
}
private boolean strike()
{
return itsThrows[ball] == 10;
}
private boolean spare()
{
return (itsThrows[ball] + itsThrows[ball+1]) == 10;
}
private int nextTwoBallsForStrike()
{
return itsThrows[ball+1] + itsThrows[ball+2];
}
private int nextBallForSpare()
{
return itsThrows[ball+2];
}
private int twoBallsInFrame()
{
return itsThrows[ball] + itsThrows[ball+1];
}
private int ball;
private int[] itsThrows = new int[21];
private int itsCurrentThrow = 0;
}
import junit.framework.*;
public class TestGame extends TestCase
{
public TestGame(String name)
{
super(name);
}
private Game g;
public void setUp()
{
g = new Game();
}
public void testTwoThrowsNoMark()
{
g.add(5);
g.add(4);
assertEquals(9, g.score());
}
public void testFourThrowsNoMark()
{
g.add(5);
g.add(4);
g.add(7);
g.add(2);
assertEquals(18, g.score());
assertEquals(9, g.scoreForFrame(1));
assertEquals(18, g.scoreForFrame(2));
}
public void testSimpleSpare()
{
g.add(3);
g.add(7);
g.add(3);
assertEquals(13, g.scoreForFrame(1));
}
public void testSimpleFrameAfterSpare()
{
g.add(3);
g.add(7);
g.add(3);
g.add(2);
assertEquals(13, g.scoreForFrame(1));
assertEquals(18, g.scoreForFrame(2));
assertEquals(18, g.score());
}
public void testSimpleStrike()
{
g.add(10);
g.add(3);
g.add(6);
assertEquals(19, g.scoreForFrame(1));
assertEquals(28, g.score());
}
public void testPerfectGame()
{
for (int i=0; i<12; i++)
{
g.add(10);
}
assertEquals(300, g.score());
}
public void testEndOfArray()
{
for (int i=0; i<9; i++)
{
g.add(0);
g.add(0);
}
g.add(2);
g.add(8); // 10th frame spare
g.add(10); // Strike in last position of array.
assertEquals(20, g.score());
}
public void testSampleGame()
{
g.add(1);
g.add(4);
g.add(4);
g.add(5);
g.add(6);
g.add(4);
g.add(5);
g.add(5);
g.add(10);
g.add(0);
g.add(1);
g.add(7);
g.add(3);
g.add(6);
g.add(4);
g.add(10);
g.add(2);
g.add(8);
g.add(6);
assertEquals(133, g.score());
}
public void testHeartBreak()
{
for (int i=0; i<11; i++)
g.add(10);
g.add(9);
assertEquals(299, g.score());
}
public void testTenthFrameSpare()
{
for (int i=0; i<9; i++)
g.add(10);
g.add(9);
g.add(1);
g.add(1);
assertEquals(270, g.score());
}
}