C++ Bowling Kata Result 65

Posted by Brett Schuchert on 10/27/2009

I’m teaching a TDD and Refactoring class this week using C++. Since I had not recently wrote the bowling kata in C++, I figured it was about time to do it again.

Unlike the previous Scala version, this one only addresses the happy-path. I do not consider throwing too many balls or scoring too many pins in any frame. However, having just written this in Scala, I’m sure I could do something similar in C++.

I just switched to CppUTest 2.0 and something I noticed is that if you use <vector> or other std-based classes, you need to make sure to include those first before including <CppUTest/TestHarness.h>. This is because CppUTest overloads new and delete, which causes havoc with the std-based classes. No big deal, I just made sure to include that file as the last header (rather than the first, which is what I used to do).

Here are the various files:

RunAllTests.cpp

1
2
3
4
5
#include <CppUTest/CommandLineTestRunner.h>

int main(int argc, char** argv) {
  CommandLineTestRunner::RunAllTests(argc, argv);
}

BowlingScoreCardTest.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "BowlingScoreCard.h"

#include <CppUTest/TestHarness.h>

TEST_GROUP(BowlingScoreCard) {
  BowlingScoreCard* card;

  TEST_SETUP() {
    card = new BowlingScoreCard;
  }

  TEST_TEARDOWN() {
    delete card;
  }

  void throwOne(int value) {
      card->recordThrow(value);
  }

  void throwMany(int rolls, int value) {
    for(int i = 0; i < rolls; ++i)
      throwOne(value);
  }

  void confirmScoreIs(int expected) {
    LONGS_EQUAL(expected, card->score());
  }
};

TEST(BowlingScoreCard, noRollsGame) {
  confirmScoreIs(0);
}

TEST(BowlingScoreCard, throwAll0s) {
  throwMany(20, 0);
  confirmScoreIs(0);
}

TEST(BowlingScoreCard, throwAll1s) {
  throwMany(20, 1);
  confirmScoreIs(20);
}

TEST(BowlingScoreCard, throwOneSpare) {
  throwOne(7);
  throwOne(3);
  throwOne(6);
  throwMany(17, 0);
  confirmScoreIs(22);
}

TEST(BowlingScoreCard, all5sthrown) {
  throwMany(21, 5);
  confirmScoreIs(150);
}

TEST(BowlingScoreCard, throwOneStrike) {
  throwOne(10);
  throwOne(4);
  throwOne(3);
  confirmScoreIs(24);
}

TEST(BowlingScoreCard, perfectGame) {
  throwMany(12, 10);
  confirmScoreIs(300);
}

TEST(BowlingScoreCard, dutch200StrikeSpare) {
  for(int i = 0; i < 10; ++i) {
    throwOne(10);
    throwMany(2, 5);
  }
  throwOne(10);
  confirmScoreIs(200);
}

TEST(BowlingScoreCard, dutch200SpareStrike) {
  for(int i = 0; i < 10; ++i) {
    throwMany(2, 5);
    throwOne(10);
  }
  throwMany(2, 5);
  confirmScoreIs(200);
}

BowlingScoreCard.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#pragma once

#ifndef BOWLING_SCORE_CARD_H
#define BOWLING_SCORE_CARD_H

#include <vector>
using namespace std;

class BowlingScoreCard
{
public:
  enum { Frames = 10, Mark = 10 };

  BowlingScoreCard();
  virtual ~BowlingScoreCard();
  int score();
  void recordThrow(int roll);

private:
  typedef vector<int> v_int;
  typedef v_int::size_type size_type;

  int scoreFrameAt(size_type index);
  int nextTwoRollsSummed(size_type index);
  int scoreAt(size_type index);
  int frameSizeAt(size_type index);
  bool isStrikeAt(size_type index);
  bool isSpareAt(size_type index);
  int scoreStrikeAt(size_type index);
  int scoreSpareAt(size_type index);

  v_int rolls;
};

#endif

BowlingScoreCard.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "BowlingScoreCard.h"

