Bowling Game Kata in Ruby 62

Posted by Brett Schuchert Thu, 01 Oct 2009 18:37:00 GMT

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

Comments

Leave a response

  1. Avatar
    David Chelimsky about 1 hour later:

    describe “something” {} => ExampleGroup

  2. Avatar
    GBGames about 2 hours later:

    I don’t know Ruby, and therefore, RSpec, but now I know what the “it” keyword is. B-)

    My only concern is that the word “kata” is used when there is no form being followed. Uncle Bob’s Bowling kata is specifically in Java. You are trying to follow along with the spirit, but as you are not using the same language (the same form) and especially because you diverged in approach, it’s no longer a kata, right?

    It’s an exercise. It’s good for developing your skill as a programmer, but until there is a form you follow precisely and accurately, calling it a kata seems like a misnomer to me. I know in programming circles that there are plenty of things called katas that aren’t what I say they should be, but is this just something to accept, or should there be a push for katas to be things that a programmer should be able to follow step-by-step?

  3. Avatar
    Brett L. Schuchert about 3 hours later:

    Thanks David, too damn obvious for my knuckle head!

    GB, as for whether or not it is a kata, I think it is. I did practice it. I did work with many of the same tests that bob used. I took advantage of some of the tricks I’ve picked up from the bdd community (in this example, only a few).

    That I did not go with the same solution, I think, is good.

    In fact, I started with the same solution, then I tried changing it around. Then when I thought I could score complete and incomplete games correctly, I spent time looking at different ways to write things. I messed around with it.

    Kata is defined as “choreographed patterns of movements practiced either solo…” (according to wikipedia). Given that, I did use the bowling game example to practice using RSpec. I’ve done the bowling kata as bob does it in Java (and C# and I think I might have done it once in C++).

    So now the questions is this, to what, precisely, does the word kata apply? It is the practice of writing a test, getting it to pass, refactoring, or is the particular problem?

    I see your take on the word. I don’t hold the same definition. It’s quite possible my definition is wrong, but I’m going to stick to it until I’m convinced otherwise. FWIW, I’ve practiced forms in martial arts. In that case, the sequence of steps was the practice. So I grok the idea, I’m just not sure how direct I want to interpret the metaphor.

  4. Avatar
    David Vrensk 3 days later:

    Brett, I’m confused by the example “it should score a dutch-200, strike-spare, correctly”. It looks like you’re rolling 31 times (10*(2+1)+1). I’m not a bowler, but it looks to me like you are playing 21 frames which surely must be too much?

    Regarding the use of the word “kata”, I think it is correct. A programming kata is not the exakt same thing as a martial arts kata. In the latter, the point is to do the exact same thing every time, with total precision and focus. Ideally, if you’d superimpose two video recordings of a master performing a kata on two different days, you’d never know that there were two recordings. If we did a programming kata the same way, we’d strive to end up with the exact same code written in the exact same order and pace. I don’t think that would be useful (but I’m willing to be proven wrong).

    Instead, the programming kata (in my mind) borrows the purpose and confinements (if that’s the best word) from the martial arts kata. The purpose is to hone and perfect our basic moves (creating test cases/specs, doing the red-green-refactor dance, doing the simplest thing that works, etc). The confinements, as I see it, is that you should be able to perform the kata without external references. If you need to look up commands or regexp syntax or anything that a programmer at some level knows about the language, the kata is above your current level. And if you need to look up the rules for bowling scoring, you have not prepared for the kata. A kata is not a time to learn new things, but to practise and hone what you know.

  5. Avatar
    Philip Schwarz 3 days later:

    @Brett,

    thanks to your post I finally got round to trying a BDD tool.

    I took your specification, turned Ruby into Groovy, trivially turned RSpec syntax into easyb syntax, and then run it against the Java code I wrote some time ago for a Bowling Kata: the only behaviours that failed where the two dutch-200 ones, which I need to investigate, possibly in the light of what David Vrensk said in the previous comment.

    Here is the translated specification:

    def roll(int pins){ game.roll(pins) } 
    def roll_many(int pins, int rolls){ rolls.times{ game.roll(pins) } }
    def score_should_be(int score) { game.score().shouldBe(score) }
    
    before "Scores for Complete Games", { game = new Game() }
    
    it "should score 0 for an all gutter game",
    {
        roll_many(0,20)
        score_should_be 0
    }
    
    it "should show 20 for an all 1 game",
    {
        roll_many(1,20)
        score_should_be 20
    }
    
    it "should score game with single spare correctly",
    {
        roll_many(5,3)
        roll_many(0,17)
        score_should_be 20
    }
    
    it "should score game with single strike correctly",
    {
        roll 10
        roll 5
        roll 2
        roll_many(0, 17) 
        score_should_be 24   
    }
    
    it "should score a dutch-200, spare-strike, correctly",
    {
        [1..10].each{
          roll_many(5, 2)
          roll 10
        }
        roll_many(5, 2)
        score_should_be 200
    }
    
    it "should score a dutch-200, strike-spare, correctly",
    {
      [1..10].each
      {
        roll 10
        roll_many(5,2)
      }
      roll 10
      score_should_be 200
    }
    
    it "should score all 5's game as 150",
    {
      roll_many(5,21)
      score_should_be 150
    }
    
    it "should score a perfect game correctly",
    {
      roll_many(10,12)
      score_should_be 300
    }
    
    it "should not count a 0, 10 roll as a strike",
    {
      roll 0
      roll 10
      roll_many(1,18)
      score_should_be 29
     }
    
    before "Scoring for open games", { game = new Game() }
    
    it "should score just an open frame",
    {
      roll 4
      roll 3
      score_should_be 7
    }
    
    it "should score just a spare",
    {
      roll_many(5,2)
      score_should_be 10
    }
    
    it "should score partial game with spare and following frame only",
    {
      roll_many(5,3)
      score_should_be 20
    }
    
    it "should score an opening turkey correctly", 
    {
      roll_many(10,3)
      score_should_be 60
    }
    
    before "Scoring open game starting with a strike",
    {
      game = new Game()
      roll 10
    }
    
    it "should score partial game with only strike",
    {
      score_should_be 10
    }
    
    it "should score partial game with strike and half-open frame", 
    {
      roll 4
      score_should_be 18
    }
    
    it "should score partial game with strike and open frame",
    {
      roll 3
      roll 6
      score_should_be 28
    }
    
    it "should score partial game with strike and spare",
    { 
      roll 3
      roll 7
      score_should_be 30
    }      
    
    before "Open game starting with two Strikes",
    {
      game = new Game()
      roll 10
      roll 10
    }
    
    it "should have a score of 30",
    {
      score_should_be 30  
    }
    
    it "should score correctly with following non-mark",
    {
      roll 4
      score_should_be 42
    }
    
    it "should score correclty with third frame open",
    {
      roll 4
      roll 3
      score_should_be 48  
    }
    
  6. Avatar
    Brett L. Schuchert 4 days later:

    David Vrensk wrote:

    Brett, I’m confused by the example …

    Do’h! David, you are correct, I am rolling too many frames. It works because of the score method (and the fact that alternating spares or strikes will result in 200 and both approaches fill up the available score slots):

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

    I only score 10 frames, so the extra “crap” is ignored. In both of my dutch-200 games I should have 5.times …, not 10.

    I had not yet added negative cases:
    • Rolling over 10
    • Rolling over 10 in a single frame
    • Rolling too many frames
    • ...

    If I had added those (and I thought about it but didn’t do it), I would have caught those errors and never posted the 10.times.

    I’ll leave the errors in the blog, but I’ll fix my code by adding code to validate the input, those tests will fail, then I’ll fix the tests.

    Great example of why having a navigator is good.

  7. Avatar
    Brett L. Schuchert 4 days later:

    Philip Schwarz wrote:

    ...two dutch-200 ones, which I need to investigate, possibly in the light of what…
    Yep, as David mentioned, the examples are wrong. See post just above this one.

    And cool seeing easyb. Thanks for showing us that.

  8. Avatar
    Brett L. Schuchert 4 days later:
    Whew! That took a bit more than I expected. First, there was another error in one of the examples:
          it 'should score game with single strike correctly' do
                roll 10
                roll 5
                roll 2
                roll_many 17, 0
                score_should_be 24
            end

    Rolled one too many (17—> 16). Makes sense I supose.

    Next, I added several more negative examples than expected:
        describe '10th frame number of rolls allowed' do
            before(:each) do
                roll_many 18,0
            end
    
            it 'should fail with open 10th and additional roll' do
                roll_many 2, 0
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with spare 10th frame and 2 additional rolls' do
                roll_many 2, 5
                roll 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with strike, spare and 1 additional roll' do
                roll 10
                roll_many 2, 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with strike, strike and 2 additional rolls' do
                roll 10
                roll 10
                roll 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
        end
    
        describe 'Too many pins in a frame' do
            it 'should not allow more than 10 on a single roll' do
                lambda { roll 11 }.should raise_error(ArgumentError)
            end
    
            it 'should not allow more than 10 in two rolls' do
                roll 6
                lambda { roll 5 }.should raise_error(ArgumentError)
            end
        end
    Ultimately, I ended up with a bit of changed code (and one ugly method:
        def roll value
            verify value
            record value
        end
    
        def verify value
            raise IndexError, 'Too many rolls in game' if !should_allow_roll?
            raise ArgumentError, 'Too many pins rolled' if too_many_pins? value
        end
    
        def record value
            @rolls << value
            @rolls << 0 if first_throw_is_strike?
        end
    
        def too_many_pins? value
            (open_score_for current_frame) + value > 10
        end
    
        def current_frame
            (@rolls.length / 2) + 1
        end
    
        def should_allow_roll?
            max = 20
            max = 21 if is_spare_at? 10
            max = 22 if is_strike_at? 10
            max = 23 if is_strike_at? 11
            @rolls.length < max
        end

    As you can probably guess, the should_allow_roll? method is a bit cryptic. In addition to it being long and full of magic numbers, it also has the mythical 11th frame, which is a side-effect of not handling the 10th frame as special.

    On the other hand, the score card hides all of this, so before I say this is truly bad, I need to go back to uncle bob’s solution and add in the same negative examples and see how well it grows.

    Here is the full source of the results:

    bowling_score_card_spec.rb
    require 'spec_helper'
    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 16, 0
                score_should_be 24
            end
    
            it 'should score a dutch-200, spare-strike, correclty' do
                5.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
                5.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
    
        describe '10th frame number of rolls allowed' do
            before(:each) do
                roll_many 18,0
            end
    
            it 'should fail with open 10th and additional roll' do
                roll_many 2, 0
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with spare 10th frame and 2 additional rolls' do
                roll_many 2, 5
                roll 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with strike, spare and 1 additional roll' do
                roll 10
                roll_many 2, 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
    
            it 'should fail with strike, strike and 2 additional rolls' do
                roll 10
                roll 10
                roll 5
                lambda { roll 0 }.should raise_error(IndexError)
            end
        end
    
        describe 'Too many pins in a frame' do
            it 'should not allow more than 10 on a single roll' do
                lambda { roll 11 }.should raise_error(ArgumentError)
            end
    
            it 'should not allow more than 10 in two rolls' do
                roll 6
                lambda { roll 5 }.should raise_error(ArgumentError)
            end
        end
    end

    bowling_score_card.rb

    class BowlingScoreCard
        def initialize
            @rolls = []
        end
    
        def roll value
            verify value
            record value
        end
    
        def verify value
            raise IndexError, 'Too many rolls in game' if !should_allow_roll?
            raise ArgumentError, 'Too many pins rolled' if too_many_pins? value
        end
    
        def record value
            @rolls << value
            @rolls << 0 if first_throw_is_strike?
        end
    
        def too_many_pins? value
            (open_score_for current_frame) + value > 10
        end
    
        def current_frame
            (@rolls.length / 2) + 1
        end
    
        def should_allow_roll?
            max = 20
            max = 21 if is_spare_at? 10
            max = 22 if is_strike_at? 10
            max = 23 if is_strike_at? 11
            @rolls.length < max
        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_open_at? frame
            (open_score_for frame) < 10
        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 index_for frame
            (frame - 1) * 2
        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 score_at_throw index
            @rolls.length > index ? @rolls[index] : 0
        end
    end

    And finally, here’s the output from running spec at the command line (minus the coloring):

    BowlingScoreCard
    - should score 0
    
    BowlingScoreCard Scores for Complete Games
    - should score 0 for an all gutter game
    - should show 20 for an all 1 game
    - should score game with single spare correctly
    - should score game with single strike correctly
    - should score a dutch-200, spare-strike, correclty
    - should score a dutch-200, strike-spare, correctly
    - should score all 5's game as 150
    - should score a perfect game correctly
    - should not count a 0, 10 roll as a strike
    
    BowlingScoreCard Scoring for open games
    - should score just an open frame
    - should score just a spare
    - should score partial game with spare and following frame only
    - should score an opening turkey correctly
    
    BowlingScoreCard Scoring open game starting with a srike
    - should score partial game with only strike
    - should score partial game with strike and half-open frame
    - should score partial game with strike and open frame
    - should score partial game with strike and spare
    
    BowlingScoreCard Open game starting with two Strikes
    - should have a score of 30
    - should score correctly with following non-mark
    - should score correclty with third frame open
    
    BowlingScoreCard 10th frame number of rolls allowed
    - should fail with open 10th and additional roll
    - should fail with spare 10th frame and 2 additional rolls
    - should fail with strike, spare and 1 additional roll
    - should fail with strike, strike and 2 additional rolls
    
    BowlingScoreCard Too many pins in a frame
    - should not allow more than 10 on a single roll
    - should not allow more than 10 in two rolls
    
    Finished in 0.125306 seconds
    
    27 examples, 0 failures
    
  9. Avatar
    Games 8 months later:

    It works great. Thanks

  10. Avatar
    Games 8 months later:

    Works great

  11. Avatar
    Game Fair 9 months later:

    The access was actual c-esque. I didn’t like that basis all over the place, so I approved to abolish it by refactoring. It took several apocryphal starts afore I bit the ammo and artlessly bifold anniversary of the methods, one at a time, application alongside development. The old adaptation application an index, the new one use a 1-based anatomy number. Thank you so much for sharing details about game.

  12. Avatar
    Games Collection 10 months later:

    I started with a anatomy in the account adjustment as a bounded variable, but it bound got adapted to an index, and the basis was mostly anesthetized about afterward that. The access was actual c-esque. I didn’t like that basis all over the place, so I approved to abolish it by re-factoring.

  13. Avatar
    pass4sure 10 months later:

    Nice post.

  14. Avatar
    pass4sure dumps 10 months later:

    Thanks for sharing.

  15. Avatar
    cheap vps 11 months later:

    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. cheap VPS 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.

  16. Avatar
    Designer Bags about 1 year later:

    Good topic.Thanks for sharing! It really helpful to me about those information!!

  17. Avatar
    Harrishcolin about 1 year later:

    Thank you for this nice post

    my blogs : calories in food | how to put on a condom

  18. Avatar
    Harrishcolin about 1 year later:

    Thank you for this nice post

    my blogs : how to finger a girl | how to eat a girl out

  19. Avatar
    puma about 1 year later:

    If you mean to find great shoes for your children puma speed trainers also provides a mixture of finicky and affordable shoes for them. There are a lot of choices, it is up ring call,Ugg Boots, after by people that indigence an incredible quantity of column. This will make the customers happier. If you are often tangled in Singapore womens puma future cat shoes sale at Sainte Marie that could enhance operational efficiency, range visibility and turnaround time,” said Desmond Chan, managing boss, South Asia, Menlo Worldwide Logistics. “Our multi-client facility in Boon Lay Way provides puma trainers with different flag. puma uk’s youngest targets are toddlers. The puma for sale shoes are incredibly affordable, yet they still hold the grace. Wearing comfortable shoes will help children exploit better.

  20. Avatar
    [url=http://www.whiteiphone4transformer.com][/url] about 1 year later:

    white iphone 4 available now. It is the best news today.

  21. Avatar
    hublot replicas about 1 year later:

    and a small amount replica panerai watches amount of brain and doesn’t go directly armani sport watches directly through the whole brain is one Hermes scarf one case,” said

  22. Avatar
    iPhone SMS to Mac Backup about 1 year later:

    Thanks for shareing! I agree with you. The artical improve me so much! I will come here frequently. Would you like to banckup iphone SMS to mac, macBook, macbookPro as .txt files? Now a software iphone SMS to Mac Backup can help you to realize it.

  23. Avatar
    iPad to Mac Transfer about 1 year later:

    iPad to Mac Transfer can help you transfer music, movie, photo, ePub, PDF, Audiobook, Podcast and TV Show from ipad to mac freely.

  24. Avatar
    evaporator about 1 year later:

    Your site is amazing.I am very impressed to see this,i want to come back for visiting your site.Keep doing Good as well as you can.

  25. Avatar
    cable ties about 1 year later:

    Amazing post. Love the ideas.

  26. Avatar
    dswehfhh about 1 year later:

    We are the professional t-shirts manufacturer. t-shirts supplier. t-shirts factory, custom t-shirts.

  27. Avatar
    http://www.tiffanyandcooutlet.net/ about 1 year later:

    Almost any situation--good or bad --is affected by the attitude we bring to. Adversity reveals genius; fortune conceals it. As fruit needs not only sunshine but cold nights and chilling showers to ripen it, so character needs not only joy but trial and difficulty to mellow it. Although the world is full of suffering, it is full also of the overcoming of it. tiffany and co outlet

  28. Avatar
    Seobaglyak about 1 year later:

    Thank you for this nice post

  29. Avatar
    <a href="http://GameFlash.CA">Game Flash</a> about 1 year later:

    While searching for “flash game” on Google I found your blog, read your article, along with many concepts like you, I thank to you

  30. Avatar
    Game Flash about 1 year later:

    Game is an eternal theme that everyone likes. Thanks very much the blog, wish you good health to write better and more

  31. Avatar
    Baking games about 1 year later:

    Your blog has many interesting, nice words of thanks be sent to you

    Love game day

  32. Avatar
    <a href="http://games.mufasu.com/" rel="dofollow" >Games</a> about 1 year later:

    Thanks it’s very help me

  33. Avatar
    okey oyunu oyna about 1 year later:

    nice post.

    internette görüntülü olarak okey oyunu oyna, gerçek kisilerle tanis, turnuva heyecanini yasa.

  34. Avatar
    ford leveling kit about 1 year later:

    thanks for this blog,, nice ideas.

  35. Avatar
    leveling kit ford about 1 year later:

    oh so nice blog and good idea,, maybe you should visit on my website too.. thanks a lot.

  36. Avatar
    leveling kit f250 about 1 year later:

    i love the article so nice and very informative.

  37. Avatar
    f350 leveling kit about 1 year later:

    wow!!! amazing ideas.. i found your blogs in google and it is so awesome very useful and informative,, try to visit my website too. thanks a lot God bless :)

  38. Avatar
    real estate advertising about 1 year later:

    wow!!! amazing ideas.. i found your blogs in google and it is so awesome very useful and informative,, try to visit my website too. thanks a lot God bless :)

  39. Avatar
    mma news about 1 year later:

    hey, amazing blog with all the things i learn here.

  40. Avatar
    Best Phone Lookup about 1 year later:

    I visited this page first time and found it Very Good Job of acknowledgment and a marvelous source of info…......Thanks Admin!

  41. Avatar
    beats by dr dre headphones about 1 year later:

    For people that adore music, i suggest the monster powerbeats sport headphones to you, Just Beats Studio Purple has three color, red, whit and black. It is significant efficacy on this monster diddybeats in-ear headphones.

  42. Avatar
    Christian louboutin shoes on sale about 1 year later:

    What a wonderful article! And are doing well on the whole, but their work also has shortcomings.

  43. Avatar
    lose thigh about 1 year later:

    great ruby discussion…

  44. Avatar
    deadbeat millionaire about 1 year later:

    I visited this page first time and found it Very Good Job of acknowledgment and a marvelous source of info……...Thanks Admin!

  45. Avatar
    commission predators about 1 year later:

    What a wonderful article! And are doing well on the whole, but their work also has shortcomings.

  46. Avatar
    sales territory mapping about 1 year later:

    I didn’t know that this is possible in Ruby. I have to try this out.

  47. Avatar
    job description over 2 years later:

    Frequently Project Manager Job Description I am searching the great info is visible in Legal Secretary Job Description this blog and using the nice technology in this blog Medical Transcriptionist Job Description This is really superb info is visible in this blog and really great technology in this blog and using Paralegal Job Description the nice services in this blog

  48. Avatar
    Louboutins over 2 years later:

    asdas df+8s99s9sss

  49. Avatar
    moncler over 2 years later:

    asdfs d9gh8f7h7f74f444

  50. Avatar
    Christian over 2 years later:

    asas df+9s9s9sss

  51. Avatar
    Ashley Bowling over 2 years later:

    gooood article

  52. Avatar
    Orya Maqbool Jan Columns over 2 years later:

    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.

  53. Avatar
    iPhone contacts backup over 2 years later:

    If you hide it. will the code run very well? it is worth thinking twice.

  54. Avatar
    clarkreed over 2 years later:

    Thanks for the information, I’ll visit the site again to get update information online shopping

  55. Avatar
    bladeless fans over 3 years later:

    Bowling Game Kata in Ruby 54 good post61

  56. Avatar
    louboutin sales over 3 years later:

    Bowling Game Kata in Ruby 55 hoo,good article!!I like the post!176

  57. Avatar
    Injection mold over 3 years later:

    Intertech Machinery Inc. provides the most precise Plastic Injection Mold and Rubber Molds from Taiwan. With applying excellent unscrewing device in molds,

    Intertech is also very professional for making flip top Cap Molds in the world. Mold making is the core business of Intertech (Taiwan). With world level technology, Intertech enjoys a very good reputation for making Injection Mold and Plastic Molds for their worldwide customers.

  58. Avatar
    cheap mlb hats over 3 years later:

    This “average” report on the Wonderlic Analyze can be a Thirty, that is traditionally shown to characterize baseball hats the IQ of around Hundred. This kind of scores shows the exam taker might supply the correct solution for 20 of your 55 published multiple-choice concerns expected throughout the A dozen a matter of minutes helped. The particular hardest score in reported heritage involving test takers for the Football Merge at this point is assigned to original LSU cornerback and high level Next year Nba Draft potential customer Morris Claiborne, who seem to said to be have scored a new 5.

  59. Avatar
    game flash free over 3 years later:

    Thank’s U for this nice post for games.

    Thanks a gain.

  60. Avatar
    Cap Mold over 3 years later:

    With more than 20 years of experience, Intertech provides an extensive integrated operational ability from design to production of molds 100% made in Taiwan. Additional to our own mold making factory, we also cooperate with our team vendors to form a very strong working force in Taiwan.

    For the overseas market, we work very closely with local representatives in order to take care of the technical communication and after-sales service to our customers. We also participate in the EUROMOLD & FAKUMA exhibitions and meet our customers every year in Europe. By concentrating on mold “niche markets”, we play a very useful mold maker role from the Far East whenever customers want to develop their new projects. We provide services from A to Z to our customers on a very economic cost and effect basis.

  61. Avatar
    li wo over 3 years later:

    beats by dre headphone vivienne westwood Melissa chirstian louboutin sale michael kors outlet store vivienne westwood handbags

    michael kors outlet storeThe newly elected President of Egypt Morsy muhammad published the first speech since his victory over ahmed ShaFei g announced on Sunday night, vowed to “protect the international agreement and obligations”, this seems to be a reference of the peace treaty with Israel..chirstian louboutin outlet

    vivienne westwood melissa Morsy tried to appease those worried that he will take immediate action to change the whole Egypt, is expected to become the President all the egyptians, “muslims, christians, old people, children, women and men, farmers, teachers, workers, those engaged in the private and public sectors, the businessmen.”beats by dre headphone

    michael kors clearance bags Morsy welcome Obama’s support, the two leaders reaffirm their dedicated to advancing US-Egypt partnership, agreed to maintain close contact with the future of a few weeks, months, according to the statement. Christian Louboutin Daffodile 160mm Pumps

  62. Avatar
    fitflop over 3 years later:

    Thanks for sharing these items

Comments