To make the first strike test pass, I changed the code like this:

    class Scorer
    {
        int bonusRolls = 0;
        int score = 0;
        int frame = 0;
    public:
        void AddFirstRoll            (int pins) { AddRoll(pins); }
        void AddSecondRollOfOpenFrame(int pins) { AddRoll(pins); ++frame; }
        void AddSpare(int pins)
        {
            score += pins;
            bonusRolls = 1;
            ++frame;
        }
        void AddStrike()
        {
            score += 10;
            bonusRolls = 2;
            ++frame;
        }
        int Score() const { return score; }
    private:
        void AddRoll(int pins)
        {
            if ((frame > 10) || ((frame == 10) && (bonusRolls == 0)))
                throw std::out_of_range("can't roll after game has ended");

            if (frame < 10)
                score += pins;
            if (bonusRolls == 1) {
                score += pins;
                bonusRolls = 0;
            }
            if (bonusRolls == 2) {
                score += pins;
                bonusRolls = 1;
            }
        }
    };

    struct WaitingForFirstRoll : public State
    {
        std::unique_ptr<State> Update(Scorer& scorer, int pins) const override
        {
            if (pins == 10) {
                scorer.AddStrike();
                return std::make_unique<WaitingForFirstRoll>();
            } else {
                scorer.AddFirstRoll(pins);
                return std::make_unique<WaitingForSecondRoll>(pins);
            }
        }
    };

The big change is to change the bool bonusRoll to int bonusRolls. And that worries me a little, as we now are hanging onto 3 ints in a row. Maybe I’ll change this to an enum, later.

I also added an AddStrike method to call from the WaitingForFirstRoll::Update method.

I’m going to do an optional refactoring that I like but I’m not sure if most people would like it, and that is to make the code look more tabular. The WaitingForFirstRoll::Update method comes out like this:

    struct WaitingForFirstRoll : public State
    {
        std::unique_ptr<State> Update(Scorer& scorer, int pins) const override
        {
            if (pins == 10) { scorer.AddStrike();        return std::make_unique<WaitingForFirstRoll >();     }
            else            { scorer.AddFirstRoll(pins); return std::make_unique<WaitingForSecondRoll>(pins); }
        }
    };

while the Scorer::AddRoll method comes out like this:

        void AddRoll(int pins)
        {
            if ((frame > 10) || ((frame == 10) && (bonusRolls == 0)))
                throw std::out_of_range("can't roll after game has ended");
            if (frame < 10)
                score += pins;
            if (bonusRolls == 1) { score += pins; bonusRolls = 0; }
            if (bonusRolls == 2) { score += pins; bonusRolls = 1; }
        }

Nothing further to refactor that I can see, so let’s write the next test. I know that two strikes in a row causes some overlapping bonus rolls, so let’s write that next, say 2 strikes, then a 1 and a 2.

After you’ve written that test, click next.