BowlingScoreCard::BowlingScoreCard() {
}

BowlingScoreCard::~BowlingScoreCard() {
}

int BowlingScoreCard::score() {
  int score = 0;

  for(int index = 0, frame = 0; frame < Frames; ++frame) {
    score += scoreFrameAt(index);
    index += frameSizeAt(index);
  }

  return score;
}

int BowlingScoreCard::scoreFrameAt(size_type index) {
  if(isStrikeAt(index))
    return scoreStrikeAt(index);
  else if(isSpareAt(index))
    return scoreSpareAt(index);

  return nextTwoRollsSummed(index);
}

bool BowlingScoreCard::isStrikeAt(size_type index) {
  return scoreAt(index) == Mark;
}

bool BowlingScoreCard::isSpareAt(size_type index) {
  return !isStrikeAt(index) && nextTwoRollsSummed(index) == Mark;
}

int BowlingScoreCard::scoreStrikeAt(size_type index) {
  return Mark + nextTwoRollsSummed(index + 1);
}

int BowlingScoreCard::scoreSpareAt(size_type index) {
  return Mark + scoreAt(index + 2);
}

int BowlingScoreCard::frameSizeAt(size_type index) {
  if(scoreAt(index) == Mark)
    return 1;
  return 2;
}

int BowlingScoreCard::nextTwoRollsSummed(size_type index) {
  return scoreAt(index) + scoreAt(index + 1);
}

int BowlingScoreCard::scoreAt(size_type index) {
  return index < rolls.size() ? rolls[index] : 0;
}

void BowlingScoreCard::recordThrow(int roll) {
  rolls.push_back(roll);
}

I sure do miss refactoring tools!-)

Scala Bowling Kata - still in the middle I suppose 79

Posted by Brett Schuchert on 10/7/2009

I had a 3.5 hour flight today. I realized I was missing some of the validation from the Ruby version related to how many rolls a valid game should allow:
  "One more roll on a game with 20 rolls and an open 10th frame" should {
    20 times { roll(1) }
    roll(1) must throwA[IllegalArgumentException]
  }

  "Two more rolls a game with 10 spares" should {
    10 times { spare }
    roll(1)
    roll(1) must throwA[IllegalArgumentException]
  }

  "Two marks in the 10th frame should" should {
    18 times { roll(1) }
    strike
    spare
    roll(1) must throwA[IllegalArgumentException]
  }

On my flight from DFW to SNA, I got these behaviors implemented. The code was pretty ugly!

However, ugly code in hand, passing examples, a slight understanding of some of the problems with my code and a desire to make the BowlingScorer immutable was all I needed to make progress.

