Source: "Agile Software Development: Principles, Patterns, and Practices" by Robert C. Martin. Available at www.objectmentor.com/PPP.

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());
	}
}

This is an example from CSci 3601 course.

The views and opinions expressed in this page are strictly those of the page author. The contents of this page have not been reviewed or approved by the University of Minnesota.