Spoiler - My n00by but somehow nice solution!

I was a total coding noob when I started the course, so passing this ‘Epic TDD challenge’ was super-rewarding to me… or at least it was until I watched Ben’s awesome solution! :cold_sweat:

If I had known about this, my life would have been much easier:

  • You can do ‘i+2’ for loops.
  • You can look ahead in a list.
  • You can get the length of a list.
    …but I didn’t realise any of that, and this was my final solution! :stuck_out_tongue:

The code checks whether a bowl is the first or the second one of a frame, and picks the correct action according to that:

  • Spare bonus points are stored in a variable, only on second bowl of a frame.
  • Strike bonus points are accumulated in a variable, only on first bowl of a frame.
  • Spares are scored on first bowl of the next frame.
  • Single-Strikes are scored on second bowl of the next frame (strike bonus points are equal to 10).
  • Multi-Strikes are scored on first bowl of a frame (strike bonus points are equal to 20).
  • Normal Score is added on second bowl, unless there are spare bonus points stored.

It takes way too many variables and most of the code is just handling those variables, but I might be holding some additional valuable info to show on the user interface, so I think I’m sticking to my solution for a while…

[Scroll to the right to see the comments]

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

public static class ScoreMaster
{
    private static List<int> frameList = new List<int>();

    private static int spareBonus = 0;
    private static int strikeBonus = 0;
    private static bool frame9Strike = false;

    private static int currentRoll = 0;
    private static int currentRollInFrame = 1;

    private static int frameScore = 0;

    private static void Reset()
    {
        frameList = new List<int>();

        spareBonus = 0;
        strikeBonus = 0;
        frame9Strike = false;

        currentRoll = 0;
        currentRollInFrame = 1;

        frameScore = 0;
    }

    /// Used in the ScoreFrames Function bellow
    private static void ScoreSpare() {
        if (spareBonus == 10) {
            frameList.Add(spareBonus + frameScore);
            spareBonus -= 10;
        }
    }

    private static void ScoreStrike(int threshold) {
        if (strikeBonus >= threshold) {
            frameList.Add(strikeBonus + frameScore);
            strikeBonus -= 10;
        }
    }


    // Returns List of Individual Frame Scores
    public static List<int> ScoreFrames(List<int> rolls)
    {
        Reset();
        foreach (int roll in rolls)
        {
            currentRoll++;
            frameScore += roll;

            if (currentRollInFrame == 1 || currentRoll >= 20)                           // FIRST BALL OF A FRAME + Balls 20-21
            {
                ScoreSpare();                                                           // Score Spare (Always on First Ball of a frame)
                ScoreStrike(20);                                                        // Score Multi-Strike (Always on First Ball of a frame)

                if (currentRoll == 20 && frame9Strike == true) {                        // SPECIAL CASE: BALL 20
                    ScoreStrike(10);                                                    // Score Frame 9 in case of a Strike
                }
                if (currentRoll == 21 || (currentRoll == 20 && frameScore < 10)) {      // SPECIAL CASE: LAST BALL
                    frameList.Add(frameScore);                                          // Always Submit Score
                }

                if (roll == 10 && currentRoll < 19) {                                   // STRIKE (Balls 1-18)
                    currentRoll++;                                                      // Skip the Second ball of the Frame
                    currentRollInFrame = 1;                                             // Reset to Start a New Frame
                    frameScore = 0;

                    strikeBonus += 10;                                                  // Remember Strike Bonus Points
                    if(currentRoll == 18) { frame9Strike = true; }                      // Condition for Ball 20 Special Case
                }
                else { currentRollInFrame++; }                                          // Next Ball will be The Second of the Frame (third in case of Ball 21)
            }

            else if (currentRollInFrame == 2 && currentRoll != 20)                      // SECOND BALL OF A FRAME (Ball 20 excluded)
            {
                ScoreStrike(10);                                                        // Score Normal Strike (Always on Second Ball of a frame)

                if (frameScore == 10) {                                                 // SPARE (Balls 1-18)
                    spareBonus += 10;                                                   // Remember Spare Bonus Points
                }

                if (spareBonus == 0) { frameList.Add(frameScore); }                     // Don't Score yet in case of a Spare, Score otherwise

                frameScore = 0;                                                         // Reset to Start a New Frame
                currentRollInFrame = 1;
            }
        }
        return frameList;
    }

    // Returns a List of Cumulative Scores like a Normal Score Card
    public static List<int> ScoreCumulative(List<int> rolls)
    {
        List<int> cumulativeScores = new List<int>();
        int runningTotal = 0;
        foreach (int frameScore in ScoreFrames(rolls))
        {
            runningTotal += frameScore;
            cumulativeScores.Add(runningTotal);
        }

        return cumulativeScores;
    }
}
3 Likes

Congratulations of the achievement, there’s nothing wrong with finding your own way and the fact that it’s different to Ben’s solution is ok to if the end result is that it’s working.

I quite often start with more variables or considerbaly longer code than is actually needed and that’s where refactoring comes in. If you can look at your code and find some obviosu duplication or area that lend themselves to be separated out into a separate method, that’s a good way to go, especially when, as you’ve stated you may be able to use that for something on the UI, e.g
more than one purpose.

Your Code is neat. You went a little overkill though.

Privacy & Terms