I removed the index instance field by rewriting the score method and injecting a tuple into foldLeft (written here using the short-hand notation /:):
  def scoreAt(frame:Int) = 
    ((0,0) /: (1 to frame)) { (t, _) =>  
      (t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
    }._1
I had a mini state machine to track whether the first ball had been thrown yet or not. I replaced that by walking the list of scores:
  def onFirstThrow = {
    var index = 0
    while(index < rolls.length)
      if(isStrike(index)) index += 1 else index += 2
    index == rolls.length
  }

While I am happy I was able to remove the index variable, which was really a parameter being passed around in a field (ugly), I am not happy with this method.

I changed the roll method to return a new instance of a BowlingScorer, making the bowling scorer immutable:
  def roll(roll:Int) = {
    validate(roll)
    new BowlingScorer(rolls ++ Array(roll))
  }

So I think I’m still somewhere in the middle of working through this code. Again, I’m still learning Scala. I have a lot to learn. I really only barely understand functional programming and, frankly, the Eclipse IDE, while functional, is getting in the way quite a bit. So for a toy example it is OK. Given the choice of this environment or vi and the command line, I’d not pick the former. (I might give the other IDE’s a go, but that’s not really what I’m interested in learning right now.)

So here’s the next version. I plan to work through all of the comments I’ve yet to process from the previous blog posting over the next few days. If you can recommend a better implementation of onFirstThrow, I’d appreciate it.

Other general comments also welcome.

BowlingScorerExampleGroup.scala

package com.om.example

import org.specs._

object BowlingScorerExampleGroup extends SpecificationWithJUnit {
  var scorer = new BowlingScorer(Nil);

  def roll(value:Int) =
    scorer = scorer.roll(value) 

  def haveAScoreOf(expected:Int) =
    scorer.score must_== expected

  def strike =
    roll(10)

  def spare {
    roll(5)
    roll(5)
  }

  implicit def intToDo(count: Int) = {
    new {
      def times(f: => Unit) = {
        1 to count foreach { _ => f }
      }
    }
  }

  "A Newly Created Bowling Scorer" should {
    haveAScoreOf(0)
  }

  "A game with all 0's" should {
    20 times { roll(0) }
    haveAScoreOf(0)
  }

  "A game with all 1's" should {
    20 times { roll(1) }
    haveAScoreOf(20)
  }

  "A game with a single spare followed by a 5" should {
    spare
    roll(5)
    haveAScoreOf(20)
  }

  "A game with all 5's" should {
    10 times { spare }
    roll(5)
    haveAScoreOf(150)
  }

  "A game with a single strike followed by a 4" should {
    strike
    roll(4)
    haveAScoreOf(18)
  }

  "A game with a strike, spare then an open frame with two 3's" should {
    strike
    spare
    2 times { roll(3) }
    haveAScoreOf(39)
  }

  "A game with strike, spare then an open frame with two 3's" should {
    spare
    strike
    2 times { roll(3) }
    haveAScoreOf(42)
  }

  "A Dutch 200 game, Spare-Strike" should {
    5 times {
      spare 
      strike
    }
    spare
    haveAScoreOf(200)
  }

  "A Dutch 200 game, Strike-Spare" should {
    5 times {
      strike
      spare 
    }
    strike
    haveAScoreOf(200)
  } 

  "A Perfect game" should {
    12 times { strike }
    haveAScoreOf(300)
  }

  "The score for each frame of a Perfect game, each frame" should {
    12 times { strike }
    1 to 10 foreach { frame => scorer.scoreAt(frame) must_== 30 * frame }
  }

  "An individaul roll of > 10" should {
    roll(11) must throwA[IllegalArgumentException]
  }

  "An iniviaul roll of < 0" should {
    roll(-1) must throwA[IllegalArgumentException]
  }

  "A frame trying to contain more than 10 pins" should {
    roll(8)
    roll(3) must throwA[IllegalArgumentException]
  }

  "One more roll on a game with 20 rolls and an open 10th frame" should {
    20 times { roll(1) }
    roll(1) must throwA[IllegalArgumentException]
  }

  "Two more rolls a game with 10 spares" should {
    10 times { spare }
    roll(1)
    roll(1) must throwA[IllegalArgumentException]
  }

  "Two marks in the 10th frame should" should {
    18 times { roll(1) }
    strike
    spare
    roll(1) must throwA[IllegalArgumentException]
  }
}

BowlingScorer.scala

package com.om.example

class BowlingScorer(rollsSoFar:List[Int]){
   val rolls:List[Int] = rollsSoFar

  def roll(roll:Int) = {
    validate(roll)
    new BowlingScorer(rolls ++ Array(roll))
  }

  def validate(roll:Int) {
    if(invalidRoll(roll))
      throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")

    if(frameRollTooHigh(roll))
      throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");

    if(willBeTooManyRolls)
      throw new IllegalArgumentException("Game over, no more rolls allowed")
  }

  def invalidRoll(roll:Int) = 
    (0 to 10 contains(roll)) == false  

  def frameRollTooHigh(roll:Int) =
    openScoreAt(indexToValidate) + roll > 10

  def willBeTooManyRolls = 
    tenthRolled(indexOf10thFrame) && nextRollTooMany(indexOf10thFrame)

  def tenthRolled(tenthIndex:Int) = 
    tenthIndex < rolls.length

  def nextRollTooMany(tenthIndex: Int) = 
    allowedTenthFrameRolls(tenthIndex) < rollsInTenthFrame(tenthIndex) + 1

  def indexOf10thFrame = 
    (0 /: (1 until 10)) {(c, _) => c + incrementAt(c)}

  def allowedTenthFrameRolls(index:Int) =
    if(isMark(index)) 3 else 2

  def rollsInTenthFrame(index: Int) =
    rolls.length - index

  def indexToValidate =
    if(onFirstThrow) rolls.length else rolls.length - 1

  def onFirstThrow = {
    var index = 0
    while(index < rolls.length)
      if(isStrike(index)) index += 1 else index += 2
    index == rolls.length
  }

  def scoreAt(frame:Int) = 
    ((0,0) /: (1 to frame)) { (t, _) =>  
      (t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
    }._1

  def score = scoreAt(10)

  def scoreAtIndex(index:Int) =
    if(isMark(index)) markScoreAt(index) else openScoreAt(index)

  def incrementAt(index:Int) =
    if(isStrike(index)) 1 else 2

  def isMark(index:Int) =
    isStrike(index) || isSpare(index)

  def isStrike(index:Int) =
    valueAt(index) == 10

  def markScoreAt(index:Int) =
    sumNext(index, 3)

  def isSpare(index:Int) =
    openScoreAt(index) == 10 && valueAt(index) != 10

  def openScoreAt(index:Int) =
    sumNext(index, 2)

  def sumNext(index:Int, count:Int) =
    (0 /: (index until index+count))(_ + valueAt(_))

  def valueAt(index:Int) = 
    if(rolls.length > index) rolls(index) else 0
}

Scala Bowling Kata - somewhere in the middle... 44

Posted by Brett Schuchert on 10/6/2009

I need to do some work with Scala to update our Concurrency in Java class. We want to demonstrate some other approaches to concurrency, e.g., Scala Actors (among others). I began by shaving yaks:
  • Installed the Eclipse Scala Plugin
  • Installed Scala using Mac Ports
  • Figured out how to get those things playing nice (the plugin page pretty much did that, but in a nutshell, add a few jar files to the classpath)
Next, I wanted to use some BDD tool. I’m going to try and stop using the term TDD simply because the T, which stands for Test in TDD, really means “desired behavior”. I considered calling it Trait Driven Development, but:
  • We don’t need YADT – Yet another damn term
  • Trait is a heavily overloaded word
  • I like the term BDD better and it fits.

Anyway, one such choice was Specs, which is what I decided to use.

So back to yak shaving:
  • I added another jar to my classpath in Eclipse
  • Then read how to get it running in Eclipse. Not too bad, I suppose.

So now I need to learn Scala. Sure, I’ve used it, but far less than Ruby. So it took me several hours to get specs running along with writing some Scala code to score a game – I’m glad I know the domain at least.

I wanted to make similar behaviors to the ones I wrote for the Ruby version, which I did.

However, unlike the Ruby version, I was curious what would happen if I:
  • Took an approach similar to Uncle Bob – strikes take one slot in an array
  • Added input validation

On the one hand, there are some interesting things I managed to create. On the other hand, I’ve got a bit of a mess. I have a stateful object to avoid passing parameters so that I can write some of the code cleanly. I know I need to add in an intermediate computational object, and I’m going to get to that. However, I wanted to get feedback on what I’ve put out there so far.

Specifically,
  • What do you think of the (bdd-style) examples from specc?
  • What is the correct way to write the Times(20).Do( ...) thing I came up with, there has be a better way?
  • For the part of the bowling scoring code that is not stateful (read this as, does not violate the SRP), what do you think of it?
  • How would you remove most/all of the state (other than the individual rolls) out of the Bowling scorer class? (Or would you choose to have the roll() method return a new instance of BowlingScorer with the new score recorded?)
  • Notice that the class maintains a mini state machine in the form of tracking whether the first ball of he current frame (not tracked) has or has not been thrown. That’s only there to be able to perform input validation. I considered:
    • Walking the array
    • Going to 2 slots for every frame (making it easy to find the frame)
    • Storing a frame object (ok, I didn’t really consider it, but I did think about it)
    • The mini state machine
  • nextFrameScore uses the index instance variable, and changes it. This both violates command-query separation and demonstrates a violation of the SRP, but it made the scoreAt method look nice.

An interesting side effect is that scoring marks (strikes and spares) uses the same approach, sum up three rolls total.

I know this needs work. What I’ve got works according to its current specification (its examples), so in a sense, that’s a good thing because I’ve already stared experimenting with trying out different solutions. However, I am painfully aware of how unaware I am of Scala at the moment, so your (hopefully gentle) feedback will tell me what I need to learn next.

Looking forward to the virtual beating …

Brett

Here are the two files I’ve created so far (and to be clear, all of the examples pass):

BowlingScorerExampleGroup.scala
package com.om.example

import org.specs._

object BowlingScorerExampleGroup extends SpecificationWithJUnit {
  var scorer = new BowlingScorer();

  def roll(value:Int) {
    scorer.roll(value) 
  }

  def rollMany(rolls:Int, value:Int) {
    0.until(rolls).foreach { arg => scorer.roll(value) }
  }

  def haveAScoreOf(expected:Int) {
    scorer.score must_== expected
  }

  def strike {
    roll(10)
  }

  def spare {
    rollMany(2, 5) 
  }

  abstract class IDo {
    def Do(block: => Unit) 
  }

  def Times(count:Int): IDo = {
    return new IDo {
      def Do(block: => Unit) {
        1.to(count).foreach( arg => block )
      }
    }
  }

  "A Newly Created Bowling Scorer" should {
    haveAScoreOf(0)
  }

  "A game with all 0's" should {
    Times(20).Do( roll(0) )
    haveAScoreOf(0)
  }

  "A game with all 1's" should {
    Times(20).Do { roll(1) }
    haveAScoreOf(20)
  }

  "A game with a single spare followed by a 5" should {
    spare
    roll(5)
    haveAScoreOf(20)
  }

  "A game with all 5's" should {
    Times(10).Do( spare ) 
    roll(5)
    haveAScoreOf(150)
  }

  "A game with a single strike followed by a 4" should {
    strike
    roll(4)
    haveAScoreOf(18)
  }

  "A game with a strike, spare then an open frame with two 3's" should {
    strike
    spare
    Times(2).Do( roll(3) )
    haveAScoreOf(39)
  }

  "A game with strike, spare then an open frame with two 3's" should {
    spare
    strike
    Times(2).Do( roll(3) )
    haveAScoreOf(42)
  }

  "A Dutch 200 game, Spare-Strike" should {
    Times(5).Do { 
      spare 
      strike
    }
    spare
    haveAScoreOf(200)
  }

  "A Dutch 200 game, Strike-Spare" should {
    Times(5).Do { 
      strike
      spare 
    }
    strike
    haveAScoreOf(200)
  } 

  "A Perfect game" should {
    Times(12).Do( strike ) 
    haveAScoreOf(300)
  }

  "The score for each frame of a Perfect game, each frame" should {
    Times(12).Do( strike ) 
    1.to(10).foreach{ frame => scorer.scoreAt(frame) must_== 30 * frame }
  }

  "An individaul roll of > 10" should {
    roll(11) must throwA[IllegalArgumentException]
  }

  "An iniviaul roll of < 0" should {
    roll(-1) must throwA[IllegalArgumentException]
  }

  "A frame trying to contain more than 10 pins" should {
    roll(8)
    roll(3) must throwA[IllegalArgumentException]
  }
}

BowlingScorer.scala

package com.om.example

class BowlingScorer {
  var rolls:Array[Int] = Array()
  var index:Int = 0
  var firstBallInFrameThrown: Boolean = false;

  def roll(roll:Int) = {
    validate(roll)
    record(roll)
  }

  def validate(roll:Int) {
    if((0).to(10).contains(roll) == false)
      throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")

    if(openScoreAt(indexToValidate) + roll > 10)
      throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");
  }

  def record(roll: Int) {
    rolls = rolls ++ Array(roll)
    firstBallInFrameThrown = firstBallInFrameThrown == false && roll != 10
  }

  def indexToValidate = {
    if(firstBallInFrameThrown) rolls.length - 1 else rolls.length
  }

  def scoreAt(frame:Int) = {
    1.to(frame).foldLeft(0) { (total, frame) =>  total + nextFrameScore  }
  }

  def score = {
    scoreAt(10)
  }

  def nextFrameScore = {
    var result = 0;
    if(isStrike(index)) {
      result += markScoreAt(index)
      index += 1
    } else if(isSpare(index)) {
      result += markScoreAt(index);
      index += 2
    } else {
      result += openScoreAt(index);
      index += 2
    }
    result
  }

  def isStrike(index:Int) = {
    valueAt(index) == 10
  }

  def markScoreAt(index:Int) = {
    sumNext(index, 3)
  }

  def isSpare(index:Int) = {
    openScoreAt(index) == 10
  }

  def openScoreAt(index:Int) = {
    sumNext(index, 2)
  }

  def sumNext(index:Int, count:Int) = {
    index.until(index+count).foldLeft(0)(_ + valueAt(_))
  }

  def valueAt(index:Int) = {
    if(rolls.length > index) rolls.apply(index) else 0
  }
}

Bowling Game Kata in Ruby 57

Posted by Brett Schuchert on 10/1/2009

I have not really used Ruby much. I’ve written a few tutorials, messed around with RSpec and Test::Unit and even Rails a bit, but I really don’t know Ruby that well. I get Ruby (the MOP, instances, blocks, open classes, ...) but there’s a difference between understanding that stuff and using it day-to-day.

Last night we had a Dojo in Oklahoma City and I wanted to get refreshed with RSpec, so I decided to jump in and do the bowling game kata. I did not follow uncle bob’s lead exactly. For one, I went ahead and stored two throws for each frame. While what he ends up with is a bit shorter, it bothers me a little bit. I’ve also seen people surprised by how bob stores his scores, so in a sense it violates the law of least astonishment.

That’s neither here nor there, I got it working just fine – though handling strikes was a bit more difficult because I decided to store two rolls instead of one (so clearly, there’s no best answer, just ones that suck for different reasons).

After my first go around, I had a single spec with examples all under a single describe (what’s that term they’d use for what the describe expression creates?). I added several examples for partial scores, to make sure I was handling incomplete games correctly. I restructured those a bit and tried to make the names a bit more clear, not sure if I was successful.

In my original version I started with a frame in the score method as a local variable, but it quickly got converted to an index, and the index was mostly passed around after that. The approach was very c-esque. I didn’t like that index all over the place, so I tried to remove it by refactoring. It took several false starts before I bit the bullet and simply duplicated each of the methods, one at a time, using parallel development. The old version using an index, the new one use a 1-based frame number. After I got that working with frames, I removed most of the methods using an index, except for a few.

What follows is the spec file and the ruby class. If you read the names of some of the examples, you might think I used to bowl in league, I did. My average was a paltry 158, my best game ever a 248. Best split I ever picked up? 4, 6, 7, 10.

Comments welcome.

bowling_score_card_spec.rb

require 'bowling_score_card'

describe BowlingScoreCard do
    before(:each) do
        @bowling_game_scorer = BowlingScoreCard.new
    end

    def roll value
        @bowling_game_scorer.roll value
    end

    def roll_many count, value
        count.times { roll value }
    end

    def score_should_be value
        @bowling_game_scorer.score.should == value
    end

    it 'should score 0' do
        score_should_be 0
    end

    describe 'Scores for Complete Games' do
        it 'should score 0 for an all gutter game' do
            roll_many 20, 0
            score_should_be 0
        end

        it 'should show 20 for an all 1 game' do
            roll_many 20, 1
            score_should_be 20
        end

        it 'should score game with single spare correctly' do
            roll_many 3, 5
            roll_many 17, 0
            score_should_be 20
        end

        it 'should score game with single strike correctly' do
            roll 10
            roll 5
            roll 2
            roll_many 17, 0
            score_should_be 24
        end

        it 'should score a dutch-200, spare-strike, correclty' do
            10.times do
                roll_many 2, 5
                roll 10
            end
            roll_many 2, 5

            score_should_be 200
        end

        it 'should score a dutch-200, strike-spare, correctly' do
            10.times do
                roll 10
                roll_many 2, 5
            end
            roll 10
            score_should_be 200
        end

        it "should score all 5's game as 150" do
            roll_many 21, 5
            score_should_be 150
        end

        it 'should score a perfect game correctly' do
            roll_many 12, 10
            score_should_be 300
        end

        it 'should not count a 0, 10 roll as a strike' do
            roll 0
            roll 10
            roll_many 18, 1
            score_should_be 29
        end

    end

    describe 'Scoring for open games' do
        it 'should score just an open frame' do
            roll 4
            roll 3
            score_should_be 7
        end

        it 'should score just a spare' do
            roll_many 2, 5
            score_should_be 10
        end

        it 'should score partial game with spare and following frame only' do
            roll_many 3, 5
            score_should_be 20
        end

        it 'should score an opening turkey correctly' do
            roll_many 3, 10
            score_should_be 60
        end
    end

    describe 'Scoring open game starting with a srike' do
        before(:each) do
            roll 10
        end
        it 'should score partial game with only strike' do
            score_should_be 10
        end

        it 'should score partial game with strike and half-open frame' do
            roll 4
            score_should_be 18
        end

        it 'should score partial game with strike and open frame' do
            roll 3
            roll 6
            score_should_be 28
        end

        it 'should score partial game with strike and spare' do
            roll 3
            roll 7
            score_should_be 30
        end
    end

    describe 'Open game starting with two Strikes' do
        before(:each) do
            roll 10
            roll 10
        end

        it 'should have a score of 30' do
            score_should_be 30
        end

        it 'should score correctly with following non-mark' do
            roll 4
            score_should_be 42
        end

        it 'should score correclty with third frame open' do
            roll 4
            roll 3
            score_should_be 48
        end
    end
end

bowling_score_card.rb

class BowlingScoreCard
    def initialize
        @rolls = []
    end

    def roll value
        @rolls << value
        @rolls << 0 if first_throw_is_strike?
    end

    def score
        (1..10).inject(0) { |score, frame| score += score_for frame }
    end

    def score_for frame
        return strike_score_for frame if is_strike_at? frame
        return spare_score_for frame if is_spare_at? frame
        open_score_for frame
    end

    def first_throw_is_strike?
        is_first_throw_in_frame? && @rolls.last == 10
    end

    def is_first_throw_in_frame?
        @rolls.length.odd?
    end

    def open_score_for frame
        first_throw_for(frame) + second_throw_for(frame);
    end

    def spare_score_for frame
        open_score_for(frame) + first_throw_for(next_frame(frame))
    end

    def strike_score_for frame
        score = open_score_for(frame) + open_score_for(next_frame(frame))
        if is_strike_at? next_frame(frame)
            score += first_throw_for(next_frame(next_frame(frame)))
        end
        score
    end

    def next_frame frame
        frame + 1
    end

    def is_spare_at? frame
        (open_score_for frame) == 10 && is_strike_at?(frame) == false
    end

    def is_strike_at? frame
        first_throw_for(frame) == 10
    end

    def first_throw_for frame
        score_at_throw(index_for(frame))
    end

    def second_throw_for frame
        score_at_throw(index_for(frame) + 1)
    end

    def index_for frame
        (frame - 1) * 2
    end

    def score_at_throw index
        @rolls.length > index ? @rolls[index] : 0
    end
end