Time for another BDD-session on my Yatzy program. I’ve been thinking a bit and it’s time to introduce the bonus. Short briefing here for the not so initiated. “If a player obtains or exceeds 63 points, a bonus of 35 points is added to the upper section score”. This should be enough for some new behaviour.

After considering a few implementations and some other things I add this test.

public void testShouldAddBonusToScoreIfUpperSectionExceedsOrEqualSixtyThree() throws Exception {
	game.addRollToUpperSection("Player", new int[] {1, 1, 1, 1, 1});
	game.addRollToUpperSection("Player", new int[] {5, 5, 5, 5, 5});
	game.addRollToUpperSection("Player", new int[] {6, 6, 6, 6, 6});
	assertThat(game.score("Player"), is.eq(5 + 25 + 36 + 15 + 35));
}

Note: New method addRollToUpperSection.

I toyed with the idea of adding an indication whether it’s upper or lower. I prefer the approach with another method instead. The existing method will probably change to another name. I’ll get back to that after this.

The testdata above will give me a score exceeding 63. They’re also valid Yatzy rolls too. In the future I might add tests for invalid rolls. Or maybe not. That’s a descision that’ll have to wait though. Being the disciplined programmer I am. I add the method and run the tests. UnsupportedOperationException. Great!

I was aiming to add another map to handle the upper section when I noted that getScoreForPlayer-method return rolls rather than scores. Taking a step back I comment out the newly added test. Rename the method, run the tests (GREEN) and comment back the newest test, run them again (RED). Back where I wanted to be.

Now: Adding a new map which will be used for upper section scores. This isn’t very OO-ish but it’ll do for now. Some pre-factoring of getRollsForPlayer is nescessary for this. The newly added test gets commented out again. After the refactoring the getRollsForPlayer looks like this.

 private List<int[]> getRollsForPlayer(String playerName, Map<String, List<int[]>> playerScores) {
	List<int[]> rolls = new ArrayList<int[]>();
	if (playerScores.containsKey(playerName)) {
		rolls = playerScores.get(playerName);
	}
	return rolls;
}

Implementing the addRollToUpperSection is a breeze.

public void addRollToUpperSection(String playerName, int[] roll) {
	List rolls = getRollsForPlayer(playerName, playerUpperScores);

	rolls.add(roll);
	playerUpperScores.put(playerName, rolls);
}

Will the tests run. Probably not but I’ll take my chances. Ctrl-F11. Nope. Red. <15> does not pass the constraint <eq(<116>)>.

Ah, the scores aren’t added from playerUpperScores. Back to the code. After a few minutes of coding and thinking I end up with a new score-method. Looking like this.

 public int score(String playerName) {
	List<int[]> rolls = getRollsForPlayer(playerName, playerScores);
	List<int[]> upperRolls = getRollsForPlayer(playerName, playerUpperScores);

	int score = 0;
	int upperScore = 0;
	int bonus = 0;

	score = getScoreForRolls(rolls, score);

	upperScore = getScoreForRolls(upperRolls, upperScore);
	if (upperScore >= 63) {
		bonus = 35;
	}

	return upperScore + score + bonus;
}

And a getScoreForRolls looking like this:

private int getScoreForRolls(List<int[]> rolls, int score) {
	for (int[] roll : rolls) {
		for (int i = 0; i < roll.length; i++) {
			score += roll[i];
		}
	}
	return score;
}

This should work. Nope. <75> does not pass the constraint <eq(<116>)>. Now what?! No bonus? A few minutes later when my brain starts to cool down I realize my mistake. Five times six != 36. It’s 30. Also 30 + 25 + 5 isn’t > 63. Damn testdata, damn myself. I bet this wouldn’t have happened with a PPP (pair programming partner). A few quick changes to the testdata. Ctrl-F11. GREEEEN! Yiahaaa! Time for lunch. Here’s the resulting code (after refactorings). Test and Implementation.

The implementation:

public class Game {

	private Map<String, List<int[]>> playerScores = new HashMap<String, List<int[]>>();

	private Map<String, List<int[]>> playerUpperScores = new HashMap<String, List<int[]>>();

	private final int bonusLimit = 63;

	private final int bonus = 35;

	public void addRollToUpperSection(String playerName, int[] roll) {
		List<int[]> rolls = getRollsForPlayer(playerName, playerUpperScores);

		rolls.add(roll);
		playerUpperScores.put(playerName, rolls);
	}

	public void addRollToLowerSection(String playerName, int[] roll) {
		List<int[]> rolls = getRollsForPlayer(playerName, playerScores);

		rolls.add(roll);
		playerScores.put(playerName, rolls);
	}

	public int score(String playerName) {
		List<int[]> rolls = getRollsForPlayer(playerName, playerScores);
		List<int[]> upperRolls = getRollsForPlayer(playerName, playerUpperScores);

		int upperScore = sumScoreFor(upperRolls);
		int score = sumScoreFor(rolls);

		if (bonusLimitReached(upperScore)) {
			upperScore += bonus;
		}

		return upperScore + score;
	}

	private boolean bonusLimitReached(int upperScore) {
		return upperScore >= bonusLimit;
	}

	private int sumScoreFor(List<int[]> rolls) {
		int score = 0;
		for (int[] roll : rolls) {
			for (int i = 0; i < roll.length; i++) {
				score += roll[i];
			}
		}
		return score;
	}

	private List<int[]> getRollsForPlayer(String playerName, Map<String, List<int[]>> playerScores) {
		List<int[]> rolls = new ArrayList<int[]>();
		if (playerScores.containsKey(playerName)) {
			rolls = playerScores.get(playerName);
		}
		return rolls;
	}

}

And test:

public class GameBehaviour extends RMockTestCase {

	private Game game;

	protected void setUp() throws Exception {
		game = new Game();
		addRoll(new int[] { 1, 2, 3, 4, 5 });
	}

	public void testShouldComputeScorePerPlayer() throws Exception {
		assertThat(game.score("Player"), is.eq(15));
		assertThat(game.score("AnotherPlayer"), is.eq(0));
	}

	public void testShouldComputeAllRollsForAGivenplayer() throws Exception {
		game.addRollToLowerSection("Player", new int[] { 1, 1, 1, 1, 1 });
		assertThat(game.score("Player"), is.eq(20));
	}

	public void testShouldAddBonusToScoreIfUpperSectionExceedsOrEqualSixtyThree() throws Exception {
		addRoll(new int[] { 2, 2, 2, 2, 2 });
		addRoll(new int[] { 5, 5, 5, 5, 5 });
		addRoll(new int[] { 6, 6, 6, 6, 6 });
		final int bonus = 35;
		assertThat(game.score("Player"), is.eq(10 + 25 + 30 + 15 + bonus));
	}

	private void addRoll(int[] roll) {
		game.addRollToUpperSection("Player", roll);
	}

}
Advertisements

About Ola Ellnestam

Agile Coach, Systems developer, Agile Practitioner and father of three.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s