Spoiler - My ScoreFrames Solution w/ Couple of Bonus Tests

Not sure if will help assist anyone but I thought I’d share my heavily-annotated solution in just under 60 lines with comments removed. I think of myself as a pretty experienced game developer outside of Unity but I’ve honestly always struggled with coding a Bowling scorer, so this was a refreshing 3 hours!

Anyway, this solution is more or less a C# version of what I’d do in my head when totaling bowling scores. No fancy tricks here!

public static List<int> ScoreFrames(List<int> pinFalls) {
	// Track list of frame scores
	List<int> scores = new List<int>();

	// The current roll number
	int rollNumber = 1;
	// Temporary running total
	int runningTotal = 0;
	// Temporary bonus total
	int bonusTotal = 0;
	// Temporarily remember the previously "bonused" ball
	int lastScoredBall = 0;
	// Bonus balls (used for calculating strike/spare score)
	int bonusBalls = 0;

	// Loop through each pin fall count
	for (int i = 0; i < pinFalls.Count; i++) {
		// Extract total pins value to mimic foreach
		int total = pinFalls[i];

		if (bonusBalls > 0) {
			// This is a continuation of a bonus ball aggregation due to strikes/spares. Add this current ball to bonus total
			bonusTotal += total;

			// Decrease the bonus balls count
			bonusBalls--;

			// If there are no bonus balls left
			if (bonusBalls <= 0) {
				// Add score to bonus total
				scores.Add(bonusTotal);
				bonusTotal = 0;

				// Rewind back to lastScoredFrame
				i = lastScoredBall;
			}
		} else {
			// Begin normal scoring logic 

			// Increment running total
			runningTotal += total;

			// If is the final frame
			if (scores.Count >= 9) {
				// Only add score once we reach the final bowl
				// i.e. If last bowl, and 2nd roll or greater, and the first roll WASNT a strike
				if (i >= pinFalls.Count - 1 && rollNumber > 1 && !(pinFalls[i - 1] == 10 && rollNumber < 3)) {
					scores.Add(runningTotal);
				}

				// Not required but for consistency
				rollNumber++;
			} else if (rollNumber >= 2 || runningTotal >= 10) {
				// If is the second roll, or a strike/spare and is NOT the final frame
				if (runningTotal >= 10) {
					// If newly started strike/spare (First roll = strike, second roll = spare)
					// Note: Strikes count the next two balls worth of points, while spares count the next one
					bonusBalls = (rollNumber == 1) ? 2 : 1;
					bonusTotal = 10;
					lastScoredBall = i;

					// Reset the roll number and running total
					runningTotal = 0;
					rollNumber = 1;
				} else {
					// This is just a normal completed frame, add to running total and reset roll count
					scores.Add(runningTotal);
					lastScoredBall = i;
					runningTotal = 0;
					rollNumber = 1;
				}
			} else {
				// Normal roll, increment roll number
				rollNumber++;
			}
		}
	}

	if (scores.Count > 10) {
		throw new UnityException("Error, scores should not be beyond 10");
	}

	return scores;
}

I also added a few additional bonus tests that weren’t initially covered by my program:

[Test]
public void T22IncompleteLastFrame () {
	int[] rolls = { 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 3};
	int[] totals = {  2,   4,   6,   8,  10,  12,  14,  16,  18 };
	Assert.AreEqual (totals.ToList(), ScoreMaster.ScoreCumulative (rolls.ToList()));
}

[Test]
public void T23IncompleteLastFrameStrike () {
	int[] rolls = { 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 10, 5};
	int[] totals = {  2,   4,   6,   8,  10,  12,  14,  16,  18 };
	Assert.AreEqual (totals.ToList(), ScoreMaster.ScoreCumulative (rolls.ToList()));
}

[Test]
public void T24TenSpare () {
	int[] rolls = { 0, 10, 9, 0};
	int[] totals = {19, 28  };
	Assert.AreEqual (totals.ToList(), ScoreMaster.ScoreCumulative (rolls.ToList()));
}

Privacy & Terms